summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--drivers/net/wireless/sd8797/Makefile474
-rw-r--r--drivers/net/wireless/sd8797/mlan/mlan.h35
-rw-r--r--drivers/net/wireless/sd8797/mlan/mlan_11d.c1514
-rw-r--r--drivers/net/wireless/sd8797/mlan/mlan_11h.c3180
-rw-r--r--drivers/net/wireless/sd8797/mlan/mlan_11h.h158
-rw-r--r--drivers/net/wireless/sd8797/mlan/mlan_11n.c1937
-rw-r--r--drivers/net/wireless/sd8797/mlan/mlan_11n.h420
-rw-r--r--drivers/net/wireless/sd8797/mlan/mlan_11n_aggr.c508
-rw-r--r--drivers/net/wireless/sd8797/mlan/mlan_11n_aggr.h37
-rw-r--r--drivers/net/wireless/sd8797/mlan/mlan_11n_rxreorder.c1135
-rw-r--r--drivers/net/wireless/sd8797/mlan/mlan_11n_rxreorder.h102
-rw-r--r--drivers/net/wireless/sd8797/mlan/mlan_cfp.c1148
-rw-r--r--drivers/net/wireless/sd8797/mlan/mlan_cmdevt.c2927
-rw-r--r--drivers/net/wireless/sd8797/mlan/mlan_decl.h883
-rw-r--r--drivers/net/wireless/sd8797/mlan/mlan_fw.h4630
-rw-r--r--drivers/net/wireless/sd8797/mlan/mlan_ieee.h1318
-rw-r--r--drivers/net/wireless/sd8797/mlan/mlan_init.c1038
-rw-r--r--drivers/net/wireless/sd8797/mlan/mlan_init.h88
-rw-r--r--drivers/net/wireless/sd8797/mlan/mlan_ioctl.h2918
-rw-r--r--drivers/net/wireless/sd8797/mlan/mlan_join.c1853
-rw-r--r--drivers/net/wireless/sd8797/mlan/mlan_join.h40
-rw-r--r--drivers/net/wireless/sd8797/mlan/mlan_main.h2693
-rw-r--r--drivers/net/wireless/sd8797/mlan/mlan_meas.c464
-rw-r--r--drivers/net/wireless/sd8797/mlan/mlan_meas.h54
-rw-r--r--drivers/net/wireless/sd8797/mlan/mlan_misc.c2153
-rw-r--r--drivers/net/wireless/sd8797/mlan/mlan_module.c47
-rw-r--r--drivers/net/wireless/sd8797/mlan/mlan_scan.c4155
-rw-r--r--drivers/net/wireless/sd8797/mlan/mlan_sdio.c1661
-rw-r--r--drivers/net/wireless/sd8797/mlan/mlan_sdio.h307
-rw-r--r--drivers/net/wireless/sd8797/mlan/mlan_shim.c939
-rw-r--r--drivers/net/wireless/sd8797/mlan/mlan_sta_cmd.c1888
-rw-r--r--drivers/net/wireless/sd8797/mlan/mlan_sta_cmdresp.c1640
-rw-r--r--drivers/net/wireless/sd8797/mlan/mlan_sta_event.c595
-rw-r--r--drivers/net/wireless/sd8797/mlan/mlan_sta_ioctl.c5257
-rw-r--r--drivers/net/wireless/sd8797/mlan/mlan_sta_rx.c287
-rw-r--r--drivers/net/wireless/sd8797/mlan/mlan_sta_tx.c276
-rw-r--r--drivers/net/wireless/sd8797/mlan/mlan_txrx.c374
-rw-r--r--drivers/net/wireless/sd8797/mlan/mlan_uap.h104
-rw-r--r--drivers/net/wireless/sd8797/mlan/mlan_uap_cmdevent.c3021
-rw-r--r--drivers/net/wireless/sd8797/mlan/mlan_uap_ioctl.c1393
-rw-r--r--drivers/net/wireless/sd8797/mlan/mlan_uap_txrx.c556
-rw-r--r--drivers/net/wireless/sd8797/mlan/mlan_util.h526
-rw-r--r--drivers/net/wireless/sd8797/mlan/mlan_wmm.c2534
-rw-r--r--drivers/net/wireless/sd8797/mlan/mlan_wmm.h182
-rw-r--r--drivers/net/wireless/sd8797/mlinux/moal_cfg80211.c1263
-rw-r--r--drivers/net/wireless/sd8797/mlinux/moal_cfg80211.h195
-rw-r--r--drivers/net/wireless/sd8797/mlinux/moal_debug.c674
-rw-r--r--drivers/net/wireless/sd8797/mlinux/moal_eth_ioctl.c1143
-rw-r--r--drivers/net/wireless/sd8797/mlinux/moal_eth_ioctl.h69
-rw-r--r--drivers/net/wireless/sd8797/mlinux/moal_ioctl.c4307
-rw-r--r--drivers/net/wireless/sd8797/mlinux/moal_main.c3773
-rw-r--r--drivers/net/wireless/sd8797/mlinux/moal_main.h1510
-rw-r--r--drivers/net/wireless/sd8797/mlinux/moal_priv.c6596
-rw-r--r--drivers/net/wireless/sd8797/mlinux/moal_priv.h715
-rw-r--r--drivers/net/wireless/sd8797/mlinux/moal_proc.c631
-rw-r--r--drivers/net/wireless/sd8797/mlinux/moal_sdio.h140
-rw-r--r--drivers/net/wireless/sd8797/mlinux/moal_sdio_mmc.c728
-rw-r--r--drivers/net/wireless/sd8797/mlinux/moal_shim.c1458
-rw-r--r--drivers/net/wireless/sd8797/mlinux/moal_shim.h95
-rw-r--r--drivers/net/wireless/sd8797/mlinux/moal_sta_cfg80211.c2476
-rw-r--r--drivers/net/wireless/sd8797/mlinux/moal_sta_cfg80211.h41
-rw-r--r--drivers/net/wireless/sd8797/mlinux/moal_uap.c2692
-rw-r--r--drivers/net/wireless/sd8797/mlinux/moal_uap.h410
-rw-r--r--drivers/net/wireless/sd8797/mlinux/moal_uap_cfg80211.c1762
-rw-r--r--drivers/net/wireless/sd8797/mlinux/moal_uap_cfg80211.h30
-rw-r--r--drivers/net/wireless/sd8797/mlinux/moal_uap_priv.c175
-rw-r--r--drivers/net/wireless/sd8797/mlinux/moal_uap_priv.h194
-rw-r--r--drivers/net/wireless/sd8797/mlinux/moal_uap_wext.c1766
-rw-r--r--drivers/net/wireless/sd8797/mlinux/moal_wext.c3048
-rw-r--r--drivers/net/wireless/sd8797/mlinux/moal_wext.h116
70 files changed, 93456 insertions, 0 deletions
diff --git a/drivers/net/wireless/sd8797/Makefile b/drivers/net/wireless/sd8797/Makefile
new file mode 100644
index 000000000000..52e3a3df3988
--- /dev/null
+++ b/drivers/net/wireless/sd8797/Makefile
@@ -0,0 +1,474 @@
+# File: Makefile
+#
+# Copyright (C) 2008-2012, Marvell International Ltd.
+#
+# This software file (the "File") is distributed by Marvell International
+# Ltd. under the terms of the GNU General Public License Version 2, June 1991
+# (the "License"). You may use, redistribute and/or modify this File in
+# accordance with the terms and conditions of the License, a copy of which
+# is available by writing to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
+# worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
+#
+# A copy of the GPL is available in file gpl-2.0.txt accompanying in this
+# deliverables.
+#
+# THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
+# ARE EXPRESSLY DISCLAIMED. The License provides additional details about
+# this warranty disclaimer.
+
+CC= $(CROSS_COMPILE)gcc
+LD= $(CROSS_COMPILE)ld
+BACKUP= /root/backup
+YMD= `date +%Y%m%d%H%M`
+
+#############################################################################
+# Configuration Options
+#############################################################################
+
+# Debug Option
+# DEBUG LEVEL n/1/2:
+# n: NO DEBUG
+# 1: Only PRINTM(MMSG,...), PRINTM(MFATAL,...), ...
+# 2: All PRINTM()
+CONFIG_DEBUG=1
+
+# Proc debug file
+CONFIG_PROC_DEBUG=y
+
+# Enable STA mode support
+CONFIG_STA_SUPPORT=y
+
+# Enable uAP mode support
+CONFIG_UAP_SUPPORT=y
+
+# Enable WIFIDIRECT support
+CONFIG_WIFI_DIRECT_SUPPORT=y
+
+# Enable WIFIDISPLAY support
+CONFIG_WIFI_DISPLAY_SUPPORT=y
+
+# Re-association in driver
+CONFIG_REASSOCIATION=y
+
+# Enable WEXT for STA
+CONFIG_STA_WEXT=y
+
+# Enable WEXT for uAP
+CONFIG_UAP_WEXT=y
+
+# Enable CFG80211 for STA
+ifeq ($(CONFIG_CFG80211),y)
+CONFIG_STA_CFG80211=y
+else
+ifeq ($(CONFIG_CFG80211),m)
+CONFIG_STA_CFG80211=y
+else
+CONFIG_STA_CFG80211=n
+endif
+endif
+
+# Enable CFG80211 for uAP
+ifeq ($(CONFIG_CFG80211),y)
+CONFIG_UAP_CFG80211=y
+else
+ifeq ($(CONFIG_CFG80211),m)
+CONFIG_UAP_CFG80211=y
+else
+CONFIG_UAP_CFG80211=n
+endif
+endif
+
+# Manufacturing firmware support
+CONFIG_MFG_CMD_SUPPORT=y
+
+# Big-endian platform
+CONFIG_BIG_ENDIAN=n
+
+# Enable SDIO multi-port Tx aggregation
+CONFIG_SDIO_MULTI_PORT_TX_AGGR=y
+
+# Enable SDIO multi-port Rx aggregation
+CONFIG_SDIO_MULTI_PORT_RX_AGGR=y
+
+
+# SDIO suspend/resume
+CONFIG_SDIO_SUSPEND_RESUME=y
+
+# DFS testing support
+CONFIG_DFS_TESTING_SUPPORT=y
+
+# Use static link for app build
+export CONFIG_STATIC_LINK=y
+
+#############################################################################
+# Select Platform Tools
+#############################################################################
+
+MODEXT = ko
+EXTRA_CFLAGS += -I$(M)/mlan
+EXTRA_CFLAGS += -DLINUX
+
+# KERNELDIR point to the installed kernel directory.
+# KERNELDIR can be set on the command line,
+# make KERNELDIR=/usr/src/arm/<arch-bsp-path>
+# Alternatively KERNELDIR can be set in the environment.
+# Default value for KERNELDIR is set below.
+KERNELDIR ?= /usr/src/arm/linux-2.6.39-T3T
+
+# CROSS_COMPILE specify the prefix used for all executables used
+# during compilation. Only gcc and related bin-utils executables
+# CROSS_COMPILE can be set on the command line
+# make CROSS_COMPILE=</usr/local/arm/4.1.1/bin/>arm-linux-
+# Alternatively CROSS_COMPILE can be set in the environment.
+# Default value for CROSS_COMPILE is set below.
+CROSS_COMPILE ?= /usr/local/arm-eabi-4.4.3/bin/arm-eabi-
+
+# INSTALLDIR specify the path to install the kernel module after
+# succesful compilation.
+# INSTALLDIR can be set on the command line
+# make INSTALLDIR=/tftpboot/<rootfs>
+# Alternatively INSTALLDIR can be set in the environment.
+# Default value for INSTALL is set below.
+INSTALLDIR ?= /tftpboot/pxa9xx/root
+
+# ARCH specifies the architecture of the target processor, this kernel
+# module will run.
+# ARCH can be set on the command line
+# make ARCH=<arm/i386>
+# Alternatively ARCH can be set in the environment
+# Default values of ARCH for specific platform are set below.
+ARCH ?= arm
+
+LD += -S
+
+BINDIR = ../bin_sd8797
+APPDIR= $(shell if test -d "mapp"; then echo mapp; fi)
+
+#############################################################################
+# Compiler Flags
+#############################################################################
+
+ EXTRA_CFLAGS += -I$(KERNELDIR)/include
+
+ EXTRA_CFLAGS += -DFPNUM='"69"'
+
+ifeq ($(CONFIG_DEBUG),1)
+ EXTRA_CFLAGS += -DDEBUG_LEVEL1
+endif
+
+ifeq ($(CONFIG_DEBUG),2)
+ EXTRA_CFLAGS += -DDEBUG_LEVEL1
+ EXTRA_CFLAGS += -DDEBUG_LEVEL2
+ DBG= -dbg
+endif
+
+ifeq ($(CONFIG_PROC_DEBUG),y)
+ EXTRA_CFLAGS += -DPROC_DEBUG
+ export CONFIG_PROC_DEBUG
+endif
+
+ifeq ($(CONFIG_64BIT), y)
+ EXTRA_CFLAGS += -DMLAN_64BIT
+endif
+
+ifeq ($(CONFIG_STA_SUPPORT),y)
+ EXTRA_CFLAGS += -DSTA_SUPPORT
+ifeq ($(CONFIG_REASSOCIATION),y)
+ EXTRA_CFLAGS += -DREASSOCIATION
+endif
+ifeq ($(CONFIG_STA_WEXT),y)
+ EXTRA_CFLAGS += -DSTA_WEXT
+endif
+ifeq ($(CONFIG_STA_CFG80211),y)
+ EXTRA_CFLAGS += -DSTA_CFG80211
+endif
+else
+CONFIG_WIFI_DIRECT_SUPPORT=n
+CONFIG_WIFI_DISPLAY_SUPPORT=n
+CONFIG_STA_WEXT=n
+CONFIG_STA_CFG80211=n
+endif
+
+ifeq ($(CONFIG_UAP_SUPPORT),y)
+ EXTRA_CFLAGS += -DUAP_SUPPORT
+ifeq ($(CONFIG_UAP_WEXT),y)
+ EXTRA_CFLAGS += -DUAP_WEXT
+endif
+ifeq ($(CONFIG_UAP_CFG80211),y)
+ EXTRA_CFLAGS += -DUAP_CFG80211
+endif
+else
+CONFIG_WIFI_DIRECT_SUPPORT=n
+CONFIG_WIFI_DISPLAY_SUPPORT=n
+CONFIG_UAP_WEXT=n
+CONFIG_UAP_CFG80211=n
+endif
+
+ifeq ($(CONFIG_WIFI_DIRECT_SUPPORT),y)
+ EXTRA_CFLAGS += -DWIFI_DIRECT_SUPPORT
+endif
+ifeq ($(CONFIG_WIFI_DISPLAY_SUPPORT),y)
+ EXTRA_CFLAGS += -DWIFI_DISPLAY_SUPPORT
+endif
+
+ifeq ($(CONFIG_MFG_CMD_SUPPORT),y)
+ EXTRA_CFLAGS += -DMFG_CMD_SUPPORT
+endif
+
+ifeq ($(CONFIG_BIG_ENDIAN),y)
+ EXTRA_CFLAGS += -DBIG_ENDIAN_SUPPORT
+endif
+
+ifeq ($(CONFIG_SDIO_MULTI_PORT_TX_AGGR),y)
+ EXTRA_CFLAGS += -DSDIO_MULTI_PORT_TX_AGGR
+endif
+
+ifeq ($(CONFIG_SDIO_MULTI_PORT_RX_AGGR),y)
+ EXTRA_CFLAGS += -DSDIO_MULTI_PORT_RX_AGGR
+endif
+
+
+ifeq ($(CONFIG_SDIO_SUSPEND_RESUME),y)
+ EXTRA_CFLAGS += -DSDIO_SUSPEND_RESUME
+endif
+
+ifeq ($(CONFIG_DFS_TESTING_SUPPORT),y)
+ EXTRA_CFLAGS += -DDFS_TESTING_SUPPORT
+endif
+
+#############################################################################
+# Make Targets
+#############################################################################
+
+ifneq ($(KERNELRELEASE),)
+
+MOALOBJS = mlinux/moal_main.o \
+ mlinux/moal_ioctl.o \
+ mlinux/moal_shim.o \
+ mlinux/moal_eth_ioctl.o
+
+MLANOBJS = mlan/mlan_shim.o mlan/mlan_init.o \
+ mlan/mlan_txrx.o \
+ mlan/mlan_cmdevt.o mlan/mlan_misc.o \
+ mlan/mlan_cfp.o \
+ mlan/mlan_module.o
+
+MLANOBJS += mlan/mlan_wmm.o
+MLANOBJS += mlan/mlan_sdio.o
+MLANOBJS += mlan/mlan_11n_aggr.o
+MLANOBJS += mlan/mlan_11n_rxreorder.o
+MLANOBJS += mlan/mlan_11n.o
+MLANOBJS += mlan/mlan_11d.o
+MLANOBJS += mlan/mlan_11h.o
+ifeq ($(CONFIG_STA_SUPPORT),y)
+MLANOBJS += mlan/mlan_meas.o
+MLANOBJS += mlan/mlan_scan.o \
+ mlan/mlan_sta_ioctl.o \
+ mlan/mlan_sta_rx.o \
+ mlan/mlan_sta_tx.o \
+ mlan/mlan_sta_event.o \
+ mlan/mlan_sta_cmd.o \
+ mlan/mlan_sta_cmdresp.o \
+ mlan/mlan_join.o
+ifeq ($(CONFIG_STA_WEXT),y)
+MOALOBJS += mlinux/moal_priv.o \
+ mlinux/moal_wext.o
+endif
+endif
+ifeq ($(CONFIG_UAP_SUPPORT),y)
+MLANOBJS += mlan/mlan_uap_ioctl.o
+MLANOBJS += mlan/mlan_uap_cmdevent.o
+MLANOBJS += mlan/mlan_uap_txrx.o
+MOALOBJS += mlinux/moal_uap.o
+ifeq ($(CONFIG_UAP_WEXT),y)
+MOALOBJS += mlinux/moal_uap_priv.o
+MOALOBJS += mlinux/moal_uap_wext.o
+endif
+ifeq ($(CONFIG_STA_WEXT),y)
+MOALOBJS += mlinux/moal_wext.o
+endif
+endif
+ifeq ($(CONFIG_STA_CFG80211),y)
+MOALOBJS += mlinux/moal_cfg80211.o
+MOALOBJS += mlinux/moal_sta_cfg80211.o
+endif
+ifeq ($(CONFIG_UAP_CFG80211),y)
+MOALOBJS += mlinux/moal_cfg80211.o
+MOALOBJS += mlinux/moal_uap_cfg80211.o
+endif
+
+ifdef CONFIG_PROC_FS
+MOALOBJS += mlinux/moal_proc.o
+ifeq ($(CONFIG_PROC_DEBUG),y)
+MOALOBJS += mlinux/moal_debug.o
+endif
+endif
+
+obj-m := mlan.o
+mlan-objs := $(MLANOBJS)
+MOALOBJS += mlinux/moal_sdio_mmc.o
+obj-m += sd8xxx.o
+sd8xxx-objs := $(MOALOBJS)
+
+# Otherwise we were called directly from the command line; invoke the kernel build system.
+else
+
+default:
+ifeq ($(CONFIG_STA_SUPPORT),y)
+ifeq ($(CONFIG_STA_WEXT),n)
+ifeq ($(CONFIG_STA_CFG80211),n)
+ @echo "Can not build STA without WEXT or CFG80211"
+ exit 2
+endif
+endif
+endif
+ifeq ($(CONFIG_UAP_SUPPORT),y)
+ifeq ($(CONFIG_UAP_WEXT),n)
+ifeq ($(CONFIG_UAP_CFG80211),n)
+ @echo "Can not build UAP without WEXT or CFG80211"
+ exit 2
+endif
+endif
+endif
+ $(MAKE) -C $(KERNELDIR) M=$(PWD) ARCH=$(ARCH) CROSS_COMPILE=$(CROSS_COMPILE) modules
+
+endif
+
+###############################################################
+
+export CC LD EXTRA_CFLAGS KERNELDIR
+
+ifeq ($(CONFIG_STA_SUPPORT),y)
+ifeq ($(CONFIG_UAP_SUPPORT),y)
+.PHONY: mapp/mlanconfig mapp/mlan2040coex mapp/mlanevent mapp/uaputl mapp/mlanutl clean distclean
+else
+.PHONY: mapp/mlanconfig mapp/mlanevent mapp/mlan2040coex mapp/mlanutl clean distclean
+endif
+else
+ifeq ($(CONFIG_UAP_SUPPORT),y)
+.PHONY: mapp/mlanevent mapp/uaputl clean distclean
+endif
+endif
+ @echo "Finished Making Marvell Wlan Linux Driver"
+
+ifeq ($(CONFIG_STA_SUPPORT),y)
+mapp/mlanconfig:
+ $(MAKE) -C $@
+mapp/mlanutl:
+ $(MAKE) -C $@
+mapp/mlan2040coex:
+ $(MAKE) -C $@
+endif
+ifeq ($(CONFIG_UAP_SUPPORT),y)
+mapp/uaputl:
+ $(MAKE) -C $@
+endif
+ifeq ($(CONFIG_WIFI_DIRECT_SUPPORT),y)
+mapp/wifidirectutl:
+ $(MAKE) -C $@
+endif
+mapp/mlanevent:
+ $(MAKE) -C $@
+
+echo:
+
+build: echo default
+
+ @if [ ! -d $(BINDIR) ]; then \
+ mkdir $(BINDIR); \
+ fi
+
+ cp -f mlan.$(MODEXT) $(BINDIR)/mlan$(DBG).$(MODEXT)
+ cp -f sd8xxx.$(MODEXT) $(BINDIR)/sd8797$(DBG).$(MODEXT)
+
+ifeq ($(CONFIG_STA_SUPPORT),y)
+ cp -f README $(BINDIR)
+ cp -f README_RBC $(BINDIR)
+ifneq ($(APPDIR),)
+ $(MAKE) -C mapp/mlanconfig $@ INSTALLDIR=$(BINDIR)
+ $(MAKE) -C mapp/mlanutl $@ INSTALLDIR=$(BINDIR)
+ $(MAKE) -C mapp/mlan2040coex $@ INSTALLDIR=$(BINDIR)
+endif
+endif
+ifeq ($(CONFIG_UAP_SUPPORT),y)
+ cp -f README_UAP $(BINDIR)
+ifneq ($(APPDIR),)
+ $(MAKE) -C mapp/uaputl $@ INSTALLDIR=$(BINDIR)
+endif
+endif
+ifeq ($(CONFIG_WIFI_DIRECT_SUPPORT),y)
+ cp -f README_WIFIDIRECT $(BINDIR)
+ cp -rpf script/wifidirect $(BINDIR)
+ifeq ($(CONFIG_WIFI_DISPLAY_SUPPORT),y)
+ cp -rpf script/wifidisplay $(BINDIR)
+endif
+ifneq ($(APPDIR),)
+ $(MAKE) -C mapp/wifidirectutl $@ INSTALLDIR=$(BINDIR)
+endif
+endif
+ifneq ($(APPDIR),)
+ $(MAKE) -C mapp/mlanevent $@ INSTALLDIR=$(BINDIR)
+endif
+
+clean:
+ -find . -name "*.o" -exec rm {} \;
+ -find . -name "*.ko" -exec rm {} \;
+ -find . -name ".*.cmd" -exec rm {} \;
+ -find . -name "*.mod.c" -exec rm {} \;
+ -find . -name "Module.symvers" -exec rm {} \;
+ -find . -name "Module.markers" -exec rm {} \;
+ -find . -name "modules.order" -exec rm {} \;
+ -rm -rf .tmp_versions
+ifneq ($(APPDIR),)
+ifeq ($(CONFIG_STA_SUPPORT),y)
+ $(MAKE) -C mapp/mlanconfig $@
+ $(MAKE) -C mapp/mlanutl $@
+ $(MAKE) -C mapp/mlan2040coex $@
+endif
+ifeq ($(CONFIG_UAP_SUPPORT),y)
+ $(MAKE) -C mapp/uaputl $@
+endif
+ifeq ($(CONFIG_WIFI_DIRECT_SUPPORT),y)
+ $(MAKE) -C mapp/wifidirectutl $@
+endif
+ $(MAKE) -C mapp/mlanevent $@
+endif
+
+install: default
+
+ cp -f mlan.$(MODEXT) $(INSTALLDIR)/mlan$(DBG).$(MODEXT)
+ cp -f sd8xxx.$(MODEXT) $(INSTALLDIR)/sd8797$(DBG).$(MODEXT)
+ echo "sd8797 Driver Installed"
+
+distclean:
+ -find . -name "*.o" -exec rm {} \;
+ -find . -name "*.orig" -exec rm {} \;
+ -find . -name "*.swp" -exec rm {} \;
+ -find . -name "*.*~" -exec rm {} \;
+ -find . -name "*~" -exec rm {} \;
+ -find . -name "*.d" -exec rm {} \;
+ -find . -name "*.a" -exec rm {} \;
+ -find . -name "tags" -exec rm {} \;
+ -find . -name ".*" -exec rm -rf 2> /dev/null \;
+ -find . -name "*.ko" -exec rm {} \;
+ -find . -name ".*.cmd" -exec rm {} \;
+ -find . -name "*.mod.c" -exec rm {} \;
+ -rm -rf .tmp_versions
+ifneq ($(APPDIR),)
+ifeq ($(CONFIG_STA_SUPPORT),y)
+ $(MAKE) -C mapp/mlanconfig $@
+ $(MAKE) -C mapp/mlanutl $@
+ $(MAKE) -C mapp/mlan2040coex $@
+endif
+ifeq ($(CONFIG_UAP_SUPPORT),y)
+ $(MAKE) -C mapp/uaputl $@
+endif
+ifeq ($(CONFIG_WIFI_DIRECT_SUPPORT),y)
+ $(MAKE) -C mapp/wifidirectutl $@
+endif
+ $(MAKE) -C mapp/mlanevent $@
+endif
+
+# End of file
diff --git a/drivers/net/wireless/sd8797/mlan/mlan.h b/drivers/net/wireless/sd8797/mlan/mlan.h
new file mode 100644
index 000000000000..a341e1547099
--- /dev/null
+++ b/drivers/net/wireless/sd8797/mlan/mlan.h
@@ -0,0 +1,35 @@
+/** @file mlan.h
+ *
+ * @brief This file declares all APIs that will be called from MOAL module.
+ * It also defines the data structures used for APIs between MLAN and MOAL.
+ *
+ * Copyright (C) 2008-2011, Marvell International Ltd.
+ *
+ * This software file (the "File") is distributed by Marvell International
+ * Ltd. under the terms of the GNU General Public License Version 2, June 1991
+ * (the "License"). You may use, redistribute and/or modify this File in
+ * accordance with the terms and conditions of the License, a copy of which
+ * is available by writing to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
+ * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
+ *
+ * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
+ * ARE EXPRESSLY DISCLAIMED. The License provides additional details about
+ * this warranty disclaimer.
+ */
+
+/******************************************************
+Change log:
+ 10/13/2008: initial version
+ 11/07/2008: split mlan.h into mlan_decl.h & mlan_ioctl.h
+******************************************************/
+
+#ifndef _MLAN_H_
+#define _MLAN_H_
+
+#include "mlan_decl.h"
+#include "mlan_ioctl.h"
+#include "mlan_ieee.h"
+
+#endif /* !_MLAN_H_ */
diff --git a/drivers/net/wireless/sd8797/mlan/mlan_11d.c b/drivers/net/wireless/sd8797/mlan/mlan_11d.c
new file mode 100644
index 000000000000..809de4cc9ede
--- /dev/null
+++ b/drivers/net/wireless/sd8797/mlan/mlan_11d.c
@@ -0,0 +1,1514 @@
+/** @file mlan_11d.c
+ *
+ * @brief This file contains functions for 802.11D.
+ *
+ * Copyright (C) 2008-2011, Marvell International Ltd.
+ *
+ * This software file (the "File") is distributed by Marvell International
+ * Ltd. under the terms of the GNU General Public License Version 2, June 1991
+ * (the "License"). You may use, redistribute and/or modify this File in
+ * accordance with the terms and conditions of the License, a copy of which
+ * is available by writing to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
+ * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
+ *
+ * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
+ * ARE EXPRESSLY DISCLAIMED. The License provides additional details about
+ * this warranty disclaimer.
+ *
+ */
+/********************************************************
+Change log:
+ 10/21/2008: initial version
+********************************************************/
+
+#include "mlan.h"
+#include "mlan_join.h"
+#include "mlan_util.h"
+#include "mlan_fw.h"
+#include "mlan_main.h"
+#include "mlan_11h.h"
+
+/********************************************************
+ Local Variables
+********************************************************/
+
+/** Region code mapping */
+typedef struct _region_code_mapping
+{
+ /** Region */
+ t_u8 region[COUNTRY_CODE_LEN];
+ /** Code */
+ t_u8 code;
+} region_code_mapping_t;
+
+/** Region code mapping table */
+static region_code_mapping_t region_code_mapping[] = {
+ {"US ", 0x10}, /* US FCC */
+ {"CA ", 0x20}, /* IC Canada */
+ {"SG ", 0x10}, /* Singapore */
+ {"EU ", 0x30}, /* ETSI */
+ {"AU ", 0x30}, /* Australia */
+ {"KR ", 0x30}, /* Republic Of Korea */
+ {"FR ", 0x32}, /* France */
+ {"JP ", 0x40}, /* Japan */
+ {"JP ", 0x41}, /* Japan */
+ {"CN ", 0x50}, /* China */
+ {"JP ", 0xFF}, /* Japan special */
+};
+
+#ifdef STA_SUPPORT
+/** Default Tx power */
+#define TX_PWR_DEFAULT 10
+
+/** Universal region code */
+#define UNIVERSAL_REGION_CODE 0xff
+
+/* Following two structures define the supported channels */
+/** Channels for 802.11b/g */
+static chan_freq_power_t channel_freq_power_UN_BG[] = {
+ {1, 2412, TX_PWR_DEFAULT},
+ {2, 2417, TX_PWR_DEFAULT},
+ {3, 2422, TX_PWR_DEFAULT},
+ {4, 2427, TX_PWR_DEFAULT},
+ {5, 2432, TX_PWR_DEFAULT},
+ {6, 2437, TX_PWR_DEFAULT},
+ {7, 2442, TX_PWR_DEFAULT},
+ {8, 2447, TX_PWR_DEFAULT},
+ {9, 2452, TX_PWR_DEFAULT},
+ {10, 2457, TX_PWR_DEFAULT},
+ {11, 2462, TX_PWR_DEFAULT},
+ {12, 2467, TX_PWR_DEFAULT},
+ {13, 2472, TX_PWR_DEFAULT},
+ {14, 2484, TX_PWR_DEFAULT}
+};
+
+/** Channels for 802.11a/j */
+static chan_freq_power_t channel_freq_power_UN_AJ[] = {
+ {8, 5040, TX_PWR_DEFAULT},
+ {12, 5060, TX_PWR_DEFAULT},
+ {16, 5080, TX_PWR_DEFAULT},
+ {34, 5170, TX_PWR_DEFAULT},
+ {38, 5190, TX_PWR_DEFAULT},
+ {42, 5210, TX_PWR_DEFAULT},
+ {46, 5230, TX_PWR_DEFAULT},
+ {36, 5180, TX_PWR_DEFAULT},
+ {40, 5200, TX_PWR_DEFAULT},
+ {44, 5220, TX_PWR_DEFAULT},
+ {48, 5240, TX_PWR_DEFAULT},
+ {52, 5260, TX_PWR_DEFAULT},
+ {56, 5280, TX_PWR_DEFAULT},
+ {60, 5300, TX_PWR_DEFAULT},
+ {64, 5320, TX_PWR_DEFAULT},
+ {100, 5500, TX_PWR_DEFAULT},
+ {104, 5520, TX_PWR_DEFAULT},
+ {108, 5540, TX_PWR_DEFAULT},
+ {112, 5560, TX_PWR_DEFAULT},
+ {116, 5580, TX_PWR_DEFAULT},
+ {120, 5600, TX_PWR_DEFAULT},
+ {124, 5620, TX_PWR_DEFAULT},
+ {128, 5640, TX_PWR_DEFAULT},
+ {132, 5660, TX_PWR_DEFAULT},
+ {136, 5680, TX_PWR_DEFAULT},
+ {140, 5700, TX_PWR_DEFAULT},
+ {149, 5745, TX_PWR_DEFAULT},
+ {153, 5765, TX_PWR_DEFAULT},
+ {157, 5785, TX_PWR_DEFAULT},
+ {161, 5805, TX_PWR_DEFAULT},
+ {165, 5825, TX_PWR_DEFAULT},
+/* {240, 4920, TX_PWR_DEFAULT},
+ {244, 4940, TX_PWR_DEFAULT},
+ {248, 4960, TX_PWR_DEFAULT},
+ {252, 4980, TX_PWR_DEFAULT},
+channels for 11J JP 10M channel gap */
+};
+#endif /* STA_SUPPORT */
+
+/********************************************************
+ Global Variables
+********************************************************/
+
+/********************************************************
+ Local Functions
+********************************************************/
+
+/**
+ * @brief This function converts region string to integer code
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param region Region string
+ * @param code [output] Region code
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+static mlan_status
+wlan_11d_region_2_code(pmlan_adapter pmadapter, t_u8 * region, OUT t_u8 * code)
+{
+ t_u8 i;
+ t_u8 size = sizeof(region_code_mapping) / sizeof(region_code_mapping_t);
+
+ ENTER();
+
+ /* Look for code in mapping table */
+ for (i = 0; i < size; i++) {
+ if (!memcmp(pmadapter, region_code_mapping[i].region,
+ region, COUNTRY_CODE_LEN)) {
+ *code = region_code_mapping[i].code;
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+ }
+ }
+
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+}
+
+#ifdef STA_SUPPORT
+/**
+ * @brief This function converts integer code to region string
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param code Region code
+ *
+ * @return Region string
+ */
+static t_u8 *
+wlan_11d_code_2_region(pmlan_adapter pmadapter, t_u8 code)
+{
+ t_u8 i;
+ t_u8 size = sizeof(region_code_mapping) / sizeof(region_code_mapping_t);
+
+ ENTER();
+
+ /* Look for code in mapping table */
+ for (i = 0; i < size; i++) {
+ if (region_code_mapping[i].code == code) {
+ LEAVE();
+ return (region_code_mapping[i].region);
+ }
+ }
+
+ LEAVE();
+ /* Default is US */
+ return (region_code_mapping[0].region);
+}
+
+/**
+ * @brief This function Checks if channel txpwr is learned from AP/IBSS
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param band Band number
+ * @param chan Channel number
+ * @param parsed_region_chan Pointer to parsed_region_chan_11d_t
+ *
+ * @return MTRUE or MFALSE
+ */
+static t_u8
+wlan_11d_channel_known(pmlan_adapter pmadapter,
+ t_u8 band,
+ t_u8 chan, parsed_region_chan_11d_t * parsed_region_chan)
+{
+ chan_power_11d_t *pchan_pwr = parsed_region_chan->chan_pwr;
+ t_u8 no_of_chan = parsed_region_chan->no_of_chan;
+ t_u8 i = 0;
+ t_u8 ret = MFALSE;
+ mlan_private *pmpriv;
+
+ ENTER();
+
+ HEXDUMP("11D: parsed_region_chan", (t_u8 *) pchan_pwr,
+ sizeof(chan_power_11d_t) * no_of_chan);
+
+ /* Search channel */
+ for (i = 0; i < no_of_chan; i++) {
+ if (chan == pchan_pwr[i].chan && band == pchan_pwr[i].band) {
+ PRINTM(MINFO, "11D: Found channel:%d (band:%d)\n", chan, band);
+ ret = MTRUE;
+
+ if (band & BAND_A) {
+ /* If chan is a DFS channel, we need to see an AP on it */
+ if ((pmpriv = wlan_get_priv(pmadapter, MLAN_BSS_ROLE_STA))
+ && wlan_11h_radar_detect_required(pmpriv, chan)) {
+ PRINTM(MINFO, "11H: DFS channel %d, and ap_seen=%d\n",
+ chan, pchan_pwr[i].ap_seen);
+ ret = pchan_pwr[i].ap_seen;
+ }
+ }
+
+ LEAVE();
+ return ret;
+ }
+ }
+
+ PRINTM(MINFO, "11D: Could not find channel:%d (band:%d)\n", chan, band);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function generates parsed_region_chan from Domain Info
+ * learned from AP/IBSS
+ *
+ * @param pmadapter Pointer to mlan_adapter structure
+ * @param region_chan Pointer to region_chan_t
+ * @param parsed_region_chan Pointer to parsed_region_chan_11d_t
+ *
+ * @return N/A
+ */
+static t_void
+wlan_11d_generate_parsed_region_chan(pmlan_adapter pmadapter,
+ region_chan_t * region_chan,
+ parsed_region_chan_11d_t *
+ parsed_region_chan)
+{
+ chan_freq_power_t *cfp;
+ t_u8 i;
+
+ ENTER();
+
+ /* Region channel must be provided */
+ if (!region_chan) {
+ PRINTM(MWARN, "11D: region_chan is MNULL\n");
+ LEAVE();
+ return;
+ }
+
+ /* Get channel-frequency-power trio */
+ cfp = region_chan->pcfp;
+ if (!cfp) {
+ PRINTM(MWARN, "11D: cfp equal MNULL\n");
+ LEAVE();
+ return;
+ }
+
+ /* Set channel, band and power */
+ for (i = 0; i < region_chan->num_cfp; i++, cfp++) {
+ parsed_region_chan->chan_pwr[i].chan = (t_u8) cfp->channel;
+ parsed_region_chan->chan_pwr[i].band = region_chan->band;
+ parsed_region_chan->chan_pwr[i].pwr = (t_u8) cfp->max_tx_power;
+ PRINTM(MINFO, "11D: Chan[%d] Band[%d] Pwr[%d]\n",
+ parsed_region_chan->chan_pwr[i].chan,
+ parsed_region_chan->chan_pwr[i].band,
+ parsed_region_chan->chan_pwr[i].pwr);
+ }
+ parsed_region_chan->no_of_chan = region_chan->num_cfp;
+
+ PRINTM(MINFO, "11D: no_of_chan[%d]\n", parsed_region_chan->no_of_chan);
+
+ LEAVE();
+ return;
+}
+
+/**
+ * @brief This function generates domain_info from parsed_region_chan
+ *
+ * @param pmadapter Pointer to mlan_adapter structure
+ * @param parsed_region_chan Pointer to parsed_region_chan_11d_t
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+static mlan_status
+wlan_11d_generate_domain_info(pmlan_adapter pmadapter,
+ parsed_region_chan_11d_t * parsed_region_chan)
+{
+ t_u8 no_of_sub_band = 0;
+ t_u8 no_of_chan = parsed_region_chan->no_of_chan;
+ t_u8 no_of_parsed_chan = 0;
+ t_u8 first_chan = 0, next_chan = 0, max_pwr = 0;
+ t_u8 i, flag = MFALSE;
+ wlan_802_11d_domain_reg_t *domain_info = &pmadapter->domain_reg;
+
+ ENTER();
+
+ /* Should be only place that clear domain_reg (besides init) */
+ memset(pmadapter, domain_info, 0, sizeof(wlan_802_11d_domain_reg_t));
+
+ /* Set country code */
+ memcpy(pmadapter, domain_info->country_code,
+ wlan_11d_code_2_region(pmadapter, (t_u8) pmadapter->region_code),
+ COUNTRY_CODE_LEN);
+
+ PRINTM(MINFO, "11D: Number of channel = %d\n", no_of_chan);
+ HEXDUMP("11D: parsed_region_chan", (t_u8 *) parsed_region_chan,
+ sizeof(parsed_region_chan_11d_t));
+
+ /* Set channel and power */
+ for (i = 0; i < no_of_chan; i++) {
+ if (!flag) {
+ flag = MTRUE;
+ next_chan = first_chan = parsed_region_chan->chan_pwr[i].chan;
+ max_pwr = parsed_region_chan->chan_pwr[i].pwr;
+ no_of_parsed_chan = 1;
+ continue;
+ }
+
+ if (parsed_region_chan->chan_pwr[i].chan == next_chan + 1 &&
+ parsed_region_chan->chan_pwr[i].pwr == max_pwr) {
+ next_chan++;
+ no_of_parsed_chan++;
+ } else {
+ domain_info->sub_band[no_of_sub_band].first_chan = first_chan;
+ domain_info->sub_band[no_of_sub_band].no_of_chan =
+ no_of_parsed_chan;
+ domain_info->sub_band[no_of_sub_band].max_tx_pwr = max_pwr;
+ no_of_sub_band++;
+ no_of_parsed_chan = 1;
+ next_chan = first_chan = parsed_region_chan->chan_pwr[i].chan;
+ max_pwr = parsed_region_chan->chan_pwr[i].pwr;
+ }
+ }
+
+ if (flag) {
+ domain_info->sub_band[no_of_sub_band].first_chan = first_chan;
+ domain_info->sub_band[no_of_sub_band].no_of_chan = no_of_parsed_chan;
+ domain_info->sub_band[no_of_sub_band].max_tx_pwr = max_pwr;
+ no_of_sub_band++;
+ }
+ domain_info->no_of_sub_band = no_of_sub_band;
+
+ PRINTM(MINFO, "11D: Number of sub-band =0x%x\n",
+ domain_info->no_of_sub_band);
+ HEXDUMP("11D: domain_info", (t_u8 *) domain_info,
+ COUNTRY_CODE_LEN + 1 +
+ sizeof(IEEEtypes_SubbandSet_t) * no_of_sub_band);
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function updates the channel power table with the channel
+ * present in BSSDescriptor.
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param pbss_desc A pointer to BSSDescriptor_t
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+static mlan_status
+wlan_11d_update_chan_pwr_table(mlan_private * pmpriv,
+ BSSDescriptor_t * pbss_desc)
+{
+ mlan_adapter *pmadapter = pmpriv->adapter;
+ parsed_region_chan_11d_t *parsed_region_chan =
+ &pmadapter->parsed_region_chan;
+ t_u16 i;
+ t_u8 tx_power = 0;
+ t_u8 chan;
+
+ ENTER();
+
+ chan = pbss_desc->phy_param_set.ds_param_set.current_chan;
+
+ tx_power = wlan_get_txpwr_of_chan_from_cfp(pmpriv, chan);
+
+ if (!tx_power) {
+ PRINTM(MMSG, "11D: Invalid channel\n");
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+
+ /* Check whether the channel already exists in channel power table of
+ parsed region */
+ for (i = 0; ((i < parsed_region_chan->no_of_chan) &&
+ (i < MAX_NO_OF_CHAN)); i++) {
+ if (parsed_region_chan->chan_pwr[i].chan == chan
+ && parsed_region_chan->chan_pwr[i].band == pbss_desc->bss_band) {
+ /* Channel already exists, use minimum of existing and tx_power */
+ parsed_region_chan->chan_pwr[i].pwr =
+ MIN(parsed_region_chan->chan_pwr[i].pwr, tx_power);
+ parsed_region_chan->chan_pwr[i].ap_seen = MTRUE;
+ break;
+ }
+ }
+
+ if (i == parsed_region_chan->no_of_chan && i < MAX_NO_OF_CHAN) {
+ /* Channel not found. Update the channel in the channel-power table */
+ parsed_region_chan->chan_pwr[i].chan = chan;
+ parsed_region_chan->chan_pwr[i].band = (t_u8) pbss_desc->bss_band;
+ parsed_region_chan->chan_pwr[i].pwr = tx_power;
+ parsed_region_chan->chan_pwr[i].ap_seen = MTRUE;
+ parsed_region_chan->no_of_chan++;
+ }
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function finds the no_of_chan-th chan after the first_chan
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param band Band
+ * @param first_chan First channel number
+ * @param no_of_chan Number of channels
+ * @param chan Pointer to the returned no_of_chan-th chan number
+ *
+ * @return MTRUE or MFALSE
+ */
+static t_u8
+wlan_11d_get_chan(pmlan_adapter pmadapter, t_u8 band, t_u8 first_chan,
+ t_u8 no_of_chan, t_u8 * chan)
+{
+ chan_freq_power_t *cfp = MNULL;
+ t_u8 i;
+ t_u8 cfp_no = 0;
+
+ ENTER();
+ if (band & (BAND_B | BAND_G | BAND_GN)) {
+ cfp = channel_freq_power_UN_BG;
+ cfp_no = sizeof(channel_freq_power_UN_BG) / sizeof(chan_freq_power_t);
+ } else if (band & (BAND_A | BAND_AN)) {
+ cfp = channel_freq_power_UN_AJ;
+ cfp_no = sizeof(channel_freq_power_UN_AJ) / sizeof(chan_freq_power_t);
+ } else {
+ PRINTM(MERROR, "11D: Wrong Band[%d]\n", band);
+ LEAVE();
+ return MFALSE;
+ }
+ /* Locate the first_chan */
+ for (i = 0; i < cfp_no; i++) {
+ if (cfp && ((cfp + i)->channel == first_chan)) {
+ PRINTM(MINFO, "11D: first_chan found\n");
+ break;
+ }
+ }
+
+ if (i < cfp_no) {
+ /* Check if beyond the boundary */
+ if (i + no_of_chan < cfp_no) {
+ /* Get first_chan + no_of_chan */
+ *chan = (t_u8) (cfp + i + no_of_chan)->channel;
+ LEAVE();
+ return MTRUE;
+ }
+ }
+
+ LEAVE();
+ return MFALSE;
+}
+
+/**
+ * @brief This function processes the country info present in BSSDescriptor.
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param pbss_desc A pointer to BSSDescriptor_t
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+static mlan_status
+wlan_11d_process_country_info(mlan_private * pmpriv,
+ BSSDescriptor_t * pbss_desc)
+{
+ mlan_adapter *pmadapter = pmpriv->adapter;
+ parsed_region_chan_11d_t region_chan;
+ parsed_region_chan_11d_t *parsed_region_chan =
+ &pmadapter->parsed_region_chan;
+ t_u16 i, j, num_chan_added = 0;
+
+ ENTER();
+
+ memset(pmadapter, &region_chan, 0, sizeof(parsed_region_chan_11d_t));
+
+ /* Parse 11D country info */
+ if (wlan_11d_parse_domain_info(pmadapter, &pbss_desc->country_info,
+ (t_u8) pbss_desc->bss_band,
+ &region_chan) != MLAN_STATUS_SUCCESS) {
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+
+ if (parsed_region_chan->no_of_chan != 0) {
+ /*
+ * Check if the channel number already exists in the
+ * chan-power table of parsed_region_chan
+ */
+ for (i = 0; (i < region_chan.no_of_chan && i < MAX_NO_OF_CHAN); i++) {
+ for (j = 0; (j < parsed_region_chan->no_of_chan &&
+ j < MAX_NO_OF_CHAN); j++) {
+ /*
+ * Channel already exists, update the tx power with new tx
+ * power, since country IE is valid here.
+ */
+ if (region_chan.chan_pwr[i].chan ==
+ parsed_region_chan->chan_pwr[j].chan &&
+ region_chan.chan_pwr[i].band ==
+ parsed_region_chan->chan_pwr[j].band) {
+ parsed_region_chan->chan_pwr[j].pwr =
+ region_chan.chan_pwr[i].pwr;
+ break;
+ }
+ }
+
+ if (j == parsed_region_chan->no_of_chan && j < MAX_NO_OF_CHAN) {
+ /*
+ * Channel does not exist in the channel power table,
+ * update this new chan and tx_power to the channel power table
+ */
+ parsed_region_chan->chan_pwr[parsed_region_chan->no_of_chan +
+ num_chan_added].chan =
+ region_chan.chan_pwr[i].chan;
+ parsed_region_chan->chan_pwr[parsed_region_chan->no_of_chan +
+ num_chan_added].band =
+ region_chan.chan_pwr[i].band;
+ parsed_region_chan->chan_pwr[parsed_region_chan->no_of_chan +
+ num_chan_added].pwr =
+ region_chan.chan_pwr[i].pwr;
+ parsed_region_chan->chan_pwr[parsed_region_chan->no_of_chan +
+ num_chan_added].ap_seen = MFALSE;
+ num_chan_added++;
+ }
+ }
+ parsed_region_chan->no_of_chan += num_chan_added;
+ } else {
+ /* Parsed region is empty, copy the first one */
+ memcpy(pmadapter, parsed_region_chan,
+ &region_chan, sizeof(parsed_region_chan_11d_t));
+ }
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This helper function copies chan_power_11d_t element
+ *
+ * @param chan_dst Pointer to destination of chan_power
+ * @param chan_src Pointer to source of chan_power
+ *
+ * @return N/A
+ */
+static t_void
+wlan_11d_copy_chan_power(chan_power_11d_t * chan_dst,
+ chan_power_11d_t * chan_src)
+{
+ ENTER();
+
+ chan_dst->chan = chan_src->chan;
+ chan_dst->band = chan_src->band;
+ chan_dst->pwr = chan_src->pwr;
+ chan_dst->ap_seen = chan_src->ap_seen;
+
+ LEAVE();
+ return;
+}
+
+/**
+ * @brief This function sorts parsed_region_chan in ascending
+ * channel number.
+ *
+ * @param parsed_region_chan Pointer to parsed_region_chan_11d_t
+ *
+ * @return N/A
+ */
+static t_void
+wlan_11d_sort_parsed_region_chan(parsed_region_chan_11d_t * parsed_region_chan)
+{
+ int i, j;
+ chan_power_11d_t temp;
+ chan_power_11d_t *pchan_power = parsed_region_chan->chan_pwr;
+
+ ENTER();
+
+ PRINTM(MINFO, "11D: Number of channel = %d\n",
+ parsed_region_chan->no_of_chan);
+
+ // Use insertion sort method
+ for (i = 1; i < parsed_region_chan->no_of_chan; i++) {
+ wlan_11d_copy_chan_power(&temp, pchan_power + i);
+ for (j = i; j > 0 && (pchan_power + j - 1)->chan > temp.chan; j--)
+ wlan_11d_copy_chan_power(pchan_power + j, pchan_power + j - 1);
+ wlan_11d_copy_chan_power(pchan_power + j, &temp);
+ }
+
+ HEXDUMP("11D: parsed_region_chan", (t_u8 *) parsed_region_chan,
+ sizeof(parsed_region_chan_11d_t));
+
+ LEAVE();
+ return;
+}
+#endif /* STA_SUPPORT */
+
+/**
+ * @brief This function sends domain info to FW
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param pioctl_buf A pointer to MLAN IOCTL Request buffer
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+static mlan_status
+wlan_11d_send_domain_info(mlan_private * pmpriv, t_void * pioctl_buf)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ /* Send cmd to FW to set domain info */
+ ret = wlan_prepare_cmd(pmpriv,
+ HostCmd_CMD_802_11D_DOMAIN_INFO,
+ HostCmd_ACT_GEN_SET,
+ 0, (t_void *) pioctl_buf, MNULL);
+ if (ret)
+ PRINTM(MERROR, "11D: Failed to download domain Info\n");
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function overwrites domain_info
+ *
+ * @param pmadapter Pointer to mlan_adapter structure
+ * @param band Intended operating band
+ * @param country_code Intended country code
+ * @param num_sub_band Count of tuples in list below
+ * @param sub_band_list List of sub_band tuples
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+static mlan_status
+wlan_11d_set_domain_info(mlan_private * pmpriv,
+ t_u8 band,
+ t_u8 country_code[COUNTRY_CODE_LEN],
+ t_u8 num_sub_band,
+ IEEEtypes_SubbandSet_t * sub_band_list)
+{
+ mlan_adapter *pmadapter = pmpriv->adapter;
+ wlan_802_11d_domain_reg_t *pdomain = &pmadapter->domain_reg;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ memset(pmadapter, pdomain, 0, sizeof(wlan_802_11d_domain_reg_t));
+ memcpy(pmadapter, pdomain->country_code, country_code, COUNTRY_CODE_LEN);
+ pdomain->band = band;
+ pdomain->no_of_sub_band = num_sub_band;
+ memcpy(pmadapter, pdomain->sub_band, sub_band_list,
+ MIN(MRVDRV_MAX_SUBBAND_802_11D,
+ num_sub_band) * sizeof(IEEEtypes_SubbandSet_t));
+
+ LEAVE();
+ return ret;
+}
+
+/********************************************************
+ Global functions
+********************************************************/
+
+/**
+ * @brief This function gets if priv is a station (STA)
+ *
+ * @param pmpriv Pointer to mlan_private structure
+ *
+ * @return MTRUE or MFALSE
+ */
+t_bool
+wlan_is_station(mlan_private * pmpriv)
+{
+ ENTER();
+ LEAVE();
+ return (GET_BSS_ROLE(pmpriv) == MLAN_BSS_ROLE_STA) ? MTRUE : MFALSE;
+}
+
+/**
+ * @brief This function gets if 11D is enabled
+ *
+ * @param pmpriv Pointer to mlan_private structure
+ *
+ * @return MTRUE or MFALSE
+ */
+t_bool
+wlan_11d_is_enabled(mlan_private * pmpriv)
+{
+ ENTER();
+ LEAVE();
+ return (pmpriv->state_11d.enable_11d == ENABLE_11D) ? MTRUE : MFALSE;
+}
+
+/**
+ * @brief Initialize interface variable for 11D
+ *
+ * @param pmpriv Pointer to mlan_private structure
+ *
+ * @return N/A
+ */
+t_void
+wlan_11d_priv_init(mlan_private * pmpriv)
+{
+ wlan_802_11d_state_t *state = &pmpriv->state_11d;
+
+ ENTER();
+
+ /* Start in disabled mode */
+ state->enable_11d = DISABLE_11D;
+ if (!pmpriv->adapter->init_para.cfg_11d)
+ state->user_enable_11d = DEFAULT_11D_STATE;
+ else
+ state->user_enable_11d =
+ (pmpriv->adapter->init_para.cfg_11d == MLAN_INIT_PARA_DISABLED) ?
+ DISABLE_11D : ENABLE_11D;
+
+ LEAVE();
+ return;
+}
+
+/**
+ * @brief Initialize device variable for 11D
+ *
+ * @param pmadapter Pointer to mlan_adapter structure
+ *
+ * @return N/A
+ */
+t_void
+wlan_11d_init(mlan_adapter * pmadapter)
+{
+ ENTER();
+
+#ifdef STA_SUPPORT
+ memset(pmadapter, &(pmadapter->parsed_region_chan), 0,
+ sizeof(parsed_region_chan_11d_t));
+ memset(pmadapter, &(pmadapter->universal_channel), 0,
+ sizeof(region_chan_t));
+#endif
+ memset(pmadapter, &(pmadapter->domain_reg), 0,
+ sizeof(wlan_802_11d_domain_reg_t));
+
+ LEAVE();
+ return;
+}
+
+/**
+ * @brief This function enable/disable 11D
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param pioctl_buf A pointer to MLAN IOCTL Request buffer
+ * @param flag 11D status
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status
+wlan_11d_enable(mlan_private * pmpriv, t_void * pioctl_buf, state_11d_t flag)
+{
+#ifdef STA_SUPPORT
+ mlan_adapter *pmadapter = pmpriv->adapter;
+#endif
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ state_11d_t enable = flag;
+
+ ENTER();
+
+ /* Send cmd to FW to enable/disable 11D function */
+ ret = wlan_prepare_cmd(pmpriv,
+ HostCmd_CMD_802_11_SNMP_MIB,
+ HostCmd_ACT_GEN_SET,
+ Dot11D_i, (t_void *) pioctl_buf, &enable);
+
+ if (ret) {
+ PRINTM(MERROR, "11D: Failed to %s 11D\n",
+ (flag) ? "enable" : "disable");
+ }
+#ifdef STA_SUPPORT
+ else {
+ /* clear parsed table regardless of flag */
+ memset(pmadapter, &(pmadapter->parsed_region_chan), 0,
+ sizeof(parsed_region_chan_11d_t));
+ }
+#endif
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function implements command CMD_802_11D_DOMAIN_INFO
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param pcmd A pointer to HostCmd_DS_COMMAND structure of
+ * command buffer
+ * @param cmd_action Command action
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+mlan_status
+wlan_cmd_802_11d_domain_info(mlan_private * pmpriv,
+ HostCmd_DS_COMMAND * pcmd, t_u16 cmd_action)
+{
+ mlan_adapter *pmadapter = pmpriv->adapter;
+ HostCmd_DS_802_11D_DOMAIN_INFO *pdomain_info = &pcmd->params.domain_info;
+ MrvlIEtypes_DomainParamSet_t *domain = &pdomain_info->domain;
+ t_u8 no_of_sub_band = pmadapter->domain_reg.no_of_sub_band;
+
+ ENTER();
+
+ PRINTM(MINFO, "11D: number of sub-band=0x%x\n", no_of_sub_band);
+
+ pcmd->command = wlan_cpu_to_le16(HostCmd_CMD_802_11D_DOMAIN_INFO);
+ pdomain_info->action = wlan_cpu_to_le16(cmd_action);
+ if (cmd_action == HostCmd_ACT_GEN_GET) {
+ /* Dump domain info */
+ pcmd->size = wlan_cpu_to_le16(sizeof(pdomain_info->action) + S_DS_GEN);
+ HEXDUMP("11D: 802_11D_DOMAIN_INFO", (t_u8 *) pcmd,
+ wlan_le16_to_cpu(pcmd->size));
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+ }
+
+ /* Set domain info fields */
+ domain->header.type = wlan_cpu_to_le16(TLV_TYPE_DOMAIN);
+ memcpy(pmadapter, domain->country_code,
+ pmadapter->domain_reg.country_code, sizeof(domain->country_code));
+
+ domain->header.len = ((no_of_sub_band * sizeof(IEEEtypes_SubbandSet_t)) +
+ sizeof(domain->country_code));
+
+ if (no_of_sub_band) {
+ memcpy(pmadapter, domain->sub_band,
+ pmadapter->domain_reg.sub_band,
+ MIN(MRVDRV_MAX_SUBBAND_802_11D,
+ no_of_sub_band) * sizeof(IEEEtypes_SubbandSet_t));
+
+ pcmd->size = wlan_cpu_to_le16(sizeof(pdomain_info->action) +
+ domain->header.len +
+ sizeof(MrvlIEtypesHeader_t) + S_DS_GEN);
+ } else {
+ pcmd->size = wlan_cpu_to_le16(sizeof(pdomain_info->action) + S_DS_GEN);
+ }
+ domain->header.len = wlan_cpu_to_le16(domain->header.len);
+
+ HEXDUMP("11D: 802_11D_DOMAIN_INFO", (t_u8 *) pcmd,
+ wlan_le16_to_cpu(pcmd->size));
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function handle response of CMD_802_11D_DOMAIN_INFO
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param resp Pointer to command response buffer
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status
+wlan_ret_802_11d_domain_info(mlan_private * pmpriv, HostCmd_DS_COMMAND * resp)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ HostCmd_DS_802_11D_DOMAIN_INFO_RSP *domain_info =
+ &resp->params.domain_info_resp;
+ MrvlIEtypes_DomainParamSet_t *domain = &domain_info->domain;
+ t_u16 action = wlan_le16_to_cpu(domain_info->action);
+ t_u8 no_of_sub_band = 0;
+
+ ENTER();
+
+ /* Dump domain info response data */
+ HEXDUMP("11D: DOMAIN Info Rsp Data", (t_u8 *) resp, resp->size);
+
+ no_of_sub_band =
+ (t_u8) ((wlan_le16_to_cpu(domain->header.len) - COUNTRY_CODE_LEN)
+ / sizeof(IEEEtypes_SubbandSet_t));
+
+ PRINTM(MINFO, "11D Domain Info Resp: number of sub-band=%d\n",
+ no_of_sub_band);
+
+ if (no_of_sub_band > MRVDRV_MAX_SUBBAND_802_11D) {
+ PRINTM(MWARN, "11D: Invalid number of subbands %d returned!!\n",
+ no_of_sub_band);
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+
+ switch (action) {
+ case HostCmd_ACT_GEN_SET: /* Proc Set Action */
+ break;
+ case HostCmd_ACT_GEN_GET:
+ break;
+ default:
+ PRINTM(MERROR, "11D: Invalid Action:%d\n", domain_info->action);
+ ret = MLAN_STATUS_FAILURE;
+ break;
+ }
+
+ LEAVE();
+ return ret;
+}
+
+#ifdef STA_SUPPORT
+/**
+ * @brief This function parses country information for region channel
+ *
+ * @param pmadapter Pointer to mlan_adapter structure
+ * @param country_info Country information
+ * @param band Chan band
+ * @param parsed_region_chan Pointer to parsed_region_chan_11d_t
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status
+wlan_11d_parse_domain_info(pmlan_adapter pmadapter,
+ IEEEtypes_CountryInfoFullSet_t * country_info,
+ t_u8 band,
+ parsed_region_chan_11d_t * parsed_region_chan)
+{
+ t_u8 no_of_sub_band, no_of_chan;
+ t_u8 last_chan, first_chan, cur_chan = 0;
+ t_u8 idx = 0;
+ t_u8 j, i;
+
+ ENTER();
+
+ /*
+ * Validation Rules:
+ * 1. Valid Region Code
+ * 2. First Chan increment
+ * 3. Channel range no overlap
+ * 4. Channel is valid?
+ * 5. Channel is supported by Region?
+ * 6. Others
+ */
+
+ HEXDUMP("country_info", (t_u8 *) country_info, 30);
+
+ /* Step 1: Check region_code */
+ if (!(*(country_info->country_code)) ||
+ (country_info->len <= COUNTRY_CODE_LEN)) {
+ /* No region info or wrong region info: treat as no 11D info */
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+
+ no_of_sub_band = (country_info->len - COUNTRY_CODE_LEN) /
+ sizeof(IEEEtypes_SubbandSet_t);
+
+ for (j = 0, last_chan = 0; j < no_of_sub_band; j++) {
+
+ if (country_info->sub_band[j].first_chan <= last_chan) {
+ /* Step2&3: Check First Chan Num increment and no overlap */
+ PRINTM(MINFO, "11D: Chan[%d>%d] Overlap\n",
+ country_info->sub_band[j].first_chan, last_chan);
+ continue;
+ }
+
+ first_chan = country_info->sub_band[j].first_chan;
+ no_of_chan = country_info->sub_band[j].no_of_chan;
+
+ for (i = 0; idx < MAX_NO_OF_CHAN && i < no_of_chan; i++) {
+ /* Step 4 : Channel is supported? */
+ if (wlan_11d_get_chan(pmadapter, band, first_chan, i, &cur_chan) ==
+ MFALSE) {
+ /* Chan is not found in UN table */
+ PRINTM(MWARN, "11D: channel is not supported: %d\n", i);
+ break;
+ }
+
+ last_chan = cur_chan;
+
+ /* Step 5: We don't need to check if cur_chan is supported by mrvl
+ in region */
+ parsed_region_chan->chan_pwr[idx].chan = cur_chan;
+ parsed_region_chan->chan_pwr[idx].band = band;
+ parsed_region_chan->chan_pwr[idx].pwr =
+ country_info->sub_band[j].max_tx_pwr;
+ idx++;
+ }
+
+ /* Step 6: Add other checking if any */
+ }
+
+ parsed_region_chan->no_of_chan = idx;
+
+ PRINTM(MINFO, "11D: number of channel=0x%x\n",
+ parsed_region_chan->no_of_chan);
+ HEXDUMP("11D: parsed_region_chan", (t_u8 *) parsed_region_chan->chan_pwr,
+ sizeof(chan_power_11d_t) * idx);
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function converts channel to frequency
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param chan Channel number
+ * @param band Band
+ *
+ * @return Channel frequency
+ */
+t_u32
+wlan_11d_chan_2_freq(pmlan_adapter pmadapter, t_u8 chan, t_u8 band)
+{
+ chan_freq_power_t *cf;
+ t_u16 cnt;
+ t_u16 i;
+ t_u32 freq = 0;
+
+ ENTER();
+
+ /* Get channel-frequency-power trios */
+ if (band & (BAND_A | BAND_AN)) {
+ cf = channel_freq_power_UN_AJ;
+ cnt = sizeof(channel_freq_power_UN_AJ) / sizeof(chan_freq_power_t);
+ } else {
+ cf = channel_freq_power_UN_BG;
+ cnt = sizeof(channel_freq_power_UN_BG) / sizeof(chan_freq_power_t);
+ }
+
+ /* Locate channel and return corresponding frequency */
+ for (i = 0; i < cnt; i++) {
+ if (chan == cf[i].channel)
+ freq = cf[i].freq;
+ }
+
+ LEAVE();
+ return freq;
+}
+
+/**
+ * @brief This function setups scan channels
+ *
+ * @param pmpriv Pointer to mlan_private structure
+ * @param band Band
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+mlan_status
+wlan_11d_set_universaltable(mlan_private * pmpriv, t_u8 band)
+{
+ mlan_adapter *pmadapter = pmpriv->adapter;
+ t_u16 size = sizeof(chan_freq_power_t);
+ t_u16 i = 0;
+
+ ENTER();
+
+ memset(pmadapter, pmadapter->universal_channel, 0,
+ sizeof(pmadapter->universal_channel));
+
+ if (band & (BAND_B | BAND_G | BAND_GN))
+ /* If band B, G or N */
+ {
+ /* Set channel-frequency-power */
+ pmadapter->universal_channel[i].num_cfp =
+ (t_u8) (sizeof(channel_freq_power_UN_BG) / size);
+ PRINTM(MINFO, "11D: BG-band num_cfp=%d\n",
+ pmadapter->universal_channel[i].num_cfp);
+
+ pmadapter->universal_channel[i].pcfp = channel_freq_power_UN_BG;
+ pmadapter->universal_channel[i].valid = MTRUE;
+
+ /* Set region code */
+ pmadapter->universal_channel[i].region = UNIVERSAL_REGION_CODE;
+
+ /* Set band */
+ if (band & BAND_GN)
+ pmadapter->universal_channel[i].band = BAND_G;
+ else
+ pmadapter->universal_channel[i].band =
+ (band & BAND_G) ? BAND_G : BAND_B;
+ i++;
+ }
+
+ if (band & (BAND_A | BAND_AN)) {
+ /* If band A */
+
+ /* Set channel-frequency-power */
+ pmadapter->universal_channel[i].num_cfp =
+ sizeof(channel_freq_power_UN_AJ) / size;
+ PRINTM(MINFO, "11D: AJ-band num_cfp=%d\n",
+ pmadapter->universal_channel[i].num_cfp);
+
+ pmadapter->universal_channel[i].pcfp = channel_freq_power_UN_AJ;
+
+ pmadapter->universal_channel[i].valid = MTRUE;
+
+ /* Set region code */
+ pmadapter->universal_channel[i].region = UNIVERSAL_REGION_CODE;
+
+ /* Set band */
+ pmadapter->universal_channel[i].band = BAND_A;
+ i++;
+ }
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function calculates the scan type for channels
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param band Band number
+ * @param chan Chan number
+ * @param parsed_region_chan Pointer to parsed_region_chan_11d_t
+ *
+ * @return PASSIVE if chan is unknown; ACTIVE if chan is known
+ */
+t_u8
+wlan_11d_get_scan_type(pmlan_adapter pmadapter,
+ t_u8 band,
+ t_u8 chan, parsed_region_chan_11d_t * parsed_region_chan)
+{
+ t_u8 scan_type = MLAN_SCAN_TYPE_PASSIVE;
+
+ ENTER();
+
+ if (wlan_11d_channel_known(pmadapter, band, chan, parsed_region_chan)) {
+ /* Channel found */
+ PRINTM(MINFO, "11D: Channel found and doing Active Scan\n");
+ scan_type = MLAN_SCAN_TYPE_ACTIVE;
+ } else
+ PRINTM(MINFO, "11D: Channel not found and doing Passive Scan\n");
+
+ LEAVE();
+ return scan_type;
+}
+
+/**
+ * @brief This function clears the parsed region table, if 11D is enabled
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status
+wlan_11d_clear_parsedtable(mlan_private * pmpriv)
+{
+ mlan_adapter *pmadapter = pmpriv->adapter;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ if (wlan_11d_is_enabled(pmpriv))
+ memset(pmadapter, &(pmadapter->parsed_region_chan), 0,
+ sizeof(parsed_region_chan_11d_t));
+ else
+ ret = MLAN_STATUS_FAILURE;
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function generates 11D info from user specified regioncode
+ * and download to FW
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param band Band to create
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status
+wlan_11d_create_dnld_countryinfo(mlan_private * pmpriv, t_u8 band)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_adapter *pmadapter = pmpriv->adapter;
+ region_chan_t *region_chan;
+ parsed_region_chan_11d_t parsed_region_chan;
+ t_u8 j;
+
+ ENTER();
+
+ /* Only valid if 11D is enabled */
+ if (wlan_11d_is_enabled(pmpriv)) {
+
+ PRINTM(MINFO, "11D: Band[%d]\n", band);
+
+ /* Update parsed_region_chan; download domain info to FW */
+
+ /* Find region channel */
+ for (j = 0; j < MAX_REGION_CHANNEL_NUM; j++) {
+ region_chan = &pmadapter->region_channel[j];
+
+ PRINTM(MINFO, "11D: [%d] region_chan->Band[%d]\n", j,
+ region_chan->band);
+
+ if (!region_chan || !region_chan->valid || !region_chan->pcfp)
+ continue;
+ switch (region_chan->band) {
+ case BAND_A:
+ switch (band) {
+ case BAND_A:
+ case BAND_AN:
+ case BAND_A | BAND_AN:
+ break;
+ default:
+ continue;
+ }
+ break;
+ case BAND_B:
+ case BAND_G:
+ switch (band) {
+ case BAND_B:
+ case BAND_G:
+ case BAND_G | BAND_B:
+ case BAND_GN:
+ case BAND_G | BAND_GN:
+ case BAND_B | BAND_G | BAND_GN:
+ break;
+ default:
+ continue;
+ }
+ break;
+ default:
+ continue;
+ }
+ break;
+ }
+
+ /* Check if region channel found */
+ if (j >= MAX_REGION_CHANNEL_NUM) {
+ PRINTM(MERROR, "11D: region_chan not found. Band[%d]\n", band);
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+
+ /* Generate parsed region channel info from region channel */
+ memset(pmadapter, &parsed_region_chan, 0,
+ sizeof(parsed_region_chan_11d_t));
+ wlan_11d_generate_parsed_region_chan(pmadapter, region_chan,
+ &parsed_region_chan);
+
+ /* Generate domain info from parsed region channel info */
+ wlan_11d_generate_domain_info(pmadapter, &parsed_region_chan);
+
+ /* Set domain info */
+ ret = wlan_11d_send_domain_info(pmpriv, MNULL);
+ if (ret) {
+ PRINTM(MERROR, "11D: Error sending domain info to FW\n");
+ }
+ }
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function parses country info from AP and
+ * download country info to FW
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param pbss_desc A pointer to BSS descriptor
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status
+wlan_11d_parse_dnld_countryinfo(mlan_private * pmpriv,
+ BSSDescriptor_t * pbss_desc)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_adapter *pmadapter = pmpriv->adapter;
+ parsed_region_chan_11d_t region_chan;
+ parsed_region_chan_11d_t bssdesc_region_chan;
+ t_u32 i, j;
+
+ ENTER();
+
+ /* Only valid if 11D is enabled */
+ if (wlan_11d_is_enabled(pmpriv)) {
+
+ memset(pmadapter, &region_chan, 0, sizeof(parsed_region_chan_11d_t));
+ memset(pmadapter, &bssdesc_region_chan, 0,
+ sizeof(parsed_region_chan_11d_t));
+
+ memcpy(pmadapter, &region_chan,
+ &pmadapter->parsed_region_chan,
+ sizeof(parsed_region_chan_11d_t));
+
+ if (pbss_desc) {
+ /* Parse domain info if available */
+ ret =
+ wlan_11d_parse_domain_info(pmadapter, &pbss_desc->country_info,
+ (t_u8) pbss_desc->bss_band,
+ &bssdesc_region_chan);
+
+ if (ret == MLAN_STATUS_SUCCESS) {
+ /* Update the channel-power table */
+ for (i = 0; ((i < bssdesc_region_chan.no_of_chan)
+ && (i < MAX_NO_OF_CHAN)); i++) {
+
+ for (j = 0; ((j < region_chan.no_of_chan)
+ && (j < MAX_NO_OF_CHAN)); j++) {
+ /*
+ * Channel already exists, use minimum of existing
+ * tx power and tx_power received from
+ * country info of the current AP
+ */
+ if (region_chan.chan_pwr[i].chan ==
+ bssdesc_region_chan.chan_pwr[j].chan &&
+ region_chan.chan_pwr[i].band ==
+ bssdesc_region_chan.chan_pwr[j].band) {
+ region_chan.chan_pwr[j].pwr =
+ MIN(region_chan.chan_pwr[j].pwr,
+ bssdesc_region_chan.chan_pwr[i].pwr);
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ /* Generate domain info */
+ wlan_11d_generate_domain_info(pmadapter, &region_chan);
+
+ /* Set domain info */
+ ret = wlan_11d_send_domain_info(pmpriv, MNULL);
+ if (ret) {
+ PRINTM(MERROR, "11D: Error sending domain info to FW\n");
+ }
+ }
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function prepares domain info from scan table and
+ * downloads the domain info command to the FW.
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status
+wlan_11d_prepare_dnld_domain_info_cmd(mlan_private * pmpriv)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_adapter *pmadapter = pmpriv->adapter;
+ IEEEtypes_CountryInfoFullSet_t *pcountry_full = MNULL;
+ t_u32 idx;
+
+ ENTER();
+
+ /* Only valid if 11D is enabled */
+ if (wlan_11d_is_enabled(pmpriv) && pmadapter->num_in_scan_table != 0) {
+ for (idx = 0; idx < pmadapter->num_in_scan_table; idx++) {
+ pcountry_full = &pmadapter->pscan_table[idx].country_info;
+
+ ret =
+ wlan_11d_update_chan_pwr_table(pmpriv,
+ &pmadapter->pscan_table[idx]);
+
+ if (*(pcountry_full->country_code) != 0 &&
+ (pcountry_full->len > COUNTRY_CODE_LEN)) {
+ /* Country info found in the BSS Descriptor */
+ ret =
+ wlan_11d_process_country_info(pmpriv,
+ &pmadapter->pscan_table[idx]);
+ }
+ }
+
+ /* Sort parsed_region_chan in ascending channel number */
+ wlan_11d_sort_parsed_region_chan(&pmadapter->parsed_region_chan);
+
+ /* Check if connected */
+ if (pmpriv->media_connected == MTRUE) {
+ ret =
+ wlan_11d_parse_dnld_countryinfo(pmpriv,
+ &pmpriv->curr_bss_params.
+ bss_descriptor);
+ } else {
+ ret = wlan_11d_parse_dnld_countryinfo(pmpriv, MNULL);
+ }
+ }
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function sets up domain_reg and downloads CMD to FW
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req Pointer to the IOCTL request buffer
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status
+wlan_11d_cfg_domain_info(IN pmlan_adapter pmadapter,
+ IN mlan_ioctl_req * pioctl_req)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
+ mlan_ds_11d_domain_info *domain_info = MNULL;
+ mlan_ds_11d_cfg *cfg_11d = MNULL;
+ t_u8 region_code = 0;
+
+ ENTER();
+
+ cfg_11d = (mlan_ds_11d_cfg *) pioctl_req->pbuf;
+ domain_info = &cfg_11d->param.domain_info;
+
+ /* Update region code and table based on country code */
+ if (wlan_11d_region_2_code(pmadapter, domain_info->country_code,
+ &region_code) == MLAN_STATUS_SUCCESS) {
+ pmadapter->region_code = region_code;
+ ret = wlan_set_regiontable(pmpriv, region_code, pmadapter->fw_bands);
+ if (ret != MLAN_STATUS_SUCCESS)
+ goto done;
+ }
+
+ wlan_11d_set_domain_info(pmpriv, domain_info->band,
+ domain_info->country_code,
+ domain_info->no_of_sub_band,
+ (IEEEtypes_SubbandSet_t *) domain_info->sub_band);
+ ret = wlan_11d_send_domain_info(pmpriv, pioctl_req);
+
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+
+ done:
+ LEAVE();
+ return ret;
+}
+#endif /* STA_SUPPORT */
+
+#if defined(UAP_SUPPORT)
+/**
+ * @brief This function handles domain info data from UAP interface.
+ * Checks conditions, sets up domain_reg, then downloads CMD.
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param band Band interface is operating on
+ * @param domain_tlv Pointer to domain_info tlv
+ * @param pioctl_buf Pointer to the IOCTL buffer
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status
+wlan_11d_handle_uap_domain_info(mlan_private * pmpriv,
+ t_u8 band,
+ t_u8 * domain_tlv, t_void * pioctl_buf)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_adapter *pmadapter = pmpriv->adapter;
+ MrvlIEtypes_DomainParamSet_t *pdomain_tlv;
+ t_u8 num_sub_band = 0;
+ t_u8 region_code = 0;
+
+ ENTER();
+
+ pdomain_tlv = (MrvlIEtypes_DomainParamSet_t *) domain_tlv;
+
+ // update region code & table based on country string
+ if (wlan_11d_region_2_code(pmadapter, pdomain_tlv->country_code,
+ &region_code) == MLAN_STATUS_SUCCESS) {
+ pmadapter->region_code = region_code;
+ ret = wlan_set_regiontable(pmpriv, region_code, pmadapter->fw_bands);
+ }
+
+ num_sub_band = ((pdomain_tlv->header.len - COUNTRY_CODE_LEN) /
+ sizeof(IEEEtypes_SubbandSet_t));
+
+ // TODO: don't just clobber pmadapter->domain_reg.
+ // Add some checking or merging between STA & UAP domain_info
+
+ wlan_11d_set_domain_info(pmpriv, band, pdomain_tlv->country_code,
+ num_sub_band, pdomain_tlv->sub_band);
+ ret = wlan_11d_send_domain_info(pmpriv, pioctl_buf);
+
+ LEAVE();
+ return ret;
+}
+#endif
diff --git a/drivers/net/wireless/sd8797/mlan/mlan_11h.c b/drivers/net/wireless/sd8797/mlan/mlan_11h.c
new file mode 100644
index 000000000000..23970861db1e
--- /dev/null
+++ b/drivers/net/wireless/sd8797/mlan/mlan_11h.c
@@ -0,0 +1,3180 @@
+/** @file mlan_11h.c
+ *
+ * @brief This file contains functions for 802.11H.
+ *
+ * Copyright (C) 2008-2011, Marvell International Ltd.
+ *
+ * This software file (the "File") is distributed by Marvell International
+ * Ltd. under the terms of the GNU General Public License Version 2, June 1991
+ * (the "License"). You may use, redistribute and/or modify this File in
+ * accordance with the terms and conditions of the License, a copy of which
+ * is available by writing to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
+ * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
+ *
+ * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
+ * ARE EXPRESSLY DISCLAIMED. The License provides additional details about
+ * this warranty disclaimer.
+ *
+ */
+
+/*************************************************************
+Change Log:
+ 03/26/2009: initial version
+************************************************************/
+
+#include "mlan.h"
+#include "mlan_join.h"
+#include "mlan_util.h"
+#include "mlan_fw.h"
+#include "mlan_main.h"
+#include "mlan_ioctl.h"
+#include "mlan_11h.h"
+#ifdef UAP_SUPPORT
+#include "mlan_uap.h"
+#endif
+
+/********************************************************
+ Local Variables
+********************************************************/
+
+/** Default IBSS DFS recovery interval (in TBTTs); used for adhoc start */
+#define WLAN_11H_DEFAULT_DFS_RECOVERY_INTERVAL 100
+
+/** Default 11h power constraint used to offset the maximum transmit power */
+#define WLAN_11H_TPC_POWERCONSTRAINT 0
+
+/** 11h TPC Power capability minimum setting, sent in TPC_INFO command to fw */
+#define WLAN_11H_TPC_POWERCAPABILITY_MIN 5
+
+/** 11h TPC Power capability maximum setting, sent in TPC_INFO command to fw */
+#define WLAN_11H_TPC_POWERCAPABILITY_MAX 20
+
+/** Regulatory requirement for the duration of a channel availability check */
+#define WLAN_11H_CHANNEL_AVAIL_CHECK_DURATION 60000 /* in ms */
+
+/** Starting Frequency for 11A band */
+#define START_FREQ_11A_BAND 5000 /* in MHz */
+
+/** Regulatory requirement for the duration of a non-occupancy period */
+#define WLAN_11H_NON_OCCUPANCY_PERIOD 1800 /* in sec (30mins) */
+
+/** Maximum allowable age (seconds) on DFS report data */
+#define MAX_DFS_REPORT_USABLE_AGE_SEC (120) // 2 minutes
+
+/** Minimum delay for CHAN_SW IE to broadcast by FW */
+#define MIN_RDH_CHAN_SW_IE_PERIOD_MSEC (500) // 5 beacons @ 100ms
+
+/** Maximum delay for CHAN_SW IE to broadcast by FW */
+#define MAX_RDH_CHAN_SW_IE_PERIOD_MSEC (3000) // 5 beacons @ 600ms
+
+/** Maximum retries on selecting new random channel */
+#define MAX_RANDOM_CHANNEL_RETRIES (20)
+
+/** Maximum retries on selecting new random non-dfs channel */
+#define MAX_SWITCH_CHANNEL_RETRIES (30)
+
+/** Value for undetermined priv_curr_idx on first entry to new RDH stage */
+#define RDH_STAGE_FIRST_ENTRY_PRIV_IDX (0xff)
+
+/** Region codes 0x10, 0x20: channels 1 thru 11 supported */
+static const
+ IEEEtypes_SupportChan_Subband_t wlan_11h_2_4G_region_FCC = { 1, 11 };
+
+/** Region codes 0x30, 0x32, 0x41, 0x50: channels 1 thru 13 supported */
+static const
+ IEEEtypes_SupportChan_Subband_t wlan_11h_2_4G_region_EU = { 1, 13 };
+
+/** Region code 0x40: only channel 14 supported */
+static const
+ IEEEtypes_SupportChan_Subband_t wlan_11h_2_4G_region_JPN40 = { 14, 1 };
+
+/** JPN sub-band config : Start Channel = 8, NumChans = 3 */
+static const
+ IEEEtypes_SupportChan_Subband_t wlan_11h_JPN_bottom_band = { 8, 3 };
+
+/** U-NII sub-band config : Start Channel = 36, NumChans = 4 */
+static const
+ IEEEtypes_SupportChan_Subband_t wlan_11h_unii_lower_band = { 36, 4 };
+
+/** U-NII sub-band config : Start Channel = 52, NumChans = 4 */
+static const
+ IEEEtypes_SupportChan_Subband_t wlan_11h_unii_middle_band = { 52, 4 };
+
+/** U-NII sub-band config : Start Channel = 100, NumChans = 11 */
+static const
+ IEEEtypes_SupportChan_Subband_t wlan_11h_unii_mid_upper_band = { 100, 11 };
+
+/** U-NII sub-band config : Start Channel = 149, NumChans = 5 */
+static const
+ IEEEtypes_SupportChan_Subband_t wlan_11h_unii_upper_band = { 149, 5 };
+
+/** Internally passed structure used to send a CMD_802_11_TPC_INFO command */
+typedef struct
+{
+ t_u8 chan; /**< Channel to which the power constraint applies */
+ t_u8 power_constraint; /**< Local power constraint to send to firmware */
+} wlan_11h_tpc_info_param_t;
+
+/********************************************************
+ Global Variables
+********************************************************/
+
+/********************************************************
+ Local Functions
+********************************************************/
+
+/**
+ * @brief Utility function to get a random number based on the underlying OS
+ *
+ * @param pmadapter Pointer to mlan_adapter
+ * @return random integer
+ */
+static t_u32
+wlan_11h_get_random_num(pmlan_adapter pmadapter)
+{
+ t_u32 sec, usec;
+
+ ENTER();
+ pmadapter->callbacks.moal_get_system_time(pmadapter->pmoal_handle, &sec,
+ &usec);
+ sec = (sec & 0xFFFF) + (sec >> 16);
+ usec = (usec & 0xFFFF) + (usec >> 16);
+
+ LEAVE();
+ return ((usec << 16) | sec);
+}
+
+/**
+ * @brief Convert an IEEE formatted IE to 16-bit ID/Len Marvell
+ * proprietary format
+ *
+ * @param pmadapter Pointer to mlan_adapter
+ * @param pout_buf Output parameter: Buffer to output Marvell formatted IE
+ * @param pin_ie Pointer to IEEE IE to be converted to Marvell format
+ *
+ * @return Number of bytes output to pout_buf parameter return
+ */
+static t_u32
+wlan_11h_convert_ieee_to_mrvl_ie(mlan_adapter * pmadapter,
+ t_u8 * pout_buf, const t_u8 * pin_ie)
+{
+ MrvlIEtypesHeader_t mrvl_ie_hdr;
+ t_u8 *ptmp_buf = pout_buf;
+
+ ENTER();
+ /* Assign the Element Id and Len to the Marvell struct attributes */
+ mrvl_ie_hdr.type = wlan_cpu_to_le16(pin_ie[0]);
+ mrvl_ie_hdr.len = wlan_cpu_to_le16(pin_ie[1]);
+
+ /* If the element ID is zero, return without doing any copying */
+ if (!mrvl_ie_hdr.type) {
+ LEAVE();
+ return 0;
+ }
+
+ /* Copy the header to the buffer pointer */
+ memcpy(pmadapter, ptmp_buf, &mrvl_ie_hdr, sizeof(mrvl_ie_hdr));
+
+ /* Increment the temp buffer pointer by the size appended */
+ ptmp_buf += sizeof(mrvl_ie_hdr);
+
+ /* Append the data section of the IE; length given by the IEEE IE length */
+ memcpy(pmadapter, ptmp_buf, pin_ie + 2, pin_ie[1]);
+
+ LEAVE();
+ /* Return the number of bytes appended to pout_buf */
+ return (sizeof(mrvl_ie_hdr) + pin_ie[1]);
+}
+
+#ifdef STA_SUPPORT
+/**
+ * @brief Setup the IBSS DFS element passed to the firmware in adhoc start
+ * and join commands
+ *
+ * The DFS Owner and recovery fields are set to be our MAC address and
+ * a predetermined constant recovery value. If we are joining an adhoc
+ * network, these values are replaced with the existing IBSS values.
+ * They are valid only when starting a new IBSS.
+ *
+ * The IBSS DFS Element is variable in size based on the number of
+ * channels supported in our current region.
+ *
+ * @param priv Private driver information structure
+ * @param pdfs Output parameter: Pointer to the IBSS DFS element setup by
+ * this function.
+ *
+ * @return
+ * - Length of the returned element in pdfs output parameter
+ * - 0 if returned element is not setup
+ */
+static t_u32
+wlan_11h_set_ibss_dfs_ie(mlan_private * priv, IEEEtypes_IBSS_DFS_t * pdfs)
+{
+ t_u8 num_chans = 0;
+ MeasRptBasicMap_t initial_map;
+ mlan_adapter *adapter = priv->adapter;
+
+ ENTER();
+
+ memset(adapter, pdfs, 0x00, sizeof(IEEEtypes_IBSS_DFS_t));
+
+ /*
+ * A basic measurement report is included with each channel in the
+ * map field. Initial value for the map for each supported channel
+ * is with only the unmeasured bit set.
+ */
+ memset(adapter, &initial_map, 0x00, sizeof(initial_map));
+ initial_map.unmeasured = 1;
+
+ /* Set the DFS Owner and recovery interval fields */
+ memcpy(adapter, pdfs->dfs_owner, priv->curr_addr, sizeof(pdfs->dfs_owner));
+ pdfs->dfs_recovery_interval = WLAN_11H_DEFAULT_DFS_RECOVERY_INTERVAL;
+
+ for (; (num_chans < adapter->parsed_region_chan.no_of_chan)
+ && (num_chans < WLAN_11H_MAX_IBSS_DFS_CHANNELS); num_chans++) {
+ pdfs->channel_map[num_chans].channel_number =
+ adapter->parsed_region_chan.chan_pwr[num_chans].chan;
+
+ /*
+ * Set the initial map field with a basic measurement
+ */
+ pdfs->channel_map[num_chans].rpt_map = initial_map;
+ }
+
+ /*
+ * If we have an established channel map, include it and return
+ * a valid DFS element
+ */
+ if (num_chans) {
+ PRINTM(MINFO, "11h: Added %d channels to IBSS DFS Map\n", num_chans);
+
+ pdfs->element_id = IBSS_DFS;
+ pdfs->len =
+ (sizeof(pdfs->dfs_owner) + sizeof(pdfs->dfs_recovery_interval)
+ + num_chans * sizeof(IEEEtypes_ChannelMap_t));
+
+ LEAVE();
+ return (pdfs->len + sizeof(pdfs->len) + sizeof(pdfs->element_id));
+ }
+
+ /* Ensure the element is zeroed out for an invalid return */
+ memset(adapter, pdfs, 0x00, sizeof(IEEEtypes_IBSS_DFS_t));
+
+ LEAVE();
+ return 0;
+}
+#endif
+
+/**
+ * @brief Setup the Supported Channel IE sent in association requests
+ *
+ * The Supported Channels IE is required to be sent when the spectrum
+ * management capability (11h) is enabled. The element contains a
+ * starting channel and number of channels tuple for each sub-band
+ * the STA supports. This information is based on the operating region.
+ *
+ * @param priv Private driver information structure
+ * @param band Band in use
+ * @param psup_chan Output parameter: Pointer to the Supported Chan element
+ * setup by this function.
+ *
+ * @return
+ * - Length of the returned element in psup_chan output parameter
+ * - 0 if returned element is not setup
+ */
+static t_u16
+wlan_11h_set_supp_channels_ie(mlan_private * priv,
+ t_u8 band,
+ IEEEtypes_SupportedChannels_t * psup_chan)
+{
+ t_u16 num_subbands = 0;
+ t_u16 ret_len = 0;
+ t_u8 cfp_bg, cfp_a;
+
+ ENTER();
+ memset(priv->adapter, psup_chan, 0x00,
+ sizeof(IEEEtypes_SupportedChannels_t));
+
+ cfp_bg = cfp_a = priv->adapter->region_code;
+
+ if ((band & BAND_B) || (band & BAND_G)) {
+ /*
+ * Channels are contiguous in 2.4GHz, usually only one subband.
+ */
+ switch (cfp_bg) {
+ case 0x10: /* USA FCC */
+ case 0x20: /* Canada IC */
+ default:
+ psup_chan->subband[num_subbands++] = wlan_11h_2_4G_region_FCC;
+ break;
+ case 0x30: /* Europe ETSI */
+ case 0x32: /* France */
+ case 0x41: /* Japan */
+ case 0x50: /* China */
+ psup_chan->subband[num_subbands++] = wlan_11h_2_4G_region_EU;
+ break;
+ case 0x40: /* Japan */
+ psup_chan->subband[num_subbands++] = wlan_11h_2_4G_region_JPN40;
+ break;
+ case 0xff: /* Japan special */
+ psup_chan->subband[num_subbands++] = wlan_11h_2_4G_region_EU;
+ psup_chan->subband[num_subbands++] = wlan_11h_2_4G_region_JPN40;
+ break;
+ }
+ } else if (band & BAND_A) {
+ /*
+ * Set the supported channel elements based on the region code,
+ * incrementing num_subbands for each sub-band we append to the
+ * element.
+ */
+ switch (cfp_a) {
+ case 0x10: /* USA FCC */
+ case 0x20: /* Canada IC */
+ case 0x32: /* France */
+ psup_chan->subband[num_subbands++] = wlan_11h_unii_lower_band;
+ psup_chan->subband[num_subbands++] = wlan_11h_unii_middle_band;
+ psup_chan->subband[num_subbands++] = wlan_11h_unii_mid_upper_band;
+ psup_chan->subband[num_subbands++] = wlan_11h_unii_upper_band;
+ break;
+ case 0x30: /* Europe ETSI */
+ default:
+ psup_chan->subband[num_subbands++] = wlan_11h_unii_lower_band;
+ psup_chan->subband[num_subbands++] = wlan_11h_unii_middle_band;
+ psup_chan->subband[num_subbands++] = wlan_11h_unii_mid_upper_band;
+ break;
+ case 0x50: /* China */
+ psup_chan->subband[num_subbands++] = wlan_11h_unii_upper_band;
+ break;
+ case 0x40: /* Japan */
+ case 0x41: /* Japan */
+ case 0xff: /* Japan special */
+ psup_chan->subband[num_subbands++] = wlan_11h_JPN_bottom_band;
+ psup_chan->subband[num_subbands++] = wlan_11h_unii_lower_band;
+ psup_chan->subband[num_subbands++] = wlan_11h_unii_middle_band;
+ psup_chan->subband[num_subbands++] = wlan_11h_unii_mid_upper_band;
+ break;
+ }
+ }
+
+ /*
+ * If we have setup any supported subbands in the element, return a
+ * valid IE along with its size, else return 0.
+ */
+ if (num_subbands) {
+ psup_chan->element_id = SUPPORTED_CHANNELS;
+ psup_chan->len = num_subbands * sizeof(IEEEtypes_SupportChan_Subband_t);
+
+ ret_len = (t_u16) (psup_chan->len
+ + sizeof(psup_chan->len) +
+ sizeof(psup_chan->element_id));
+
+ HEXDUMP("11h: SupChan", (t_u8 *) psup_chan, ret_len);
+ }
+
+ LEAVE();
+ return ret_len;
+}
+
+/**
+ * @brief Prepare CMD_802_11_TPC_ADAPT_REQ firmware command
+ *
+ * @param priv Private driver information structure
+ * @param pcmd_ptr Output parameter: Pointer to the command being prepared
+ * for the firmware
+ * @param pinfo_buf HostCmd_DS_802_11_TPC_ADAPT_REQ passed as void data block
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+static mlan_status
+wlan_11h_cmd_tpc_request(mlan_private * priv,
+ HostCmd_DS_COMMAND * pcmd_ptr,
+ const t_void * pinfo_buf)
+{
+ ENTER();
+
+ memcpy(priv->adapter, &pcmd_ptr->params.tpc_req, pinfo_buf,
+ sizeof(HostCmd_DS_802_11_TPC_ADAPT_REQ));
+
+ pcmd_ptr->params.tpc_req.req.timeout =
+ wlan_cpu_to_le16(pcmd_ptr->params.tpc_req.req.timeout);
+
+ /* Converted to little endian in wlan_11h_cmd_process */
+ pcmd_ptr->size = sizeof(HostCmd_DS_802_11_TPC_ADAPT_REQ) + S_DS_GEN;
+
+ HEXDUMP("11h: 11_TPC_ADAPT_REQ:", (t_u8 *) pcmd_ptr,
+ (t_u32) pcmd_ptr->size);
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief Prepare CMD_802_11_TPC_INFO firmware command
+ *
+ * @param priv Private driver information structure
+ * @param pcmd_ptr Output parameter: Pointer to the command being prepared
+ * for the firmware
+ * @param pinfo_buf wlan_11h_tpc_info_param_t passed as void data block
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+static mlan_status
+wlan_11h_cmd_tpc_info(mlan_private * priv,
+ HostCmd_DS_COMMAND * pcmd_ptr, const t_void * pinfo_buf)
+{
+ HostCmd_DS_802_11_TPC_INFO *ptpc_info = &pcmd_ptr->params.tpc_info;
+ MrvlIEtypes_LocalPowerConstraint_t *pconstraint =
+ &ptpc_info->local_constraint;
+ MrvlIEtypes_PowerCapability_t *pcap = &ptpc_info->power_cap;
+
+ wlan_11h_device_state_t *pstate = &priv->adapter->state_11h;
+ const wlan_11h_tpc_info_param_t *ptpc_info_param =
+ (wlan_11h_tpc_info_param_t *) pinfo_buf;
+
+ ENTER();
+
+ pcap->min_power = pstate->min_tx_power_capability;
+ pcap->max_power = pstate->max_tx_power_capability;
+ pcap->header.len = wlan_cpu_to_le16(2);
+ pcap->header.type = wlan_cpu_to_le16(TLV_TYPE_POWER_CAPABILITY);
+
+ pconstraint->chan = ptpc_info_param->chan;
+ pconstraint->constraint = ptpc_info_param->power_constraint;
+ pconstraint->header.type = wlan_cpu_to_le16(TLV_TYPE_POWER_CONSTRAINT);
+ pconstraint->header.len = wlan_cpu_to_le16(2);
+
+ /* Converted to little endian in wlan_11h_cmd_process */
+ pcmd_ptr->size = sizeof(HostCmd_DS_802_11_TPC_INFO) + S_DS_GEN;
+
+ HEXDUMP("11h: TPC INFO", (t_u8 *) pcmd_ptr, (t_u32) pcmd_ptr->size);
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief Prepare CMD_802_11_CHAN_SW_ANN firmware command
+ *
+ * @param priv Private driver information structure
+ * @param pcmd_ptr Output parameter: Pointer to the command being
+ * prepared to for firmware
+ * @param pinfo_buf HostCmd_DS_802_11_CHAN_SW_ANN passed as void data block
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+static mlan_status
+wlan_11h_cmd_chan_sw_ann(mlan_private * priv,
+ HostCmd_DS_COMMAND * pcmd_ptr,
+ const t_void * pinfo_buf)
+{
+ const HostCmd_DS_802_11_CHAN_SW_ANN *pch_sw_ann =
+ (HostCmd_DS_802_11_CHAN_SW_ANN *) pinfo_buf;
+
+ ENTER();
+
+ /* Converted to little endian in wlan_11h_cmd_process */
+ pcmd_ptr->size = sizeof(HostCmd_DS_802_11_CHAN_SW_ANN) + S_DS_GEN;
+
+ memcpy(priv->adapter, &pcmd_ptr->params.chan_sw_ann, pch_sw_ann,
+ sizeof(HostCmd_DS_802_11_CHAN_SW_ANN));
+
+ PRINTM(MINFO, "11h: ChSwAnn: %#x-%u, Seq=%u, Ret=%u\n",
+ pcmd_ptr->command, pcmd_ptr->size, pcmd_ptr->seq_num,
+ pcmd_ptr->result);
+ PRINTM(MINFO, "11h: ChSwAnn: Ch=%d, Cnt=%d, Mode=%d\n",
+ pch_sw_ann->new_chan, pch_sw_ann->switch_count,
+ pch_sw_ann->switch_mode);
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief Prepare CMD_CHAN_REPORT_REQUEST firmware command
+ *
+ * @param priv Private driver information structure
+ * @param pcmd_ptr Output parameter: Pointer to the command being
+ * prepared to for firmware
+ * @param pinfo_buf HostCmd_DS_CHAN_RPT_REQ passed as void data block
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_PENDING
+ */
+static mlan_status
+wlan_11h_cmd_chan_rpt_req(mlan_private * priv,
+ HostCmd_DS_COMMAND * pcmd_ptr,
+ const t_void * pinfo_buf)
+{
+ const HostCmd_DS_CHAN_RPT_REQ *pchan_rpt_req =
+ (HostCmd_DS_CHAN_RPT_REQ *) pinfo_buf;
+ wlan_dfs_device_state_t *pstate_dfs = &priv->adapter->state_dfs;
+ MrvlIEtypes_ChanRpt11hBasic_t *ptlv_basic;
+
+ ENTER();
+
+ if (pstate_dfs->dfs_check_pending) {
+ PRINTM(MERROR, "11h: ChanRptReq - previous CMD_CHAN_REPORT_REQUEST has"
+ " not returned its result yet (as EVENT_CHANNEL_READY)."
+ " This command will be dropped.\n");
+ LEAVE();
+ return MLAN_STATUS_PENDING;
+ }
+
+ /* Converted to little endian in wlan_11h_cmd_process */
+ pcmd_ptr->size = sizeof(HostCmd_DS_CHAN_RPT_REQ) + S_DS_GEN;
+
+ memcpy(priv->adapter, &pcmd_ptr->params.chan_rpt_req, pchan_rpt_req,
+ sizeof(HostCmd_DS_CHAN_RPT_REQ));
+
+ /* if DFS channel, add BASIC report TLV, and set radar bit */
+ if (wlan_11h_radar_detect_required(priv, pchan_rpt_req->chan_desc.chanNum)) {
+ ptlv_basic =
+ (MrvlIEtypes_ChanRpt11hBasic_t *) (((t_u8 *) (pcmd_ptr)) +
+ pcmd_ptr->size);
+ ptlv_basic->Header.type = wlan_cpu_to_le16(TLV_TYPE_CHANRPT_11H_BASIC);
+ ptlv_basic->Header.len = wlan_cpu_to_le16(sizeof(MeasRptBasicMap_t));
+ memset(priv->adapter, &ptlv_basic->map, 0, sizeof(MeasRptBasicMap_t));
+ ptlv_basic->map.radar = 1;
+ pcmd_ptr->size += sizeof(MrvlIEtypes_ChanRpt11hBasic_t);
+ }
+
+ /* update dfs sturcture. dfs_check_pending is set when we receive CMD_RESP
+ == SUCCESS */
+ pstate_dfs->dfs_check_pending = MFALSE;
+ pstate_dfs->dfs_radar_found = MFALSE;
+ pstate_dfs->dfs_check_channel = pchan_rpt_req->chan_desc.chanNum;
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief Set the local power capability and constraint TLV
+ *
+ * @param ppbuffer The buffer to add these two TLVs
+ * @param channel Channel to which the power constraint applies
+ * @param power_constraint Power constraint to be applied on the channel
+ * @param min_tx_power_capability Min. Tx Power in Power Capability IE
+ * @param max_tx_power_capability Max. Tx Power in Power Capability IE
+ *
+ * @return The len increased
+ */
+static t_u32
+wlan_11h_set_local_power_constraint_tlv(t_u8 ** ppbuffer,
+ t_u8 channel,
+ t_u8 power_constraint,
+ t_u8 min_tx_power_capability,
+ t_u8 max_tx_power_capability)
+{
+ MrvlIEtypes_PowerCapability_t *pcap;
+ MrvlIEtypes_LocalPowerConstraint_t *pconstraint;
+ t_u8 *startPtr = MNULL;
+
+ ENTER();
+
+ /* Null Checks */
+ if ((ppbuffer == MNULL) || (((t_u8 *) (*ppbuffer)) == MNULL)) {
+ LEAVE();
+ return 0;
+ }
+
+ startPtr = (t_u8 *) (*ppbuffer);
+
+ PRINTM(MINFO,
+ "11h: Set local power constraint = %d channel=%d min_tx_pwr=%d max_tx_pwr=%d\n",
+ power_constraint, channel, min_tx_power_capability,
+ max_tx_power_capability);
+
+ pcap = (MrvlIEtypes_PowerCapability_t *) * ppbuffer;
+ pcap->header.type = wlan_cpu_to_le16(TLV_TYPE_POWER_CAPABILITY);
+ pcap->header.len = wlan_cpu_to_le16(2);
+ pcap->min_power = min_tx_power_capability;
+ pcap->max_power = max_tx_power_capability;
+ *ppbuffer += sizeof(MrvlIEtypesHeader_t) + 2;
+
+ pconstraint = (MrvlIEtypes_LocalPowerConstraint_t *) * ppbuffer;
+ pconstraint->header.type = wlan_cpu_to_le16(TLV_TYPE_POWER_CONSTRAINT);
+ pconstraint->header.len = wlan_cpu_to_le16(2);
+ pconstraint->chan = channel;
+ pconstraint->constraint = power_constraint;
+ *ppbuffer += sizeof(MrvlIEtypesHeader_t) + 2;
+
+ LEAVE();
+ return (t_u32) (*ppbuffer - startPtr);
+}
+
+/**
+ * @brief Utility function to process a join to an infrastructure BSS
+ *
+ * @param priv Private driver information structure
+ * @param ppbuffer Output parameter: Pointer to the TLV output buffer,
+ * modified on return to point after the appended 11h TLVs
+ * @param band Band on which we are joining the BSS
+ * @param channel Channel on which we are joining the BSS
+ * @param p11h_bss_info Pointer to the 11h BSS information for this network
+ * that was parsed out of the scan response.
+ *
+ * @return Integer number of bytes appended to the TLV output
+ * buffer (ppbuffer)
+ */
+static t_u32
+wlan_11h_process_infra_join(mlan_private * priv,
+ t_u8 ** ppbuffer,
+ t_u8 band,
+ t_u32 channel, wlan_11h_bss_info_t * p11h_bss_info)
+{
+ MrvlIEtypesHeader_t ie_header;
+ IEEEtypes_SupportedChannels_t sup_chan_ie;
+ t_u32 ret_len = 0;
+ t_u16 sup_chan_len = 0;
+
+ ENTER();
+
+ /* Null Checks */
+ if ((ppbuffer == MNULL) || (((t_u8 *) (*ppbuffer)) == MNULL)) {
+ LEAVE();
+ return 0;
+ }
+
+ ret_len += wlan_11h_set_local_power_constraint_tlv(ppbuffer, (t_u8) channel,
+ (t_u8) p11h_bss_info->
+ power_constraint.
+ local_constraint,
+ (t_u8) priv->adapter->
+ state_11h.
+ min_tx_power_capability,
+ (t_u8) priv->adapter->
+ state_11h.
+ max_tx_power_capability);
+
+ /* Setup the Supported Channels IE */
+ sup_chan_len = wlan_11h_set_supp_channels_ie(priv, band, &sup_chan_ie);
+
+ /*
+ * If we returned a valid Supported Channels IE, wrap and append it
+ */
+ if (sup_chan_len) {
+ /* Wrap the supported channels IE with a passthrough TLV type */
+ ie_header.type = wlan_cpu_to_le16(TLV_TYPE_PASSTHROUGH);
+ ie_header.len = sup_chan_len;
+ memcpy(priv->adapter, *ppbuffer, &ie_header, sizeof(ie_header));
+
+ /* Increment the return size and the return buffer pointer param */
+ *ppbuffer += sizeof(ie_header);
+ ret_len += sizeof(ie_header);
+
+ /* Copy the supported channels IE to the output buf, advance pointer */
+ memcpy(priv->adapter, *ppbuffer, &sup_chan_ie, sup_chan_len);
+ *ppbuffer += sup_chan_len;
+ ret_len += sup_chan_len;
+ }
+
+ LEAVE();
+ return ret_len;
+}
+
+/**
+ * @brief Utility function to process a start or join to an adhoc network
+ *
+ * Add the elements to the TLV buffer needed in the start/join adhoc commands:
+ * - IBSS DFS IE
+ * - Quiet IE
+ *
+ * Also send the local constraint to the firmware in a TPC_INFO command.
+ *
+ * @param priv Private driver information structure
+ * @param ppbuffer Output parameter: Pointer to the TLV output buffer,
+ * modified on return to point after the appended 11h TLVs
+ * @param channel Channel on which we are starting/joining the IBSS
+ * @param p11h_bss_info Pointer to the 11h BSS information for this network
+ * that was parsed out of the scan response. NULL
+ * indicates we are starting the adhoc network
+ *
+ * @return Integer number of bytes appended to the TLV output
+ * buffer (ppbuffer)
+ */
+static t_u32
+wlan_11h_process_adhoc(mlan_private * priv,
+ t_u8 ** ppbuffer,
+ t_u32 channel, wlan_11h_bss_info_t * p11h_bss_info)
+{
+ IEEEtypes_IBSS_DFS_t dfs_elem;
+ t_u32 size_appended;
+ t_u32 ret_len = 0;
+ t_s8 local_constraint = 0;
+ mlan_adapter *adapter = priv->adapter;
+
+ ENTER();
+
+#ifdef STA_SUPPORT
+ /* Format our own IBSS DFS Element. Include our channel map fields */
+ wlan_11h_set_ibss_dfs_ie(priv, &dfs_elem);
+#endif
+
+ if (p11h_bss_info) {
+ /*
+ * Copy the DFS Owner/Recovery Interval from the BSS we are joining
+ */
+ memcpy(adapter, dfs_elem.dfs_owner,
+ p11h_bss_info->ibss_dfs.dfs_owner, sizeof(dfs_elem.dfs_owner));
+ dfs_elem.dfs_recovery_interval =
+ p11h_bss_info->ibss_dfs.dfs_recovery_interval;
+ }
+
+ /* Append the dfs element to the TLV buffer */
+ size_appended =
+ wlan_11h_convert_ieee_to_mrvl_ie(adapter, (t_u8 *) * ppbuffer,
+ (t_u8 *) & dfs_elem);
+
+ HEXDUMP("11h: IBSS-DFS", (t_u8 *) * ppbuffer, size_appended);
+ *ppbuffer += size_appended;
+ ret_len += size_appended;
+
+ /*
+ * Check to see if we are joining a network. Join is indicated by the
+ * BSS Info pointer being valid (not NULL)
+ */
+ if (p11h_bss_info) {
+ /*
+ * If there was a quiet element, include it in adhoc join command
+ */
+ if (p11h_bss_info->quiet.element_id == QUIET) {
+ size_appended
+ = wlan_11h_convert_ieee_to_mrvl_ie(adapter, (t_u8 *) * ppbuffer,
+ (t_u8 *) & p11h_bss_info->
+ quiet);
+ HEXDUMP("11h: Quiet", (t_u8 *) * ppbuffer, size_appended);
+ *ppbuffer += size_appended;
+ ret_len += size_appended;
+ }
+
+ /* Copy the local constraint from the network */
+ local_constraint = p11h_bss_info->power_constraint.local_constraint;
+ } else {
+ /*
+ * If we are the adhoc starter, we can add a quiet element
+ */
+ if (adapter->state_11h.quiet_ie.quiet_period) {
+ size_appended =
+ wlan_11h_convert_ieee_to_mrvl_ie(adapter, (t_u8 *) * ppbuffer,
+ (t_u8 *) & adapter->state_11h.
+ quiet_ie);
+ HEXDUMP("11h: Quiet", (t_u8 *) * ppbuffer, size_appended);
+ *ppbuffer += size_appended;
+ ret_len += size_appended;
+ }
+ /* Use the local_constraint configured in the driver state */
+ local_constraint = adapter->state_11h.usr_def_power_constraint;
+ }
+
+ PRINTM(MINFO, "WEILIE 1: ppbuffer = %p\n", *ppbuffer);
+
+ ret_len +=
+ wlan_11h_set_local_power_constraint_tlv(ppbuffer, (t_u8) channel,
+ (t_u8) local_constraint,
+ (t_u8) priv->adapter->state_11h.
+ min_tx_power_capability,
+ (t_u8) priv->adapter->state_11h.
+ max_tx_power_capability);
+ PRINTM(MINFO, "WEILIE 2: ppbuffer = %p\n", *ppbuffer);
+
+ LEAVE();
+ return ret_len;
+}
+
+/**
+ * @brief Return whether the driver has enabled 11h for the interface
+ *
+ * Association/Join commands are dynamic in that they enable 11h in the
+ * driver/firmware when they are detected in the existing BSS.
+ *
+ * @param priv Private driver information structure
+ *
+ * @return
+ * - MTRUE if 11h is enabled
+ * - MFALSE otherwise
+ */
+static t_bool
+wlan_11h_is_enabled(mlan_private * priv)
+{
+ ENTER();
+ LEAVE();
+ return (priv->intf_state_11h.is_11h_enabled);
+}
+
+/**
+ * @brief Return whether the device has activated slave radar detection.
+ *
+ * @param priv Private driver information structure
+ *
+ * @return
+ * - MTRUE if slave radar detection is enabled in firmware
+ * - MFALSE otherwise
+ */
+static t_bool
+wlan_11h_is_slave_radar_det_active(mlan_private * priv)
+{
+ ENTER();
+ LEAVE();
+ return (priv->adapter->state_11h.is_slave_radar_det_active);
+}
+
+/**
+ * @brief Return whether the slave interface is active, and on DFS channel.
+ * priv is assumed to already be a dfs slave interface, doesn't check this.
+ *
+ * @param priv Private driver information structure
+ *
+ * @return
+ * - MTRUE if priv is slave, and meets both conditions
+ * - MFALSE otherwise
+ */
+static t_bool
+wlan_11h_is_slave_active_on_dfs_chan(mlan_private * priv)
+{
+ t_bool ret = MFALSE;
+
+ ENTER();
+ if ((priv->media_connected == MTRUE) &&
+ (priv->curr_bss_params.band & BAND_A) &&
+ wlan_11h_radar_detect_required(priv,
+ priv->curr_bss_params.bss_descriptor.
+ channel))
+ ret = MTRUE;
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Return whether the master interface is active, and on DFS channel.
+ * priv is assumed to already be a dfs master interface, doesn't check this.
+ *
+ * @param priv Private driver information structure
+ *
+ * @return
+ * - MTRUE if priv is master, and meets both conditions
+ * - MFALSE otherwise
+ */
+static t_bool
+wlan_11h_is_master_active_on_dfs_chan(mlan_private * priv)
+{
+ t_bool ret = MFALSE;
+
+ ENTER();
+ if (GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_STA) {
+ /* Ad-hoc creator */
+ if (((priv->media_connected == MTRUE)
+ || (priv->adhoc_state == ADHOC_STARTING)) &&
+ (priv->adapter->adhoc_start_band & BAND_A) &&
+ wlan_11h_radar_detect_required(priv, priv->adhoc_channel))
+ ret = MTRUE;
+ } else if (GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_UAP) {
+ /* UAP */
+#ifdef UAP_SUPPORT
+ if ((priv->uap_bss_started == MTRUE) &&
+ (priv->uap_state_chan_cb.band_config & BAND_CONFIG_5GHZ) &&
+ wlan_11h_radar_detect_required(priv,
+ priv->uap_state_chan_cb.channel))
+ ret = MTRUE;
+#endif
+ }
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Determine if priv is DFS Master interface
+ *
+ * @param priv Pointer to mlan_private
+ *
+ * @return MTRUE or MFALSE
+ */
+static t_bool
+wlan_11h_is_dfs_master(mlan_private * priv)
+{
+ t_bool ret = MFALSE;
+
+ ENTER();
+ /* UAP: all are master */
+ if (GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_UAP) {
+ ret = MTRUE;
+ }
+ /* STA: only ad-hoc creator is master */
+ else if ((GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_STA) &&
+ (priv->bss_mode == MLAN_BSS_MODE_IBSS) &&
+ (priv->adhoc_state == ADHOC_STARTED ||
+ priv->adhoc_state == ADHOC_STARTING)) {
+ ret = MTRUE;
+ }
+ /* all other cases = slave interface */
+ LEAVE();
+ return ret;
+}
+
+/* Need this as function to pass to wlan_count_priv_cond() */
+/**
+ * @brief Determine if priv is DFS Slave interface
+ *
+ * @param priv Pointer to mlan_private
+ *
+ * @return MTRUE or MFALSE
+ */
+
+static t_bool
+wlan_11h_is_dfs_slave(mlan_private * priv)
+{
+ t_bool ret = MFALSE;
+ ENTER();
+ ret = !wlan_11h_is_dfs_master(priv);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function checks if interface is active.
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ *
+ * @return MTRUE or MFALSE
+ */
+static t_bool
+wlan_is_intf_active(mlan_private * pmpriv)
+{
+ t_bool ret = MFALSE;
+ ENTER();
+
+#ifdef UAP_SUPPORT
+ if (GET_BSS_ROLE(pmpriv) == MLAN_BSS_ROLE_UAP)
+ /* NOTE: UAP's media_connected == true only after first STA associated.
+ Need different variable to tell if UAP has been started. */
+ ret = pmpriv->uap_bss_started;
+ else
+#endif
+ if (GET_BSS_ROLE(pmpriv) == MLAN_BSS_ROLE_STA)
+ ret = pmpriv->media_connected;
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function gets current radar detect flags
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ *
+ * @return 11H MIB setting for radar detect
+ */
+static t_u32
+wlan_11h_get_current_radar_detect_flags(mlan_adapter * pmadapter)
+{
+ t_u32 radar_det_flags = 0;
+
+ ENTER();
+ if (pmadapter->state_11h.is_master_radar_det_active)
+ radar_det_flags |= MASTER_RADAR_DET_MASK;
+ if (pmadapter->state_11h.is_slave_radar_det_active)
+ radar_det_flags |= SLAVE_RADAR_DET_MASK;
+
+ PRINTM(MINFO, "%s: radar_det_state_curr=0x%x\n",
+ __FUNCTION__, radar_det_flags);
+
+ LEAVE();
+ return radar_det_flags;
+}
+
+/**
+ * @brief This function checks if radar detect flags have/should be changed.
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pnew_state Output param with new state, if return MTRUE.
+ *
+ * @return MTRUE (need update) or MFALSE (no change in flags)
+ */
+static t_bool
+wlan_11h_check_radar_det_state(mlan_adapter * pmadapter, OUT t_u32 * pnew_state)
+{
+ t_u32 radar_det_state_new = 0;
+ t_bool ret;
+
+ ENTER();
+ PRINTM(MINFO, "%s: master_radar_det_pending=%d, "
+ " slave_radar_det_pending=%d\n", __FUNCTION__,
+ pmadapter->state_11h.master_radar_det_enable_pending,
+ pmadapter->state_11h.slave_radar_det_enable_pending);
+
+ /* new state comes from evaluating interface states & pending starts */
+ if (pmadapter->state_11h.master_radar_det_enable_pending ||
+ (wlan_count_priv_cond(pmadapter,
+ wlan_11h_is_master_active_on_dfs_chan,
+ wlan_11h_is_dfs_master) > 0))
+ radar_det_state_new |= MASTER_RADAR_DET_MASK;
+ if (pmadapter->state_11h.slave_radar_det_enable_pending ||
+ (wlan_count_priv_cond(pmadapter,
+ wlan_11h_is_slave_active_on_dfs_chan,
+ wlan_11h_is_dfs_slave) > 0))
+ radar_det_state_new |= SLAVE_RADAR_DET_MASK;
+
+ PRINTM(MINFO, "%s: radar_det_state_new=0x%x\n",
+ __FUNCTION__, radar_det_state_new);
+
+ /* now compare flags with current state */
+ ret = (wlan_11h_get_current_radar_detect_flags(pmadapter)
+ != radar_det_state_new) ? MTRUE : MFALSE;
+ if (ret)
+ *pnew_state = radar_det_state_new;
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Determine if mlan_private list only contains UAP interface(s)
+ *
+ * @param priv_list List of mlan_private pointers
+ * @param priv_list_count Number of mlan_privates in above list
+ *
+ * @return MTRUE or MFALSE
+ */
+static t_bool
+wlan_only_uap_priv_in_list(mlan_private ** priv_list, t_u8 priv_list_count)
+{
+#if defined(STA_SUPPORT) && !defined(UAP_SUPPORT)
+ return MFALSE;
+#else
+ t_u8 uap_count = 0;
+ t_u8 sta_count = 0;
+ t_u8 i;
+
+ ENTER();
+ for (i = 0; i < priv_list_count; i++) {
+ if (GET_BSS_ROLE(priv_list[i]) == MLAN_BSS_ROLE_UAP)
+ uap_count++;
+ else
+ sta_count++;
+ }
+
+ LEAVE();
+ return ((uap_count > 0) && (sta_count == 0)) ? MTRUE : MFALSE;
+#endif
+}
+
+/**
+ * @brief Prepare ioctl for add/remove CHAN_SW IE - RADAR_DETECTED event handling
+ *
+ * @param pmadapter Pointer to mlan_adapter
+ * @param pioctl_req Pointer to completed mlan_ioctl_req (allocated inside)
+ * @param is_adding_ie CHAN_SW IE is to be added (MTRUE), or removed (MFALSE)
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+static mlan_status
+wlan_11h_prepare_custom_ie_chansw(IN mlan_adapter * pmadapter,
+ OUT mlan_ioctl_req ** ppioctl_req,
+ IN t_bool is_adding_ie)
+{
+ mlan_ioctl_req *pioctl_req = MNULL;
+ mlan_ds_misc_cfg *pds_misc_cfg = MNULL;
+ custom_ie *pcust_chansw_ie = MNULL;
+ IEEEtypes_ChanSwitchAnn_t *pchansw_ie = MNULL;
+ mlan_status ret;
+
+ ENTER();
+
+ if (pmadapter == MNULL || ppioctl_req == MNULL) {
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+
+ /* allocate buffer for mlan_ioctl_req and mlan_ds_misc_cfg */
+ /* FYI - will be freed as part of cmd_response handler */
+ ret = pmadapter->callbacks.moal_malloc(pmadapter->pmoal_handle,
+ sizeof(mlan_ioctl_req) +
+ sizeof(mlan_ds_misc_cfg),
+ MLAN_MEM_DEF,
+ (t_u8 **) & pioctl_req);
+ if ((ret != MLAN_STATUS_SUCCESS) || !pioctl_req) {
+ PRINTM(MERROR, "%s(): Could not allocate ioctl req\n", __FUNCTION__);
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+ pds_misc_cfg = (mlan_ds_misc_cfg *) ((t_u8 *) pioctl_req +
+ sizeof(mlan_ioctl_req));
+
+ /* prepare mlan_ioctl_req */
+ memset(pmadapter, pioctl_req, 0x00, sizeof(mlan_ioctl_req));
+ pioctl_req->req_id = MLAN_IOCTL_MISC_CFG;
+ pioctl_req->action = MLAN_ACT_SET;
+ pioctl_req->pbuf = (t_u8 *) pds_misc_cfg;
+ pioctl_req->buf_len = sizeof(mlan_ds_misc_cfg);
+
+ /* prepare mlan_ds_misc_cfg */
+ memset(pmadapter, pds_misc_cfg, 0x00, sizeof(mlan_ds_misc_cfg));
+ pds_misc_cfg->sub_command = MLAN_OID_MISC_CUSTOM_IE;
+ pds_misc_cfg->param.cust_ie.type = TLV_TYPE_MGMT_IE;
+ pds_misc_cfg->param.cust_ie.len = (sizeof(custom_ie) - MAX_IE_SIZE);
+
+ /* configure custom_ie api settings */
+ pcust_chansw_ie =
+ (custom_ie *) & pds_misc_cfg->param.cust_ie.ie_data_list[0];
+ pcust_chansw_ie->ie_index = 0xffff; /* Auto index */
+ pcust_chansw_ie->ie_length = sizeof(IEEEtypes_ChanSwitchAnn_t);
+ pcust_chansw_ie->mgmt_subtype_mask = (is_adding_ie)
+ ? MBIT(8) | MBIT(5) /* add IE for BEACON | PROBE_RSP */
+ : 0; /* remove IE */
+
+ /* prepare CHAN_SW IE inside ioctl */
+ pchansw_ie = (IEEEtypes_ChanSwitchAnn_t *) pcust_chansw_ie->ie_buffer;
+ pchansw_ie->element_id = CHANNEL_SWITCH_ANN;
+ pchansw_ie->len =
+ sizeof(IEEEtypes_ChanSwitchAnn_t) - sizeof(IEEEtypes_Header_t);
+ pchansw_ie->chan_switch_mode = 1; /* STA should not transmit */
+ pchansw_ie->new_channel_num = pmadapter->state_rdh.new_channel;
+ pchansw_ie->chan_switch_count = 0; /* simplification */
+
+ pds_misc_cfg->param.cust_ie.len += pcust_chansw_ie->ie_length;
+ DBG_HEXDUMP(MCMD_D, "11h: custom_ie containing CHAN_SW IE",
+ (t_u8 *) pcust_chansw_ie, pds_misc_cfg->param.cust_ie.len);
+
+ /* assign output pointer before returning */
+ *ppioctl_req = pioctl_req;
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+#ifdef UAP_SUPPORT
+/**
+ * @brief Retrieve a randomly selected starting channel if needed for 11h
+ *
+ * If 11h is enabled and 5GHz band is selected in band_config
+ * return a random channel in A band, else one from BG band.
+ *
+ * @param priv Private driver information structure
+ * @param uap_band_cfg Private driver information structure
+ *
+ * @return Starting channel
+ */
+static t_u8
+wlan_11h_get_uap_start_channel(mlan_private * priv, t_u8 uap_band_cfg)
+{
+ t_u8 start_chn;
+ mlan_adapter *adapter = priv->adapter;
+ t_u32 region;
+ t_u32 rand_entry;
+ region_chan_t *chn_tbl;
+ t_u8 rand_tries = 0;
+
+ // TODO: right now mostly a copy of wlan_11h_get_adhoc_start_channel.
+ // Improve to be more specfic to UAP, e.g.
+ // 1. take into account COUNTRY_CODE -> region_code
+ // 2. check domain_info for value channels
+
+ ENTER();
+
+ /*
+ * Set start_chn to the Default. Used if 11h is disabled or the band
+ * does not require 11h support.
+ */
+ start_chn = DEFAULT_AD_HOC_CHANNEL;
+
+ /*
+ * Check that we are looking for a channel in the A Band
+ */
+ if (uap_band_cfg & UAP_BAND_CONFIG_5GHZ) {
+ /*
+ * Set default to the A Band default. Used if random selection fails
+ * or if 11h is not enabled
+ */
+ start_chn = DEFAULT_AD_HOC_CHANNEL_A;
+
+ /*
+ * Check that 11h is enabled in the driver
+ */
+ if (wlan_11h_is_enabled(priv)) {
+ /*
+ * Search the region_channel tables for a channel table
+ * that is marked for the A Band.
+ */
+ for (region = 0; (region < MAX_REGION_CHANNEL_NUM); region++) {
+ chn_tbl = &adapter->region_channel[region];
+
+ /* Check if table is valid and marked for A Band */
+ if (chn_tbl->valid
+ && chn_tbl->region == adapter->region_code
+ && chn_tbl->band & BAND_A) {
+ /*
+ * Set the start channel. Get a random number and
+ * use it to pick an entry in the table between 0
+ * and the number of channels in the table (NumCFP).
+ */
+ do {
+ rand_entry =
+ wlan_11h_get_random_num(adapter) % chn_tbl->num_cfp;
+ start_chn = (t_u8) chn_tbl->pcfp[rand_entry].channel;
+ } while (wlan_11h_is_channel_under_nop(adapter, start_chn)
+ && (++rand_tries < MAX_RANDOM_CHANNEL_RETRIES));
+ }
+ }
+ }
+ }
+
+ PRINTM(MCMD_D, "11h: UAP Get Start Channel %d\n", start_chn);
+ LEAVE();
+ return start_chn;
+}
+#endif /* UAP_SUPPORT */
+
+#ifdef DEBUG_LEVEL1
+static const char *DFS_TS_REPR_STRINGS[] = { "",
+ "NOP_start",
+ "CAC_completed"
+};
+#endif
+
+/**
+ * @brief Search for a dfs timestamp in the list with desired channel.
+ *
+ * Assumes there will only be one timestamp per channel in the list.
+ *
+ * @param pmadapter Pointer to mlan_adapter
+ * @param channel Channel number
+ *
+ * @return Pointer to timestamp if found, or MNULL
+ */
+static wlan_dfs_timestamp_t *
+wlan_11h_find_dfs_timestamp(mlan_adapter * pmadapter, t_u8 channel)
+{
+ wlan_dfs_timestamp_t *pts = MNULL, *pts_found = MNULL;
+
+ ENTER();
+ pts = (wlan_dfs_timestamp_t *) util_peek_list(pmadapter->pmoal_handle,
+ &pmadapter->state_dfs.
+ dfs_ts_head, MNULL, MNULL);
+
+ while (pts &&
+ pts != (wlan_dfs_timestamp_t *) & pmadapter->state_dfs.dfs_ts_head) {
+ PRINTM(MINFO,
+ "dfs_timestamp(@ %p) - chan=%d, repr=%d(%s),"
+ " time(sec.usec)=%lu.%06lu\n", pts, pts->channel,
+ pts->represents, DFS_TS_REPR_STRINGS[pts->represents],
+ pts->ts_sec, pts->ts_usec);
+
+ if (pts->channel == channel) {
+ pts_found = pts;
+ break;
+ }
+ pts = pts->pnext;
+ }
+
+ LEAVE();
+ return pts_found;
+}
+
+/**
+ * @brief Removes dfs timestamp from list.
+ *
+ * @param pmadapter Pointer to mlan_adapter
+ * @param pdfs_ts Pointer to dfs_timestamp to remove
+ */
+static t_void
+wlan_11h_remove_dfs_timestamp(mlan_adapter * pmadapter,
+ wlan_dfs_timestamp_t * pdfs_ts)
+{
+ ENTER();
+ // dequeue and delete timestamp
+ util_unlink_list(pmadapter->pmoal_handle,
+ &pmadapter->state_dfs.dfs_ts_head,
+ (pmlan_linked_list) pdfs_ts, MNULL, MNULL);
+ pmadapter->callbacks.moal_mfree(pmadapter->pmoal_handle, (t_u8 *) pdfs_ts);
+ LEAVE();
+}
+
+/**
+ * @brief Add a dfs timestamp to the list
+ *
+ * Assumes there will only be one timestamp per channel in the list,
+ * and that timestamp modes (represents) are mutually exclusive.
+ *
+ * @param pmadapter Pointer to mlan_adapter
+ * @param repr Timestamp 'represents' value (see _dfs_timestamp_repr_e)
+ * @param channel Channel number
+ *
+ * @return Pointer to timestamp if found, or MNULL
+ */
+static mlan_status
+wlan_11h_add_dfs_timestamp(mlan_adapter * pmadapter, t_u8 repr, t_u8 channel)
+{
+ wlan_dfs_timestamp_t *pdfs_ts = MNULL;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+ pdfs_ts = wlan_11h_find_dfs_timestamp(pmadapter, channel);
+
+ if (!pdfs_ts) {
+ // need to allocate new timestamp
+ ret = pmadapter->callbacks.moal_malloc(pmadapter->pmoal_handle,
+ sizeof(wlan_dfs_timestamp_t),
+ MLAN_MEM_DEF,
+ (t_u8 **) & pdfs_ts);
+ if ((ret != MLAN_STATUS_SUCCESS) || !pdfs_ts) {
+ PRINTM(MERROR, "%s(): Could not allocate dfs_ts\n", __FUNCTION__);
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+
+ memset(pmadapter, (t_u8 *) pdfs_ts, 0, sizeof(wlan_dfs_timestamp_t));
+
+ util_enqueue_list_tail(pmadapter->pmoal_handle,
+ &pmadapter->state_dfs.dfs_ts_head,
+ (pmlan_linked_list) pdfs_ts, MNULL, MNULL);
+ pdfs_ts->channel = channel;
+ }
+ // (else, use existing timestamp for channel; see assumptions above)
+
+ // update params
+ pmadapter->callbacks.moal_get_system_time(pmadapter->pmoal_handle,
+ &pdfs_ts->ts_sec,
+ &pdfs_ts->ts_usec);
+ pdfs_ts->represents = repr;
+
+ PRINTM(MCMD_D, "11h: add/update dfs_timestamp - chan=%d, repr=%d(%s),"
+ " time(sec.usec)=%lu.%06lu\n", pdfs_ts->channel,
+ pdfs_ts->represents, DFS_TS_REPR_STRINGS[pdfs_ts->represents],
+ pdfs_ts->ts_sec, pdfs_ts->ts_usec);
+
+ LEAVE();
+ return ret;
+}
+
+/********************************************************
+ Global functions
+********************************************************/
+
+/**
+ * @brief Return whether the device has activated master radar detection.
+ *
+ * @param priv Private driver information structure
+ *
+ * @return
+ * - MTRUE if master radar detection is enabled in firmware
+ * - MFALSE otherwise
+ */
+t_bool
+wlan_11h_is_master_radar_det_active(mlan_private * priv)
+{
+ ENTER();
+ LEAVE();
+ return (priv->adapter->state_11h.is_master_radar_det_active);
+}
+
+/**
+ * @brief Configure master radar detection.
+ * Call wlan_11h_check_update_radar_det_state() afterwards
+ * to push this to firmware.
+ *
+ * @param priv Private driver information structure
+ * @param enable Whether to enable or disable master radar detection
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ *
+ * @sa wlan_11h_check_update_radar_det_state
+ */
+mlan_status
+wlan_11h_config_master_radar_det(mlan_private * priv, t_bool enable)
+{
+ mlan_status ret = MLAN_STATUS_FAILURE;
+
+ ENTER();
+ if (wlan_11h_is_dfs_master(priv) &&
+ priv->adapter->init_para.dfs_master_radar_det_en) {
+ priv->adapter->state_11h.master_radar_det_enable_pending = enable;
+ ret = MLAN_STATUS_SUCCESS;
+ }
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Configure slave radar detection.
+ * Call wlan_11h_check_update_radar_det_state() afterwards
+ * to push this to firmware.
+ *
+ * @param priv Private driver information structure
+ * @param enable Whether to enable or disable slave radar detection
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ *
+ * @sa wlan_11h_check_update_radar_det_state
+ */
+mlan_status
+wlan_11h_config_slave_radar_det(mlan_private * priv, t_bool enable)
+{
+ mlan_status ret = MLAN_STATUS_FAILURE;
+
+ ENTER();
+ if (wlan_11h_is_dfs_slave(priv) &&
+ priv->adapter->init_para.dfs_slave_radar_det_en) {
+ priv->adapter->state_11h.slave_radar_det_enable_pending = enable;
+ ret = MLAN_STATUS_SUCCESS;
+ }
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Checks all interfaces and determines if radar_detect flag states
+ * have/should be changed. If so, sends SNMP_MIB 11H command to FW.
+ * Call this function on any interface enable/disable/channel change.
+ *
+ * @param pmpriv Pointer to mlan_private structure
+ *
+ * @return MLAN_STATUS_SUCCESS (update or not)
+ * or MLAN_STATUS_FAILURE (cmd failure)
+ *
+ * @sa wlan_11h_check_radar_det_state
+ */
+mlan_status
+wlan_11h_check_update_radar_det_state(mlan_private * pmpriv)
+{
+ t_u32 new_radar_det_state = 0;
+ t_u32 mib_11h = 0;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ if (wlan_11h_check_radar_det_state(pmpriv->adapter, &new_radar_det_state)) {
+ PRINTM(MCMD_D, "%s: radar_det_state being updated.\n", __FUNCTION__);
+
+ mib_11h |= new_radar_det_state;
+ /* keep priv's existing 11h state */
+ if (pmpriv->intf_state_11h.is_11h_active)
+ mib_11h |= ENABLE_11H_MASK;
+
+ /* Send cmd to FW to enable/disable 11h function in firmware */
+ ret = wlan_prepare_cmd(pmpriv,
+ HostCmd_CMD_802_11_SNMP_MIB,
+ HostCmd_ACT_GEN_SET, Dot11H_i, MNULL, &mib_11h);
+ if (ret)
+ ret = MLAN_STATUS_FAILURE;
+ }
+
+ /* updated state sent OR no change, thus no longer pending */
+ pmpriv->adapter->state_11h.master_radar_det_enable_pending = MFALSE;
+ pmpriv->adapter->state_11h.slave_radar_det_enable_pending = MFALSE;
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Query 11h firmware enabled state.
+ *
+ * Return whether the firmware currently has 11h extensions enabled
+ *
+ * @param priv Private driver information structure
+ *
+ * @return
+ * - MTRUE if 11h has been activated in the firmware
+ * - MFALSE otherwise
+ *
+ * @sa wlan_11h_activate
+ */
+t_bool
+wlan_11h_is_active(mlan_private * priv)
+{
+ ENTER();
+ LEAVE();
+ return (priv->intf_state_11h.is_11h_active);
+}
+
+/**
+ * @brief Enable the transmit interface and record the state.
+ *
+ * @param priv Private driver information structure
+ *
+ * @return N/A
+ */
+t_void
+wlan_11h_tx_enable(mlan_private * priv)
+{
+ ENTER();
+ if (priv->intf_state_11h.tx_disabled) {
+ wlan_recv_event(priv, MLAN_EVENT_ID_FW_START_TX, MNULL);
+ priv->intf_state_11h.tx_disabled = MFALSE;
+ }
+ LEAVE();
+}
+
+/**
+ * @brief Disable the transmit interface and record the state.
+ *
+ * @param priv Private driver information structure
+ *
+ * @return N/A
+ */
+t_void
+wlan_11h_tx_disable(mlan_private * priv)
+{
+ ENTER();
+ if (!priv->intf_state_11h.tx_disabled) {
+ priv->intf_state_11h.tx_disabled = MTRUE;
+ wlan_recv_event(priv, MLAN_EVENT_ID_FW_STOP_TX, MNULL);
+ }
+ LEAVE();
+}
+
+/**
+ * @brief Enable or Disable the 11h extensions in the firmware
+ *
+ * @param priv Private driver information structure
+ * @param pioctl_buf A pointer to MLAN IOCTL Request buffer
+ * @param flag Enable 11h if MTRUE, disable otherwise
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status
+wlan_11h_activate(mlan_private * priv, t_void * pioctl_buf, t_bool flag)
+{
+ t_u32 enable = flag & ENABLE_11H_MASK;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+ /* add bits for master/slave radar detect into enable. */
+ enable |= wlan_11h_get_current_radar_detect_flags(priv->adapter);
+
+ /*
+ * Send cmd to FW to enable/disable 11h function in firmware
+ */
+ ret = wlan_prepare_cmd(priv,
+ HostCmd_CMD_802_11_SNMP_MIB,
+ HostCmd_ACT_GEN_SET,
+ Dot11H_i, (t_void *) pioctl_buf, &enable);
+ if (ret)
+ ret = MLAN_STATUS_FAILURE;
+ else
+ /* Set boolean flag in driver 11h state */
+ priv->intf_state_11h.is_11h_active = flag;
+
+ PRINTM(MINFO, "11h: %s\n", flag ? "Activate" : "Deactivate");
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Initialize the 11h parameters and enable 11h when starting an IBSS
+ *
+ * @param adapter mlan_adapter structure
+ *
+ * @return N/A
+ */
+t_void
+wlan_11h_init(mlan_adapter * adapter)
+{
+ wlan_11h_device_state_t *pstate_11h = &adapter->state_11h;
+ IEEEtypes_Quiet_t *pquiet = &adapter->state_11h.quiet_ie;
+ wlan_dfs_device_state_t *pstate_dfs = &adapter->state_dfs;
+ wlan_radar_det_hndlg_state_t *pstate_rdh = &adapter->state_rdh;
+#ifdef DFS_TESTING_SUPPORT
+ wlan_dfs_testing_settings_t *pdfs_test = &adapter->dfs_test_params;
+#endif
+
+ ENTER();
+
+ /* Initialize 11H struct */
+ pstate_11h->usr_def_power_constraint = WLAN_11H_TPC_POWERCONSTRAINT;
+ pstate_11h->min_tx_power_capability = WLAN_11H_TPC_POWERCAPABILITY_MIN;
+ pstate_11h->max_tx_power_capability = WLAN_11H_TPC_POWERCAPABILITY_MAX;
+
+ pstate_11h->recvd_chanswann_event = MFALSE;
+ pstate_11h->master_radar_det_enable_pending = MFALSE;
+ pstate_11h->slave_radar_det_enable_pending = MFALSE;
+ pstate_11h->is_master_radar_det_active = MFALSE;
+ pstate_11h->is_slave_radar_det_active = MFALSE;
+
+ /* Initialize quiet_ie */
+ memset(adapter, pquiet, 0, sizeof(IEEEtypes_Quiet_t));
+ pquiet->element_id = QUIET;
+ pquiet->len = (sizeof(pquiet->quiet_count) + sizeof(pquiet->quiet_period)
+ + sizeof(pquiet->quiet_duration)
+ + sizeof(pquiet->quiet_offset));
+
+ /* Initialize DFS struct */
+ pstate_dfs->dfs_check_pending = MFALSE;
+ pstate_dfs->dfs_radar_found = MFALSE;
+ pstate_dfs->dfs_check_channel = 0;
+ pstate_dfs->dfs_report_time_sec = 0;
+ util_init_list((pmlan_linked_list) & pstate_dfs->dfs_ts_head);
+
+ /* Initialize RDH struct */
+ pstate_rdh->stage = RDH_OFF;
+ pstate_rdh->priv_list_count = 0;
+ pstate_rdh->priv_curr_idx = 0;
+ pstate_rdh->curr_channel = 0;
+ pstate_rdh->new_channel = 0;
+ pstate_rdh->uap_band_cfg = 0;
+ pstate_rdh->max_bcn_dtim_ms = 0;
+ memset(adapter, pstate_rdh->priv_list, 0, sizeof(pstate_rdh->priv_list));
+
+#ifdef DFS_TESTING_SUPPORT
+ /* Initialize DFS testing struct */
+ pdfs_test->user_cac_period_msec = 0;
+ pdfs_test->user_nop_period_sec = 0;
+ pdfs_test->no_channel_change_on_radar = MFALSE;
+ pdfs_test->fixed_new_channel_on_radar = 0;
+#endif
+
+ LEAVE();
+}
+
+/**
+ * @brief Cleanup for the 11h parameters that allocated memory, etc.
+ *
+ * @param adapter mlan_adapter structure
+ *
+ * @return N/A
+ */
+t_void
+wlan_11h_cleanup(mlan_adapter * adapter)
+{
+ wlan_dfs_device_state_t *pstate_dfs = &adapter->state_dfs;
+ wlan_dfs_timestamp_t *pdfs_ts;
+
+ ENTER();
+
+ /* cleanup dfs_timestamp list */
+ pdfs_ts = (wlan_dfs_timestamp_t *) util_peek_list(adapter->pmoal_handle,
+ &pstate_dfs->dfs_ts_head,
+ MNULL, MNULL);
+ while (pdfs_ts) {
+ util_unlink_list(adapter->pmoal_handle, &pstate_dfs->dfs_ts_head,
+ (pmlan_linked_list) pdfs_ts, MNULL, MNULL);
+ adapter->callbacks.moal_mfree(adapter->pmoal_handle, (t_u8 *) pdfs_ts);
+
+ pdfs_ts = (wlan_dfs_timestamp_t *) util_peek_list(adapter->pmoal_handle,
+ &pstate_dfs->
+ dfs_ts_head, MNULL,
+ MNULL);
+ }
+
+ LEAVE();
+}
+
+/**
+ * @brief Initialize the 11h parameters and enable 11h when starting an IBSS
+ *
+ * @param pmpriv Pointer to mlan_private structure
+ *
+ * @return N/A
+ */
+t_void
+wlan_11h_priv_init(mlan_private * pmpriv)
+{
+ wlan_11h_interface_state_t *pistate_11h = &pmpriv->intf_state_11h;
+
+ ENTER();
+
+ pistate_11h->is_11h_enabled = MTRUE;
+ pistate_11h->is_11h_active = MFALSE;
+ pistate_11h->adhoc_auto_sel_chan = MTRUE;
+ pistate_11h->tx_disabled = MFALSE;
+
+ LEAVE();
+}
+
+/**
+ * @brief Retrieve a randomly selected starting channel if needed for 11h
+ *
+ * If 11h is enabled and an A-Band channel start band preference
+ * configured in the driver, the start channel must be random in order
+ * to meet with
+ *
+ * @param priv Private driver information structure
+ *
+ * @return Starting channel
+ */
+t_u8
+wlan_11h_get_adhoc_start_channel(mlan_private * priv)
+{
+ t_u8 start_chn;
+ mlan_adapter *adapter = priv->adapter;
+ t_u32 region;
+ t_u32 rand_entry;
+ region_chan_t *chn_tbl;
+ t_u8 rand_tries = 0;
+
+ ENTER();
+
+ /*
+ * Set start_chn to the Default. Used if 11h is disabled or the band
+ * does not require 11h support.
+ */
+ start_chn = DEFAULT_AD_HOC_CHANNEL;
+
+ /*
+ * Check that we are looking for a channel in the A Band
+ */
+ if ((adapter->adhoc_start_band & BAND_A)
+ || (adapter->adhoc_start_band & BAND_AN)
+ ) {
+ /*
+ * Set default to the A Band default. Used if random selection fails
+ * or if 11h is not enabled
+ */
+ start_chn = DEFAULT_AD_HOC_CHANNEL_A;
+
+ /*
+ * Check that 11h is enabled in the driver
+ */
+ if (wlan_11h_is_enabled(priv)) {
+ /*
+ * Search the region_channel tables for a channel table
+ * that is marked for the A Band.
+ */
+ for (region = 0; (region < MAX_REGION_CHANNEL_NUM); region++) {
+ chn_tbl = &adapter->region_channel[region];
+
+ /* Check if table is valid and marked for A Band */
+ if (chn_tbl->valid
+ && chn_tbl->region == adapter->region_code
+ && chn_tbl->band & BAND_A) {
+ /*
+ * Set the start channel. Get a random number and
+ * use it to pick an entry in the table between 0
+ * and the number of channels in the table (NumCFP).
+ */
+ do {
+ rand_entry =
+ wlan_11h_get_random_num(adapter) % chn_tbl->num_cfp;
+ start_chn = (t_u8) chn_tbl->pcfp[rand_entry].channel;
+ } while ((wlan_11h_is_channel_under_nop(adapter, start_chn)
+ ||
+ ((adapter->state_rdh.stage ==
+ RDH_GET_INFO_CHANNEL) &&
+ wlan_11h_radar_detect_required(priv, start_chn)))
+ && (++rand_tries < MAX_RANDOM_CHANNEL_RETRIES));
+ }
+ }
+ }
+ }
+
+ PRINTM(MINFO, "11h: %s: AdHoc Channel set to %u\n",
+ wlan_11h_is_enabled(priv) ? "Enabled" : "Disabled", start_chn);
+
+ LEAVE();
+ return start_chn;
+}
+
+/**
+ * @brief Check if the current region's regulations require the input channel
+ * to be scanned for radar.
+ *
+ * Based on statically defined requirements for sub-bands per regulatory
+ * agency requirements.
+ *
+ * Used in adhoc start to determine if channel availability check is required
+ *
+ * @param priv Private driver information structure
+ * @param channel Channel to determine radar detection requirements
+ *
+ * @return
+ * - MTRUE if radar detection is required
+ * - MFALSE otherwise
+ */
+/** @sa wlan_11h_issue_radar_detect
+ */
+t_bool
+wlan_11h_radar_detect_required(mlan_private * priv, t_u8 channel)
+{
+ t_bool required = MFALSE;
+
+ ENTER();
+
+ /*
+ * No checks for 11h or measurement code being enabled is placed here
+ * since regulatory requirements exist whether we support them or not.
+ */
+
+ required = wlan_get_cfp_radar_detect(priv, channel);
+
+ PRINTM(MINFO, "11h: Radar detection in region %#02x "
+ "is %srequired for channel %d\n",
+ priv->adapter->region_code, (required ? "" : "not "), channel);
+
+ if (required == MTRUE && priv->media_connected == MTRUE
+ && priv->curr_bss_params.bss_descriptor.channel == channel) {
+ required = MFALSE;
+
+ PRINTM(MINFO, "11h: Radar detection not required. "
+ "Already operating on the channel\n");
+ }
+
+ LEAVE();
+ return required;
+}
+
+/**
+ * @brief Perform a radar measurement if required on given channel
+ *
+ * Check to see if the provided channel requires a channel availability
+ * check (60 second radar detection measurement). If required, perform
+ * measurement, stalling calling thread until the measurement completes
+ * and then report result.
+ *
+ * Used when starting an adhoc or AP network.
+ *
+ * @param priv Private driver information structure
+ * @param pioctl_req Pointer to IOCTL request buffer
+ * @param channel Channel on which to perform radar measurement
+ *
+ * @return
+ * - MTRUE if radar measurement request was successfully issued
+ * - MFALSE if radar detection is not required
+ * - < 0 for error during radar detection (if performed)
+ *
+ * @sa wlan_11h_radar_detect_required
+ */
+t_s32
+wlan_11h_issue_radar_detect(mlan_private * priv,
+ pmlan_ioctl_req pioctl_req, t_u8 channel)
+{
+ t_s32 ret;
+ HostCmd_DS_CHAN_RPT_REQ chan_rpt_req;
+
+ ENTER();
+
+ ret = wlan_11h_radar_detect_required(priv, channel);
+ if (ret) {
+ /* Prepare and issue CMD_CHAN_RPT_REQ. */
+ memset(priv->adapter, &chan_rpt_req, 0x00, sizeof(chan_rpt_req));
+
+ chan_rpt_req.chan_desc.startFreq = START_FREQ_11A_BAND;
+ chan_rpt_req.chan_desc.chanWidth = 0; // 1 for 40Mhz
+ chan_rpt_req.chan_desc.chanNum = channel;
+ chan_rpt_req.millisec_dwell_time =
+ WLAN_11H_CHANNEL_AVAIL_CHECK_DURATION;
+#ifdef DFS_TESTING_SUPPORT
+ if (priv->adapter->dfs_test_params.user_cac_period_msec) {
+ PRINTM(MCMD_D, "dfs_testing - user CAC period=%d (msec)\n",
+ priv->adapter->dfs_test_params.user_cac_period_msec);
+ chan_rpt_req.millisec_dwell_time =
+ priv->adapter->dfs_test_params.user_cac_period_msec;
+ }
+#endif
+
+ PRINTM(MMSG, "11h: issuing DFS Radar check for channel=%d."
+ " Please wait for response...\n", channel);
+
+ ret = wlan_prepare_cmd(priv, HostCmd_CMD_CHAN_REPORT_REQUEST,
+ HostCmd_ACT_GEN_SET, 0,
+ (t_void *) pioctl_req,
+ (t_void *) & chan_rpt_req);
+ }
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Checks if a radar measurement was performed on channel,
+ * and if so, whether radar was detected on it.
+ *
+ * Used when starting an adhoc network.
+ *
+ * @param priv Private driver information structure
+ * @param chan Channel to check upon
+ *
+ * @return
+ * - MLAN_STATUS_SUCCESS if no radar on channel
+ * - MLAN_STATUS_FAILURE if radar was found on channel
+ * - (TBD??) MLAN_STATUS_PENDING if radar report NEEDS TO BE REISSUED
+ *
+ * @sa wlan_11h_issue_radar_detect
+ * @sa wlan_11h_process_start
+ */
+mlan_status
+wlan_11h_check_chan_report(mlan_private * priv, t_u8 chan)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ wlan_dfs_device_state_t *pstate_dfs = &priv->adapter->state_dfs;
+ t_u32 sec, usec;
+
+ ENTER();
+
+ /* check report we hold is valid or not */
+ priv->adapter->callbacks.moal_get_system_time(priv->adapter->pmoal_handle,
+ &sec, &usec);
+
+ PRINTM(MINFO, "11h: %s()\n", __FUNCTION__);
+ PRINTM(MINFO, "- sec_now=%d, sec_report=%d.\n",
+ sec, pstate_dfs->dfs_report_time_sec);
+ PRINTM(MINFO, "- rpt_channel=%d, rpt_radar=%d.\n",
+ pstate_dfs->dfs_check_channel, pstate_dfs->dfs_radar_found);
+
+ if ((!pstate_dfs->dfs_check_pending) &&
+ (chan == pstate_dfs->dfs_check_channel) &&
+ ((sec - pstate_dfs->dfs_report_time_sec) <
+ MAX_DFS_REPORT_USABLE_AGE_SEC)) {
+ /* valid and not out-dated, check if radar */
+ if (pstate_dfs->dfs_radar_found) {
+ PRINTM(MMSG, "Radar was detected on channel %d.\n", chan);
+ ret = MLAN_STATUS_FAILURE;
+ }
+ } else {
+ // TODO: reissue report request if not pending.
+ // BUT HOW to make the code wait for it???
+ /* For now, just fail since we don't have the info. */
+ ret = MLAN_STATUS_PENDING;
+ }
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Process an TLV buffer for a pending BSS Adhoc start command.
+ *
+ * Activate 11h functionality in the firmware if driver has is enabled
+ * for 11h (configured by the application via IOCTL).
+ *
+ * @param priv Private driver information structure
+ * @param ppbuffer Output parameter: Pointer to the TLV output buffer,
+ * modified on return to point after the appended 11h TLVs
+ * @param pcap_info Pointer to the capability info for the BSS to join
+ * @param channel Channel on which we are starting the IBSS
+ * @param p11h_bss_info Input/Output parameter: Pointer to the 11h BSS
+ * information for this network that we are establishing.
+ * 11h sensed flag set on output if warranted.
+ *
+ * @return
+ * - MLAN_STATUS_SUCCESS if 11h is disabled
+ * - Integer number of bytes appended to the TLV output buffer (ppbuffer)
+ * - < 0 for error (e.g. radar detected on channel)
+ */
+t_s32
+wlan_11h_process_start(mlan_private * priv,
+ t_u8 ** ppbuffer,
+ IEEEtypes_CapInfo_t * pcap_info,
+ t_u32 channel, wlan_11h_bss_info_t * p11h_bss_info)
+{
+ mlan_adapter *adapter = priv->adapter;
+ t_s32 ret = MLAN_STATUS_SUCCESS;
+ t_bool is_dfs_chan = MFALSE;
+
+ ENTER();
+ if (wlan_11h_is_enabled(priv)
+ && ((adapter->adhoc_start_band & BAND_A)
+ || (adapter->adhoc_start_band & BAND_AN)
+ )
+ ) {
+ if (!wlan_11d_is_enabled(priv)) {
+ /* No use having 11h enabled without 11d enabled */
+ wlan_11d_enable(priv, MNULL, ENABLE_11D);
+#ifdef STA_SUPPORT
+ wlan_11d_create_dnld_countryinfo(priv, adapter->adhoc_start_band);
+#endif
+ }
+
+ /* Activate 11h functions in firmware, turns on capability bit */
+ wlan_11h_activate(priv, MNULL, MTRUE);
+ pcap_info->spectrum_mgmt = MTRUE;
+
+ /* If using a DFS channel, enable radar detection. */
+ is_dfs_chan = wlan_11h_radar_detect_required(priv, channel);
+ if (is_dfs_chan) {
+ if (!wlan_11h_is_master_radar_det_active(priv))
+ wlan_11h_config_master_radar_det(priv, MTRUE);
+ }
+ wlan_11h_check_update_radar_det_state(priv);
+
+ /* Set flag indicating this BSS we are starting is using 11h */
+ p11h_bss_info->sensed_11h = MTRUE;
+
+ if (is_dfs_chan) {
+ /* check if this channel is under NOP */
+ if (wlan_11h_is_channel_under_nop(adapter, channel))
+ ret = MLAN_STATUS_FAILURE;
+ /* check last channel report, if this channel is free of radar */
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = wlan_11h_check_chan_report(priv, channel);
+ }
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = wlan_11h_process_adhoc(priv, ppbuffer, channel, MNULL);
+ else
+ ret = MLAN_STATUS_FAILURE;
+ } else {
+ /* Deactivate 11h functions in the firmware */
+ wlan_11h_activate(priv, MNULL, MFALSE);
+ pcap_info->spectrum_mgmt = MFALSE;
+ wlan_11h_check_update_radar_det_state(priv);
+ }
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Process an TLV buffer for a pending BSS Join command for
+ * both adhoc and infra networks
+ *
+ * The TLV command processing for a BSS join for either adhoc or
+ * infrastructure network is performed with this function. The
+ * capability bits are inspected for the IBSS flag and the appropriate
+ * local routines are called to setup the necessary TLVs.
+ *
+ * Activate 11h functionality in the firmware if the spectrum management
+ * capability bit is found in the network information for the BSS we are
+ * joining.
+ *
+ * @param priv Private driver information structure
+ * @param ppbuffer Output parameter: Pointer to the TLV output buffer,
+ * modified on return to point after the appended 11h TLVs
+ * @param pcap_info Pointer to the capability info for the BSS to join
+ * @param band Band on which we are joining the BSS
+ * @param channel Channel on which we are joining the BSS
+ * @param p11h_bss_info Pointer to the 11h BSS information for this
+ * network that was parsed out of the scan response.
+ *
+ * @return Integer number of bytes appended to the TLV output
+ * buffer (ppbuffer), MLAN_STATUS_FAILURE (-1),
+ * or MLAN_STATUS_SUCCESS (0)
+ */
+t_s32
+wlan_11h_process_join(mlan_private * priv,
+ t_u8 ** ppbuffer,
+ IEEEtypes_CapInfo_t * pcap_info,
+ t_u8 band,
+ t_u32 channel, wlan_11h_bss_info_t * p11h_bss_info)
+{
+ t_s32 ret = 0;
+
+ ENTER();
+
+ if (priv->media_connected == MTRUE) {
+ if (wlan_11h_is_active(priv) == p11h_bss_info->sensed_11h) {
+ /* Assume DFS parameters are the same for roaming as long as the
+ current & next APs have the same spectrum mgmt capability bit
+ setting */
+ ret = MLAN_STATUS_SUCCESS;
+
+ } else {
+ /* No support for roaming between DFS/non-DFS yet */
+ ret = MLAN_STATUS_FAILURE;
+ }
+
+ LEAVE();
+ return ret;
+ }
+
+ if (p11h_bss_info->sensed_11h) {
+ if (!wlan_11d_is_enabled(priv)) {
+ /* No use having 11h enabled without 11d enabled */
+ wlan_11d_enable(priv, MNULL, ENABLE_11D);
+#ifdef STA_SUPPORT
+ wlan_11d_parse_dnld_countryinfo(priv, priv->pattempted_bss_desc);
+#endif
+ }
+ /* Activate 11h functions in firmware, turns on capability bit */
+ wlan_11h_activate(priv, MNULL, MTRUE);
+ pcap_info->spectrum_mgmt = MTRUE;
+
+ /* If using a DFS channel, enable radar detection. */
+ if ((band & BAND_A) && wlan_11h_radar_detect_required(priv, channel)) {
+ if (!wlan_11h_is_slave_radar_det_active(priv))
+ wlan_11h_config_slave_radar_det(priv, MTRUE);
+ }
+ wlan_11h_check_update_radar_det_state(priv);
+
+ if (pcap_info->ibss) {
+ PRINTM(MINFO, "11h: Adhoc join: Sensed\n");
+ ret = wlan_11h_process_adhoc(priv, ppbuffer, channel,
+ p11h_bss_info);
+ } else {
+ PRINTM(MINFO, "11h: Infra join: Sensed\n");
+ ret = wlan_11h_process_infra_join(priv, ppbuffer, band,
+ channel, p11h_bss_info);
+ }
+ } else {
+ /* Deactivate 11h functions in the firmware */
+ wlan_11h_activate(priv, MNULL, MFALSE);
+ pcap_info->spectrum_mgmt = MFALSE;
+ wlan_11h_check_update_radar_det_state(priv);
+ }
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ *
+ * @brief Prepare the HostCmd_DS_Command structure for an 11h command.
+ *
+ * Use the Command field to determine if the command being set up is for
+ * 11h and call one of the local command handlers accordingly for:
+ *
+ * - HostCmd_CMD_802_11_TPC_ADAPT_REQ
+ * - HostCmd_CMD_802_11_TPC_INFO
+ * - HostCmd_CMD_802_11_CHAN_SW_ANN
+ */
+/** - HostCmd_CMD_CHAN_REPORT_REQUEST
+ */
+/**
+ * @param priv Private driver information structure
+ * @param pcmd_ptr Output parameter: Pointer to the command being prepared
+ * for the firmware
+ * @param pinfo_buf Void buffer pass through with data necessary for a
+ * specific command type
+ */
+/** @return MLAN_STATUS_SUCCESS, MLAN_STATUS_FAILURE or MLAN_STATUS_PENDING
+ */
+/** @sa wlan_11h_cmd_tpc_request
+ * @sa wlan_11h_cmd_tpc_info
+ * @sa wlan_11h_cmd_chan_sw_ann
+ */
+/** @sa wlan_11h_cmd_chan_report_req
+ */
+mlan_status
+wlan_11h_cmd_process(mlan_private * priv,
+ HostCmd_DS_COMMAND * pcmd_ptr, const t_void * pinfo_buf)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+ switch (pcmd_ptr->command) {
+ case HostCmd_CMD_802_11_TPC_ADAPT_REQ:
+ ret = wlan_11h_cmd_tpc_request(priv, pcmd_ptr, pinfo_buf);
+ break;
+ case HostCmd_CMD_802_11_TPC_INFO:
+ ret = wlan_11h_cmd_tpc_info(priv, pcmd_ptr, pinfo_buf);
+ break;
+ case HostCmd_CMD_802_11_CHAN_SW_ANN:
+ ret = wlan_11h_cmd_chan_sw_ann(priv, pcmd_ptr, pinfo_buf);
+ break;
+ case HostCmd_CMD_CHAN_REPORT_REQUEST:
+ ret = wlan_11h_cmd_chan_rpt_req(priv, pcmd_ptr, pinfo_buf);
+ break;
+ default:
+ ret = MLAN_STATUS_FAILURE;
+ }
+
+ pcmd_ptr->command = wlan_cpu_to_le16(pcmd_ptr->command);
+ pcmd_ptr->size = wlan_cpu_to_le16(pcmd_ptr->size);
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Handle the command response from the firmware if from an 11h command
+ *
+ * Use the Command field to determine if the command response being
+ * is for 11h. Call the local command response handler accordingly for:
+ *
+ * - HostCmd_CMD_802_11_TPC_ADAPT_REQ
+ * - HostCmd_CMD_802_11_TPC_INFO
+ * - HostCmd_CMD_802_11_CHAN_SW_ANN
+ */
+/** - HostCmd_CMD_CHAN_REPORT_REQUEST
+ */
+/**
+ * @param priv Private driver information structure
+ * @param resp HostCmd_DS_COMMAND struct returned from the firmware
+ * command
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status
+wlan_11h_cmdresp_process(mlan_private * priv, const HostCmd_DS_COMMAND * resp)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+ switch (resp->command) {
+ case HostCmd_CMD_802_11_TPC_ADAPT_REQ:
+ HEXDUMP("11h: TPC REQUEST Rsp:", (t_u8 *) resp, (t_u32) resp->size);
+ memcpy(priv->adapter, priv->adapter->curr_cmd->pdata_buf,
+ &resp->params.tpc_req, sizeof(HostCmd_DS_802_11_TPC_ADAPT_REQ));
+ break;
+
+ case HostCmd_CMD_802_11_TPC_INFO:
+ HEXDUMP("11h: TPC INFO Rsp Data:", (t_u8 *) resp, (t_u32) resp->size);
+ break;
+
+ case HostCmd_CMD_802_11_CHAN_SW_ANN:
+ PRINTM(MINFO, "11h: Ret ChSwAnn: Sz=%u, Seq=%u, Ret=%u\n",
+ resp->size, resp->seq_num, resp->result);
+ break;
+
+ case HostCmd_CMD_CHAN_REPORT_REQUEST:
+ PRINTM(MINFO, "11h: Ret ChanRptReq. Set dfs_check_pending and wait"
+ " for EVENT_CHANNEL_REPORT.\n");
+ priv->adapter->state_dfs.dfs_check_pending = MTRUE;
+ break;
+
+ default:
+ ret = MLAN_STATUS_FAILURE;
+ }
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Process an element from a scan response, copy relevant info for 11h
+ *
+ * @param pmadapter Pointer to mlan_adapter
+ * @param p11h_bss_info Output parameter: Pointer to the 11h BSS information
+ * for the network that is being processed
+ * @param pelement Pointer to the current IE we are inspecting for 11h
+ * relevance
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status
+wlan_11h_process_bss_elem(mlan_adapter * pmadapter,
+ wlan_11h_bss_info_t * p11h_bss_info,
+ const t_u8 * pelement)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ t_u8 element_len = *((t_u8 *) pelement + 1);
+
+ ENTER();
+ switch (*pelement) {
+ case POWER_CONSTRAINT:
+ PRINTM(MINFO, "11h: Power Constraint IE Found\n");
+ p11h_bss_info->sensed_11h = MTRUE;
+ memcpy(pmadapter, &p11h_bss_info->power_constraint, pelement,
+ MIN((element_len + sizeof(IEEEtypes_Header_t)),
+ sizeof(IEEEtypes_PowerConstraint_t)));
+ p11h_bss_info->power_constraint.len =
+ MIN(element_len, (sizeof(IEEEtypes_PowerConstraint_t)
+ - sizeof(IEEEtypes_Header_t)));
+ break;
+
+ case POWER_CAPABILITY:
+ PRINTM(MINFO, "11h: Power Capability IE Found\n");
+ p11h_bss_info->sensed_11h = MTRUE;
+ memcpy(pmadapter, &p11h_bss_info->power_capability, pelement,
+ MIN((element_len + sizeof(IEEEtypes_Header_t)),
+ sizeof(IEEEtypes_PowerCapability_t)));
+ p11h_bss_info->power_capability.len =
+ MIN(element_len, (sizeof(IEEEtypes_PowerCapability_t)
+ - sizeof(IEEEtypes_Header_t)));
+ break;
+
+ case TPC_REPORT:
+ PRINTM(MINFO, "11h: Tpc Report IE Found\n");
+ p11h_bss_info->sensed_11h = MTRUE;
+ memcpy(pmadapter, &p11h_bss_info->tpc_report, pelement,
+ MIN((element_len + sizeof(IEEEtypes_Header_t)),
+ sizeof(IEEEtypes_TPCReport_t)));
+ p11h_bss_info->tpc_report.len =
+ MIN(element_len, (sizeof(IEEEtypes_TPCReport_t)
+ - sizeof(IEEEtypes_Header_t)));
+ break;
+
+ case CHANNEL_SWITCH_ANN:
+ PRINTM(MINFO, "11h: Channel Switch Ann IE Found\n");
+ p11h_bss_info->sensed_11h = MTRUE;
+ memcpy(pmadapter, &p11h_bss_info->chan_switch_ann, pelement,
+ MIN((element_len + sizeof(IEEEtypes_Header_t)),
+ sizeof(IEEEtypes_ChanSwitchAnn_t)));
+ p11h_bss_info->chan_switch_ann.len =
+ MIN(element_len, (sizeof(IEEEtypes_ChanSwitchAnn_t)
+ - sizeof(IEEEtypes_Header_t)));
+ break;
+
+ case QUIET:
+ PRINTM(MINFO, "11h: Quiet IE Found\n");
+ p11h_bss_info->sensed_11h = MTRUE;
+ memcpy(pmadapter, &p11h_bss_info->quiet, pelement,
+ MIN((element_len + sizeof(IEEEtypes_Header_t)),
+ sizeof(IEEEtypes_Quiet_t)));
+ p11h_bss_info->quiet.len = MIN(element_len, (sizeof(IEEEtypes_Quiet_t)
+ -
+ sizeof
+ (IEEEtypes_Header_t)));
+ break;
+
+ case IBSS_DFS:
+ PRINTM(MINFO, "11h: Ibss Dfs IE Found\n");
+ p11h_bss_info->sensed_11h = MTRUE;
+ memcpy(pmadapter, &p11h_bss_info->ibss_dfs, pelement,
+ MIN((element_len + sizeof(IEEEtypes_Header_t)),
+ sizeof(IEEEtypes_IBSS_DFS_t)));
+ p11h_bss_info->ibss_dfs.len =
+ MIN(element_len, (sizeof(IEEEtypes_IBSS_DFS_t)
+ - sizeof(IEEEtypes_Header_t)));
+ break;
+
+ case SUPPORTED_CHANNELS:
+ case TPC_REQUEST:
+ /*
+ * These elements are not in beacons/probe responses. Included here
+ * to cover set of enumerated 11h elements.
+ */
+ break;
+
+ default:
+ ret = MLAN_STATUS_FAILURE;
+ }
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Driver handling for CHANNEL_SWITCH_ANN event
+ *
+ * @param priv Pointer to mlan_private
+ *
+ * @return MLAN_STATUS_SUCCESS, MLAN_STATUS_FAILURE or MLAN_STATUS_PENDING
+ */
+mlan_status
+wlan_11h_handle_event_chanswann(mlan_private * priv)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ ENTER();
+ priv->adapter->state_11h.recvd_chanswann_event = MTRUE;
+
+#ifdef STA_SUPPORT
+ /* do directed deauth. priv flag above will cause different reason code */
+ PRINTM(MINFO, "11h: handle_event_chanswann() - sending deauth\n");
+ ret = wlan_disconnect(priv, MNULL,
+ &priv->curr_bss_params.bss_descriptor.mac_address);
+
+ /* clear region table so next scan will be all passive */
+ PRINTM(MINFO, "11h: handle_event_chanswann() - clear region table\n");
+ wlan_11d_clear_parsedtable(priv);
+#endif
+
+ priv->adapter->state_11h.recvd_chanswann_event = MFALSE;
+ LEAVE();
+ return ret;
+}
+
+#ifdef DFS_TESTING_SUPPORT
+/**
+ * @brief 802.11h DFS Testing configuration
+ *
+ * @param pmadapter Pointer to mlan_adapter
+ * @param pioctl_req Pointer to mlan_ioctl_req
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status
+wlan_11h_ioctl_dfs_testing(pmlan_adapter pmadapter, pmlan_ioctl_req pioctl_req)
+{
+ mlan_ds_11h_cfg *ds_11hcfg = MNULL;
+ mlan_ds_11h_dfs_testing *dfs_test = MNULL;
+ wlan_dfs_testing_settings_t *pdfs_test_params = MNULL;
+
+ ENTER();
+
+ ds_11hcfg = (mlan_ds_11h_cfg *) pioctl_req->pbuf;
+ dfs_test = &ds_11hcfg->param.dfs_testing;
+ pdfs_test_params = &pmadapter->dfs_test_params;
+
+ if (pioctl_req->action == MLAN_ACT_GET) {
+ dfs_test->usr_cac_period_msec = pdfs_test_params->user_cac_period_msec;
+ dfs_test->usr_nop_period_sec = pdfs_test_params->user_nop_period_sec;
+ dfs_test->usr_no_chan_change =
+ pdfs_test_params->no_channel_change_on_radar;
+ dfs_test->usr_fixed_new_chan =
+ pdfs_test_params->fixed_new_channel_on_radar;
+ } else {
+ pdfs_test_params->user_cac_period_msec = dfs_test->usr_cac_period_msec;
+ pdfs_test_params->user_nop_period_sec = dfs_test->usr_nop_period_sec;
+ pdfs_test_params->no_channel_change_on_radar =
+ dfs_test->usr_no_chan_change;
+ pdfs_test_params->fixed_new_channel_on_radar =
+ dfs_test->usr_fixed_new_chan;
+ }
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+#endif // DFS_TESTING_SUPPORT
+
+/**
+ * @brief Check if channel is under NOP (Non-Occupancy Period)
+ * If so, the channel should not be used until the period expires.
+ *
+ * @param pmadapter Pointer to mlan_adapter
+ * @param channel Channel number
+ *
+ * @return MTRUE or MFALSE
+ */
+t_bool
+wlan_11h_is_channel_under_nop(mlan_adapter * pmadapter, t_u8 channel)
+{
+ wlan_dfs_timestamp_t *pdfs_ts = MNULL;
+ t_u32 now_sec, now_usec;
+ t_bool ret = MFALSE;
+
+ ENTER();
+ pdfs_ts = wlan_11h_find_dfs_timestamp(pmadapter, channel);
+
+ if (pdfs_ts && (pdfs_ts->channel == channel)
+ && (pdfs_ts->represents == DFS_TS_REPR_NOP_START)) {
+ /* found NOP_start timestamp entry on channel */
+ pmadapter->callbacks.moal_get_system_time(pmadapter->pmoal_handle,
+ &now_sec, &now_usec);
+#ifdef DFS_TESTING_SUPPORT
+ if (pmadapter->dfs_test_params.user_nop_period_sec) {
+ PRINTM(MCMD_D, "dfs_testing - user NOP period=%d (sec)\n",
+ pmadapter->dfs_test_params.user_nop_period_sec);
+ if ((now_sec - pdfs_ts->ts_sec) <=
+ pmadapter->dfs_test_params.user_nop_period_sec) {
+ ret = MTRUE;
+ }
+ } else
+#endif
+ {
+ if ((now_sec - pdfs_ts->ts_sec) <= WLAN_11H_NON_OCCUPANCY_PERIOD)
+ ret = MTRUE;
+ }
+
+ /* if entry is expired, remove it */
+ if (!ret)
+ wlan_11h_remove_dfs_timestamp(pmadapter, pdfs_ts);
+ else
+ PRINTM(MMSG, "11h: channel %d is under NOP - can't use.\n",
+ channel);
+ }
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Driver handling for CHANNEL_REPORT_RDY event
+ * This event will have the channel report data appended.
+ *
+ * @param priv Pointer to mlan_private
+ * @param pevent Pointer to mlan_event
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status
+wlan_11h_handle_event_chanrpt_ready(mlan_private * priv, mlan_event * pevent)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ HostCmd_DS_CHAN_RPT_RSP *pChanRptRsp;
+ MrvlIEtypes_Data_t *pTlv;
+ MeasRptBasicMap_t *pMeasRptBasic;
+ t_u8 *pBuffer;
+ t_s32 evtLen;
+ t_u16 tlvLen;
+ t_u32 sec, uSec;
+ wlan_dfs_device_state_t *pstate_dfs = &priv->adapter->state_dfs;
+
+ ENTER();
+ pChanRptRsp = (HostCmd_DS_CHAN_RPT_RSP *) & pevent->event_buf;
+ DBG_HEXDUMP(MCMD_D, "11h: Event ChanRptReady (HostCmd_DS_CHAN_RPT_RSP)",
+ (t_u8 *) pChanRptRsp, wlan_le32_to_cpu(pevent->event_len));
+
+ if (wlan_le32_to_cpu(pChanRptRsp->cmd_result) == MLAN_CMD_RESULT_SUCCESS) {
+ pBuffer = (t_u8 *) & pChanRptRsp->tlv_buffer;
+ evtLen = wlan_le32_to_cpu(pevent->event_len);
+ evtLen -=
+ sizeof(HostCmd_DS_CHAN_RPT_RSP) - sizeof(pChanRptRsp->tlv_buffer);
+
+ while (evtLen >= sizeof(MrvlIEtypesHeader_t)) {
+ pTlv = (MrvlIEtypes_Data_t *) pBuffer;
+ tlvLen = wlan_le16_to_cpu(pTlv->header.len);
+
+ switch (wlan_le16_to_cpu(pTlv->header.type)) {
+ case TLV_TYPE_CHANRPT_11H_BASIC:
+ pMeasRptBasic = (MeasRptBasicMap_t *) & pTlv->data;
+ if (pMeasRptBasic->radar) {
+ pstate_dfs->dfs_radar_found = MTRUE;
+ PRINTM(MMSG, "RADAR Detected on channel %d!\n",
+ pstate_dfs->dfs_check_channel);
+ /* add channel to NOP list */
+ wlan_11h_add_dfs_timestamp(priv->adapter,
+ DFS_TS_REPR_NOP_START,
+ pstate_dfs->dfs_check_channel);
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ pBuffer += (tlvLen + sizeof(pTlv->header));
+ evtLen -= (tlvLen + sizeof(pTlv->header));
+ evtLen = (evtLen > 0) ? evtLen : 0;
+ }
+ } else {
+ ret = MLAN_STATUS_FAILURE;
+ }
+
+ /* Update DFS structure. */
+ priv->adapter->callbacks.moal_get_system_time(priv->adapter->pmoal_handle,
+ &sec, &uSec);
+ pstate_dfs->dfs_report_time_sec = sec;
+ pstate_dfs->dfs_check_pending = MFALSE;
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Check if RADAR_DETECTED handling is blocking data tx
+ *
+ * @param pmadapter Pointer to mlan_adapter
+ *
+ * @return MTRUE or MFALSE
+ */
+t_bool
+wlan_11h_radar_detected_tx_blocked(mlan_adapter * pmadapter)
+{
+ switch (pmadapter->state_rdh.stage) {
+ case RDH_OFF:
+ case RDH_CHK_INTFS:
+ case RDH_STOP_TRAFFIC:
+ return MFALSE;
+ }
+ return MTRUE;
+}
+
+/**
+ * @brief Callback for RADAR_DETECTED event driver handling
+ *
+ * @param priv Void pointer to mlan_private
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status
+wlan_11h_radar_detected_callback(t_void * priv)
+{
+ mlan_status ret;
+ ENTER();
+ ret = wlan_11h_radar_detected_handling(((mlan_private *) (priv))->adapter);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Driver handling for RADAR_DETECTED event
+ *
+ * @param pmadapter Pointer to mlan_adapter
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE or MLAN_STATUS_PENDING
+ */
+mlan_status
+wlan_11h_radar_detected_handling(mlan_adapter * pmadapter)
+{
+#ifdef DEBUG_LEVEL1
+ const char *RDH_stage_str[] = {
+ "RDH_OFF",
+ "RDH_CHK_INTFS",
+ "RDH_STOP_TRAFFIC",
+ "RDH_GET_INFO_CHANNEL",
+ "RDH_GET_INFO_BEACON_DTIM",
+ "RDH_SET_CUSTOM_IE",
+ "RDH_REM_CUSTOM_IE",
+ "RDH_STOP_INTFS",
+ "RDH_SET_NEW_CHANNEL",
+ "RDH_RESTART_INTFS",
+ "RDH_RESTART_TRAFFIC"
+ };
+#endif
+
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_private *pmpriv = MNULL;
+ t_u32 i;
+ wlan_radar_det_hndlg_state_t *pstate_rdh = &pmadapter->state_rdh;
+
+ ENTER();
+
+ switch (pstate_rdh->stage) {
+ case RDH_CHK_INTFS:
+ PRINTM(MCMD_D, "%s(): stage(%d)=%s\n",
+ __FUNCTION__, pstate_rdh->stage,
+ RDH_stage_str[pstate_rdh->stage]);
+
+ /* get active interfaces */
+ memset(pmadapter, pstate_rdh->priv_list, 0x00,
+ sizeof(pstate_rdh->priv_list));
+ pstate_rdh->priv_list_count = wlan_get_privs_by_cond(pmadapter,
+ wlan_is_intf_active,
+ pstate_rdh->
+ priv_list);
+ PRINTM(MCMD_D, "%s(): priv_list_count = %d\n", __FUNCTION__,
+ pstate_rdh->priv_list_count);
+ for (i = 0; i < pstate_rdh->priv_list_count; i++)
+ PRINTM(MINFO, "%s(): priv_list[%d] = %p\n",
+ __FUNCTION__, i, pstate_rdh->priv_list[i]);
+
+ if (pstate_rdh->priv_list_count == 0) {
+ /* no interfaces active... nothing to do */
+ PRINTM(MMSG, "11h: Radar Detected - no active priv's,"
+ " skip event handling.\n");
+ pstate_rdh->stage = RDH_OFF;
+ PRINTM(MCMD_D, "%s(): finished - stage(%d)=%s\n",
+ __FUNCTION__, pstate_rdh->stage,
+ RDH_stage_str[pstate_rdh->stage]);
+ break; // EXIT CASE
+ }
+ // else: start handling
+ pstate_rdh->curr_channel = 0;
+ pstate_rdh->new_channel = 0;
+ pstate_rdh->uap_band_cfg = 0;
+ pstate_rdh->max_bcn_dtim_ms = 0;
+ pstate_rdh->priv_curr_idx = RDH_STAGE_FIRST_ENTRY_PRIV_IDX;
+ pstate_rdh->stage = RDH_STOP_TRAFFIC;
+ // FALL THROUGH TO NEXT STAGE
+
+ case RDH_STOP_TRAFFIC:
+ PRINTM(MCMD_D, "%s(): stage(%d)=%s\n",
+ __FUNCTION__, pstate_rdh->stage,
+ RDH_stage_str[pstate_rdh->stage]);
+
+ PRINTM(MMSG, "11h: Radar Detected - stopping host tx traffic.\n");
+ for (i = 0; i < pstate_rdh->priv_list_count; i++) {
+ wlan_11h_tx_disable(pstate_rdh->priv_list[i]);
+ }
+
+ pstate_rdh->priv_curr_idx = RDH_STAGE_FIRST_ENTRY_PRIV_IDX;
+ pstate_rdh->stage = RDH_GET_INFO_CHANNEL;
+ // FALL THROUGH TO NEXT STAGE
+
+ case RDH_GET_INFO_CHANNEL:
+ PRINTM(MCMD_D, "%s(): stage(%d)=%s, priv_idx=%d\n",
+ __FUNCTION__, pstate_rdh->stage,
+ RDH_stage_str[pstate_rdh->stage], pstate_rdh->priv_curr_idx);
+
+ /* here, prefer STA info over UAP info - one less CMD to send */
+ if (pstate_rdh->priv_curr_idx == RDH_STAGE_FIRST_ENTRY_PRIV_IDX) {
+ if (wlan_only_uap_priv_in_list(pstate_rdh->priv_list,
+ pstate_rdh->priv_list_count)) {
+#ifdef UAP_SUPPORT
+ /* Assume all UAPs on same channel, use first UAP */
+ pmpriv = pstate_rdh->priv_list[0];
+ pstate_rdh->priv_curr_idx = 0;
+ /* send cmd to get first UAP's info */
+ pmpriv->uap_state_chan_cb.pioctl_req_curr = MNULL;
+ pmpriv->uap_state_chan_cb.get_chan_callback
+ = wlan_11h_radar_detected_callback;
+ ret = wlan_uap_get_channel(pmpriv);
+ break; // EXIT CASE
+#endif
+ } else {
+ /* Assume all STAs on same channel, find first STA */
+ MASSERT(pstate_rdh->priv_list_count > 0);
+ for (i = 0; i < pstate_rdh->priv_list_count; i++) {
+ pmpriv = pstate_rdh->priv_list[i];
+ if (GET_BSS_ROLE(pmpriv) == MLAN_BSS_ROLE_STA)
+ break;
+ }
+ /* STA info kept in driver, just copy */
+ pstate_rdh->curr_channel =
+ pmpriv->curr_bss_params.bss_descriptor.channel;
+ }
+ }
+#ifdef UAP_SUPPORT
+ else if (pstate_rdh->priv_curr_idx < pstate_rdh->priv_list_count) {
+ /* repeat entry: UAP return with info */
+ pmpriv = pstate_rdh->priv_list[pstate_rdh->priv_curr_idx];
+ pstate_rdh->curr_channel = pmpriv->uap_state_chan_cb.channel;
+ pstate_rdh->uap_band_cfg = pmpriv->uap_state_chan_cb.band_config;
+ PRINTM(MCMD_D, "%s(): uap_band_cfg=0x%02x\n",
+ __FUNCTION__, pstate_rdh->uap_band_cfg);
+ }
+#endif
+
+ /* add channel to NOP list */
+ wlan_11h_add_dfs_timestamp(pmadapter, DFS_TS_REPR_NOP_START,
+ pstate_rdh->curr_channel);
+
+ /* choose new channel (!= curr channel) and move on */
+ i = 0;
+ do {
+#ifdef UAP_SUPPORT
+ if (GET_BSS_ROLE(pmpriv) == MLAN_BSS_ROLE_UAP)
+ pstate_rdh->new_channel = wlan_11h_get_uap_start_channel(pmpriv,
+ pmpriv->
+ uap_state_chan_cb.
+ band_config);
+ else
+#endif
+ pstate_rdh->new_channel =
+ wlan_11h_get_adhoc_start_channel(pmpriv);
+ } while ((pstate_rdh->new_channel == pstate_rdh->curr_channel) && (++i < MAX_RANDOM_CHANNEL_RETRIES)); /* avoid
+ deadloop
+ */
+ if (i >= MAX_RANDOM_CHANNEL_RETRIES) /* report error */
+ PRINTM(MERROR, "%s(): ERROR - could not choose new_chan"
+ " (!= curr_chan) !!\n", __FUNCTION__);
+
+#ifdef DFS_TESTING_SUPPORT
+ if (pmadapter->dfs_test_params.fixed_new_channel_on_radar) {
+ PRINTM(MCMD_D, "dfs_testing - user fixed new_chan=%d\n",
+ pmadapter->dfs_test_params.fixed_new_channel_on_radar);
+ pstate_rdh->new_channel =
+ pmadapter->dfs_test_params.fixed_new_channel_on_radar;
+ }
+#endif
+ PRINTM(MCMD_D, "%s(): curr_chan=%d, new_chan=%d\n",
+ __FUNCTION__, pstate_rdh->curr_channel, pstate_rdh->new_channel);
+
+ pstate_rdh->priv_curr_idx = RDH_STAGE_FIRST_ENTRY_PRIV_IDX;
+ pstate_rdh->stage = RDH_GET_INFO_BEACON_DTIM;
+ // FALL THROUGH TO NEXT STAGE
+
+ case RDH_GET_INFO_BEACON_DTIM:
+ PRINTM(MCMD_D, "%s(): stage(%d)=%s, priv_idx=%d\n",
+ __FUNCTION__, pstate_rdh->stage,
+ RDH_stage_str[pstate_rdh->stage], pstate_rdh->priv_curr_idx);
+
+#ifdef UAP_SUPPORT
+ /* check all intfs in this stage to find longest period */
+ /* UAP intf callback returning with info */
+ if (pstate_rdh->priv_curr_idx < pstate_rdh->priv_list_count) {
+ t_u16 bcn_dtim_msec;
+ pmpriv = pstate_rdh->priv_list[pstate_rdh->priv_curr_idx];
+ PRINTM(MCMD_D, "%s(): uap.bcn_pd=%d, uap.dtim_pd=%d\n",
+ __FUNCTION__, pmpriv->uap_state_chan_cb.beacon_period,
+ pmpriv->uap_state_chan_cb.dtim_period);
+ bcn_dtim_msec = (pmpriv->uap_state_chan_cb.beacon_period
+ * pmpriv->uap_state_chan_cb.dtim_period);
+ if (bcn_dtim_msec > pstate_rdh->max_bcn_dtim_ms)
+ pstate_rdh->max_bcn_dtim_ms = bcn_dtim_msec;
+ }
+#endif
+
+ /* check next intf */
+ while ((++pstate_rdh->priv_curr_idx) < pstate_rdh->priv_list_count) {
+ pmpriv = pstate_rdh->priv_list[pstate_rdh->priv_curr_idx];
+
+#ifdef UAP_SUPPORT
+ if (GET_BSS_ROLE(pmpriv) == MLAN_BSS_ROLE_UAP) {
+ pmpriv->uap_state_chan_cb.pioctl_req_curr = MNULL;
+ pmpriv->uap_state_chan_cb.get_chan_callback
+ = wlan_11h_radar_detected_callback;
+ ret = wlan_uap_get_beacon_dtim(pmpriv);
+ break; // leads to exit case
+ } else
+#endif
+ { /* get STA info from driver and compare here */
+ t_u16 bcn_pd_msec = 100;
+ t_u16 dtim_pd_msec = 1;
+ t_u16 bcn_dtim_msec;
+
+ if (wlan_11h_is_dfs_master(pmpriv)) { /* adhoc creator */
+ bcn_pd_msec = pmpriv->beacon_period;
+ } else {
+ bcn_pd_msec =
+ pmpriv->curr_bss_params.bss_descriptor.beacon_period;
+ // if (priv->bss_mode != MLAN_BSS_MODE_IBSS)
+ /* TODO: mlan_scan.c needs to parse TLV 0x05 (TIM) for
+ dtim_period */
+ }
+ PRINTM(MCMD_D, "%s(): sta.bcn_pd=%d, sta.dtim_pd=%d\n",
+ __FUNCTION__, bcn_pd_msec, dtim_pd_msec);
+ bcn_dtim_msec = (bcn_pd_msec * dtim_pd_msec);
+ if (bcn_dtim_msec > pstate_rdh->max_bcn_dtim_ms)
+ pstate_rdh->max_bcn_dtim_ms = bcn_dtim_msec;
+ }
+ }
+
+ if (pstate_rdh->priv_curr_idx < pstate_rdh->priv_list_count)
+ break; // EXIT CASE (for UAP)
+ // else
+ pstate_rdh->priv_curr_idx = RDH_STAGE_FIRST_ENTRY_PRIV_IDX;
+ pstate_rdh->stage = RDH_SET_CUSTOM_IE;
+ // FALL THROUGH TO NEXT STAGE
+
+ case RDH_SET_CUSTOM_IE:
+ PRINTM(MCMD_D, "%s(): stage(%d)=%s, priv_idx=%d\n",
+ __FUNCTION__, pstate_rdh->stage,
+ RDH_stage_str[pstate_rdh->stage], pstate_rdh->priv_curr_idx);
+
+ /* add CHAN_SW IE - firmware will accept on any interface, and apply to
+ all */
+ if (pstate_rdh->priv_curr_idx == RDH_STAGE_FIRST_ENTRY_PRIV_IDX) {
+ mlan_ioctl_req *pioctl_req = MNULL;
+
+ ret =
+ wlan_11h_prepare_custom_ie_chansw(pmadapter, &pioctl_req,
+ MTRUE);
+ if ((ret != MLAN_STATUS_SUCCESS) || !pioctl_req) {
+ PRINTM(MERROR, "%s(): Error in preparng CHAN_SW IE.\n",
+ __FUNCTION__);
+ break; // EXIT CASE
+ }
+
+ PRINTM(MMSG,
+ "11h: Radar Detected - adding CHAN_SW IE to interfaces.\n");
+ pmpriv = pstate_rdh->priv_list[0];
+ pstate_rdh->priv_curr_idx = 0;
+ pioctl_req->bss_index = pmpriv->bss_index;
+ ret = wlan_misc_ioctl_custom_ie_list(pmadapter, pioctl_req, MFALSE);
+ if (ret != MLAN_STATUS_SUCCESS && ret != MLAN_STATUS_PENDING) {
+ PRINTM(MERROR,
+ "%s(): Could not set IE for priv=%p [priv_bss_idx=%d]!\n",
+ __FUNCTION__, pmpriv, pmpriv->bss_index);
+ // TODO: how to handle this error case?? ignore & continue?
+ }
+ /* free ioctl buffer memory before we leave */
+ pmadapter->callbacks.moal_mfree(pmadapter->pmoal_handle,
+ (t_u8 *) pioctl_req);
+ break; // EXIT CASE
+ }
+ // else
+ pstate_rdh->priv_curr_idx = RDH_STAGE_FIRST_ENTRY_PRIV_IDX;
+ pstate_rdh->stage = RDH_REM_CUSTOM_IE;
+ // FALL THROUGH TO NEXT STAGE
+
+ case RDH_REM_CUSTOM_IE:
+ PRINTM(MCMD_D, "%s(): stage(%d)=%s, priv_idx=%d\n",
+ __FUNCTION__, pstate_rdh->stage,
+ RDH_stage_str[pstate_rdh->stage], pstate_rdh->priv_curr_idx);
+
+ /* remove CHAN_SW IE - firmware will accept on any interface, and apply
+ to all */
+ if (pstate_rdh->priv_curr_idx == RDH_STAGE_FIRST_ENTRY_PRIV_IDX) {
+ mlan_ioctl_req *pioctl_req = MNULL;
+
+ /* first entry to this stage, do delay DFS requires a minimum of 5
+ chances for clients to hear this IE. Use delay: 5 beacons <=
+ (BCN_DTIM_MSEC*5) <= 3 seconds). */
+ t_u16 delay_ms = MAX(MIN_RDH_CHAN_SW_IE_PERIOD_MSEC,
+ MIN((5 * pstate_rdh->max_bcn_dtim_ms),
+ MAX_RDH_CHAN_SW_IE_PERIOD_MSEC));
+ PRINTM(MMSG, "11h: Radar Detected - delay %d ms for FW to"
+ " broadcast CHAN_SW IE.\n", delay_ms);
+ wlan_mdelay(pmadapter, delay_ms);
+ PRINTM(MMSG, "11h: Radar Detected - delay over, removing"
+ " CHAN_SW IE from interfaces.\n");
+
+ ret =
+ wlan_11h_prepare_custom_ie_chansw(pmadapter, &pioctl_req,
+ MFALSE);
+ if ((ret != MLAN_STATUS_SUCCESS) || !pioctl_req) {
+ PRINTM(MERROR, "%s(): Error in preparng CHAN_SW IE.\n",
+ __FUNCTION__);
+ break; // EXIT CASE
+ }
+
+ pmpriv = pstate_rdh->priv_list[0];
+ pstate_rdh->priv_curr_idx = 0;
+ pioctl_req->bss_index = pmpriv->bss_index;
+ ret = wlan_misc_ioctl_custom_ie_list(pmadapter, pioctl_req, MFALSE);
+ if (ret != MLAN_STATUS_SUCCESS && ret != MLAN_STATUS_PENDING) {
+ PRINTM(MERROR,
+ "%s(): Could not set IE for priv=%p [priv_bss_idx=%d]!\n",
+ __FUNCTION__, pmpriv, pmpriv->bss_index);
+ // TODO: how to handle this error case?? ignore & continue?
+ }
+ /* free ioctl buffer memory before we leave */
+ pmadapter->callbacks.moal_mfree(pmadapter->pmoal_handle,
+ (t_u8 *) pioctl_req);
+ break; // EXIT CASE
+ }
+ // else
+ pstate_rdh->priv_curr_idx = RDH_STAGE_FIRST_ENTRY_PRIV_IDX;
+ pstate_rdh->stage = RDH_STOP_INTFS;
+#ifdef DFS_TESTING_SUPPORT
+ if (pmadapter->dfs_test_params.no_channel_change_on_radar) {
+ PRINTM(MCMD_D, "dfs_testing - no channel change on radar."
+ " Also skip stop/restart interface stages.\n",
+ pmadapter->dfs_test_params.no_channel_change_on_radar);
+ pstate_rdh->priv_curr_idx = RDH_STAGE_FIRST_ENTRY_PRIV_IDX;
+ pstate_rdh->stage = RDH_RESTART_TRAFFIC;
+ goto rdh_restart_traffic; // skip several stages
+ }
+#endif
+ // FALL THROUGH TO NEXT STAGE
+
+ case RDH_STOP_INTFS:
+ PRINTM(MCMD_D, "%s(): stage(%d)=%s, priv_idx=%d\n",
+ __FUNCTION__, pstate_rdh->stage,
+ RDH_stage_str[pstate_rdh->stage], pstate_rdh->priv_curr_idx);
+
+ /* issues one cmd (DEAUTH/ADHOC_STOP/BSS_STOP) to each intf */
+ while ((++pstate_rdh->priv_curr_idx) < pstate_rdh->priv_list_count) {
+ pmpriv = pstate_rdh->priv_list[pstate_rdh->priv_curr_idx];
+#ifdef UAP_SUPPORT
+ if (GET_BSS_ROLE(pmpriv) == MLAN_BSS_ROLE_UAP) {
+ ret = wlan_prepare_cmd(pmpriv, HOST_CMD_APCMD_BSS_STOP,
+ HostCmd_ACT_GEN_SET, 0, MNULL, MNULL);
+ break; // leads to exit case
+ }
+#endif
+#ifdef STA_SUPPORT
+ if (GET_BSS_ROLE(pmpriv) == MLAN_BSS_ROLE_STA) {
+ if (wlan_11h_is_dfs_master(pmpriv)) {
+ /* Save ad-hoc creator state before stop clears it */
+ pmpriv->adhoc_state_prev = pmpriv->adhoc_state;
+ }
+ if (pmpriv->media_connected == MTRUE) {
+ wlan_disconnect(pmpriv, MNULL, MNULL);
+ break; // leads to exit case
+ }
+ }
+#endif
+ }
+
+ if (pstate_rdh->priv_curr_idx < pstate_rdh->priv_list_count)
+ break; // EXIT CASE
+ // else
+ pstate_rdh->priv_curr_idx = RDH_STAGE_FIRST_ENTRY_PRIV_IDX;
+ pstate_rdh->stage = RDH_SET_NEW_CHANNEL;
+ // FALL THROUGH TO NEXT STAGE
+
+ case RDH_SET_NEW_CHANNEL:
+ PRINTM(MCMD_D, "%s(): stage(%d)=%s, priv_idx=%d\n",
+ __FUNCTION__, pstate_rdh->stage,
+ RDH_stage_str[pstate_rdh->stage], pstate_rdh->priv_curr_idx);
+
+ /* only set new channel for UAP intfs */
+ while ((++pstate_rdh->priv_curr_idx) < pstate_rdh->priv_list_count) {
+ pmpriv = pstate_rdh->priv_list[pstate_rdh->priv_curr_idx];
+#ifdef UAP_SUPPORT
+ if (GET_BSS_ROLE(pmpriv) == MLAN_BSS_ROLE_UAP) {
+ pmpriv->uap_state_chan_cb.pioctl_req_curr = MNULL;
+ pmpriv->uap_state_chan_cb.get_chan_callback
+ = wlan_11h_radar_detected_callback;
+ pstate_rdh->uap_band_cfg |= UAP_BAND_CONFIG_5GHZ; /* DFS
+ only
+ in
+ 5GHz
+ */
+ ret = wlan_uap_set_channel(pmpriv, pstate_rdh->uap_band_cfg,
+ pstate_rdh->new_channel);
+ break; // leads to exit case
+ }
+#endif
+ }
+
+ if (pstate_rdh->priv_curr_idx < pstate_rdh->priv_list_count)
+ break; // EXIT CASE (for UAP)
+ // else
+ pstate_rdh->priv_curr_idx = RDH_STAGE_FIRST_ENTRY_PRIV_IDX;
+ pstate_rdh->stage = RDH_RESTART_INTFS;
+ // FALL THROUGH TO NEXT STAGE
+
+ case RDH_RESTART_INTFS:
+ PRINTM(MCMD_D, "%s(): stage(%d)=%s, priv_idx=%d\n",
+ __FUNCTION__, pstate_rdh->stage,
+ RDH_stage_str[pstate_rdh->stage], pstate_rdh->priv_curr_idx);
+
+ /* can only restart master intfs */
+ while ((++pstate_rdh->priv_curr_idx) < pstate_rdh->priv_list_count) {
+ pmpriv = pstate_rdh->priv_list[pstate_rdh->priv_curr_idx];
+#ifdef UAP_SUPPORT
+ if (GET_BSS_ROLE(pmpriv) == MLAN_BSS_ROLE_UAP) {
+ if (wlan_11h_radar_detect_required(pmpriv,
+ pstate_rdh->new_channel)) {
+ /* Radar detection is required for this channel, make sure
+ 11h is activated in the firmware */
+ ret = wlan_11h_activate(pmpriv, MNULL, MTRUE);
+ ret = wlan_11h_config_master_radar_det(pmpriv, MTRUE);
+ ret = wlan_11h_check_update_radar_det_state(pmpriv);
+ }
+ ret = wlan_prepare_cmd(pmpriv, HOST_CMD_APCMD_BSS_START,
+ HostCmd_ACT_GEN_SET, 0, MNULL, MNULL);
+ break; // leads to exit case
+ }
+#endif
+#ifdef STA_SUPPORT
+ if (GET_BSS_ROLE(pmpriv) == MLAN_BSS_ROLE_STA) {
+ /* Check previous state to find former Ad-hoc creator
+ interface. Set new state to Starting, so it'll be seen as a
+ DFS master. */
+ if (pmpriv->adhoc_state_prev == ADHOC_STARTED) {
+ pmpriv->adhoc_state = ADHOC_STARTING;
+ pmpriv->adhoc_state_prev = ADHOC_IDLE;
+ }
+ if (wlan_11h_is_dfs_master(pmpriv)) {
+ /* set new adhoc channel here */
+ pmpriv->adhoc_channel = pstate_rdh->new_channel;
+ if (wlan_11h_radar_detect_required(pmpriv,
+ pstate_rdh->
+ new_channel)) {
+ /* Radar detection is required for this channel, make
+ sure 11h is activated in the firmware */
+ ret = wlan_11h_activate(pmpriv, MNULL, MTRUE);
+ ret = wlan_11h_config_master_radar_det(pmpriv, MTRUE);
+ ret = wlan_11h_check_update_radar_det_state(pmpriv);
+ }
+ ret =
+ wlan_prepare_cmd(pmpriv,
+ HostCmd_CMD_802_11_AD_HOC_START,
+ HostCmd_ACT_GEN_SET, 0, MNULL,
+ &pmpriv->adhoc_last_start_ssid);
+ break; // leads to exit case
+ }
+
+ /* NOTE: DON'T reconnect slave STA intfs - infra/adhoc_joiner
+ Do we want to return to same AP/network (on radar channel)?
+ If want to connect back, depend on either: 1. driver's
+ reassoc thread 2. wpa_supplicant, or other user-space app */
+ }
+#endif
+ }
+
+ if (pstate_rdh->priv_curr_idx < pstate_rdh->priv_list_count)
+ break; // EXIT CASE (for UAP)
+ // else
+ pstate_rdh->priv_curr_idx = RDH_STAGE_FIRST_ENTRY_PRIV_IDX;
+ pstate_rdh->stage = RDH_RESTART_TRAFFIC;
+ // FALL THROUGH TO NEXT STAGE
+
+ case RDH_RESTART_TRAFFIC:
+#ifdef DFS_TESTING_SUPPORT
+ rdh_restart_traffic:
+#endif
+ PRINTM(MCMD_D, "%s(): stage(%d)=%s\n",
+ __FUNCTION__, pstate_rdh->stage,
+ RDH_stage_str[pstate_rdh->stage]);
+
+ /* continue traffic for reactivated interfaces */
+ PRINTM(MMSG, "11h: Radar Detected - restarting host tx traffic.\n");
+ for (i = 0; i < pstate_rdh->priv_list_count; i++) {
+ wlan_11h_tx_enable(pstate_rdh->priv_list[i]);
+ }
+
+ pstate_rdh->stage = RDH_OFF; /* DONE! */
+ PRINTM(MCMD_D, "%s(): finished - stage(%d)=%s\n",
+ __FUNCTION__, pstate_rdh->stage,
+ RDH_stage_str[pstate_rdh->stage]);
+ break;
+
+ default:
+ pstate_rdh->stage = RDH_OFF; /* cancel RDH to unblock Tx packets */
+ break;
+ }
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief DFS Event Preprocessing.
+ * Operates directly on pmadapter variables.
+ *
+ * 1. EVENT_RADAR_DETECTED comes from firmware without specific
+ * bss_num/bss_type. Find it an appropriate interface and
+ * update event_cause field in event_buf.
+ *
+ * @param pmadapter Pointer to mlan_adapter
+ *
+ * @return MLAN_STATUS_SUCCESS (update successful)
+ * or MLAN_STATUS_FAILURE (no change)
+ */
+mlan_status
+wlan_11h_dfs_event_preprocessing(mlan_adapter * pmadapter)
+{
+ mlan_status ret = MLAN_STATUS_FAILURE;
+ mlan_private *pmpriv = MNULL;
+ mlan_private *priv_list[MLAN_MAX_BSS_NUM];
+
+ ENTER();
+ switch (pmadapter->event_cause & EVENT_ID_MASK) {
+ case EVENT_RADAR_DETECTED:
+ /* find active intf: prefer dfs_master over dfs_slave */
+ if (wlan_get_privs_by_two_cond(pmadapter,
+ wlan_11h_is_master_active_on_dfs_chan,
+ wlan_11h_is_dfs_master,
+ MTRUE, priv_list)) {
+ pmpriv = priv_list[0];
+ PRINTM(MINFO, "%s: found dfs_master priv=%p\n",
+ __FUNCTION__, pmpriv);
+ } else if (wlan_get_privs_by_two_cond(pmadapter,
+ wlan_11h_is_slave_active_on_dfs_chan,
+ wlan_11h_is_dfs_slave,
+ MTRUE, priv_list)) {
+ pmpriv = priv_list[0];
+ PRINTM(MINFO, "%s: found dfs_slave priv=%p\n",
+ __FUNCTION__, pmpriv);
+ }
+
+ /* update event_cause if we found an appropriate priv */
+ if (pmpriv) {
+ pmlan_buffer pmevbuf = pmadapter->pmlan_buffer_event;
+ t_u32 new_event_cause = pmadapter->event_cause & EVENT_ID_MASK;
+ new_event_cause |= ((GET_BSS_NUM(pmpriv) & 0xff) << 16) |
+ ((pmpriv->bss_type & 0xff) << 24);
+ PRINTM(MINFO, "%s: priv - bss_num=%d, bss_type=%d\n",
+ __FUNCTION__, GET_BSS_NUM(pmpriv), pmpriv->bss_type);
+ memcpy(pmadapter, pmevbuf->pbuf + pmevbuf->data_offset,
+ &new_event_cause, sizeof(new_event_cause));
+ ret = MLAN_STATUS_SUCCESS;
+ }
+ break;
+ }
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief try to switch to a non-dfs channel
+ *
+ * @param priv Void pointer to mlan_private
+ *
+ * @param chan pointer to channel
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE or MLAN_STATUS_PENDING
+ */
+mlan_status
+wlan_11h_switch_non_dfs_chan(mlan_private * priv, t_u8 * chan)
+{
+ mlan_status ret = MLAN_STATUS_FAILURE;
+ t_u32 i;
+ t_u32 rand_entry;
+ t_u8 def_chan;
+ t_u8 rand_tries = 0;
+ region_chan_t *chn_tbl = MNULL;
+ pmlan_adapter pmadapter = priv->adapter;
+
+ ENTER();
+
+ /* get the channel table first */
+ for (i = 0; i < MAX_REGION_CHANNEL_NUM; i++) {
+ if (pmadapter->region_channel[i].band == BAND_A
+ && pmadapter->region_channel[i].valid) {
+ chn_tbl = &pmadapter->region_channel[i];
+ break;
+ }
+ }
+
+ if (!chn_tbl || !chn_tbl->pcfp) {
+ goto done;
+ }
+
+ do {
+ rand_entry = wlan_11h_get_random_num(pmadapter) % chn_tbl->num_cfp;
+ def_chan = (t_u8) chn_tbl->pcfp[rand_entry].channel;
+ rand_tries++;
+ } while ((wlan_11h_is_channel_under_nop(pmadapter, def_chan) ||
+ chn_tbl->pcfp[rand_entry].radar_detect == MTRUE) &&
+ (rand_tries < MAX_SWITCH_CHANNEL_RETRIES));
+
+ /* meet max retries, use the lowest non-dfs channel */
+ if (rand_tries == MAX_SWITCH_CHANNEL_RETRIES) {
+ for (i = 0; i < chn_tbl->num_cfp; i++) {
+ if (chn_tbl->pcfp[i].radar_detect == MFALSE &&
+ !wlan_11h_is_channel_under_nop(pmadapter,
+ (t_u8) chn_tbl->pcfp[i].
+ channel)) {
+ def_chan = (t_u8) chn_tbl->pcfp[i].channel;
+ break;
+ }
+ }
+ if (i == chn_tbl->num_cfp) {
+ goto done;
+ }
+ }
+
+ *chan = def_chan;
+ ret = MLAN_STATUS_SUCCESS;
+ done:
+ LEAVE();
+ return ret;
+}
diff --git a/drivers/net/wireless/sd8797/mlan/mlan_11h.h b/drivers/net/wireless/sd8797/mlan/mlan_11h.h
new file mode 100644
index 000000000000..cfa7fb915b39
--- /dev/null
+++ b/drivers/net/wireless/sd8797/mlan/mlan_11h.h
@@ -0,0 +1,158 @@
+/** @file mlan_11h.h
+ *
+ * @brief This header file contains data structures and
+ * function declarations of 802.11h
+ *
+ * Copyright (C) 2008-2011, Marvell International Ltd.
+ *
+ * This software file (the "File") is distributed by Marvell International
+ * Ltd. under the terms of the GNU General Public License Version 2, June 1991
+ * (the "License"). You may use, redistribute and/or modify this File in
+ * accordance with the terms and conditions of the License, a copy of which
+ * is available by writing to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
+ * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
+ *
+ * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
+ * ARE EXPRESSLY DISCLAIMED. The License provides additional details about
+ * this warranty disclaimer.
+ *
+ */
+
+/*************************************************************
+Change Log:
+ 03/26/2009: initial creation
+*************************************************************/
+
+#ifndef _MLAN_11H_
+#define _MLAN_11H_
+
+/** 11H OID bitmasks */
+#define ENABLE_11H_MASK MBIT(0)
+#define MASTER_RADAR_DET_MASK MBIT(1)
+#define SLAVE_RADAR_DET_MASK MBIT(2)
+
+/** DFS Master Radar Detect global enable */
+#define DFS_MASTER_RADAR_DETECT_EN (MTRUE)
+/** DFS Slave Radar Detect global enable */
+#define DFS_SLAVE_RADAR_DETECT_EN (MFALSE)
+
+/**
+ * 11H APIs
+ */
+
+/* Is master radar detection enabled in firmware? */
+extern t_bool wlan_11h_is_master_radar_det_active(mlan_private * priv);
+
+/** Configure master radar detection. Need call wlan_11h_check_update_radar_det_state() after. */
+extern mlan_status wlan_11h_config_master_radar_det(mlan_private * priv,
+ t_bool enable);
+
+/** Configure slave radar detection. Need call wlan_11h_check_update_radar_det_state() after. */
+extern mlan_status wlan_11h_config_slave_radar_det(mlan_private * priv,
+ t_bool enable);
+
+/** Checks all interfaces and updates radar detect flags if necessary */
+extern mlan_status wlan_11h_check_update_radar_det_state(mlan_private * pmpriv);
+
+/** Return 1 if 11h is active in the firmware, 0 if it is inactive */
+extern t_bool wlan_11h_is_active(mlan_private * priv);
+
+/** Enable the tx interface and record the new transmit state */
+extern void wlan_11h_tx_enable(mlan_private * priv);
+
+/** Disable the tx interface and record the new transmit state */
+extern void wlan_11h_tx_disable(mlan_private * priv);
+
+/** Activate 11h extensions in the firmware */
+extern mlan_status wlan_11h_activate(mlan_private * priv, t_void * pioctl_buf,
+ t_bool flag);
+
+/** Initialize the 11h device structure */
+extern void wlan_11h_init(mlan_adapter * pmadapter);
+
+/** Cleanup for the 11h device structure */
+extern void wlan_11h_cleanup(mlan_adapter * pmadapter);
+
+/** Initialize the 11h interface structure */
+extern void wlan_11h_priv_init(mlan_private * pmpriv);
+
+/** Get an initial random channel to start an adhoc network on */
+extern t_u8 wlan_11h_get_adhoc_start_channel(mlan_private * priv);
+
+/** Check if radar detection is required on the specified channel */
+extern t_bool wlan_11h_radar_detect_required(mlan_private * priv, t_u8 channel);
+
+/** Perform a standard availibility check on the specified channel */
+extern t_s32 wlan_11h_issue_radar_detect(mlan_private * priv,
+ pmlan_ioctl_req pioctl_req,
+ t_u8 channel);
+
+/** Check previously issued radar report for a channel */
+extern mlan_status wlan_11h_check_chan_report(mlan_private * priv, t_u8 chan);
+
+/** Add any 11h TLVs necessary to complete an adhoc start command */
+extern t_s32 wlan_11h_process_start(mlan_private * priv,
+ t_u8 ** ppbuffer,
+ IEEEtypes_CapInfo_t * pcap_info,
+ t_u32 channel,
+ wlan_11h_bss_info_t * p11h_bss_info);
+
+/** Add any 11h TLVs necessary to complete a join command (adhoc or infra) */
+extern t_s32 wlan_11h_process_join(mlan_private * priv,
+ t_u8 ** ppbuffer,
+ IEEEtypes_CapInfo_t * pcap_info,
+ t_u8 band,
+ t_u32 channel,
+ wlan_11h_bss_info_t * p11h_bss_info);
+
+/** Complete the firmware command preparation for an 11h command function */
+extern mlan_status wlan_11h_cmd_process(mlan_private * priv,
+ HostCmd_DS_COMMAND * pcmd_ptr,
+ const t_void * pinfo_buf);
+
+/** Process the response of an 11h firmware command */
+extern mlan_status wlan_11h_cmdresp_process(mlan_private * priv,
+ const HostCmd_DS_COMMAND * resp);
+
+/** Receive IEs from scan processing and record any needed info for 11h */
+extern mlan_status wlan_11h_process_bss_elem(mlan_adapter * pmadapter,
+ wlan_11h_bss_info_t *
+ p11h_bss_info,
+ const t_u8 * pelement);
+
+/** Handler for EVENT_CHANNEL_SWITCH_ANN */
+extern mlan_status wlan_11h_handle_event_chanswann(mlan_private * priv);
+
+/** Handler for EVENT_CHANNEL_REPORT_RDY */
+extern mlan_status wlan_11h_handle_event_chanrpt_ready(mlan_private * priv,
+ mlan_event * pevent);
+
+#ifdef DFS_TESTING_SUPPORT
+/** Handler for DFS_TESTING IOCTL */
+extern mlan_status wlan_11h_ioctl_dfs_testing(pmlan_adapter pmadapter,
+ pmlan_ioctl_req pioctl_req);
+#endif
+
+/** Check if channel is under a NOP duration (should not be used) */
+extern t_bool wlan_11h_is_channel_under_nop(mlan_adapter * pmadapter,
+ t_u8 channel);
+
+/** Check if RADAR_DETECTED handling is blocking data tx */
+extern t_bool wlan_11h_radar_detected_tx_blocked(mlan_adapter * pmadapter);
+
+/** Callback for RADAR_DETECTED (for UAP cmdresp) */
+extern mlan_status wlan_11h_radar_detected_callback(t_void * priv);
+
+/** Handler for RADAR_DETECTED */
+extern mlan_status wlan_11h_radar_detected_handling(mlan_adapter * pmadapter);
+
+/** DFS Event pre-processing */
+extern mlan_status wlan_11h_dfs_event_preprocessing(mlan_adapter * pmadapter);
+
+/** DFS switch to non-DFS channel */
+extern mlan_status wlan_11h_switch_non_dfs_chan(mlan_private * priv,
+ t_u8 * chan);
+
+#endif /*_MLAN_11H_ */
diff --git a/drivers/net/wireless/sd8797/mlan/mlan_11n.c b/drivers/net/wireless/sd8797/mlan/mlan_11n.c
new file mode 100644
index 000000000000..d55c2e7e4ab3
--- /dev/null
+++ b/drivers/net/wireless/sd8797/mlan/mlan_11n.c
@@ -0,0 +1,1937 @@
+/** @file mlan_11n.c
+ *
+ * @brief This file contains functions for 11n handling.
+ *
+ * Copyright (C) 2008-2011, Marvell International Ltd.
+ *
+ * This software file (the "File") is distributed by Marvell International
+ * Ltd. under the terms of the GNU General Public License Version 2, June 1991
+ * (the "License"). You may use, redistribute and/or modify this File in
+ * accordance with the terms and conditions of the License, a copy of which
+ * is available by writing to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
+ * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
+ *
+ * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
+ * ARE EXPRESSLY DISCLAIMED. The License provides additional details about
+ * this warranty disclaimer.
+ *
+ */
+
+/********************************************************
+Change log:
+ 11/10/2008: initial version
+********************************************************/
+
+#include "mlan.h"
+#include "mlan_join.h"
+#include "mlan_util.h"
+#include "mlan_fw.h"
+#include "mlan_main.h"
+#include "mlan_wmm.h"
+#include "mlan_11n.h"
+
+/********************************************************
+ Local Variables
+********************************************************/
+
+/********************************************************
+ Global Variables
+********************************************************/
+
+/********************************************************
+ Local Functions
+********************************************************/
+
+/**
+ *
+ * @brief set/get max tx buf size
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static mlan_status
+wlan_11n_ioctl_max_tx_buf_size(IN pmlan_adapter pmadapter,
+ IN pmlan_ioctl_req pioctl_req)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_ds_11n_cfg *cfg = MNULL;
+
+ ENTER();
+
+ cfg = (mlan_ds_11n_cfg *) pioctl_req->pbuf;
+ cfg->param.tx_buf_size = (t_u32) pmadapter->max_tx_buf_size;
+ pioctl_req->data_read_written = sizeof(t_u32) + MLAN_SUB_COMMAND_SIZE;
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set/get htcapinfo configuration
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static mlan_status
+wlan_11n_ioctl_htusrcfg(IN pmlan_adapter pmadapter,
+ IN pmlan_ioctl_req pioctl_req)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
+ mlan_ds_11n_cfg *cfg = MNULL;
+
+ ENTER();
+
+ cfg = (mlan_ds_11n_cfg *) pioctl_req->pbuf;
+
+ if (pioctl_req->action == MLAN_ACT_SET) {
+ if (((cfg->param.htcap_cfg.htcap & ~IGN_HW_DEV_CAP) &
+ pmpriv->adapter->hw_dot_11n_dev_cap)
+ != (cfg->param.htcap_cfg.htcap & ~IGN_HW_DEV_CAP)) {
+ pioctl_req->status_code = MLAN_ERROR_INVALID_PARAMETER;
+ ret = MLAN_STATUS_FAILURE;
+ } else {
+ if (cfg->param.htcap_cfg.misc_cfg == BAND_SELECT_BG) {
+ pmadapter->usr_dot_11n_dev_cap_bg = cfg->param.htcap_cfg.htcap;
+ PRINTM(MINFO, "Set: UsrDot11nCap for 2.4GHz 0x%x\n",
+ pmadapter->usr_dot_11n_dev_cap_bg);
+ }
+ if (cfg->param.htcap_cfg.misc_cfg == BAND_SELECT_A) {
+ pmadapter->usr_dot_11n_dev_cap_a = cfg->param.htcap_cfg.htcap;
+ PRINTM(MINFO, "Set: UsrDot11nCap for 5GHz 0x%x\n",
+ pmadapter->usr_dot_11n_dev_cap_a);
+ }
+ if (cfg->param.htcap_cfg.misc_cfg == BAND_SELECT_BOTH) {
+ pmadapter->usr_dot_11n_dev_cap_bg = cfg->param.htcap_cfg.htcap;
+ pmadapter->usr_dot_11n_dev_cap_a = cfg->param.htcap_cfg.htcap;
+ PRINTM(MINFO, "Set: UsrDot11nCap for 2.4GHz and 5GHz 0x%x\n",
+ cfg->param.htcap_cfg.htcap);
+ }
+ }
+ } else {
+ /* Hardware 11N device capability required */
+ if (cfg->param.htcap_cfg.hw_cap_req)
+ cfg->param.htcap_cfg.htcap = pmadapter->hw_dot_11n_dev_cap;
+ else {
+ if (cfg->param.htcap_cfg.misc_cfg == BAND_SELECT_BG) {
+ cfg->param.htcap_cfg.htcap = pmadapter->usr_dot_11n_dev_cap_bg;
+ PRINTM(MINFO, "Get: UsrDot11nCap for 2.4GHz 0x%x\n",
+ cfg->param.htcap_cfg.htcap);
+ }
+ if (cfg->param.htcap_cfg.misc_cfg == BAND_SELECT_A) {
+ cfg->param.htcap_cfg.htcap = pmadapter->usr_dot_11n_dev_cap_a;
+ PRINTM(MINFO, "Get: UsrDot11nCap for 5GHz 0x%x\n",
+ cfg->param.htcap_cfg.htcap);
+ }
+ }
+ }
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Enable/Disable AMSDU AGGR CTRL
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_PENDING --success, otherwise fail
+ */
+static mlan_status
+wlan_11n_ioctl_amsdu_aggr_ctrl(IN pmlan_adapter pmadapter,
+ IN pmlan_ioctl_req pioctl_req)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
+ mlan_ds_11n_cfg *cfg = MNULL;
+ t_u16 cmd_action = 0;
+
+ ENTER();
+
+ cfg = (mlan_ds_11n_cfg *) pioctl_req->pbuf;
+ if (pioctl_req->action == MLAN_ACT_SET)
+ cmd_action = HostCmd_ACT_GEN_SET;
+ else
+ cmd_action = HostCmd_ACT_GEN_GET;
+
+ /* Send request to firmware */
+ ret = wlan_prepare_cmd(pmpriv,
+ HostCmd_CMD_AMSDU_AGGR_CTRL,
+ cmd_action,
+ 0,
+ (t_void *) pioctl_req,
+ (t_void *) & cfg->param.amsdu_aggr_ctrl);
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set/get 11n configuration
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_PENDING --success, otherwise fail
+ */
+static mlan_status
+wlan_11n_ioctl_httxcfg(IN pmlan_adapter pmadapter,
+ IN pmlan_ioctl_req pioctl_req)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
+ mlan_ds_11n_cfg *cfg = MNULL;
+ t_u16 cmd_action = 0;
+
+ ENTER();
+
+ cfg = (mlan_ds_11n_cfg *) pioctl_req->pbuf;
+ if (pioctl_req->action == MLAN_ACT_SET)
+ cmd_action = HostCmd_ACT_GEN_SET;
+ else
+ cmd_action = HostCmd_ACT_GEN_GET;
+
+ /* Send request to firmware */
+ ret = wlan_prepare_cmd(pmpriv,
+ HostCmd_CMD_11N_CFG,
+ cmd_action,
+ 0,
+ (t_void *) pioctl_req,
+ (t_void *) & cfg->param.tx_cfg);
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set/get TX beamforming capabilities
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_SUCCESS --success
+ */
+static mlan_status
+wlan_11n_ioctl_tx_bf_cap(IN pmlan_adapter pmadapter,
+ IN pmlan_ioctl_req pioctl_req)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
+ mlan_ds_11n_cfg *cfg = MNULL;
+
+ ENTER();
+
+ cfg = (mlan_ds_11n_cfg *) pioctl_req->pbuf;
+ if (pioctl_req->action == MLAN_ACT_SET)
+ pmpriv->tx_bf_cap = cfg->param.tx_bf_cap;
+ else
+ cfg->param.tx_bf_cap = pmpriv->tx_bf_cap;
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set/get TX beamforming configurations
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_PENDING --success, otherwise fail
+ */
+static mlan_status
+wlan_11n_ioctl_tx_bf_cfg(IN pmlan_adapter pmadapter,
+ IN pmlan_ioctl_req pioctl_req)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
+ mlan_ds_11n_cfg *cfg = MNULL;
+ t_u16 cmd_action = 0;
+
+ ENTER();
+
+ cfg = (mlan_ds_11n_cfg *) pioctl_req->pbuf;
+ if (pioctl_req->action == MLAN_ACT_SET)
+ cmd_action = HostCmd_ACT_GEN_SET;
+ else
+ cmd_action = HostCmd_ACT_GEN_GET;
+
+ /* Send request to firmware */
+ ret = wlan_prepare_cmd(pmpriv,
+ HostCmd_CMD_TX_BF_CFG,
+ cmd_action,
+ 0,
+ (t_void *) pioctl_req,
+ (t_void *) & cfg->param.tx_bf);
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set/get HT stream configurations
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static mlan_status
+wlan_11n_ioctl_stream_cfg(IN pmlan_adapter pmadapter,
+ IN pmlan_ioctl_req pioctl_req)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_ds_11n_cfg *cfg = MNULL;
+
+ ENTER();
+
+ cfg = (mlan_ds_11n_cfg *) pioctl_req->pbuf;
+ if (pioctl_req->action == MLAN_ACT_GET) {
+ cfg->param.stream_cfg = pmadapter->usr_dev_mcs_support;
+ } else if (pioctl_req->action == MLAN_ACT_SET) {
+ switch (cfg->param.stream_cfg) {
+ case HT_STREAM_MODE_2X2:
+ if (pmadapter->hw_dev_mcs_support == HT_STREAM_MODE_1X1) {
+ PRINTM(MERROR, "HW does not support this mode\n");
+ ret = MLAN_STATUS_FAILURE;
+ } else
+ pmadapter->usr_dev_mcs_support = cfg->param.stream_cfg;
+ break;
+ case HT_STREAM_MODE_1X1:
+ pmadapter->usr_dev_mcs_support = cfg->param.stream_cfg;
+ break;
+ default:
+ PRINTM(MERROR, "Invalid stream mode\n");
+ pioctl_req->status_code = MLAN_ERROR_INVALID_PARAMETER;
+ ret = MLAN_STATUS_FAILURE;
+ break;
+ }
+ }
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function will resend addba request to all
+ * the peer in the TxBAStreamTbl
+ *
+ * @param priv A pointer to mlan_private
+ *
+ * @return N/A
+ */
+static void
+wlan_11n_update_addba_request(mlan_private * priv)
+{
+
+ TxBAStreamTbl *ptx_tbl;
+
+ ENTER();
+
+ if (!
+ (ptx_tbl =
+ (TxBAStreamTbl *) util_peek_list(priv->adapter->pmoal_handle,
+ &priv->tx_ba_stream_tbl_ptr,
+ priv->adapter->callbacks.
+ moal_spin_lock,
+ priv->adapter->callbacks.
+ moal_spin_unlock))) {
+ LEAVE();
+ return;
+ }
+
+ while (ptx_tbl != (TxBAStreamTbl *) & priv->tx_ba_stream_tbl_ptr) {
+ wlan_send_addba(priv, ptx_tbl->tid, ptx_tbl->ra);
+ ptx_tbl = ptx_tbl->pnext;
+ }
+ /* Signal MOAL to trigger mlan_main_process */
+ wlan_recv_event(priv, MLAN_EVENT_ID_DRV_DEFER_HANDLING, MNULL);
+ LEAVE();
+ return;
+}
+
+/**
+ * @brief Set/get addba parameter
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_SUCCESS --success
+ */
+static mlan_status
+wlan_11n_ioctl_addba_param(IN pmlan_adapter pmadapter,
+ IN pmlan_ioctl_req pioctl_req)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
+ mlan_ds_11n_cfg *cfg = MNULL;
+ t_u32 timeout;
+
+ ENTER();
+
+ cfg = (mlan_ds_11n_cfg *) pioctl_req->pbuf;
+ if (pioctl_req->action == MLAN_ACT_GET) {
+ cfg->param.addba_param.timeout = pmpriv->add_ba_param.timeout;
+ cfg->param.addba_param.txwinsize = pmpriv->add_ba_param.tx_win_size;
+ cfg->param.addba_param.rxwinsize = pmpriv->add_ba_param.rx_win_size;
+ cfg->param.addba_param.txamsdu = pmpriv->add_ba_param.tx_amsdu;
+ cfg->param.addba_param.rxamsdu = pmpriv->add_ba_param.rx_amsdu;
+ } else {
+ timeout = pmpriv->add_ba_param.timeout;
+ pmpriv->add_ba_param.timeout = cfg->param.addba_param.timeout;
+ pmpriv->add_ba_param.tx_win_size = cfg->param.addba_param.txwinsize;
+ pmpriv->add_ba_param.rx_win_size = cfg->param.addba_param.rxwinsize;
+ pmpriv->add_ba_param.tx_amsdu = cfg->param.addba_param.txamsdu;
+ pmpriv->add_ba_param.rx_amsdu = cfg->param.addba_param.rxamsdu;
+ if (timeout != pmpriv->add_ba_param.timeout) {
+ wlan_11n_update_addba_request(pmpriv);
+ }
+ }
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set/get addba reject set
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static mlan_status
+wlan_11n_ioctl_addba_reject(IN pmlan_adapter pmadapter,
+ IN pmlan_ioctl_req pioctl_req)
+{
+ int i = 0;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
+ mlan_ds_11n_cfg *cfg = MNULL;
+
+ ENTER();
+
+ cfg = (mlan_ds_11n_cfg *) pioctl_req->pbuf;
+
+ if (pioctl_req->action == MLAN_ACT_GET) {
+ PRINTM(MINFO, "Get Addba reject\n");
+ memcpy(pmadapter, cfg->param.addba_reject, pmpriv->addba_reject,
+ MAX_NUM_TID);
+ } else {
+ if (pmpriv->media_connected == MTRUE) {
+ PRINTM(MERROR, "Can not set aggr priority table in connected"
+ " state\n");
+ pioctl_req->status_code = MLAN_ERROR_IOCTL_INVALID;
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+
+ for (i = 0; i < MAX_NUM_TID; i++) {
+ /* For AMPDU */
+ if (cfg->param.addba_reject[i] > ADDBA_RSP_STATUS_REJECT) {
+ pioctl_req->status_code = MLAN_ERROR_INVALID_PARAMETER;
+ ret = MLAN_STATUS_FAILURE;
+ break;
+ }
+
+ pmpriv->addba_reject[i] = cfg->param.addba_reject[i];
+ }
+ }
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set/get aggr_prio_tbl
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static mlan_status
+wlan_11n_ioctl_aggr_prio_tbl(IN pmlan_adapter pmadapter,
+ IN pmlan_ioctl_req pioctl_req)
+{
+ int i = 0;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
+ mlan_ds_11n_cfg *cfg = MNULL;
+
+ ENTER();
+
+ cfg = (mlan_ds_11n_cfg *) pioctl_req->pbuf;
+
+ if (pioctl_req->action == MLAN_ACT_GET) {
+ for (i = 0; i < MAX_NUM_TID; i++) {
+ cfg->param.aggr_prio_tbl.ampdu[i] =
+ pmpriv->aggr_prio_tbl[i].ampdu_user;
+ cfg->param.aggr_prio_tbl.amsdu[i] = pmpriv->aggr_prio_tbl[i].amsdu;
+ }
+ } else {
+ if (pmpriv->media_connected == MTRUE) {
+ PRINTM(MERROR, "Can not set aggr priority table in connected"
+ " state\n");
+ pioctl_req->status_code = MLAN_ERROR_IOCTL_INVALID;
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+
+ for (i = 0; i < MAX_NUM_TID; i++) {
+ /* For AMPDU */
+ if ((cfg->param.aggr_prio_tbl.ampdu[i] > HIGH_PRIO_TID) &&
+ (cfg->param.aggr_prio_tbl.ampdu[i] != BA_STREAM_NOT_ALLOWED)) {
+ pioctl_req->status_code = MLAN_ERROR_INVALID_PARAMETER;
+ ret = MLAN_STATUS_FAILURE;
+ break;
+ }
+
+ pmpriv->aggr_prio_tbl[i].ampdu_ap =
+ pmpriv->aggr_prio_tbl[i].ampdu_user =
+ cfg->param.aggr_prio_tbl.ampdu[i];
+
+ /* For AMSDU */
+ if ((cfg->param.aggr_prio_tbl.amsdu[i] > HIGH_PRIO_TID &&
+ cfg->param.aggr_prio_tbl.amsdu[i] != BA_STREAM_NOT_ALLOWED)) {
+ pioctl_req->status_code = MLAN_ERROR_INVALID_PARAMETER;
+ ret = MLAN_STATUS_FAILURE;
+ break;
+ } else {
+ pmpriv->aggr_prio_tbl[i].amsdu =
+ cfg->param.aggr_prio_tbl.amsdu[i];
+ }
+ }
+ }
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Get supported MCS set
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static mlan_status
+wlan_11n_ioctl_supported_mcs_set(IN pmlan_adapter pmadapter,
+ IN pmlan_ioctl_req pioctl_req)
+{
+ mlan_ds_11n_cfg *cfg = MNULL;
+ int rx_mcs_supp;
+ t_u8 mcs_set[NUM_MCS_FIELD];
+
+ ENTER();
+
+ if (pioctl_req->action == MLAN_ACT_SET) {
+ PRINTM(MERROR, "Set operation is not supported\n");
+ pioctl_req->status_code = MLAN_ERROR_IOCTL_INVALID;
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+ rx_mcs_supp = GET_RXMCSSUPP(pmadapter->usr_dev_mcs_support);
+ /* Set MCS for 1x1/2x2 */
+ memset(pmadapter, (t_u8 *) mcs_set, 0xff, rx_mcs_supp);
+ /* Clear all the other values */
+ memset(pmadapter, (t_u8 *) & mcs_set[rx_mcs_supp], 0,
+ NUM_MCS_FIELD - rx_mcs_supp);
+ /* Set MCS32 with 40MHz support */
+ if (ISSUPP_CHANWIDTH40(pmadapter->usr_dot_11n_dev_cap_bg)
+ || ISSUPP_CHANWIDTH40(pmadapter->usr_dot_11n_dev_cap_a)
+ )
+ SETHT_MCS32(mcs_set);
+
+ cfg = (mlan_ds_11n_cfg *) pioctl_req->pbuf;
+ memcpy(pmadapter, cfg->param.supported_mcs_set, mcs_set, NUM_MCS_FIELD);
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function checks if the given pointer is valid entry of
+ * Tx BA Stream table
+ *
+ * @param priv Pointer to mlan_private
+ * @param ptxtblptr Pointer to tx ba stream entry
+ *
+ * @return MTRUE or MFALSE
+ */
+static int
+wlan_is_txbastreamptr_valid(mlan_private * priv, TxBAStreamTbl * ptxtblptr)
+{
+ TxBAStreamTbl *ptx_tbl;
+
+ ENTER();
+
+ if (!
+ (ptx_tbl =
+ (TxBAStreamTbl *) util_peek_list(priv->adapter->pmoal_handle,
+ &priv->tx_ba_stream_tbl_ptr, MNULL,
+ MNULL))) {
+ LEAVE();
+ return MFALSE;
+ }
+
+ while (ptx_tbl != (TxBAStreamTbl *) & priv->tx_ba_stream_tbl_ptr) {
+ if (ptx_tbl == ptxtblptr) {
+ LEAVE();
+ return MTRUE;
+ }
+
+ ptx_tbl = ptx_tbl->pnext;
+ }
+
+ LEAVE();
+ return MFALSE;
+}
+
+/**
+ * @brief This function will return the pointer to a entry in BA Stream
+ * table which matches the ba_status requested
+ *
+ * @param priv A pointer to mlan_private
+ * @param ba_status Current status of the BA stream
+ *
+ * @return A pointer to first entry matching status in BA stream
+ * NULL if not found
+ */
+static TxBAStreamTbl *
+wlan_11n_get_txbastream_status(mlan_private * priv, baStatus_e ba_status)
+{
+ TxBAStreamTbl *ptx_tbl;
+
+ ENTER();
+
+ if (!
+ (ptx_tbl =
+ (TxBAStreamTbl *) util_peek_list(priv->adapter->pmoal_handle,
+ &priv->tx_ba_stream_tbl_ptr,
+ priv->adapter->callbacks.
+ moal_spin_lock,
+ priv->adapter->callbacks.
+ moal_spin_unlock))) {
+ LEAVE();
+ return MNULL;
+ }
+
+ while (ptx_tbl != (TxBAStreamTbl *) & priv->tx_ba_stream_tbl_ptr) {
+ if (ptx_tbl->ba_status == ba_status) {
+ LEAVE();
+ return ptx_tbl;
+ }
+
+ ptx_tbl = ptx_tbl->pnext;
+ }
+
+ LEAVE();
+ return MNULL;
+}
+
+/********************************************************
+ Global Functions
+********************************************************/
+
+#ifdef STA_SUPPORT
+/**
+ * @brief This function fills the cap info
+ *
+ * @param priv A pointer to mlan_private structure
+ * @param pht_cap A pointer to MrvlIETypes_HTCap_t structure
+ * @param bands Band configuration
+ *
+ * @return N/A
+ */
+static void
+wlan_fill_cap_info(mlan_private * priv,
+ MrvlIETypes_HTCap_t * pht_cap, t_u8 bands)
+{
+ mlan_adapter *pmadapter = priv->adapter;
+ t_u32 usr_dot_11n_dev_cap;
+
+ ENTER();
+
+ if (bands & BAND_A)
+ usr_dot_11n_dev_cap = pmadapter->usr_dot_11n_dev_cap_a;
+ else
+ usr_dot_11n_dev_cap = pmadapter->usr_dot_11n_dev_cap_bg;
+
+ if (ISSUPP_CHANWIDTH40(usr_dot_11n_dev_cap))
+ SETHT_SUPPCHANWIDTH(pht_cap->ht_cap.ht_cap_info);
+ else
+ RESETHT_SUPPCHANWIDTH(pht_cap->ht_cap.ht_cap_info);
+
+ if (ISSUPP_GREENFIELD(usr_dot_11n_dev_cap))
+ SETHT_GREENFIELD(pht_cap->ht_cap.ht_cap_info);
+ else
+ RESETHT_GREENFIELD(pht_cap->ht_cap.ht_cap_info);
+
+ if (ISSUPP_SHORTGI20(usr_dot_11n_dev_cap))
+ SETHT_SHORTGI20(pht_cap->ht_cap.ht_cap_info);
+ else
+ RESETHT_SHORTGI20(pht_cap->ht_cap.ht_cap_info);
+
+ if (ISSUPP_SHORTGI40(usr_dot_11n_dev_cap))
+ SETHT_SHORTGI40(pht_cap->ht_cap.ht_cap_info);
+ else
+ RESETHT_SHORTGI40(pht_cap->ht_cap.ht_cap_info);
+
+ if (ISSUPP_RXSTBC(usr_dot_11n_dev_cap))
+ SETHT_RXSTBC(pht_cap->ht_cap.ht_cap_info, 1);
+ else
+ RESETHT_RXSTBC(pht_cap->ht_cap.ht_cap_info);
+
+ if (ISENABLED_40MHZ_INTOLARENT(usr_dot_11n_dev_cap))
+ SETHT_40MHZ_INTOLARANT(pht_cap->ht_cap.ht_cap_info);
+ else
+ RESETHT_40MHZ_INTOLARANT(pht_cap->ht_cap.ht_cap_info);
+
+ /* No user config for LDPC coding capability yet */
+ if (ISSUPP_RXLDPC(pmadapter->hw_dot_11n_dev_cap))
+ SETHT_LDPCCODINGCAP(pht_cap->ht_cap.ht_cap_info);
+ else
+ RESETHT_LDPCCODINGCAP(pht_cap->ht_cap.ht_cap_info);
+
+ /* No user config for TX STBC yet */
+ if (ISSUPP_TXSTBC(pmadapter->hw_dot_11n_dev_cap))
+ SETHT_TXSTBC(pht_cap->ht_cap.ht_cap_info);
+ else
+ RESETHT_TXSTBC(pht_cap->ht_cap.ht_cap_info);
+
+ /* No user config for Delayed BACK yet */
+ if (GET_DELAYEDBACK(pmadapter->hw_dot_11n_dev_cap))
+ SETHT_DELAYEDBACK(pht_cap->ht_cap.ht_cap_info);
+ else
+ RESETHT_DELAYEDBACK(pht_cap->ht_cap.ht_cap_info);
+
+ /* Need change to support 8k AMSDU receive */
+ RESETHT_MAXAMSDU(pht_cap->ht_cap.ht_cap_info);
+
+ LEAVE();
+}
+
+/**
+ * @brief This function fills the HT cap tlv
+ *
+ * @param priv A pointer to mlan_private structure
+ * @param pht_cap A pointer to MrvlIETypes_HTCap_t structure
+ * @param bands Band configuration
+ *
+ * @return N/A
+ */
+void
+wlan_fill_ht_cap_tlv(mlan_private * priv,
+ MrvlIETypes_HTCap_t * pht_cap, t_u8 bands)
+{
+ mlan_adapter *pmadapter = priv->adapter;
+ int rx_mcs_supp;
+ t_u32 usr_dot_11n_dev_cap;
+
+ ENTER();
+
+ if (bands & BAND_A)
+ usr_dot_11n_dev_cap = pmadapter->usr_dot_11n_dev_cap_a;
+ else
+ usr_dot_11n_dev_cap = pmadapter->usr_dot_11n_dev_cap_bg;
+
+ /* Fill HT cap info */
+ wlan_fill_cap_info(priv, pht_cap, bands);
+ pht_cap->ht_cap.ht_cap_info = wlan_cpu_to_le16(pht_cap->ht_cap.ht_cap_info);
+
+ /* Set ampdu param */
+ SETAMPDU_SIZE(pht_cap->ht_cap.ampdu_param, AMPDU_FACTOR_64K);
+ SETAMPDU_SPACING(pht_cap->ht_cap.ampdu_param, 0);
+
+ rx_mcs_supp = GET_RXMCSSUPP(pmadapter->usr_dev_mcs_support);
+ /* Set MCS for 1x1/2x2 */
+ memset(pmadapter, (t_u8 *) pht_cap->ht_cap.supported_mcs_set, 0xff,
+ rx_mcs_supp);
+ /* Clear all the other values */
+ memset(pmadapter, (t_u8 *) & pht_cap->ht_cap.supported_mcs_set[rx_mcs_supp],
+ 0, NUM_MCS_FIELD - rx_mcs_supp);
+ /* Set MCS32 with 40MHz support */
+ if (ISSUPP_CHANWIDTH40(usr_dot_11n_dev_cap))
+ SETHT_MCS32(pht_cap->ht_cap.supported_mcs_set);
+
+ /* Clear RD responder bit */
+ RESETHT_EXTCAP_RDG(pht_cap->ht_cap.ht_ext_cap);
+ pht_cap->ht_cap.ht_ext_cap = wlan_cpu_to_le16(pht_cap->ht_cap.ht_ext_cap);
+
+ /* Set Tx BF cap */
+ pht_cap->ht_cap.tx_bf_cap = wlan_cpu_to_le32(priv->tx_bf_cap);
+
+ LEAVE();
+ return;
+}
+#endif /* STA_SUPPORT */
+
+/**
+ * @brief This function prints the 802.11n device capability
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param cap Capability value
+ *
+ * @return N/A
+ */
+void
+wlan_show_dot11ndevcap(pmlan_adapter pmadapter, t_u32 cap)
+{
+ ENTER();
+
+ PRINTM(MINFO, "GET_HW_SPEC: Maximum MSDU length = %s octets\n",
+ (ISSUPP_MAXAMSDU(cap) ? "7935" : "3839"));
+ PRINTM(MINFO, "GET_HW_SPEC: Beam forming %s\n",
+ (ISSUPP_BEAMFORMING(cap) ? "supported" : "not supported"));
+ PRINTM(MINFO, "GET_HW_SPEC: Greenfield preamble %s\n",
+ (ISSUPP_GREENFIELD(cap) ? "supported" : "not supported"));
+ PRINTM(MINFO, "GET_HW_SPEC: AMPDU %s\n",
+ (ISSUPP_AMPDU(cap) ? "supported" : "not supported"));
+ PRINTM(MINFO, "GET_HW_SPEC: MIMO Power Save %s\n",
+ (ISSUPP_MIMOPS(cap) ? "supported" : "not supported"));
+ PRINTM(MINFO, "GET_HW_SPEC: Rx STBC %s\n",
+ (ISSUPP_RXSTBC(cap) ? "supported" : "not supported"));
+ PRINTM(MINFO, "GET_HW_SPEC: Tx STBC %s\n",
+ (ISSUPP_TXSTBC(cap) ? "supported" : "not supported"));
+ PRINTM(MINFO, "GET_HW_SPEC: Short GI for 40 Mhz %s\n",
+ (ISSUPP_SHORTGI40(cap) ? "supported" : "not supported"));
+ PRINTM(MINFO, "GET_HW_SPEC: Short GI for 20 Mhz %s\n",
+ (ISSUPP_SHORTGI20(cap) ? "supported" : "not supported"));
+ PRINTM(MINFO, "GET_HW_SPEC: LDPC coded packet receive %s\n",
+ (ISSUPP_RXLDPC(cap) ? "supported" : "not supported"));
+ PRINTM(MINFO, "GET_HW_SPEC: Number of Delayed Block Ack streams = %d\n",
+ GET_DELAYEDBACK(cap));
+ PRINTM(MINFO, "GET_HW_SPEC: Number of Immediate Block Ack streams = %d\n",
+ GET_IMMEDIATEBACK(cap));
+ PRINTM(MINFO, "GET_HW_SPEC: 40 Mhz channel width %s\n",
+ (ISSUPP_CHANWIDTH40(cap) ? "supported" : "not supported"));
+ PRINTM(MINFO, "GET_HW_SPEC: 20 Mhz channel width %s\n",
+ (ISSUPP_CHANWIDTH20(cap) ? "supported" : "not supported"));
+ PRINTM(MINFO, "GET_HW_SPEC: 10 Mhz channel width %s\n",
+ (ISSUPP_CHANWIDTH10(cap) ? "supported" : "not supported"));
+
+ if (ISSUPP_RXANTENNAA(cap)) {
+ PRINTM(MINFO, "GET_HW_SPEC: Presence of Rx antenna A\n");
+ }
+ if (ISSUPP_RXANTENNAB(cap)) {
+ PRINTM(MINFO, "GET_HW_SPEC: Presence of Rx antenna B\n");
+ }
+ if (ISSUPP_RXANTENNAC(cap)) {
+ PRINTM(MINFO, "GET_HW_SPEC: Presence of Rx antenna C\n");
+ }
+ if (ISSUPP_RXANTENNAD(cap)) {
+ PRINTM(MINFO, "GET_HW_SPEC: Presence of Rx antenna D\n");
+ }
+ if (ISSUPP_TXANTENNAA(cap)) {
+ PRINTM(MINFO, "GET_HW_SPEC: Presence of Tx antenna A\n");
+ }
+ if (ISSUPP_TXANTENNAB(cap)) {
+ PRINTM(MINFO, "GET_HW_SPEC: Presence of Tx antenna B\n");
+ }
+ if (ISSUPP_TXANTENNAC(cap)) {
+ PRINTM(MINFO, "GET_HW_SPEC: Presence of Tx antenna C\n");
+ }
+ if (ISSUPP_TXANTENNAD(cap)) {
+ PRINTM(MINFO, "GET_HW_SPEC: Presence of Tx antenna D\n");
+ }
+
+ LEAVE();
+ return;
+}
+
+/**
+ * @brief This function prints the 802.11n device MCS
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param support Support value
+ *
+ * @return N/A
+ */
+void
+wlan_show_devmcssupport(pmlan_adapter pmadapter, t_u8 support)
+{
+ ENTER();
+
+ PRINTM(MINFO, "GET_HW_SPEC: MCSs for %dx%d MIMO\n", GET_RXMCSSUPP(support),
+ GET_TXMCSSUPP(support));
+
+ LEAVE();
+ return;
+}
+
+/**
+ * @brief This function handles the command response of
+ * delete a block ack request
+ *
+ * @param priv A pointer to mlan_private structure
+ * @param resp A pointer to HostCmd_DS_COMMAND
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+mlan_status
+wlan_ret_11n_delba(mlan_private * priv, HostCmd_DS_COMMAND * resp)
+{
+ int tid;
+ TxBAStreamTbl *ptx_ba_tbl;
+ HostCmd_DS_11N_DELBA *pdel_ba =
+ (HostCmd_DS_11N_DELBA *) & resp->params.del_ba;
+
+ ENTER();
+
+ pdel_ba->del_ba_param_set = wlan_le16_to_cpu(pdel_ba->del_ba_param_set);
+ pdel_ba->reason_code = wlan_le16_to_cpu(pdel_ba->reason_code);
+
+ tid = pdel_ba->del_ba_param_set >> DELBA_TID_POS;
+ if (pdel_ba->del_result == BA_RESULT_SUCCESS) {
+ mlan_11n_delete_bastream_tbl(priv, tid, pdel_ba->peer_mac_addr,
+ TYPE_DELBA_SENT,
+ INITIATOR_BIT(pdel_ba->del_ba_param_set));
+
+ if ((ptx_ba_tbl = wlan_11n_get_txbastream_status(priv,
+ BA_STREAM_SETUP_INPROGRESS)))
+ {
+ wlan_send_addba(priv, ptx_ba_tbl->tid, ptx_ba_tbl->ra);
+ }
+ } else { /*
+ * In case of failure, recreate the deleted stream in
+ * case we initiated the ADDBA
+ */
+ if (INITIATOR_BIT(pdel_ba->del_ba_param_set)) {
+ wlan_11n_create_txbastream_tbl(priv, pdel_ba->peer_mac_addr, tid,
+ BA_STREAM_SETUP_INPROGRESS);
+ if ((ptx_ba_tbl = wlan_11n_get_txbastream_status(priv,
+ BA_STREAM_SETUP_INPROGRESS)))
+ {
+ mlan_11n_delete_bastream_tbl(priv, ptx_ba_tbl->tid,
+ ptx_ba_tbl->ra, TYPE_DELBA_SENT,
+ MTRUE);
+ }
+ }
+ }
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function handles the command response of
+ * add a block ack request
+ *
+ * @param priv A pointer to mlan_private structure
+ * @param resp A pointer to HostCmd_DS_COMMAND
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+mlan_status
+wlan_ret_11n_addba_req(mlan_private * priv, HostCmd_DS_COMMAND * resp)
+{
+ t_u8 tid;
+ HostCmd_DS_11N_ADDBA_RSP *padd_ba_rsp =
+ (HostCmd_DS_11N_ADDBA_RSP *) & resp->params.add_ba_rsp;
+ TxBAStreamTbl *ptx_ba_tbl;
+ raListTbl *ra_list = MNULL;
+
+ ENTER();
+
+ padd_ba_rsp->block_ack_param_set =
+ wlan_le16_to_cpu(padd_ba_rsp->block_ack_param_set);
+ padd_ba_rsp->block_ack_tmo = wlan_le16_to_cpu(padd_ba_rsp->block_ack_tmo);
+ padd_ba_rsp->ssn = (wlan_le16_to_cpu(padd_ba_rsp->ssn)) & SSN_MASK;
+ padd_ba_rsp->status_code = wlan_le16_to_cpu(padd_ba_rsp->status_code);
+
+ tid = (padd_ba_rsp->block_ack_param_set & BLOCKACKPARAM_TID_MASK)
+ >> BLOCKACKPARAM_TID_POS;
+ if (padd_ba_rsp->status_code == BA_RESULT_SUCCESS) {
+ if ((ptx_ba_tbl = wlan_11n_get_txbastream_tbl(priv, tid,
+ padd_ba_rsp->
+ peer_mac_addr))) {
+ PRINTM(MCMND,
+ "ADDBA REQ: %02x:%02x:%02x:%02x:%02x:%02x tid=%d ssn=%d win_size=%d,amsdu=%d\n",
+ padd_ba_rsp->peer_mac_addr[0], padd_ba_rsp->peer_mac_addr[1],
+ padd_ba_rsp->peer_mac_addr[2], padd_ba_rsp->peer_mac_addr[3],
+ padd_ba_rsp->peer_mac_addr[4], padd_ba_rsp->peer_mac_addr[5],
+ tid, padd_ba_rsp->ssn,
+ ((padd_ba_rsp->
+ block_ack_param_set & BLOCKACKPARAM_WINSIZE_MASK) >>
+ BLOCKACKPARAM_WINSIZE_POS),
+ padd_ba_rsp->
+ block_ack_param_set & BLOCKACKPARAM_AMSDU_SUPP_MASK);
+ ptx_ba_tbl->ba_status = BA_STREAM_SETUP_COMPLETE;
+ if ((padd_ba_rsp->
+ block_ack_param_set & BLOCKACKPARAM_AMSDU_SUPP_MASK) &&
+ priv->add_ba_param.tx_amsdu &&
+ (priv->aggr_prio_tbl[tid].amsdu != BA_STREAM_NOT_ALLOWED))
+ ptx_ba_tbl->amsdu = MTRUE;
+ else
+ ptx_ba_tbl->amsdu = MFALSE;
+ } else {
+ PRINTM(MERROR, "BA stream not created\n");
+ }
+ } else {
+ mlan_11n_delete_bastream_tbl(priv, tid, padd_ba_rsp->peer_mac_addr,
+ TYPE_DELBA_SENT, MTRUE);
+ if (padd_ba_rsp->add_rsp_result != BA_RESULT_TIMEOUT) {
+#ifdef UAP_SUPPORT
+ if (GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_UAP)
+ disable_station_ampdu(priv, tid, padd_ba_rsp->peer_mac_addr);
+#endif /* UAP_SUPPORT */
+ priv->aggr_prio_tbl[tid].ampdu_ap = BA_STREAM_NOT_ALLOWED;
+
+ } else {
+ /* reset packet threshold */
+ ra_list =
+ wlan_wmm_get_ralist_node(priv, tid, padd_ba_rsp->peer_mac_addr);
+ if (ra_list) {
+ ra_list->packet_count = 0;
+ ra_list->ba_packet_threshold =
+ wlan_get_random_ba_threshold(priv->adapter);
+ }
+ }
+ }
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function prepares command of reconfigure tx buf
+ *
+ * @param priv A pointer to mlan_private structure
+ * @param cmd A pointer to HostCmd_DS_COMMAND structure
+ * @param cmd_action The action: GET or SET
+ * @param pdata_buf A pointer to data buffer
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+mlan_status
+wlan_cmd_recfg_tx_buf(mlan_private * priv,
+ HostCmd_DS_COMMAND * cmd, int cmd_action, void *pdata_buf)
+{
+ HostCmd_DS_TXBUF_CFG *ptx_buf = &cmd->params.tx_buf;
+ t_u16 action = (t_u16) cmd_action;
+ t_u16 buf_size = *((t_u16 *) pdata_buf);
+
+ ENTER();
+ cmd->command = wlan_cpu_to_le16(HostCmd_CMD_RECONFIGURE_TX_BUFF);
+ cmd->size = wlan_cpu_to_le16(sizeof(HostCmd_DS_TXBUF_CFG)
+ + S_DS_GEN);
+ ptx_buf->action = wlan_cpu_to_le16(action);
+ switch (action) {
+ case HostCmd_ACT_GEN_SET:
+ PRINTM(MCMND, "set tx_buf = %d\n", buf_size);
+ ptx_buf->buff_size = wlan_cpu_to_le16(buf_size);
+ break;
+ case HostCmd_ACT_GEN_GET:
+ default:
+ ptx_buf->buff_size = 0;
+ break;
+ }
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function prepares command of amsdu aggr control
+ *
+ * @param priv A pointer to mlan_private structure
+ * @param cmd A pointer to HostCmd_DS_COMMAND structure
+ * @param cmd_action The action: GET or SET
+ * @param pdata_buf A pointer to data buffer
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+mlan_status
+wlan_cmd_amsdu_aggr_ctrl(mlan_private * priv,
+ HostCmd_DS_COMMAND * cmd,
+ int cmd_action, void *pdata_buf)
+{
+ HostCmd_DS_AMSDU_AGGR_CTRL *pamsdu_ctrl = &cmd->params.amsdu_aggr_ctrl;
+ t_u16 action = (t_u16) cmd_action;
+ mlan_ds_11n_amsdu_aggr_ctrl *aa_ctrl = (mlan_ds_11n_amsdu_aggr_ctrl *)
+ pdata_buf;
+
+ ENTER();
+
+ cmd->command = wlan_cpu_to_le16(HostCmd_CMD_AMSDU_AGGR_CTRL);
+ cmd->size = wlan_cpu_to_le16(sizeof(HostCmd_DS_AMSDU_AGGR_CTRL)
+ + S_DS_GEN);
+ pamsdu_ctrl->action = wlan_cpu_to_le16(action);
+ switch (action) {
+ case HostCmd_ACT_GEN_SET:
+ pamsdu_ctrl->enable = wlan_cpu_to_le16(aa_ctrl->enable);
+ pamsdu_ctrl->curr_buf_size = 0;
+ break;
+ case HostCmd_ACT_GEN_GET:
+ default:
+ pamsdu_ctrl->curr_buf_size = 0;
+ break;
+ }
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function handles the command response of amsdu aggr ctrl
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param resp A pointer to HostCmd_DS_COMMAND
+ * @param pioctl_buf A pointer to mlan_ioctl_req structure
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+mlan_status
+wlan_ret_amsdu_aggr_ctrl(IN pmlan_private pmpriv,
+ IN HostCmd_DS_COMMAND * resp,
+ IN mlan_ioctl_req * pioctl_buf)
+{
+ mlan_ds_11n_cfg *cfg = MNULL;
+ HostCmd_DS_AMSDU_AGGR_CTRL *amsdu_ctrl = &resp->params.amsdu_aggr_ctrl;
+
+ ENTER();
+
+ if (pioctl_buf) {
+ cfg = (mlan_ds_11n_cfg *) pioctl_buf->pbuf;
+ cfg->param.amsdu_aggr_ctrl.enable =
+ wlan_le16_to_cpu(amsdu_ctrl->enable);
+ cfg->param.amsdu_aggr_ctrl.curr_buf_size =
+ wlan_le16_to_cpu(amsdu_ctrl->curr_buf_size);
+ }
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function prepares 11n cfg command
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param cmd A pointer to HostCmd_DS_COMMAND structure
+ * @param cmd_action the action: GET or SET
+ * @param pdata_buf A pointer to data buffer
+ * @return MLAN_STATUS_SUCCESS
+ */
+mlan_status
+wlan_cmd_11n_cfg(IN pmlan_private pmpriv,
+ IN HostCmd_DS_COMMAND * cmd,
+ IN t_u16 cmd_action, IN t_void * pdata_buf)
+{
+ HostCmd_DS_11N_CFG *htcfg = &cmd->params.htcfg;
+ mlan_ds_11n_tx_cfg *txcfg = (mlan_ds_11n_tx_cfg *) pdata_buf;
+
+ ENTER();
+ cmd->command = wlan_cpu_to_le16(HostCmd_CMD_11N_CFG);
+ cmd->size = wlan_cpu_to_le16(sizeof(HostCmd_DS_11N_CFG) + S_DS_GEN);
+ htcfg->action = wlan_cpu_to_le16(cmd_action);
+ htcfg->ht_tx_cap = wlan_cpu_to_le16(txcfg->httxcap);
+ htcfg->ht_tx_info = wlan_cpu_to_le16(txcfg->httxinfo);
+ htcfg->misc_config = wlan_cpu_to_le16(txcfg->misc_cfg);
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function handles the command response of 11ncfg
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param resp A pointer to HostCmd_DS_COMMAND
+ * @param pioctl_buf A pointer to mlan_ioctl_req structure
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+mlan_status
+wlan_ret_11n_cfg(IN pmlan_private pmpriv,
+ IN HostCmd_DS_COMMAND * resp, IN mlan_ioctl_req * pioctl_buf)
+{
+ mlan_ds_11n_cfg *cfg = MNULL;
+ HostCmd_DS_11N_CFG *htcfg = &resp->params.htcfg;
+
+ ENTER();
+ if (pioctl_buf && (wlan_le16_to_cpu(htcfg->action) == HostCmd_ACT_GEN_GET)) {
+ cfg = (mlan_ds_11n_cfg *) pioctl_buf->pbuf;
+ cfg->param.tx_cfg.httxcap = wlan_le16_to_cpu(htcfg->ht_tx_cap);
+ cfg->param.tx_cfg.httxinfo = wlan_le16_to_cpu(htcfg->ht_tx_info);
+ cfg->param.tx_cfg.misc_cfg = wlan_le16_to_cpu(htcfg->misc_config);
+ }
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function prepares TX BF configuration command
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param cmd A pointer to HostCmd_DS_COMMAND structure
+ * @param cmd_action The action: GET or SET
+ * @param pdata_buf A pointer to data buffer
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status
+wlan_cmd_tx_bf_cfg(IN pmlan_private pmpriv,
+ IN HostCmd_DS_COMMAND * cmd,
+ IN t_u16 cmd_action, IN t_void * pdata_buf)
+{
+ pmlan_adapter pmadapter = pmpriv->adapter;
+ HostCmd_DS_TX_BF_CFG *txbfcfg = &cmd->params.tx_bf_cfg;
+ mlan_ds_11n_tx_bf_cfg *txbf = (mlan_ds_11n_tx_bf_cfg *) pdata_buf;
+
+ ENTER();
+
+ cmd->command = wlan_cpu_to_le16(HostCmd_CMD_TX_BF_CFG);
+ cmd->size = wlan_cpu_to_le16(sizeof(HostCmd_DS_TX_BF_CFG) + S_DS_GEN);
+
+ if (txbf->bf_action == SET_GET_BF_PERIODICITY) {
+ memcpy(pmadapter, txbfcfg->body.bf_periodicity.peer_mac,
+ txbf->body.bf_periodicity[0].peer_mac, MLAN_MAC_ADDR_LENGTH);
+ }
+ txbfcfg->action = wlan_cpu_to_le16(txbf->action);
+ txbfcfg->bf_action = wlan_cpu_to_le16(txbf->bf_action);
+ if (cmd_action == HostCmd_ACT_GEN_SET) {
+ switch (txbf->bf_action) {
+ case BF_GLOBAL_CONFIGURATION:
+ txbfcfg->body.bf_global_cfg.bf_enbl =
+ txbf->body.bf_global_cfg.bf_enbl;
+ txbfcfg->body.bf_global_cfg.sounding_enbl =
+ txbf->body.bf_global_cfg.sounding_enbl;
+ txbfcfg->body.bf_global_cfg.fb_type =
+ txbf->body.bf_global_cfg.fb_type;
+ txbfcfg->body.bf_global_cfg.snr_threshold =
+ txbf->body.bf_global_cfg.snr_threshold;
+ txbfcfg->body.bf_global_cfg.sounding_interval =
+ wlan_cpu_to_le16(txbf->body.bf_global_cfg.sounding_interval);
+ txbfcfg->body.bf_global_cfg.bf_mode =
+ txbf->body.bf_global_cfg.bf_mode;
+ break;
+ case TRIGGER_SOUNDING_FOR_PEER:
+ memcpy(pmadapter, txbfcfg->body.bf_sound_args.peer_mac,
+ txbf->body.bf_sound[0].peer_mac, MLAN_MAC_ADDR_LENGTH);
+ break;
+ case SET_GET_BF_PERIODICITY:
+ txbfcfg->body.bf_periodicity.interval =
+ wlan_cpu_to_le16(txbf->body.bf_periodicity->interval);
+ break;
+ case TX_BF_FOR_PEER_ENBL:
+ memcpy(pmadapter, txbfcfg->body.tx_bf_peer.peer_mac,
+ txbf->body.tx_bf_peer[0].peer_mac, MLAN_MAC_ADDR_LENGTH);
+ txbfcfg->body.tx_bf_peer.bf_enbl = txbf->body.tx_bf_peer[0].bf_enbl;
+ txbfcfg->body.tx_bf_peer.sounding_enbl =
+ txbf->body.tx_bf_peer[0].sounding_enbl;
+ txbfcfg->body.tx_bf_peer.fb_type = txbf->body.tx_bf_peer[0].fb_type;
+ break;
+ case SET_SNR_THR_PEER:
+ memcpy(pmadapter, txbfcfg->body.bf_snr.peer_mac,
+ txbf->body.bf_snr[0].peer_mac, MLAN_MAC_ADDR_LENGTH);
+ txbfcfg->body.bf_snr.snr = txbf->body.bf_snr[0].snr;
+ break;
+ default:
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+ }
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function handles the command response
+ * of TX BF configuration
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param resp A pointer to HostCmd_DS_COMMAND
+ * @param pioctl_buf A pointer to mlan_ioctl_req structure
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status
+wlan_ret_tx_bf_cfg(IN pmlan_private pmpriv,
+ IN HostCmd_DS_COMMAND * resp, IN mlan_ioctl_req * pioctl_buf)
+{
+ pmlan_adapter pmadapter = pmpriv->adapter;
+ HostCmd_DS_TX_BF_CFG *txbfcfg = &resp->params.tx_bf_cfg;
+ mlan_ds_11n_cfg *cfg_11n = MNULL;
+ mlan_ds_11n_tx_bf_cfg *txbf = MNULL;
+ bf_peer_args *tx_bf_peer;
+ bf_snr_thr_t *bf_snr;
+ int i;
+
+ ENTER();
+
+ if (pioctl_buf) {
+ cfg_11n = (mlan_ds_11n_cfg *) pioctl_buf->pbuf;
+ txbf = (mlan_ds_11n_tx_bf_cfg *) & cfg_11n->param.tx_bf;
+ txbf->bf_action = wlan_le16_to_cpu(txbfcfg->bf_action);
+ switch (txbf->bf_action) {
+ case BF_GLOBAL_CONFIGURATION:
+ txbf->body.bf_global_cfg.bf_enbl =
+ txbfcfg->body.bf_global_cfg.bf_enbl;
+ txbf->body.bf_global_cfg.sounding_enbl =
+ txbfcfg->body.bf_global_cfg.sounding_enbl;
+ txbf->body.bf_global_cfg.fb_type =
+ txbfcfg->body.bf_global_cfg.fb_type;
+ txbf->body.bf_global_cfg.snr_threshold =
+ txbfcfg->body.bf_global_cfg.snr_threshold;
+ txbf->body.bf_global_cfg.sounding_interval =
+ wlan_le16_to_cpu(txbfcfg->body.bf_global_cfg.sounding_interval);
+ txbf->body.bf_global_cfg.bf_mode =
+ txbfcfg->body.bf_global_cfg.bf_mode;
+ break;
+ case TRIGGER_SOUNDING_FOR_PEER:
+ memcpy(pmadapter, txbf->body.bf_sound[0].peer_mac,
+ txbfcfg->body.bf_sound_args.peer_mac, MLAN_MAC_ADDR_LENGTH);
+ txbf->body.bf_sound[0].status = txbfcfg->body.bf_sound_args.status;
+ break;
+ case SET_GET_BF_PERIODICITY:
+ memcpy(pmadapter, txbf->body.bf_periodicity->peer_mac,
+ txbfcfg->body.bf_periodicity.peer_mac, MLAN_MAC_ADDR_LENGTH);
+ txbf->body.bf_periodicity->interval =
+ wlan_le16_to_cpu(txbfcfg->body.bf_periodicity.interval);
+ break;
+ case TX_BF_FOR_PEER_ENBL:
+ txbf->no_of_peers = *(t_u8 *) & txbfcfg->body;
+ tx_bf_peer =
+ (bf_peer_args *) ((t_u8 *) & txbfcfg->body + sizeof(t_u8));
+ for (i = 0; i < txbf->no_of_peers; i++) {
+ memcpy(pmadapter, txbf->body.tx_bf_peer[i].peer_mac,
+ (t_u8 *) tx_bf_peer->peer_mac, MLAN_MAC_ADDR_LENGTH);
+ txbf->body.tx_bf_peer[i].bf_enbl = tx_bf_peer->bf_enbl;
+ txbf->body.tx_bf_peer[i].sounding_enbl =
+ tx_bf_peer->sounding_enbl;
+ txbf->body.tx_bf_peer[i].fb_type = tx_bf_peer->fb_type;
+ tx_bf_peer++;
+ }
+ break;
+ case SET_SNR_THR_PEER:
+ txbf->no_of_peers = *(t_u8 *) & txbfcfg->body;
+ bf_snr = (bf_snr_thr_t *) ((t_u8 *) & txbfcfg->body + sizeof(t_u8));
+ for (i = 0; i < txbf->no_of_peers; i++) {
+ memcpy(pmadapter, txbf->body.bf_snr[i].peer_mac,
+ (t_u8 *) bf_snr->peer_mac, MLAN_MAC_ADDR_LENGTH);
+ txbf->body.bf_snr[i].snr = bf_snr->snr;
+ bf_snr++;
+ }
+ break;
+ default:
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+ }
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+#ifdef STA_SUPPORT
+/**
+ * @brief This function append the 802_11N tlv
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param pbss_desc A pointer to BSSDescriptor_t structure
+ * @param ppbuffer A Pointer to command buffer pointer
+ *
+ * @return bytes added to the buffer
+ */
+int
+wlan_cmd_append_11n_tlv(IN mlan_private * pmpriv,
+ IN BSSDescriptor_t * pbss_desc, OUT t_u8 ** ppbuffer)
+{
+ pmlan_adapter pmadapter = pmpriv->adapter;
+ MrvlIETypes_HTCap_t *pht_cap;
+ MrvlIETypes_HTInfo_t *pht_info;
+ MrvlIEtypes_ChanListParamSet_t *pchan_list;
+ MrvlIETypes_2040BSSCo_t *p2040_bss_co;
+ MrvlIETypes_ExtCap_t *pext_cap;
+ t_u32 usr_dot_11n_dev_cap;
+ int ret_len = 0;
+
+ ENTER();
+
+ /* Null Checks */
+ if (ppbuffer == MNULL) {
+ LEAVE();
+ return 0;
+ }
+ if (*ppbuffer == MNULL) {
+ LEAVE();
+ return 0;
+ }
+
+ if (pbss_desc->bss_band & BAND_A)
+ usr_dot_11n_dev_cap = pmadapter->usr_dot_11n_dev_cap_a;
+ else
+ usr_dot_11n_dev_cap = pmadapter->usr_dot_11n_dev_cap_bg;
+
+ if (pbss_desc->pht_cap) {
+ pht_cap = (MrvlIETypes_HTCap_t *) * ppbuffer;
+ memset(pmadapter, pht_cap, 0, sizeof(MrvlIETypes_HTCap_t));
+ pht_cap->header.type = wlan_cpu_to_le16(HT_CAPABILITY);
+ pht_cap->header.len = sizeof(HTCap_t);
+ memcpy(pmadapter, (t_u8 *) pht_cap + sizeof(MrvlIEtypesHeader_t),
+ (t_u8 *) pbss_desc->pht_cap + sizeof(IEEEtypes_Header_t),
+ pht_cap->header.len);
+
+ pht_cap->ht_cap.ht_cap_info =
+ wlan_le16_to_cpu(pht_cap->ht_cap.ht_cap_info);
+ pht_cap->ht_cap.ht_ext_cap =
+ wlan_le16_to_cpu(pht_cap->ht_cap.ht_ext_cap);
+ wlan_fill_ht_cap_tlv(pmpriv, pht_cap, pbss_desc->bss_band);
+
+ HEXDUMP("HT_CAPABILITIES IE", (t_u8 *) pht_cap,
+ sizeof(MrvlIETypes_HTCap_t));
+ *ppbuffer += sizeof(MrvlIETypes_HTCap_t);
+ ret_len += sizeof(MrvlIETypes_HTCap_t);
+ pht_cap->header.len = wlan_cpu_to_le16(pht_cap->header.len);
+ }
+
+ if (pbss_desc->pht_info) {
+ if (pmpriv->bss_mode == MLAN_BSS_MODE_IBSS) {
+ pht_info = (MrvlIETypes_HTInfo_t *) * ppbuffer;
+ memset(pmadapter, pht_info, 0, sizeof(MrvlIETypes_HTInfo_t));
+ pht_info->header.type = wlan_cpu_to_le16(HT_OPERATION);
+ pht_info->header.len = sizeof(HTInfo_t);
+
+ memcpy(pmadapter, (t_u8 *) pht_info + sizeof(MrvlIEtypesHeader_t),
+ (t_u8 *) pbss_desc->pht_info + sizeof(IEEEtypes_Header_t),
+ pht_info->header.len);
+
+ if (!ISSUPP_CHANWIDTH40(usr_dot_11n_dev_cap)) {
+ RESET_CHANWIDTH40(pht_info->ht_info.field2);
+ }
+
+ *ppbuffer += sizeof(MrvlIETypes_HTInfo_t);
+ ret_len += sizeof(MrvlIETypes_HTInfo_t);
+ pht_info->header.len = wlan_cpu_to_le16(pht_info->header.len);
+ }
+
+ pchan_list = (MrvlIEtypes_ChanListParamSet_t *) * ppbuffer;
+ memset(pmadapter, pchan_list, 0,
+ sizeof(MrvlIEtypes_ChanListParamSet_t));
+ pchan_list->header.type = wlan_cpu_to_le16(TLV_TYPE_CHANLIST);
+ pchan_list->header.len = sizeof(MrvlIEtypes_ChanListParamSet_t) -
+ sizeof(MrvlIEtypesHeader_t);
+ pchan_list->chan_scan_param[0].chan_number =
+ pbss_desc->pht_info->ht_info.pri_chan;
+ pchan_list->chan_scan_param[0].radio_type =
+ wlan_band_to_radio_type((t_u8) pbss_desc->bss_band);
+
+ if (ISSUPP_CHANWIDTH40(usr_dot_11n_dev_cap) &&
+ ISALLOWED_CHANWIDTH40(pbss_desc->pht_info->ht_info.field2))
+ SET_SECONDARYCHAN(pchan_list->chan_scan_param[0].radio_type,
+ GET_SECONDARYCHAN(pbss_desc->pht_info->ht_info.
+ field2));
+
+ HEXDUMP("ChanList", (t_u8 *) pchan_list,
+ sizeof(MrvlIEtypes_ChanListParamSet_t));
+ HEXDUMP("pht_info", (t_u8 *) pbss_desc->pht_info,
+ sizeof(MrvlIETypes_HTInfo_t) - 2);
+ *ppbuffer += sizeof(MrvlIEtypes_ChanListParamSet_t);
+ ret_len += sizeof(MrvlIEtypes_ChanListParamSet_t);
+ pchan_list->header.len = wlan_cpu_to_le16(pchan_list->header.len);
+ }
+
+ if (pbss_desc->pbss_co_2040) {
+ p2040_bss_co = (MrvlIETypes_2040BSSCo_t *) * ppbuffer;
+ memset(pmadapter, p2040_bss_co, 0, sizeof(MrvlIETypes_2040BSSCo_t));
+ p2040_bss_co->header.type = wlan_cpu_to_le16(BSSCO_2040);
+ p2040_bss_co->header.len = sizeof(BSSCo2040_t);
+
+ memcpy(pmadapter, (t_u8 *) p2040_bss_co + sizeof(MrvlIEtypesHeader_t),
+ (t_u8 *) pbss_desc->pbss_co_2040 + sizeof(IEEEtypes_Header_t),
+ p2040_bss_co->header.len);
+
+ HEXDUMP("20/40 BSS Coexistence IE", (t_u8 *) p2040_bss_co,
+ sizeof(MrvlIETypes_2040BSSCo_t));
+ *ppbuffer += sizeof(MrvlIETypes_2040BSSCo_t);
+ ret_len += sizeof(MrvlIETypes_2040BSSCo_t);
+ p2040_bss_co->header.len = wlan_cpu_to_le16(p2040_bss_co->header.len);
+ }
+
+ if (pbss_desc->pext_cap) {
+ pext_cap = (MrvlIETypes_ExtCap_t *) * ppbuffer;
+ memset(pmadapter, pext_cap, 0, sizeof(MrvlIETypes_ExtCap_t));
+ pext_cap->header.type = wlan_cpu_to_le16(EXT_CAPABILITY);
+ pext_cap->header.len = sizeof(ExtCap_t);
+
+ memcpy(pmadapter, (t_u8 *) pext_cap + sizeof(MrvlIEtypesHeader_t),
+ (t_u8 *) pbss_desc->pext_cap + sizeof(IEEEtypes_Header_t),
+ pext_cap->header.len);
+
+ HEXDUMP("Extended Capabilities IE", (t_u8 *) pext_cap,
+ sizeof(MrvlIETypes_ExtCap_t));
+ *ppbuffer += sizeof(MrvlIETypes_ExtCap_t);
+ ret_len += sizeof(MrvlIETypes_ExtCap_t);
+ pext_cap->header.len = wlan_cpu_to_le16(pext_cap->header.len);
+ }
+
+ LEAVE();
+ return ret_len;
+}
+
+#endif /* STA_SUPPORT */
+
+/**
+ * @brief 11n configuration handler
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+mlan_status
+wlan_11n_cfg_ioctl(IN pmlan_adapter pmadapter, IN pmlan_ioctl_req pioctl_req)
+{
+ mlan_status status = MLAN_STATUS_SUCCESS;
+ mlan_ds_11n_cfg *cfg = MNULL;
+
+ ENTER();
+
+ if (pioctl_req->buf_len < sizeof(mlan_ds_11n_cfg)) {
+ PRINTM(MINFO, "MLAN bss IOCTL length is too short.\n");
+ pioctl_req->data_read_written = 0;
+ pioctl_req->buf_len_needed = sizeof(mlan_ds_11n_cfg);
+ pioctl_req->status_code = MLAN_ERROR_INVALID_PARAMETER;
+ LEAVE();
+ return MLAN_STATUS_RESOURCE;
+ }
+ cfg = (mlan_ds_11n_cfg *) pioctl_req->pbuf;
+ switch (cfg->sub_command) {
+ case MLAN_OID_11N_CFG_TX:
+ status = wlan_11n_ioctl_httxcfg(pmadapter, pioctl_req);
+ break;
+ case MLAN_OID_11N_HTCAP_CFG:
+ status = wlan_11n_ioctl_htusrcfg(pmadapter, pioctl_req);
+ break;
+ case MLAN_OID_11N_CFG_AGGR_PRIO_TBL:
+ status = wlan_11n_ioctl_aggr_prio_tbl(pmadapter, pioctl_req);
+ break;
+ case MLAN_OID_11N_CFG_ADDBA_REJECT:
+ status = wlan_11n_ioctl_addba_reject(pmadapter, pioctl_req);
+ break;
+ case MLAN_OID_11N_CFG_ADDBA_PARAM:
+ status = wlan_11n_ioctl_addba_param(pmadapter, pioctl_req);
+ break;
+ case MLAN_OID_11N_CFG_MAX_TX_BUF_SIZE:
+ status = wlan_11n_ioctl_max_tx_buf_size(pmadapter, pioctl_req);
+ break;
+ case MLAN_OID_11N_CFG_AMSDU_AGGR_CTRL:
+ status = wlan_11n_ioctl_amsdu_aggr_ctrl(pmadapter, pioctl_req);
+ break;
+ case MLAN_OID_11N_CFG_SUPPORTED_MCS_SET:
+ status = wlan_11n_ioctl_supported_mcs_set(pmadapter, pioctl_req);
+ break;
+ case MLAN_OID_11N_CFG_TX_BF_CAP:
+ status = wlan_11n_ioctl_tx_bf_cap(pmadapter, pioctl_req);
+ break;
+ case MLAN_OID_11N_CFG_TX_BF_CFG:
+ status = wlan_11n_ioctl_tx_bf_cfg(pmadapter, pioctl_req);
+ break;
+ case MLAN_OID_11N_CFG_STREAM_CFG:
+ status = wlan_11n_ioctl_stream_cfg(pmadapter, pioctl_req);
+ break;
+ default:
+ pioctl_req->status_code = MLAN_ERROR_IOCTL_INVALID;
+ status = MLAN_STATUS_FAILURE;
+ break;
+ }
+ LEAVE();
+ return status;
+}
+
+/**
+ * @brief This function will delete the given entry in Tx BA Stream table
+ *
+ * @param priv Pointer to mlan_private
+ * @param ptx_tbl Pointer to tx ba stream entry to delete
+ *
+ * @return N/A
+ */
+void
+wlan_11n_delete_txbastream_tbl_entry(mlan_private * priv,
+ TxBAStreamTbl * ptx_tbl)
+{
+ pmlan_adapter pmadapter = priv->adapter;
+
+ ENTER();
+
+ pmadapter->callbacks.moal_spin_lock(pmadapter->pmoal_handle,
+ priv->tx_ba_stream_tbl_ptr.plock);
+
+ if (!ptx_tbl || !wlan_is_txbastreamptr_valid(priv, ptx_tbl)) {
+ goto exit;
+ }
+
+ PRINTM(MINFO, "Delete BA stream table entry: %p\n", ptx_tbl);
+
+ util_unlink_list(pmadapter->pmoal_handle, &priv->tx_ba_stream_tbl_ptr,
+ (pmlan_linked_list) ptx_tbl, MNULL, MNULL);
+
+ pmadapter->callbacks.moal_mfree(pmadapter->pmoal_handle, (t_u8 *) ptx_tbl);
+
+ exit:
+ pmadapter->callbacks.moal_spin_unlock(pmadapter->pmoal_handle,
+ priv->tx_ba_stream_tbl_ptr.plock);
+ LEAVE();
+}
+
+/**
+ * @brief This function will delete all the entries in Tx BA Stream table
+ *
+ * @param priv A pointer to mlan_private
+ *
+ * @return N/A
+ */
+void
+wlan_11n_deleteall_txbastream_tbl(mlan_private * priv)
+{
+ int i;
+ TxBAStreamTbl *del_tbl_ptr = MNULL;
+
+ ENTER();
+
+ while ((del_tbl_ptr = (TxBAStreamTbl *)
+ util_peek_list(priv->adapter->pmoal_handle,
+ &priv->tx_ba_stream_tbl_ptr,
+ priv->adapter->callbacks.moal_spin_lock,
+ priv->adapter->callbacks.moal_spin_unlock))) {
+ wlan_11n_delete_txbastream_tbl_entry(priv, del_tbl_ptr);
+ }
+
+ util_init_list((pmlan_linked_list) & priv->tx_ba_stream_tbl_ptr);
+
+ for (i = 0; i < MAX_NUM_TID; ++i) {
+ priv->aggr_prio_tbl[i].ampdu_ap = priv->aggr_prio_tbl[i].ampdu_user;
+ }
+
+ LEAVE();
+}
+
+/**
+ * @brief This function will return the pointer to an entry in BA Stream
+ * table which matches the give RA/TID pair
+ *
+ * @param priv A pointer to mlan_private
+ * @param tid TID to find in reordering table
+ * @param ra RA to find in reordering table
+ *
+ * @return A pointer to first entry matching RA/TID in BA stream
+ * NULL if not found
+ */
+TxBAStreamTbl *
+wlan_11n_get_txbastream_tbl(mlan_private * priv, int tid, t_u8 * ra)
+{
+ TxBAStreamTbl *ptx_tbl;
+ pmlan_adapter pmadapter = priv->adapter;
+
+ ENTER();
+
+ if (!(ptx_tbl = (TxBAStreamTbl *) util_peek_list(pmadapter->pmoal_handle,
+ &priv->
+ tx_ba_stream_tbl_ptr,
+ pmadapter->callbacks.
+ moal_spin_lock,
+ pmadapter->callbacks.
+ moal_spin_unlock))) {
+ LEAVE();
+ return MNULL;
+ }
+
+ while (ptx_tbl != (TxBAStreamTbl *) & priv->tx_ba_stream_tbl_ptr) {
+
+ PRINTM(MDAT_D, "get_txbastream_tbl TID %d\n", ptx_tbl->tid);
+ DBG_HEXDUMP(MDAT_D, "RA", ptx_tbl->ra, MLAN_MAC_ADDR_LENGTH);
+
+ if ((!memcmp(pmadapter, ptx_tbl->ra, ra, MLAN_MAC_ADDR_LENGTH))
+ && (ptx_tbl->tid == tid)) {
+ LEAVE();
+ return ptx_tbl;
+ }
+
+ ptx_tbl = ptx_tbl->pnext;
+ }
+
+ LEAVE();
+ return MNULL;
+}
+
+/**
+ * @brief This function will create a entry in tx ba stream table for the
+ * given RA/TID.
+ *
+ * @param priv A pointer to mlan_private
+ * @param ra RA to find in reordering table
+ * @param tid TID to find in reordering table
+ * @param ba_status BA stream status to create the stream with
+ *
+ * @return N/A
+ */
+void
+wlan_11n_create_txbastream_tbl(mlan_private * priv,
+ t_u8 * ra, int tid, baStatus_e ba_status)
+{
+ TxBAStreamTbl *newNode = MNULL;
+ pmlan_adapter pmadapter = priv->adapter;
+
+ ENTER();
+
+ if (!wlan_11n_get_txbastream_tbl(priv, tid, ra)) {
+ PRINTM(MDAT_D, "get_txbastream_tbl TID %d\n", tid);
+ DBG_HEXDUMP(MDAT_D, "RA", ra, MLAN_MAC_ADDR_LENGTH);
+
+ pmadapter->callbacks.moal_malloc(pmadapter->pmoal_handle,
+ sizeof(TxBAStreamTbl), MLAN_MEM_DEF,
+ (t_u8 **) & newNode);
+ util_init_list((pmlan_linked_list) newNode);
+
+ newNode->tid = tid;
+ newNode->ba_status = ba_status;
+ memcpy(pmadapter, newNode->ra, ra, MLAN_MAC_ADDR_LENGTH);
+
+ util_enqueue_list_tail(pmadapter->pmoal_handle,
+ &priv->tx_ba_stream_tbl_ptr,
+ (pmlan_linked_list) newNode,
+ pmadapter->callbacks.moal_spin_lock,
+ pmadapter->callbacks.moal_spin_unlock);
+ }
+
+ LEAVE();
+}
+
+/**
+ * @brief This function will send a block ack to given tid/ra
+ *
+ * @param priv A pointer to mlan_private
+ * @param tid TID to send the ADDBA
+ * @param peer_mac MAC address to send the ADDBA
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+int
+wlan_send_addba(mlan_private * priv, int tid, t_u8 * peer_mac)
+{
+ HostCmd_DS_11N_ADDBA_REQ add_ba_req;
+ static t_u8 dialog_tok;
+ mlan_status ret;
+
+ ENTER();
+
+ PRINTM(MCMND, "Send addba: TID %d\n", tid);
+ DBG_HEXDUMP(MCMD_D, "Send addba RA", peer_mac, MLAN_MAC_ADDR_LENGTH);
+
+ add_ba_req.block_ack_param_set = (t_u16) ((tid << BLOCKACKPARAM_TID_POS) |
+ (priv->add_ba_param.tx_win_size
+ << BLOCKACKPARAM_WINSIZE_POS) |
+ IMMEDIATE_BLOCK_ACK);
+ /** enable AMSDU inside AMPDU */
+ if (priv->add_ba_param.tx_amsdu &&
+ (priv->aggr_prio_tbl[tid].amsdu != BA_STREAM_NOT_ALLOWED))
+ add_ba_req.block_ack_param_set |= BLOCKACKPARAM_AMSDU_SUPP_MASK;
+ add_ba_req.block_ack_tmo = (t_u16) priv->add_ba_param.timeout;
+
+ ++dialog_tok;
+
+ if (dialog_tok == 0)
+ dialog_tok = 1;
+
+ add_ba_req.dialog_token = dialog_tok;
+ memcpy(priv->adapter, &add_ba_req.peer_mac_addr, peer_mac,
+ MLAN_MAC_ADDR_LENGTH);
+
+ /* We don't wait for the response of this command */
+ ret = wlan_prepare_cmd(priv, HostCmd_CMD_11N_ADDBA_REQ,
+ 0, 0, MNULL, &add_ba_req);
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function will delete a block ack to given tid/ra
+ *
+ * @param priv A pointer to mlan_private
+ * @param tid TID to send the ADDBA
+ * @param peer_mac MAC address to send the ADDBA
+ * @param initiator MTRUE if we have initiated ADDBA, MFALSE otherwise
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+int
+wlan_send_delba(mlan_private * priv, int tid, t_u8 * peer_mac, int initiator)
+{
+ HostCmd_DS_11N_DELBA delba;
+ mlan_status ret;
+
+ ENTER();
+
+ memset(priv->adapter, &delba, 0, sizeof(delba));
+ delba.del_ba_param_set = (tid << DELBA_TID_POS);
+
+ if (initiator)
+ DELBA_INITIATOR(delba.del_ba_param_set);
+ else
+ DELBA_RECIPIENT(delba.del_ba_param_set);
+
+ memcpy(priv->adapter, &delba.peer_mac_addr, peer_mac, MLAN_MAC_ADDR_LENGTH);
+
+ /* We don't wait for the response of this command */
+ ret = wlan_prepare_cmd(priv, HostCmd_CMD_11N_DELBA,
+ HostCmd_ACT_GEN_SET, 0, MNULL, &delba);
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function handles the command response of
+ * delete a block ack request
+ *
+ * @param priv A pointer to mlan_private structure
+ * @param del_ba A pointer to command response buffer
+ *
+ * @return N/A
+ */
+void
+wlan_11n_delete_bastream(mlan_private * priv, t_u8 * del_ba)
+{
+ HostCmd_DS_11N_DELBA *pdel_ba = (HostCmd_DS_11N_DELBA *) del_ba;
+ int tid;
+
+ ENTER();
+
+ DBG_HEXDUMP(MCMD_D, "Delba:", (t_u8 *) pdel_ba, 20);
+ pdel_ba->del_ba_param_set = wlan_le16_to_cpu(pdel_ba->del_ba_param_set);
+ pdel_ba->reason_code = wlan_le16_to_cpu(pdel_ba->reason_code);
+
+ tid = pdel_ba->del_ba_param_set >> DELBA_TID_POS;
+
+ mlan_11n_delete_bastream_tbl(priv, tid, pdel_ba->peer_mac_addr,
+ TYPE_DELBA_RECEIVE,
+ INITIATOR_BIT(pdel_ba->del_ba_param_set));
+
+ LEAVE();
+}
+
+/**
+ * @brief Get Rx reordering table
+ *
+ * @param priv A pointer to mlan_private structure
+ * @param buf A pointer to rx_reorder_tbl structure
+ * @return number of rx reorder table entry
+ */
+int
+wlan_get_rxreorder_tbl(mlan_private * priv, rx_reorder_tbl * buf)
+{
+ int i;
+ rx_reorder_tbl *ptbl = buf;
+ RxReorderTbl *rxReorderTblPtr;
+ int count = 0;
+ ENTER();
+ if (!
+ (rxReorderTblPtr =
+ (RxReorderTbl *) util_peek_list(priv->adapter->pmoal_handle,
+ &priv->rx_reorder_tbl_ptr,
+ priv->adapter->callbacks.
+ moal_spin_lock,
+ priv->adapter->callbacks.
+ moal_spin_unlock))) {
+ LEAVE();
+ return count;
+ }
+ while (rxReorderTblPtr != (RxReorderTbl *) & priv->rx_reorder_tbl_ptr) {
+ ptbl->tid = (t_u16) rxReorderTblPtr->tid;
+ memcpy(priv->adapter, ptbl->ta, rxReorderTblPtr->ta,
+ MLAN_MAC_ADDR_LENGTH);
+ ptbl->start_win = rxReorderTblPtr->start_win;
+ ptbl->win_size = rxReorderTblPtr->win_size;
+ ptbl->amsdu = rxReorderTblPtr->amsdu;
+ for (i = 0; i < rxReorderTblPtr->win_size; ++i) {
+ if (rxReorderTblPtr->rx_reorder_ptr[i])
+ ptbl->buffer[i] = MTRUE;
+ else
+ ptbl->buffer[i] = MFALSE;
+ }
+ rxReorderTblPtr = rxReorderTblPtr->pnext;
+ ptbl++;
+ count++;
+ if (count >= MLAN_MAX_RX_BASTREAM_SUPPORTED)
+ break;
+ }
+ LEAVE();
+ return count;
+}
+
+/**
+ * @brief Get transmit BA stream table
+ *
+ * @param priv A pointer to mlan_private structure
+ * @param buf A pointer to tx_ba_stream_tbl structure
+ * @return number of ba stream table entry
+ */
+int
+wlan_get_txbastream_tbl(mlan_private * priv, tx_ba_stream_tbl * buf)
+{
+ TxBAStreamTbl *ptxtbl;
+ tx_ba_stream_tbl *ptbl = buf;
+ int count = 0;
+
+ ENTER();
+
+ if (!(ptxtbl = (TxBAStreamTbl *) util_peek_list(priv->adapter->pmoal_handle,
+ &priv->tx_ba_stream_tbl_ptr,
+ priv->adapter->callbacks.
+ moal_spin_lock,
+ priv->adapter->callbacks.
+ moal_spin_unlock))) {
+ LEAVE();
+ return count;
+ }
+
+ while (ptxtbl != (TxBAStreamTbl *) & priv->tx_ba_stream_tbl_ptr) {
+ ptbl->tid = (t_u16) ptxtbl->tid;
+ PRINTM(MINFO, "tid=%d\n", ptbl->tid);
+ memcpy(priv->adapter, ptbl->ra, ptxtbl->ra, MLAN_MAC_ADDR_LENGTH);
+ ptbl->amsdu = ptxtbl->amsdu;
+ ptxtbl = ptxtbl->pnext;
+ ptbl++;
+ count++;
+ if (count >= MLAN_MAX_TX_BASTREAM_SUPPORTED)
+ break;
+ }
+
+ LEAVE();
+ return count;
+}
+
+/**
+ * @brief This function cleans up txbastream_tbl for specific station
+ *
+ * @param priv A pointer to mlan_private
+ * @param ra RA to find in txbastream_tbl
+ * @return N/A
+ */
+void
+wlan_11n_cleanup_txbastream_tbl(mlan_private * priv, t_u8 * ra)
+{
+ TxBAStreamTbl *ptx_tbl = MNULL;
+ t_u8 i;
+ ENTER();
+ for (i = 0; i < MAX_NUM_TID; ++i) {
+ if ((ptx_tbl = wlan_11n_get_txbastream_tbl(priv, i, ra))) {
+ wlan_11n_delete_txbastream_tbl_entry(priv, ptx_tbl);
+ }
+ }
+ LEAVE();
+ return;
+}
diff --git a/drivers/net/wireless/sd8797/mlan/mlan_11n.h b/drivers/net/wireless/sd8797/mlan/mlan_11n.h
new file mode 100644
index 000000000000..dc3d98974f03
--- /dev/null
+++ b/drivers/net/wireless/sd8797/mlan/mlan_11n.h
@@ -0,0 +1,420 @@
+/** @file mlan_11n.h
+ *
+ * @brief Interface for the 802.11n mlan_11n module implemented in mlan_11n.c
+ *
+ * Driver interface functions and type declarations for the 11n module
+ * implemented in mlan_11n.c.
+ *
+ * Copyright (C) 2008-2011, Marvell International Ltd.
+ *
+ * This software file (the "File") is distributed by Marvell International
+ * Ltd. under the terms of the GNU General Public License Version 2, June 1991
+ * (the "License"). You may use, redistribute and/or modify this File in
+ * accordance with the terms and conditions of the License, a copy of which
+ * is available by writing to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
+ * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
+ *
+ * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
+ * ARE EXPRESSLY DISCLAIMED. The License provides additional details about
+ * this warranty disclaimer.
+ *
+ */
+
+/********************************************************
+Change log:
+ 12/01/2008: initial version
+********************************************************/
+
+#ifndef _MLAN_11N_H_
+#define _MLAN_11N_H_
+
+#include "mlan_11n_aggr.h"
+#include "mlan_11n_rxreorder.h"
+#include "mlan_wmm.h"
+
+/** Print the 802.11n device capability */
+void wlan_show_dot11ndevcap(pmlan_adapter pmadapter, t_u32 cap);
+/** Print the 802.11n device MCS */
+void wlan_show_devmcssupport(pmlan_adapter pmadapter, t_u8 support);
+/** Handle the command response of a delete block ack request */
+mlan_status wlan_ret_11n_delba(mlan_private * priv, HostCmd_DS_COMMAND * resp);
+/** Handle the command response of an add block ack request */
+mlan_status wlan_ret_11n_addba_req(mlan_private * priv,
+ HostCmd_DS_COMMAND * resp);
+/** Handle the command response of 11ncfg command */
+mlan_status wlan_ret_11n_cfg(IN pmlan_private pmpriv,
+ IN HostCmd_DS_COMMAND * resp,
+ IN mlan_ioctl_req * pioctl_buf);
+/** Prepare 11ncfg command */
+mlan_status wlan_cmd_11n_cfg(IN pmlan_private pmpriv,
+ IN HostCmd_DS_COMMAND * cmd, IN t_u16 cmd_action,
+ IN t_void * pdata_buf);
+/** Prepare TX BF configuration command */
+mlan_status wlan_cmd_tx_bf_cfg(IN pmlan_private pmpriv,
+ IN HostCmd_DS_COMMAND * cmd,
+ IN t_u16 cmd_action, IN t_void * pdata_buf);
+/** Handle the command response TX BF configuration */
+mlan_status wlan_ret_tx_bf_cfg(IN pmlan_private pmpriv,
+ IN HostCmd_DS_COMMAND * resp,
+ IN mlan_ioctl_req * pioctl_buf);
+#ifdef STA_SUPPORT
+/** Append the 802_11N tlv */
+int wlan_cmd_append_11n_tlv(IN mlan_private * pmpriv,
+ IN BSSDescriptor_t * pbss_desc,
+ OUT t_u8 ** ppbuffer);
+/** wlan fill HT cap tlv */
+void wlan_fill_ht_cap_tlv(mlan_private * priv, MrvlIETypes_HTCap_t * pht_cap,
+ t_u8 band);
+#endif /* STA_SUPPORT */
+/** Miscellaneous configuration handler */
+mlan_status wlan_11n_cfg_ioctl(IN pmlan_adapter pmadapter,
+ IN pmlan_ioctl_req pioctl_req);
+/** Delete Tx BA stream table entry */
+void wlan_11n_delete_txbastream_tbl_entry(mlan_private * priv,
+ TxBAStreamTbl * ptx_tbl);
+/** Delete all Tx BA stream table entries */
+void wlan_11n_deleteall_txbastream_tbl(mlan_private * priv);
+/** Get Tx BA stream table */
+TxBAStreamTbl *wlan_11n_get_txbastream_tbl(mlan_private * priv, int tid,
+ t_u8 * ra);
+/** Create Tx BA stream table */
+void wlan_11n_create_txbastream_tbl(mlan_private * priv, t_u8 * ra, int tid,
+ baStatus_e ba_status);
+/** Send ADD BA request */
+int wlan_send_addba(mlan_private * priv, int tid, t_u8 * peer_mac);
+/** Send DEL BA request */
+int wlan_send_delba(mlan_private * priv, int tid, t_u8 * peer_mac,
+ int initiator);
+/** This function handles the command response of delete a block ack request*/
+void wlan_11n_delete_bastream(mlan_private * priv, t_u8 * del_ba);
+/** get rx reorder table */
+int wlan_get_rxreorder_tbl(mlan_private * priv, rx_reorder_tbl * buf);
+/** get tx ba stream table */
+int wlan_get_txbastream_tbl(mlan_private * priv, tx_ba_stream_tbl * buf);
+/** Minimum number of AMSDU */
+#define MIN_NUM_AMSDU 2
+/** AMSDU Aggr control cmd resp */
+mlan_status wlan_ret_amsdu_aggr_ctrl(pmlan_private pmpriv,
+ HostCmd_DS_COMMAND * resp,
+ mlan_ioctl_req * pioctl_buf);
+/** reconfigure tx buf size */
+mlan_status wlan_cmd_recfg_tx_buf(mlan_private * priv,
+ HostCmd_DS_COMMAND * cmd,
+ int cmd_action, void *pdata_buf);
+/** AMSDU aggr control cmd */
+mlan_status wlan_cmd_amsdu_aggr_ctrl(mlan_private * priv,
+ HostCmd_DS_COMMAND * cmd,
+ int cmd_action, void *pdata_buf);
+
+/** clean up txbastream_tbl */
+void wlan_11n_cleanup_txbastream_tbl(mlan_private * priv, t_u8 * ra);
+/**
+ * @brief This function checks whether a station has 11N enabled or not
+ *
+ * @param priv A pointer to mlan_private
+ * @param mac station mac address
+ * @return MTRUE or MFALSE
+ */
+static INLINE t_u8
+is_station_11n_enabled(mlan_private * priv, t_u8 * mac)
+{
+ sta_node *sta_ptr = MNULL;
+ if ((sta_ptr = wlan_get_station_entry(priv, mac))) {
+ return (sta_ptr->is_11n_enabled) ? MTRUE : MFALSE;
+ }
+ return MFALSE;
+}
+
+/**
+ * @brief This function get station max amsdu size
+ *
+ * @param priv A pointer to mlan_private
+ * @param mac station mac address
+ * @return max amsdu size statio supported
+ */
+static INLINE t_u16
+get_station_max_amsdu_size(mlan_private * priv, t_u8 * mac)
+{
+ sta_node *sta_ptr = MNULL;
+ if ((sta_ptr = wlan_get_station_entry(priv, mac))) {
+ return sta_ptr->max_amsdu;
+ }
+ return 0;
+}
+
+/**
+ * @brief This function checks whether a station allows AMPDU or not
+ *
+ * @param priv A pointer to mlan_private
+ * @param ptr A pointer to RA list table
+ * @param tid TID value for ptr
+ * @return MTRUE or MFALSE
+ */
+static INLINE t_u8
+is_station_ampdu_allowed(mlan_private * priv, raListTbl * ptr, int tid)
+{
+ sta_node *sta_ptr = MNULL;
+ if ((sta_ptr = wlan_get_station_entry(priv, ptr->ra))) {
+ if (GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_UAP) {
+ if (priv->sec_info.wapi_enabled && !sta_ptr->wapi_key_on)
+ return MFALSE;
+ }
+ return ((sta_ptr->ampdu_sta[tid] != BA_STREAM_NOT_ALLOWED)
+ ? MTRUE : MFALSE);
+ }
+ return MFALSE;
+}
+
+/**
+ * @brief This function disable station ampdu for specific tid
+ *
+ * @param priv A pointer to mlan_private
+ * @param tid tid index
+ * @param ra station mac address
+ * @return N/A
+ */
+static INLINE void
+disable_station_ampdu(mlan_private * priv, t_u8 tid, t_u8 * ra)
+{
+ sta_node *sta_ptr = MNULL;
+ if ((sta_ptr = wlan_get_station_entry(priv, ra))) {
+ sta_ptr->ampdu_sta[tid] = BA_STREAM_NOT_ALLOWED;
+ }
+ return;
+}
+
+/**
+ * @brief This function checks whether current BA stream is high priority or not
+ *
+ * @param priv A pointer to mlan_private
+ * @param tid TID
+ *
+ * @return MTRUE or MFALSE
+ */
+static INLINE t_u8
+wlan_is_cur_bastream_high_prio(mlan_private * priv, int tid)
+{
+ TxBAStreamTbl *ptx_tbl;
+
+ ENTER();
+
+ if (!
+ (ptx_tbl =
+ (TxBAStreamTbl *) util_peek_list(priv->adapter->pmoal_handle,
+ &priv->tx_ba_stream_tbl_ptr,
+ priv->adapter->callbacks.
+ moal_spin_lock,
+ priv->adapter->callbacks.
+ moal_spin_unlock)))
+ return MFALSE;
+
+ while (ptx_tbl != (TxBAStreamTbl *) & priv->tx_ba_stream_tbl_ptr) {
+ if (priv->aggr_prio_tbl[tid].ampdu_user >
+ priv->aggr_prio_tbl[ptx_tbl->tid].ampdu_user) {
+ LEAVE();
+ return MTRUE;
+ }
+
+ ptx_tbl = ptx_tbl->pnext;
+ }
+
+ LEAVE();
+ return MFALSE;
+}
+
+/**
+ * @brief This function checks whether AMPDU is allowed or not
+ *
+ * @param priv A pointer to mlan_private
+ * @param ptr A pointer to RA list table
+ * @param tid TID value for ptr
+ *
+ * @return MTRUE or MFALSE
+ */
+static INLINE t_u8
+wlan_is_ampdu_allowed(mlan_private * priv, raListTbl * ptr, int tid)
+{
+#ifdef UAP_SUPPORT
+ if (GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_UAP)
+ return is_station_ampdu_allowed(priv, ptr, tid);
+#endif /* UAP_SUPPORT */
+ if (priv->sec_info.wapi_enabled && !priv->sec_info.wapi_key_on)
+ return MFALSE;
+
+ return ((priv->aggr_prio_tbl[tid].ampdu_ap != BA_STREAM_NOT_ALLOWED)
+ ? MTRUE : MFALSE);
+}
+
+/**
+ * @brief This function checks whether AMSDU is allowed for BA stream
+ *
+ * @param priv A pointer to mlan_private
+ * @param ptr A pointer to RA list table
+ * @param tid TID value for ptr
+ *
+ * @return MTRUE or MFALSE
+ */
+static int INLINE
+wlan_is_amsdu_in_ampdu_allowed(mlan_private * priv, raListTbl * ptr, int tid)
+{
+ TxBAStreamTbl *ptx_tbl;
+ ENTER();
+ if ((ptx_tbl = wlan_11n_get_txbastream_tbl(priv, tid, ptr->ra))) {
+ LEAVE();
+ return ptx_tbl->amsdu;
+ }
+ LEAVE();
+ return MFALSE;
+}
+
+/**
+ * @brief This function checks whether AMSDU is allowed or not
+ *
+ * @param priv A pointer to mlan_private
+ * @param ptr A pointer to RA list table
+ * @param tid TID value for ptr
+ *
+ * @return MTRUE or MFALSE
+ */
+static INLINE t_u8
+wlan_is_amsdu_allowed(mlan_private * priv, raListTbl * ptr, int tid)
+{
+#ifdef UAP_SUPPORT
+ sta_node *sta_ptr = MNULL;
+ if (GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_UAP) {
+ if ((sta_ptr = wlan_get_station_entry(priv, ptr->ra))) {
+ if (priv->sec_info.wapi_enabled && !sta_ptr->wapi_key_on)
+ return MFALSE;
+ }
+ }
+#endif /* UAP_SUPPORT */
+#define TXRATE_BITMAP_INDEX_MCS0_7 2
+ return (((priv->aggr_prio_tbl[tid].amsdu != BA_STREAM_NOT_ALLOWED)
+ && ((priv->is_data_rate_auto)
+ || !((priv->bitmap_rates[TXRATE_BITMAP_INDEX_MCS0_7]) & 0x03)))
+ ? MTRUE : MFALSE);
+}
+
+/**
+ * @brief This function checks whether a BA stream is available or not
+ *
+ * @param priv A pointer to mlan_private
+ *
+ * @return MTRUE or MFALSE
+ */
+static INLINE t_u8
+wlan_is_bastream_avail(mlan_private * priv)
+{
+ mlan_private *pmpriv = MNULL;
+ t_u8 i = 0;
+ t_u32 bastream_num = 0;
+ for (i = 0; i < priv->adapter->priv_num; i++) {
+ if ((pmpriv = priv->adapter->priv[i]))
+ bastream_num +=
+ wlan_wmm_list_len(priv->adapter,
+ (pmlan_list_head) & pmpriv->
+ tx_ba_stream_tbl_ptr);
+ }
+ return ((bastream_num < MLAN_MAX_TX_BASTREAM_SUPPORTED) ? MTRUE : MFALSE);
+}
+
+/**
+ * @brief This function finds the stream to delete
+ *
+ * @param priv A pointer to mlan_private
+ * @param ptr A pointer to RA list table
+ * @param ptr_tid TID value of ptr
+ * @param ptid A pointer to TID of stream to delete, if return MTRUE
+ * @param ra RA of stream to delete, if return MTRUE
+ *
+ * @return MTRUE or MFALSE
+ */
+static INLINE t_u8
+wlan_find_stream_to_delete(mlan_private * priv,
+ raListTbl * ptr, int ptr_tid, int *ptid, t_u8 * ra)
+{
+ int tid;
+ t_u8 ret = MFALSE;
+ TxBAStreamTbl *ptx_tbl;
+
+ ENTER();
+
+ if (!
+ (ptx_tbl =
+ (TxBAStreamTbl *) util_peek_list(priv->adapter->pmoal_handle,
+ &priv->tx_ba_stream_tbl_ptr,
+ priv->adapter->callbacks.
+ moal_spin_lock,
+ priv->adapter->callbacks.
+ moal_spin_unlock))) {
+ LEAVE();
+ return ret;
+ }
+
+ tid = priv->aggr_prio_tbl[ptr_tid].ampdu_user;
+
+ while (ptx_tbl != (TxBAStreamTbl *) & priv->tx_ba_stream_tbl_ptr) {
+ if (tid > priv->aggr_prio_tbl[ptx_tbl->tid].ampdu_user) {
+ tid = priv->aggr_prio_tbl[ptx_tbl->tid].ampdu_user;
+ *ptid = ptx_tbl->tid;
+ memcpy(priv->adapter, ra, ptx_tbl->ra, MLAN_MAC_ADDR_LENGTH);
+ ret = MTRUE;
+ }
+
+ ptx_tbl = ptx_tbl->pnext;
+ }
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function checks whether BA stream is setup
+ *
+ * @param priv A pointer to mlan_private
+ * @param ptr A pointer to RA list table
+ * @param tid TID value for ptr
+ *
+ * @return MTRUE or MFALSE
+ */
+static int INLINE
+wlan_is_bastream_setup(mlan_private * priv, raListTbl * ptr, int tid)
+{
+ TxBAStreamTbl *ptx_tbl;
+
+ ENTER();
+
+ if ((ptx_tbl = wlan_11n_get_txbastream_tbl(priv, tid, ptr->ra))) {
+ LEAVE();
+ return IS_BASTREAM_SETUP(ptx_tbl) ? MTRUE : MFALSE;
+ }
+
+ LEAVE();
+ return MFALSE;
+}
+
+/**
+ * @brief This function checks whether 11n is supported
+ *
+ * @param priv A pointer to mlan_private
+ * @param ra Address of the receiver STA
+ *
+ * @return MTRUE or MFALSE
+ */
+static int INLINE
+wlan_is_11n_enabled(mlan_private * priv, t_u8 * ra)
+{
+ int ret = MFALSE;
+ ENTER();
+#ifdef UAP_SUPPORT
+ if (GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_UAP) {
+ if ((!(ra[0] & 0x01)) && (priv->is_11n_enabled))
+ ret = is_station_11n_enabled(priv, ra);
+ }
+#endif /* UAP_SUPPORT */
+ LEAVE();
+ return ret;
+}
+#endif /* !_MLAN_11N_H_ */
diff --git a/drivers/net/wireless/sd8797/mlan/mlan_11n_aggr.c b/drivers/net/wireless/sd8797/mlan/mlan_11n_aggr.c
new file mode 100644
index 000000000000..239be3d67cea
--- /dev/null
+++ b/drivers/net/wireless/sd8797/mlan/mlan_11n_aggr.c
@@ -0,0 +1,508 @@
+/** @file mlan_11n_aggr.c
+ *
+ * @brief This file contains functions for 11n Aggregation.
+ *
+ * Copyright (C) 2008-2011, Marvell International Ltd.
+ *
+ * This software file (the "File") is distributed by Marvell International
+ * Ltd. under the terms of the GNU General Public License Version 2, June 1991
+ * (the "License"). You may use, redistribute and/or modify this File in
+ * accordance with the terms and conditions of the License, a copy of which
+ * is available by writing to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
+ * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
+ *
+ * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
+ * ARE EXPRESSLY DISCLAIMED. The License provides additional details about
+ * this warranty disclaimer.
+ *
+ */
+
+/********************************************************
+Change log:
+ 11/10/2008: initial version
+********************************************************/
+
+#include "mlan.h"
+#include "mlan_join.h"
+#include "mlan_util.h"
+#include "mlan_fw.h"
+#include "mlan_main.h"
+#include "mlan_wmm.h"
+#include "mlan_11n.h"
+#include "mlan_11n_aggr.h"
+#include "mlan_sdio.h"
+
+/********************************************************
+ Local Variables
+********************************************************/
+
+/********************************************************
+ Global Variables
+********************************************************/
+
+/********************************************************
+ Local Functions
+********************************************************/
+
+/**
+ * @brief Aggregate individual packets into one AMSDU packet
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param amsdu_buf A pointer to packet buffer
+ * @param data A pointer to aggregated data packet being formed
+ * @param pkt_len Length of current packet to aggregate
+ * @param pad Pad
+ *
+ * @return Final packet size
+ */
+static int
+wlan_11n_form_amsdu_pkt(pmlan_adapter pmadapter, t_u8 * amsdu_buf, t_u8 * data,
+ int pkt_len, int *pad)
+{
+ int dt_offset, amsdu_buf_offset;
+ Rfc1042Hdr_t snap = {
+ 0xaa, /* LLC DSAP */
+ 0xaa, /* LLC SSAP */
+ 0x03, /* LLC CTRL */
+ {0x00, 0x00, 0x00}, /* SNAP OUI */
+ 0x0000 /* SNAP type */
+ /*
+ * This field will be overwritten
+ * later with ethertype
+ */
+ };
+
+ ENTER();
+
+ memcpy(pmadapter, amsdu_buf, data, (MLAN_MAC_ADDR_LENGTH) * 2);
+ dt_offset = amsdu_buf_offset = (MLAN_MAC_ADDR_LENGTH) * 2;
+
+ snap.snap_type = *(t_u16 *) (data + dt_offset);
+ dt_offset += sizeof(t_u16);
+ *(t_u16 *) (amsdu_buf + amsdu_buf_offset) = mlan_htons(pkt_len +
+ LLC_SNAP_LEN -
+ ((2 *
+ MLAN_MAC_ADDR_LENGTH)
+ + sizeof(t_u16)));
+ amsdu_buf_offset += sizeof(t_u16);
+ memcpy(pmadapter, amsdu_buf + amsdu_buf_offset, &snap, LLC_SNAP_LEN);
+ amsdu_buf_offset += LLC_SNAP_LEN;
+
+ memcpy(pmadapter, amsdu_buf + amsdu_buf_offset, data + dt_offset,
+ pkt_len - dt_offset);
+ *pad =
+ (((pkt_len + LLC_SNAP_LEN) & 3)) ? (4 -
+ (((pkt_len +
+ LLC_SNAP_LEN)) & 3)) : 0;
+
+ LEAVE();
+ return (pkt_len + LLC_SNAP_LEN + *pad);
+}
+
+/**
+ * @brief Add TxPD to AMSDU header
+ *
+ * @param priv A pointer to mlan_private structure
+ * @param mbuf Pointer to buffer where the TxPD will be formed
+ *
+ * @return N/A
+ */
+static void
+wlan_11n_form_amsdu_txpd(mlan_private * priv, mlan_buffer * mbuf)
+{
+ TxPD *ptx_pd;
+ mlan_adapter *pmadapter = priv->adapter;
+
+ ENTER();
+
+ ptx_pd = (TxPD *) mbuf->pbuf;
+ memset(pmadapter, ptx_pd, 0, sizeof(TxPD));
+
+ /*
+ * Original priority has been overwritten
+ */
+ ptx_pd->priority = (t_u8) mbuf->priority;
+ ptx_pd->pkt_delay_2ms = wlan_wmm_compute_driver_packet_delay(priv, mbuf);
+ ptx_pd->bss_num = GET_BSS_NUM(priv);
+ ptx_pd->bss_type = priv->bss_type;
+ /* Always zero as the data is followed by TxPD */
+ ptx_pd->tx_pkt_offset = sizeof(TxPD);
+ ptx_pd->tx_pkt_type = PKT_TYPE_AMSDU;
+
+ if (ptx_pd->tx_control == 0)
+ /* TxCtrl set by user or default */
+ ptx_pd->tx_control = priv->pkt_tx_ctrl;
+
+ endian_convert_TxPD(ptx_pd);
+
+ LEAVE();
+}
+
+/**
+ * @brief Update the TxPktLength field in TxPD after the complete AMSDU
+ * packet is formed
+ *
+ * @param priv A pointer to mlan_private structure
+ * @param mbuf TxPD buffer
+ *
+ * @return N/A
+ */
+static INLINE void
+wlan_11n_update_pktlen_amsdu_txpd(mlan_private * priv, pmlan_buffer mbuf)
+{
+ TxPD *ptx_pd;
+ ENTER();
+
+ ptx_pd = (TxPD *) mbuf->pbuf;
+ ptx_pd->tx_pkt_length =
+ (t_u16) wlan_cpu_to_le16(mbuf->data_len - sizeof(TxPD));
+#ifdef STA_SUPPORT
+ if ((GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_STA) &&
+ (priv->adapter->pps_uapsd_mode)) {
+ if (MTRUE == wlan_check_last_packet_indication(priv)) {
+ priv->adapter->tx_lock_flag = MTRUE;
+ ptx_pd->flags = MRVDRV_TxPD_POWER_MGMT_LAST_PACKET;
+ }
+ }
+#endif /* STA_SUPPORT */
+ LEAVE();
+}
+
+/**
+ * @brief Get number of aggregated packets
+ *
+ * @param data A pointer to packet data
+ * @param total_pkt_len Total packet length
+ *
+ * @return Number of packets
+ */
+static int
+wlan_11n_get_num_aggrpkts(t_u8 * data, int total_pkt_len)
+{
+ int pkt_count = 0, pkt_len, pad;
+
+ ENTER();
+ while (total_pkt_len > 0) {
+ /* Length will be in network format, change it to host */
+ pkt_len = mlan_ntohs((*(t_u16 *) (data + (2 * MLAN_MAC_ADDR_LENGTH))));
+ pad = (((pkt_len + sizeof(Eth803Hdr_t)) & 3)) ?
+ (4 - ((pkt_len + sizeof(Eth803Hdr_t)) & 3)) : 0;
+ data += pkt_len + pad + sizeof(Eth803Hdr_t);
+ total_pkt_len -= pkt_len + pad + sizeof(Eth803Hdr_t);
+ ++pkt_count;
+ }
+ LEAVE();
+ return pkt_count;
+}
+
+/********************************************************
+ Global Functions
+********************************************************/
+
+/**
+ * @brief Deaggregate the received AMSDU packet
+ *
+ * @param priv A pointer to mlan_private structure
+ * @param pmbuf A pointer to aggregated data packet
+ *
+ * @return MLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+mlan_status
+wlan_11n_deaggregate_pkt(mlan_private * priv, pmlan_buffer pmbuf)
+{
+ t_u16 pkt_len;
+ int total_pkt_len;
+ t_u8 *data;
+ int pad;
+ mlan_status ret = MLAN_STATUS_FAILURE;
+ RxPacketHdr_t *prx_pkt;
+ mlan_buffer *daggr_mbuf = MNULL;
+ mlan_adapter *pmadapter = priv->adapter;
+ t_u8 rfc1042_eth_hdr[MLAN_MAC_ADDR_LENGTH] = { 0xaa, 0xaa, 0x03,
+ 0x00, 0x00, 0x00
+ };
+
+ ENTER();
+
+ data = (t_u8 *) (pmbuf->pbuf + pmbuf->data_offset);
+ total_pkt_len = pmbuf->data_len;
+
+ /* Sanity test */
+ if (total_pkt_len > MLAN_RX_DATA_BUF_SIZE) {
+ PRINTM(MERROR, "Total packet length greater than tx buffer"
+ " size %d\n", total_pkt_len);
+ goto done;
+ }
+
+ pmbuf->use_count = wlan_11n_get_num_aggrpkts(data, total_pkt_len);
+
+ while (total_pkt_len > 0) {
+ prx_pkt = (RxPacketHdr_t *) data;
+ /* Length will be in network format, change it to host */
+ pkt_len = mlan_ntohs((*(t_u16 *) (data + (2 * MLAN_MAC_ADDR_LENGTH))));
+ if (pkt_len > total_pkt_len) {
+ PRINTM(MERROR,
+ "Error in packet length: total_pkt_len = %d, pkt_len = %d\n",
+ total_pkt_len, pkt_len);
+ break;
+ }
+
+ pad = (((pkt_len + sizeof(Eth803Hdr_t)) & 3)) ?
+ (4 - ((pkt_len + sizeof(Eth803Hdr_t)) & 3)) : 0;
+
+ total_pkt_len -= pkt_len + pad + sizeof(Eth803Hdr_t);
+
+ if (memcmp(pmadapter, &prx_pkt->rfc1042_hdr,
+ rfc1042_eth_hdr, sizeof(rfc1042_eth_hdr)) == 0) {
+ memmove(pmadapter, data + LLC_SNAP_LEN, data, (2 *
+ MLAN_MAC_ADDR_LENGTH));
+ data += LLC_SNAP_LEN;
+ pkt_len += sizeof(Eth803Hdr_t) - LLC_SNAP_LEN;
+ } else {
+ *(t_u16 *) (data + (2 * MLAN_MAC_ADDR_LENGTH))
+ = (t_u16) 0;
+ pkt_len += sizeof(Eth803Hdr_t);
+ }
+ daggr_mbuf = wlan_alloc_mlan_buffer(pmadapter, pkt_len, 0, MFALSE);
+ if (daggr_mbuf == MNULL) {
+ PRINTM(MERROR, "Error allocating daggr mlan_buffer\n");
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+ daggr_mbuf->bss_index = pmbuf->bss_index;
+ daggr_mbuf->buf_type = pmbuf->buf_type;
+ daggr_mbuf->data_len = pkt_len;
+ daggr_mbuf->in_ts_sec = pmbuf->in_ts_sec;
+ daggr_mbuf->in_ts_usec = pmbuf->in_ts_usec;
+ daggr_mbuf->pparent = pmbuf;
+ daggr_mbuf->priority = pmbuf->priority;
+ memcpy(pmadapter, daggr_mbuf->pbuf + daggr_mbuf->data_offset, data,
+ pkt_len);
+
+#ifdef UAP_SUPPORT
+ if (GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_UAP)
+ ret = wlan_uap_recv_packet(priv, daggr_mbuf);
+ else
+#endif /* UAP_SUPPORT */
+ ret =
+ pmadapter->callbacks.moal_recv_packet(pmadapter->pmoal_handle,
+ daggr_mbuf);
+
+ switch (ret) {
+ case MLAN_STATUS_PENDING:
+ break;
+ case MLAN_STATUS_FAILURE:
+ PRINTM(MERROR, "Deaggr, send to moal failed\n");
+ daggr_mbuf->status_code = MLAN_ERROR_PKT_INVALID;
+ case MLAN_STATUS_SUCCESS:
+ wlan_recv_packet_complete(pmadapter, daggr_mbuf, ret);
+ break;
+ default:
+ break;
+ }
+
+ data += pkt_len + pad;
+ }
+
+ done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Aggregate multiple packets into one single AMSDU packet
+ *
+ * @param priv A pointer to mlan_private structure
+ * @param pra_list Pointer to the RA List table containing the pointers
+ * to packets.
+ * @param headroom Any interface specific headroom that may be need. TxPD
+ * will be formed leaving this headroom.
+ * @param ptrindex Pointer index
+ *
+ * @return Final packet size or MLAN_STATUS_FAILURE
+ */
+int
+wlan_11n_aggregate_pkt(mlan_private * priv, raListTbl * pra_list,
+ int headroom, int ptrindex)
+{
+ int pkt_size = 0;
+ pmlan_adapter pmadapter = priv->adapter;
+ mlan_buffer *pmbuf_aggr, *pmbuf_src;
+ t_u8 *data;
+ int pad = 0;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ t_u32 sec, usec;
+ mlan_tx_param tx_param;
+#ifdef STA_SUPPORT
+ TxPD *ptx_pd = MNULL;
+#endif
+ t_u32 max_amsdu_size = MIN(pra_list->max_amsdu, pmadapter->tx_buf_size);
+ ENTER();
+
+ PRINTM(MDAT_D, "Handling Aggr packet\n");
+
+ if ((pmbuf_src =
+ (pmlan_buffer) util_peek_list(pmadapter->pmoal_handle,
+ &pra_list->buf_head, MNULL, MNULL))) {
+
+ if (!(pmbuf_aggr = wlan_alloc_mlan_buffer(pmadapter,
+ pmadapter->tx_buf_size, 0,
+ MTRUE))) {
+ PRINTM(MERROR, "Error allocating mlan_buffer\n");
+ pmadapter->callbacks.moal_spin_unlock(pmadapter->pmoal_handle,
+ priv->wmm.ra_list_spinlock);
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+
+ data = pmbuf_aggr->pbuf + headroom;
+ pmbuf_aggr->bss_index = pmbuf_src->bss_index;
+ pmbuf_aggr->buf_type = pmbuf_src->buf_type;
+ pmbuf_aggr->priority = pmbuf_src->priority;
+ pmbuf_aggr->pbuf = data;
+ pmbuf_aggr->data_offset = 0;
+
+ /* Form AMSDU */
+ wlan_11n_form_amsdu_txpd(priv, pmbuf_aggr);
+ pkt_size = sizeof(TxPD);
+#ifdef STA_SUPPORT
+ if (GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_STA)
+ ptx_pd = (TxPD *) pmbuf_aggr->pbuf;
+#endif
+ } else {
+ pmadapter->callbacks.moal_spin_unlock(pmadapter->pmoal_handle,
+ priv->wmm.ra_list_spinlock);
+ goto exit;
+ }
+
+ while (pmbuf_src && ((pkt_size + (pmbuf_src->data_len + LLC_SNAP_LEN)
+ + headroom) <= max_amsdu_size)) {
+
+ pmbuf_src = (pmlan_buffer)
+ util_dequeue_list(pmadapter->pmoal_handle, &pra_list->buf_head,
+ MNULL, MNULL);
+
+ pra_list->total_pkts--;
+
+ /* decrement for every PDU taken from the list */
+ priv->wmm.pkts_queued[ptrindex]--;
+ util_scalar_decrement(pmadapter->pmoal_handle,
+ &priv->wmm.tx_pkts_queued, MNULL, MNULL);
+
+ pmadapter->callbacks.moal_spin_unlock(pmadapter->pmoal_handle,
+ priv->wmm.ra_list_spinlock);
+
+ pkt_size += wlan_11n_form_amsdu_pkt(pmadapter,
+ (data + pkt_size),
+ pmbuf_src->pbuf +
+ pmbuf_src->data_offset,
+ pmbuf_src->data_len, &pad);
+
+ DBG_HEXDUMP(MDAT_D, "pmbuf_src", pmbuf_src, sizeof(mlan_buffer));
+ wlan_write_data_complete(pmadapter, pmbuf_src, MLAN_STATUS_SUCCESS);
+
+ pmadapter->callbacks.moal_spin_lock(pmadapter->pmoal_handle,
+ priv->wmm.ra_list_spinlock);
+
+ if (!wlan_is_ralist_valid(priv, pra_list, ptrindex)) {
+ pmadapter->callbacks.moal_spin_unlock(pmadapter->pmoal_handle,
+ priv->wmm.ra_list_spinlock);
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+
+ pmbuf_src =
+ (pmlan_buffer) util_peek_list(pmadapter->pmoal_handle,
+ &pra_list->buf_head, MNULL, MNULL);
+ }
+
+ pmadapter->callbacks.moal_spin_unlock(pmadapter->pmoal_handle,
+ priv->wmm.ra_list_spinlock);
+
+ /* Last AMSDU packet does not need padding */
+ pkt_size -= pad;
+ pmbuf_aggr->data_len = pkt_size;
+ wlan_11n_update_pktlen_amsdu_txpd(priv, pmbuf_aggr);
+ pmbuf_aggr->data_len += headroom;
+ pmbuf_aggr->pbuf = data - headroom;
+ tx_param.next_pkt_len = ((pmbuf_src) ?
+ pmbuf_src->data_len + sizeof(TxPD) : 0);
+
+ ret = wlan_sdio_host_to_card(pmadapter, MLAN_TYPE_DATA,
+ pmbuf_aggr, &tx_param);
+ switch (ret) {
+ case MLAN_STATUS_RESOURCE:
+ pmadapter->callbacks.moal_spin_lock(pmadapter->pmoal_handle,
+ priv->wmm.ra_list_spinlock);
+
+ if (!wlan_is_ralist_valid(priv, pra_list, ptrindex)) {
+ pmadapter->callbacks.moal_spin_unlock(pmadapter->pmoal_handle,
+ priv->wmm.ra_list_spinlock);
+ pmbuf_aggr->status_code = MLAN_ERROR_PKT_INVALID;
+ wlan_write_data_complete(pmadapter, pmbuf_aggr,
+ MLAN_STATUS_FAILURE);
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+#ifdef STA_SUPPORT
+ /* reset tx_lock_flag */
+ if ((GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_STA) &&
+ pmadapter->pps_uapsd_mode && (pmadapter->tx_lock_flag == MTRUE)) {
+ pmadapter->tx_lock_flag = MFALSE;
+ ptx_pd->flags = 0;
+ }
+#endif
+ util_enqueue_list_head(pmadapter->pmoal_handle, &pra_list->buf_head,
+ (pmlan_linked_list) pmbuf_aggr, MNULL, MNULL);
+
+ pra_list->total_pkts++;
+
+ /* add back only one: aggregated packet is requeued as one */
+ priv->wmm.pkts_queued[ptrindex]++;
+ util_scalar_increment(pmadapter->pmoal_handle,
+ &priv->wmm.tx_pkts_queued, MNULL, MNULL);
+ pmbuf_aggr->flags |= MLAN_BUF_FLAG_REQUEUED_PKT;
+ pmadapter->callbacks.moal_spin_unlock(pmadapter->pmoal_handle,
+ priv->wmm.ra_list_spinlock);
+ PRINTM(MINFO, "MLAN_STATUS_RESOURCE is returned\n");
+ pmbuf_aggr->status_code = MLAN_ERROR_PKT_INVALID;
+ break;
+ case MLAN_STATUS_FAILURE:
+ pmadapter->data_sent = MFALSE;
+ PRINTM(MERROR, "Error: host_to_card failed: 0x%X\n", ret);
+ pmbuf_aggr->status_code = MLAN_ERROR_DATA_TX_FAIL;
+ pmadapter->dbg.num_tx_host_to_card_failure++;
+ wlan_write_data_complete(pmadapter, pmbuf_aggr, ret);
+ goto exit;
+ case MLAN_STATUS_PENDING:
+ pmadapter->data_sent = MFALSE;
+ break;
+ case MLAN_STATUS_SUCCESS:
+ wlan_write_data_complete(pmadapter, pmbuf_aggr, ret);
+ break;
+ default:
+ break;
+ }
+ if (ret != MLAN_STATUS_RESOURCE) {
+ pmadapter->callbacks.moal_spin_lock(pmadapter->pmoal_handle,
+ priv->wmm.ra_list_spinlock);
+ if (wlan_is_ralist_valid(priv, pra_list, ptrindex)) {
+ priv->wmm.packets_out[ptrindex]++;
+ priv->wmm.tid_tbl_ptr[ptrindex].ra_list_curr = pra_list;
+ }
+ pmadapter->bssprio_tbl[priv->bss_priority].bssprio_cur =
+ pmadapter->bssprio_tbl[priv->bss_priority].bssprio_cur->pnext;
+ pmadapter->callbacks.moal_spin_unlock(pmadapter->pmoal_handle,
+ priv->wmm.ra_list_spinlock);
+ }
+ pmadapter->callbacks.moal_get_system_time(pmadapter->pmoal_handle, &sec,
+ &usec);
+ PRINTM_NETINTF(MDATA, priv);
+ PRINTM(MDATA, "%lu.%06lu : Data => FW\n", sec, usec);
+
+ exit:
+ LEAVE();
+ return (pkt_size + headroom);
+}
diff --git a/drivers/net/wireless/sd8797/mlan/mlan_11n_aggr.h b/drivers/net/wireless/sd8797/mlan/mlan_11n_aggr.h
new file mode 100644
index 000000000000..ef8108a764c0
--- /dev/null
+++ b/drivers/net/wireless/sd8797/mlan/mlan_11n_aggr.h
@@ -0,0 +1,37 @@
+/** @file mlan_11n_aggr.h
+ *
+ * @brief This file contains related macros, enum, and struct
+ * of 11n aggregation functionalities
+ *
+ * Copyright (C) 2008-2011, Marvell International Ltd.
+ *
+ * This software file (the "File") is distributed by Marvell International
+ * Ltd. under the terms of the GNU General Public License Version 2, June 1991
+ * (the "License"). You may use, redistribute and/or modify this File in
+ * accordance with the terms and conditions of the License, a copy of which
+ * is available by writing to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
+ * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
+ *
+ * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
+ * ARE EXPRESSLY DISCLAIMED. The License provides additional details about
+ * this warranty disclaimer.
+ *
+ */
+
+/********************************************************
+Change log:
+ 11/10/2008: initial version
+********************************************************/
+
+#ifndef _MLAN_11N_AGGR_H_
+#define _MLAN_11N_AGGR_H_
+
+/** Aggregate 11N packets */
+mlan_status wlan_11n_deaggregate_pkt(pmlan_private priv, pmlan_buffer pmbuf);
+/** Deaggregate 11N packets */
+int wlan_11n_aggregate_pkt(mlan_private * priv, raListTbl * ptr,
+ int headroom, int ptrindex);
+
+#endif /* !_MLAN_11N_AGGR_H_ */
diff --git a/drivers/net/wireless/sd8797/mlan/mlan_11n_rxreorder.c b/drivers/net/wireless/sd8797/mlan/mlan_11n_rxreorder.c
new file mode 100644
index 000000000000..cabd78b9017f
--- /dev/null
+++ b/drivers/net/wireless/sd8797/mlan/mlan_11n_rxreorder.c
@@ -0,0 +1,1135 @@
+/** @file mlan_11n_rxreorder.c
+ *
+ * @brief This file contains the handling of RxReordering in wlan
+ * driver.
+ *
+ * Copyright (C) 2008-2011, Marvell International Ltd.
+ *
+ * This software file (the "File") is distributed by Marvell International
+ * Ltd. under the terms of the GNU General Public License Version 2, June 1991
+ * (the "License"). You may use, redistribute and/or modify this File in
+ * accordance with the terms and conditions of the License, a copy of which
+ * is available by writing to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
+ * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
+ *
+ * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
+ * ARE EXPRESSLY DISCLAIMED. The License provides additional details about
+ * this warranty disclaimer.
+ */
+
+/********************************************************
+Change log:
+ 11/10/2008: initial version
+********************************************************/
+
+#include "mlan.h"
+#include "mlan_join.h"
+#include "mlan_util.h"
+#include "mlan_fw.h"
+#include "mlan_main.h"
+#include "mlan_wmm.h"
+#include "mlan_11n.h"
+#include "mlan_11n_rxreorder.h"
+
+/********************************************************
+ Local Variables
+********************************************************/
+
+/********************************************************
+ Global Variables
+********************************************************/
+
+/********************************************************
+ Local Functions
+********************************************************/
+/**
+ * @brief This function will dispatch amsdu packet and
+ * forward it to kernel/upper layer
+ *
+ * @param priv A pointer to mlan_private
+ * @param pmbuf A pointer to the received buffer
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+static mlan_status
+wlan_11n_dispatch_amsdu_pkt(mlan_private * priv, pmlan_buffer pmbuf)
+{
+ RxPD *prx_pd;
+ prx_pd = (RxPD *) (pmbuf->pbuf + pmbuf->data_offset);
+
+ ENTER();
+ if (prx_pd->rx_pkt_type == PKT_TYPE_AMSDU) {
+ pmbuf->data_len = prx_pd->rx_pkt_length;
+ pmbuf->data_offset += prx_pd->rx_pkt_offset;
+ wlan_11n_deaggregate_pkt(priv, pmbuf);
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+ }
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+}
+
+/**
+ * @brief This function will process the rx packet and
+ * forward it to kernel/upper layer
+ *
+ * @param priv A pointer to mlan_private
+ * @param payload A pointer to rx packet payload
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+static mlan_status
+wlan_11n_dispatch_pkt(t_void * priv, t_void * payload)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+#ifdef STA_SUPPORT
+ pmlan_adapter pmadapter = ((pmlan_private) priv)->adapter;
+#endif
+ ENTER();
+ if (payload == (t_void *) RX_PKT_DROPPED_IN_FW) {
+ LEAVE();
+ return ret;
+ }
+#ifdef UAP_SUPPORT
+ if (GET_BSS_ROLE((mlan_private *) priv) == MLAN_BSS_ROLE_UAP) {
+ if (MLAN_STATUS_SUCCESS ==
+ wlan_11n_dispatch_amsdu_pkt((mlan_private *) priv,
+ (pmlan_buffer) payload)) {
+ LEAVE();
+ return ret;
+ }
+ ret = wlan_process_uap_rx_packet(priv, (pmlan_buffer) payload);
+ LEAVE();
+ return ret;
+ }
+#endif /* UAP_SUPPORT */
+
+#ifdef STA_SUPPORT
+ if (MLAN_STATUS_SUCCESS ==
+ wlan_11n_dispatch_amsdu_pkt((mlan_private *) priv,
+ (pmlan_buffer) payload)) {
+ LEAVE();
+ return ret;
+ }
+ ret = wlan_process_rx_packet(pmadapter, (pmlan_buffer) payload);
+#endif /* STA_SUPPORT */
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function restarts the reordering timeout timer
+ *
+ * @param pmadapter A pointer to mlan_adapter
+ * @param rx_reor_tbl_ptr A pointer to structure RxReorderTbl
+ *
+ * @return N/A
+ */
+static void
+mlan_11n_rxreorder_timer_restart(pmlan_adapter pmadapter,
+ RxReorderTbl * rx_reor_tbl_ptr)
+{
+ ENTER();
+ if (rx_reor_tbl_ptr->timer_context.timer_is_set)
+ pmadapter->callbacks.moal_stop_timer(pmadapter->pmoal_handle,
+ rx_reor_tbl_ptr->timer_context.
+ timer);
+
+ pmadapter->callbacks.moal_start_timer(pmadapter->pmoal_handle,
+ rx_reor_tbl_ptr->timer_context.timer,
+ MFALSE,
+ (rx_reor_tbl_ptr->win_size
+ * MIN_FLUSH_TIMER_MS));
+
+ rx_reor_tbl_ptr->timer_context.timer_is_set = MTRUE;
+ LEAVE();
+}
+
+/**
+ * @brief This function dispatches all the packets in the buffer.
+ * There could be holes in the buffer.
+ *
+ * @param priv A pointer to mlan_private
+ * @param rx_reor_tbl_ptr A pointer to structure RxReorderTbl
+ * @param start_win Start window
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+static mlan_status
+wlan_11n_dispatch_pkt_until_start_win(t_void * priv,
+ RxReorderTbl * rx_reor_tbl_ptr,
+ int start_win)
+{
+ int no_pkt_to_send, i, xchg;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ void *rx_tmp_ptr = MNULL;
+ mlan_private *pmpriv = (mlan_private *) priv;
+
+ ENTER();
+
+ no_pkt_to_send = (start_win > rx_reor_tbl_ptr->start_win) ?
+ MIN((start_win - rx_reor_tbl_ptr->start_win),
+ rx_reor_tbl_ptr->win_size) : rx_reor_tbl_ptr->win_size;
+
+ for (i = 0; i < no_pkt_to_send; ++i) {
+ pmpriv->adapter->callbacks.moal_spin_lock(pmpriv->adapter->pmoal_handle,
+ pmpriv->rx_pkt_lock);
+ rx_tmp_ptr = MNULL;
+ if (rx_reor_tbl_ptr->rx_reorder_ptr[i]) {
+ rx_tmp_ptr = rx_reor_tbl_ptr->rx_reorder_ptr[i];
+ rx_reor_tbl_ptr->rx_reorder_ptr[i] = MNULL;
+ }
+ pmpriv->adapter->callbacks.moal_spin_unlock(pmpriv->adapter->
+ pmoal_handle,
+ pmpriv->rx_pkt_lock);
+ if (rx_tmp_ptr)
+ wlan_11n_dispatch_pkt(priv, rx_tmp_ptr);
+ }
+
+ pmpriv->adapter->callbacks.moal_spin_lock(pmpriv->adapter->pmoal_handle,
+ pmpriv->rx_pkt_lock);
+ /*
+ * We don't have a circular buffer, hence use rotation to simulate
+ * circular buffer
+ */
+ xchg = rx_reor_tbl_ptr->win_size - no_pkt_to_send;
+ for (i = 0; i < xchg; ++i) {
+ rx_reor_tbl_ptr->rx_reorder_ptr[i] =
+ rx_reor_tbl_ptr->rx_reorder_ptr[no_pkt_to_send + i];
+ rx_reor_tbl_ptr->rx_reorder_ptr[no_pkt_to_send + i] = MNULL;
+ }
+
+ rx_reor_tbl_ptr->start_win = start_win;
+ pmpriv->adapter->callbacks.moal_spin_unlock(pmpriv->adapter->pmoal_handle,
+ pmpriv->rx_pkt_lock);
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function will display the rxReorder table
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param rx_reor_tbl_ptr A pointer to structure RxReorderTbl
+ *
+ * @return N/A
+ */
+static t_void
+wlan_11n_display_tbl_ptr(pmlan_adapter pmadapter,
+ RxReorderTbl * rx_reor_tbl_ptr)
+{
+ ENTER();
+
+ DBG_HEXDUMP(MDAT_D, "Reorder ptr", rx_reor_tbl_ptr->rx_reorder_ptr,
+ sizeof(t_void *) * rx_reor_tbl_ptr->win_size);
+
+ LEAVE();
+}
+
+/**
+ * @brief This function will dispatch all packets sequentially
+ * from start_win until a hole is found and adjust the
+ * start_win appropriately
+ *
+ * @param priv A pointer to mlan_private
+ * @param rx_reor_tbl_ptr A pointer to structure RxReorderTbl
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+static mlan_status
+wlan_11n_scan_and_dispatch(t_void * priv, RxReorderTbl * rx_reor_tbl_ptr)
+{
+ int i, j, xchg;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ void *rx_tmp_ptr = MNULL;
+ mlan_private *pmpriv = (mlan_private *) priv;
+
+ ENTER();
+
+ for (i = 0; i < rx_reor_tbl_ptr->win_size; ++i) {
+ pmpriv->adapter->callbacks.moal_spin_lock(pmpriv->adapter->pmoal_handle,
+ pmpriv->rx_pkt_lock);
+ if (!rx_reor_tbl_ptr->rx_reorder_ptr[i]) {
+ pmpriv->adapter->callbacks.moal_spin_unlock(pmpriv->adapter->
+ pmoal_handle,
+ pmpriv->rx_pkt_lock);
+ break;
+ }
+ rx_tmp_ptr = rx_reor_tbl_ptr->rx_reorder_ptr[i];
+ rx_reor_tbl_ptr->rx_reorder_ptr[i] = MNULL;
+ pmpriv->adapter->callbacks.moal_spin_unlock(pmpriv->adapter->
+ pmoal_handle,
+ pmpriv->rx_pkt_lock);
+ wlan_11n_dispatch_pkt(priv, rx_tmp_ptr);
+ }
+
+ pmpriv->adapter->callbacks.moal_spin_lock(pmpriv->adapter->pmoal_handle,
+ pmpriv->rx_pkt_lock);
+ /*
+ * We don't have a circular buffer, hence use rotation to simulate
+ * circular buffer
+ */
+ if (i > 0) {
+ xchg = rx_reor_tbl_ptr->win_size - i;
+ for (j = 0; j < xchg; ++j) {
+ rx_reor_tbl_ptr->rx_reorder_ptr[j] =
+ rx_reor_tbl_ptr->rx_reorder_ptr[i + j];
+ rx_reor_tbl_ptr->rx_reorder_ptr[i + j] = MNULL;
+ }
+ }
+
+ rx_reor_tbl_ptr->start_win = (rx_reor_tbl_ptr->start_win + i)
+ & (MAX_TID_VALUE - 1);
+
+ pmpriv->adapter->callbacks.moal_spin_unlock(pmpriv->adapter->pmoal_handle,
+ pmpriv->rx_pkt_lock);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function delete rxreorder table's entry
+ * and free the memory
+ *
+ * @param priv A pointer to mlan_private
+ * @param rx_reor_tbl_ptr A pointer to structure RxReorderTbl
+ *
+ * @return N/A
+ */
+static t_void
+wlan_11n_delete_rxreorder_tbl_entry(mlan_private * priv,
+ RxReorderTbl * rx_reor_tbl_ptr)
+{
+ pmlan_adapter pmadapter = priv->adapter;
+
+ ENTER();
+
+ if (!rx_reor_tbl_ptr) {
+ LEAVE();
+ return;
+ }
+
+ wlan_11n_dispatch_pkt_until_start_win(priv, rx_reor_tbl_ptr,
+ (rx_reor_tbl_ptr->start_win +
+ rx_reor_tbl_ptr->win_size)
+ & (MAX_TID_VALUE - 1));
+
+ if (rx_reor_tbl_ptr->timer_context.timer) {
+ if (rx_reor_tbl_ptr->timer_context.timer_is_set)
+ priv->adapter->callbacks.moal_stop_timer(pmadapter->pmoal_handle,
+ rx_reor_tbl_ptr->timer_context.
+ timer);
+ priv->adapter->callbacks.moal_free_timer(pmadapter->pmoal_handle,
+ rx_reor_tbl_ptr->timer_context.
+ timer);
+ }
+
+ PRINTM(MDAT_D, "Delete rx_reor_tbl_ptr: %p\n", rx_reor_tbl_ptr);
+ util_unlink_list(pmadapter->pmoal_handle,
+ &priv->rx_reorder_tbl_ptr,
+ (pmlan_linked_list) rx_reor_tbl_ptr,
+ pmadapter->callbacks.moal_spin_lock,
+ pmadapter->callbacks.moal_spin_unlock);
+
+ pmadapter->callbacks.moal_mfree(pmadapter->pmoal_handle,
+ (t_u8 *) rx_reor_tbl_ptr->rx_reorder_ptr);
+ pmadapter->callbacks.moal_mfree(pmadapter->pmoal_handle,
+ (t_u8 *) rx_reor_tbl_ptr);
+
+ LEAVE();
+}
+
+/**
+ * @brief This function returns the last used sequence number
+ *
+ * @param rx_reorder_tbl_ptr A pointer to structure RxReorderTbl
+ *
+ * @return Last used sequence number
+ */
+static int
+wlan_11n_find_last_seqnum(RxReorderTbl * rx_reorder_tbl_ptr)
+{
+ int i;
+
+ ENTER();
+ for (i = (rx_reorder_tbl_ptr->win_size - 1); i >= 0; --i) {
+ if (rx_reorder_tbl_ptr->rx_reorder_ptr[i]) {
+ LEAVE();
+ return i;
+ }
+ }
+ LEAVE();
+ return -1;
+}
+
+/**
+ * @brief This function flushes all data
+ *
+ * @param context Reorder context pointer
+ *
+ * @return N/A
+ */
+static t_void
+wlan_flush_data(t_void * context)
+{
+ reorder_tmr_cnxt_t *reorder_cnxt = (reorder_tmr_cnxt_t *) context;
+ int startWin;
+
+ ENTER();
+ reorder_cnxt->timer_is_set = MFALSE;
+ wlan_11n_display_tbl_ptr(reorder_cnxt->priv->adapter, reorder_cnxt->ptr);
+
+ if ((startWin = wlan_11n_find_last_seqnum(reorder_cnxt->ptr)) >= 0) {
+ PRINTM(MINFO, "Flush data %d\n", startWin);
+ wlan_11n_dispatch_pkt_until_start_win(reorder_cnxt->priv,
+ reorder_cnxt->ptr,
+ ((reorder_cnxt->ptr->start_win +
+ startWin + 1) & (MAX_TID_VALUE -
+ 1)));
+ }
+
+ wlan_11n_display_tbl_ptr(reorder_cnxt->priv->adapter, reorder_cnxt->ptr);
+ LEAVE();
+}
+
+/**
+ * @brief This function will create a entry in rx reordering table for the
+ * given ta/tid and will initialize it with seq_num, win_size
+ *
+ * @param priv A pointer to mlan_private
+ * @param ta ta to find in reordering table
+ * @param tid tid to find in reordering table
+ * @param win_size win_size for the give ta/tid pair.
+ * @param seq_num Starting sequence number for current entry.
+ *
+ * @return N/A
+ */
+static t_void
+wlan_11n_create_rxreorder_tbl(mlan_private * priv, t_u8 * ta, int tid,
+ int win_size, int seq_num)
+{
+ int i;
+ pmlan_adapter pmadapter = priv->adapter;
+ RxReorderTbl *rx_reor_tbl_ptr, *new_node;
+ sta_node *sta_ptr = MNULL;
+ t_u16 last_seq = 0;
+
+ ENTER();
+
+ /*
+ * If we get a TID, ta pair which is already present dispatch all the
+ * the packets and move the window size until the ssn
+ */
+ if ((rx_reor_tbl_ptr = wlan_11n_get_rxreorder_tbl(priv, tid, ta))) {
+ wlan_11n_dispatch_pkt_until_start_win(priv, rx_reor_tbl_ptr, seq_num);
+ } else {
+ PRINTM(MDAT_D, "%s: seq_num %d, tid %d, ta %02x:%02x:%02x:%02x:"
+ "%02x:%02x, win_size %d\n", __FUNCTION__,
+ seq_num, tid, ta[0], ta[1], ta[2], ta[3],
+ ta[4], ta[5], win_size);
+ if (pmadapter->callbacks.
+ moal_malloc(pmadapter->pmoal_handle, sizeof(RxReorderTbl),
+ MLAN_MEM_DEF, (t_u8 **) & new_node)) {
+ PRINTM(MERROR, "Rx reorder memory allocation failed\n");
+ LEAVE();
+ return;
+ }
+
+ util_init_list((pmlan_linked_list) new_node);
+ new_node->tid = tid;
+ memcpy(pmadapter, new_node->ta, ta, MLAN_MAC_ADDR_LENGTH);
+ new_node->start_win = seq_num;
+ if (queuing_ra_based(priv)) {
+ // TODO for adhoc
+ if (GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_UAP) {
+ if ((sta_ptr = wlan_get_station_entry(priv, ta)))
+ last_seq = sta_ptr->rx_seq[tid];
+ }
+ PRINTM(MINFO, "UAP/ADHOC:last_seq=%d start_win=%d\n", last_seq,
+ new_node->start_win);
+ } else {
+ last_seq = priv->rx_seq[tid];
+ }
+ if ((last_seq != DEFAULT_SEQ_NUM) && (last_seq >= new_node->start_win)) {
+ PRINTM(MDAT_D, "Update start_win: last_seq=%d, start_win=%d\n",
+ last_seq, new_node->start_win);
+ new_node->start_win = last_seq + 1;
+ }
+ new_node->win_size = win_size;
+
+ if (pmadapter->callbacks.
+ moal_malloc(pmadapter->pmoal_handle, sizeof(t_void *) * win_size,
+ MLAN_MEM_DEF, (t_u8 **) & new_node->rx_reorder_ptr)) {
+ PRINTM(MERROR, "Rx reorder table memory allocation" "failed\n");
+ pmadapter->callbacks.moal_mfree(pmadapter->pmoal_handle,
+ (t_u8 *) new_node);
+ LEAVE();
+ return;
+ }
+
+ PRINTM(MDAT_D, "Create ReorderPtr: %p\n", new_node);
+ new_node->timer_context.ptr = new_node;
+ new_node->timer_context.priv = priv;
+ new_node->timer_context.timer_is_set = MFALSE;
+ new_node->ba_status = BA_STREAM_SETUP_INPROGRESS;
+
+ pmadapter->callbacks.moal_init_timer(pmadapter->pmoal_handle,
+ &new_node->timer_context.timer,
+ wlan_flush_data,
+ &new_node->timer_context);
+
+ for (i = 0; i < win_size; ++i)
+ new_node->rx_reorder_ptr[i] = MNULL;
+
+ util_enqueue_list_tail(pmadapter->pmoal_handle,
+ &priv->rx_reorder_tbl_ptr,
+ (pmlan_linked_list) new_node,
+ pmadapter->callbacks.moal_spin_lock,
+ pmadapter->callbacks.moal_spin_unlock);
+ }
+
+ LEAVE();
+}
+
+/********************************************************
+ Global Functions
+********************************************************/
+
+/**
+ * @brief This function will return the pointer to a entry in rx reordering
+ * table which matches the give TA/TID pair
+ *
+ * @param priv A pointer to mlan_private
+ * @param ta ta to find in reordering table
+ * @param tid tid to find in reordering table
+ *
+ * @return A pointer to structure RxReorderTbl
+ */
+RxReorderTbl *
+wlan_11n_get_rxreorder_tbl(mlan_private * priv, int tid, t_u8 * ta)
+{
+ RxReorderTbl *rx_reor_tbl_ptr;
+
+ ENTER();
+
+ if (!
+ (rx_reor_tbl_ptr =
+ (RxReorderTbl *) util_peek_list(priv->adapter->pmoal_handle,
+ &priv->rx_reorder_tbl_ptr,
+ priv->adapter->callbacks.
+ moal_spin_lock,
+ priv->adapter->callbacks.
+ moal_spin_unlock))) {
+ LEAVE();
+ return MNULL;
+ }
+
+ while (rx_reor_tbl_ptr != (RxReorderTbl *) & priv->rx_reorder_tbl_ptr) {
+ if ((!memcmp
+ (priv->adapter, rx_reor_tbl_ptr->ta, ta, MLAN_MAC_ADDR_LENGTH)) &&
+ (rx_reor_tbl_ptr->tid == tid)) {
+ LEAVE();
+ return rx_reor_tbl_ptr;
+ }
+
+ rx_reor_tbl_ptr = rx_reor_tbl_ptr->pnext;
+ }
+
+ LEAVE();
+ return MNULL;
+}
+
+/**
+ * @brief This function prepares command for adding a block ack
+ * request.
+ *
+ * @param priv A pointer to mlan_private structure
+ * @param cmd A pointer to HostCmd_DS_COMMAND structure
+ * @param pdata_buf A pointer to data buffer
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+mlan_status
+wlan_cmd_11n_addba_req(mlan_private * priv,
+ HostCmd_DS_COMMAND * cmd, t_void * pdata_buf)
+{
+ HostCmd_DS_11N_ADDBA_REQ *padd_ba_req = (HostCmd_DS_11N_ADDBA_REQ *)
+ & cmd->params.add_ba_req;
+ ENTER();
+
+ cmd->command = wlan_cpu_to_le16(HostCmd_CMD_11N_ADDBA_REQ);
+ cmd->size = wlan_cpu_to_le16(sizeof(HostCmd_DS_11N_ADDBA_REQ) + S_DS_GEN);
+
+ memcpy(priv->adapter, padd_ba_req, pdata_buf,
+ sizeof(HostCmd_DS_11N_ADDBA_REQ));
+ padd_ba_req->block_ack_param_set =
+ wlan_cpu_to_le16(padd_ba_req->block_ack_param_set);
+ padd_ba_req->block_ack_tmo = wlan_cpu_to_le16(padd_ba_req->block_ack_tmo);
+ padd_ba_req->ssn = wlan_cpu_to_le16(padd_ba_req->ssn);
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function prepares command for adding a block ack
+ * response.
+ *
+ * @param priv A pointer to mlan_private structure
+ * @param cmd A pointer to HostCmd_DS_COMMAND structure
+ * @param pdata_buf A pointer to data buffer
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+mlan_status
+wlan_cmd_11n_addba_rspgen(mlan_private * priv,
+ HostCmd_DS_COMMAND * cmd, void *pdata_buf)
+{
+ HostCmd_DS_11N_ADDBA_RSP *padd_ba_rsp = (HostCmd_DS_11N_ADDBA_RSP *)
+ & cmd->params.add_ba_rsp;
+ HostCmd_DS_11N_ADDBA_REQ *pevt_addba_req =
+ (HostCmd_DS_11N_ADDBA_REQ *) pdata_buf;
+ t_u8 tid = 0;
+ int win_size = 0;
+
+ ENTER();
+
+ pevt_addba_req->block_ack_param_set =
+ wlan_le16_to_cpu(pevt_addba_req->block_ack_param_set);
+ pevt_addba_req->block_ack_tmo =
+ wlan_le16_to_cpu(pevt_addba_req->block_ack_tmo);
+ pevt_addba_req->ssn = wlan_le16_to_cpu(pevt_addba_req->ssn);
+
+ cmd->command = wlan_cpu_to_le16(HostCmd_CMD_11N_ADDBA_RSP);
+ cmd->size = wlan_cpu_to_le16(sizeof(HostCmd_DS_11N_ADDBA_RSP) + S_DS_GEN);
+
+ memcpy(priv->adapter, padd_ba_rsp->peer_mac_addr,
+ pevt_addba_req->peer_mac_addr, MLAN_MAC_ADDR_LENGTH);
+ padd_ba_rsp->dialog_token = pevt_addba_req->dialog_token;
+ padd_ba_rsp->block_ack_tmo =
+ wlan_cpu_to_le16(pevt_addba_req->block_ack_tmo);
+ padd_ba_rsp->ssn = wlan_cpu_to_le16(pevt_addba_req->ssn);
+
+ padd_ba_rsp->block_ack_param_set = pevt_addba_req->block_ack_param_set;
+ tid = (padd_ba_rsp->block_ack_param_set & BLOCKACKPARAM_TID_MASK)
+ >> BLOCKACKPARAM_TID_POS;
+ if (priv->addba_reject[tid]
+#ifdef STA_SUPPORT
+ || ((GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_STA)
+ && priv->wps.session_enable)
+#endif
+#ifdef UAP_SUPPORT
+ || ((GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_UAP)
+ && (priv->adapter->pending_bridge_pkts > RX_LOW_THRESHOLD))
+#endif
+ )
+ padd_ba_rsp->status_code = wlan_cpu_to_le16(ADDBA_RSP_STATUS_DECLINED);
+ else
+ padd_ba_rsp->status_code = wlan_cpu_to_le16(ADDBA_RSP_STATUS_ACCEPT);
+ padd_ba_rsp->block_ack_param_set &= ~BLOCKACKPARAM_WINSIZE_MASK;
+ if (!priv->add_ba_param.rx_amsdu ||
+ (priv->aggr_prio_tbl[tid].amsdu == BA_STREAM_NOT_ALLOWED))
+ /* We do not support AMSDU inside AMPDU, hence reset the bit */
+ padd_ba_rsp->block_ack_param_set &= ~BLOCKACKPARAM_AMSDU_SUPP_MASK;
+
+ padd_ba_rsp->block_ack_param_set |= (priv->add_ba_param.rx_win_size <<
+ BLOCKACKPARAM_WINSIZE_POS);
+ win_size = (padd_ba_rsp->block_ack_param_set & BLOCKACKPARAM_WINSIZE_MASK)
+ >> BLOCKACKPARAM_WINSIZE_POS;
+ padd_ba_rsp->block_ack_param_set =
+ wlan_cpu_to_le16(padd_ba_rsp->block_ack_param_set);
+
+ if (padd_ba_rsp->status_code == wlan_cpu_to_le16(ADDBA_RSP_STATUS_ACCEPT))
+ wlan_11n_create_rxreorder_tbl(priv, pevt_addba_req->peer_mac_addr, tid,
+ win_size, pevt_addba_req->ssn);
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function prepares command for deleting a block ack
+ * request.
+ *
+ * @param priv A pointer to mlan_private structure
+ * @param cmd A pointer to HostCmd_DS_COMMAND structure
+ * @param pdata_buf A pointer to data buffer
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+mlan_status
+wlan_cmd_11n_delba(mlan_private * priv,
+ HostCmd_DS_COMMAND * cmd, void *pdata_buf)
+{
+ HostCmd_DS_11N_DELBA *pdel_ba = (HostCmd_DS_11N_DELBA *)
+ & cmd->params.del_ba;
+
+ ENTER();
+
+ cmd->command = wlan_cpu_to_le16(HostCmd_CMD_11N_DELBA);
+ cmd->size = wlan_cpu_to_le16(sizeof(HostCmd_DS_11N_DELBA) + S_DS_GEN);
+
+ memcpy(priv->adapter, pdel_ba, pdata_buf, sizeof(HostCmd_DS_11N_DELBA));
+ pdel_ba->del_ba_param_set = wlan_cpu_to_le16(pdel_ba->del_ba_param_set);
+ pdel_ba->reason_code = wlan_cpu_to_le16(pdel_ba->reason_code);
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function will identify if RxReodering is needed for the packet
+ * and will do the reordering if required before sending it to kernel
+ *
+ * @param priv A pointer to mlan_private
+ * @param seq_num Seqence number of the current packet
+ * @param tid Tid of the current packet
+ * @param ta Transmiter address of the current packet
+ * @param pkt_type Packetype for the current packet (to identify if its a BAR)
+ * @param payload Pointer to the payload
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status
+mlan_11n_rxreorder_pkt(void *priv, t_u16 seq_num, t_u16 tid,
+ t_u8 * ta, t_u8 pkt_type, void *payload)
+{
+ RxReorderTbl *rx_reor_tbl_ptr;
+ int prev_start_win, start_win, end_win, win_size;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ pmlan_adapter pmadapter = ((mlan_private *) priv)->adapter;
+
+ ENTER();
+
+ if (!
+ (rx_reor_tbl_ptr =
+ wlan_11n_get_rxreorder_tbl((mlan_private *) priv, tid, ta))) {
+ if (pkt_type != PKT_TYPE_BAR)
+ wlan_11n_dispatch_pkt(priv, payload);
+
+ LEAVE();
+ return ret;
+
+ } else {
+ if ((pkt_type == PKT_TYPE_AMSDU) && !rx_reor_tbl_ptr->amsdu) {
+ wlan_11n_dispatch_pkt(priv, payload);
+ LEAVE();
+ return ret;
+ }
+ if (pkt_type == PKT_TYPE_BAR)
+ PRINTM(MDAT_D, "BAR ");
+ if (pkt_type == PKT_TYPE_AMSDU)
+ PRINTM(MDAT_D, "AMSDU ");
+
+ prev_start_win = start_win = rx_reor_tbl_ptr->start_win;
+ win_size = rx_reor_tbl_ptr->win_size;
+ end_win = ((start_win + win_size) - 1) & (MAX_TID_VALUE - 1);
+
+ PRINTM(MDAT_D,
+ "TID %d, TA %02x:%02x:%02x:%02x:%02x:%02x\n",
+ tid, ta[0], ta[1], ta[2], ta[3], ta[4], ta[5]);
+ PRINTM(MDAT_D,
+ "1:seq_num %d start_win %d win_size %d end_win %d\n",
+ seq_num, start_win, win_size, end_win);
+ /*
+ * If seq_num is less then starting win then ignore and drop
+ * the packet
+ */
+ if ((start_win + TWOPOW11) > (MAX_TID_VALUE - 1)) { /* Wrap */
+ if (seq_num >= ((start_win + (TWOPOW11)) &
+ (MAX_TID_VALUE - 1)) && (seq_num < start_win)) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ } else if ((seq_num < start_win) ||
+ (seq_num > (start_win + (TWOPOW11)))) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ /*
+ * If this packet is a BAR we adjust seq_num as
+ * WinStart = seq_num
+ */
+ if (pkt_type == PKT_TYPE_BAR)
+ seq_num = ((seq_num + win_size) - 1) & (MAX_TID_VALUE - 1);
+
+ PRINTM(MDAT_D,
+ "2:seq_num %d start_win %d win_size %d end_win %d\n",
+ seq_num, start_win, win_size, end_win);
+
+ if (((end_win < start_win) &&
+ (seq_num < (TWOPOW11 - (MAX_TID_VALUE - start_win))) &&
+ (seq_num > end_win))
+ || ((end_win > start_win) &&
+ ((seq_num > end_win) || (seq_num < start_win)))) {
+
+ end_win = seq_num;
+ if (((seq_num - win_size) + 1) >= 0)
+ start_win = (end_win - win_size) + 1;
+ else
+ start_win = (MAX_TID_VALUE - (win_size - seq_num)) + 1;
+
+ if ((ret = wlan_11n_dispatch_pkt_until_start_win(priv,
+ rx_reor_tbl_ptr,
+ start_win))) {
+ goto done;
+ }
+ }
+
+ PRINTM(MDAT_D, "3:seq_num %d start_win %d win_size %d"
+ " end_win %d\n", seq_num, start_win, win_size, end_win);
+ if (pkt_type != PKT_TYPE_BAR) {
+ if (seq_num >= start_win) {
+ if (rx_reor_tbl_ptr->rx_reorder_ptr[seq_num - start_win]) {
+ PRINTM(MDAT_D, "Drop Duplicate Pkt\n");
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ rx_reor_tbl_ptr->rx_reorder_ptr[seq_num - start_win] = payload;
+ } else { /* Wrap condition */
+ if (rx_reor_tbl_ptr->rx_reorder_ptr[(seq_num
+ + (MAX_TID_VALUE)) -
+ start_win]) {
+ PRINTM(MDAT_D, "Drop Duplicate Pkt\n");
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ rx_reor_tbl_ptr->rx_reorder_ptr[(seq_num
+ + (MAX_TID_VALUE)) -
+ start_win] = payload;
+ }
+ }
+
+ wlan_11n_display_tbl_ptr(pmadapter, rx_reor_tbl_ptr);
+
+ /*
+ * Dispatch all packets sequentially from start_win until a
+ * hole is found and adjust the start_win appropriately
+ */
+ ret = wlan_11n_scan_and_dispatch(priv, rx_reor_tbl_ptr);
+
+ wlan_11n_display_tbl_ptr(pmadapter, rx_reor_tbl_ptr);
+ }
+
+ done:
+ if (!rx_reor_tbl_ptr->timer_context.timer_is_set ||
+ (prev_start_win != rx_reor_tbl_ptr->start_win)) {
+
+ mlan_11n_rxreorder_timer_restart(pmadapter, rx_reor_tbl_ptr);
+ }
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function will delete an entry for a given tid/ta pair. tid/ta
+ * are taken from delba_event body
+ *
+ * @param priv A pointer to mlan_private
+ * @param tid tid to send delba
+ * @param peer_mac MAC address to send delba
+ * @param type TYPE_DELBA_SENT or TYPE_DELBA_RECEIVE
+ * @param initiator MTRUE if we are initiator of ADDBA, MFALSE otherwise
+ *
+ * @return N/A
+ */
+void
+mlan_11n_delete_bastream_tbl(mlan_private * priv, int tid,
+ t_u8 * peer_mac, t_u8 type, int initiator)
+{
+ RxReorderTbl *rx_reor_tbl_ptr;
+ TxBAStreamTbl *ptxtbl;
+ t_u8 cleanup_rx_reorder_tbl;
+
+ ENTER();
+
+ if (type == TYPE_DELBA_RECEIVE)
+ cleanup_rx_reorder_tbl = (initiator) ? MTRUE : MFALSE;
+ else
+ cleanup_rx_reorder_tbl = (initiator) ? MFALSE : MTRUE;
+
+ PRINTM(MEVENT, "DELBA: %02x:%02x:%02x:%02x:%02x:%02x tid=%d,"
+ "initiator=%d\n", peer_mac[0],
+ peer_mac[1], peer_mac[2],
+ peer_mac[3], peer_mac[4], peer_mac[5], tid, initiator);
+
+ if (cleanup_rx_reorder_tbl) {
+ if (!(rx_reor_tbl_ptr = wlan_11n_get_rxreorder_tbl(priv, tid,
+ peer_mac))) {
+ PRINTM(MWARN, "TID, TA not found in table!\n");
+ LEAVE();
+ return;
+ }
+ wlan_11n_delete_rxreorder_tbl_entry(priv, rx_reor_tbl_ptr);
+ } else {
+ if (!(ptxtbl = wlan_11n_get_txbastream_tbl(priv, tid, peer_mac))) {
+ PRINTM(MWARN, "TID, RA not found in table!\n");
+ LEAVE();
+ return;
+ }
+
+ wlan_11n_delete_txbastream_tbl_entry(priv, ptxtbl);
+ }
+
+ LEAVE();
+}
+
+/**
+ * @brief This function handles the command response of
+ * a block ack response
+ *
+ * @param priv A pointer to mlan_private structure
+ * @param resp A pointer to HostCmd_DS_COMMAND
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+mlan_status
+wlan_ret_11n_addba_resp(mlan_private * priv, HostCmd_DS_COMMAND * resp)
+{
+ HostCmd_DS_11N_ADDBA_RSP *padd_ba_rsp = (HostCmd_DS_11N_ADDBA_RSP *)
+ & resp->params.add_ba_rsp;
+ int tid;
+ RxReorderTbl *rx_reor_tbl_ptr = MNULL;
+
+ ENTER();
+
+ padd_ba_rsp->status_code = wlan_le16_to_cpu(padd_ba_rsp->status_code);
+ padd_ba_rsp->block_ack_param_set =
+ wlan_le16_to_cpu(padd_ba_rsp->block_ack_param_set);
+ padd_ba_rsp->block_ack_tmo = wlan_le16_to_cpu(padd_ba_rsp->block_ack_tmo);
+ padd_ba_rsp->ssn = wlan_le16_to_cpu(padd_ba_rsp->ssn);
+
+ tid = (padd_ba_rsp->block_ack_param_set & BLOCKACKPARAM_TID_MASK)
+ >> BLOCKACKPARAM_TID_POS;
+ /* Check if we had rejected the ADDBA, if yes then do not create the stream */
+ if (padd_ba_rsp->status_code == BA_RESULT_SUCCESS) {
+ PRINTM(MCMND,
+ "ADDBA RSP: %02x:%02x:%02x:%02x:%02x:%02x tid=%d ssn=%d win_size=%d,amsdu=%d\n",
+ padd_ba_rsp->peer_mac_addr[0], padd_ba_rsp->peer_mac_addr[1],
+ padd_ba_rsp->peer_mac_addr[2], padd_ba_rsp->peer_mac_addr[3],
+ padd_ba_rsp->peer_mac_addr[4], padd_ba_rsp->peer_mac_addr[5],
+ tid, padd_ba_rsp->ssn,
+ ((padd_ba_rsp->block_ack_param_set & BLOCKACKPARAM_WINSIZE_MASK)
+ >> BLOCKACKPARAM_WINSIZE_POS),
+ padd_ba_rsp->
+ block_ack_param_set & BLOCKACKPARAM_AMSDU_SUPP_MASK);
+
+ if ((rx_reor_tbl_ptr =
+ wlan_11n_get_rxreorder_tbl(priv, tid,
+ padd_ba_rsp->peer_mac_addr))) {
+ rx_reor_tbl_ptr->ba_status = BA_STREAM_SETUP_COMPLETE;
+ if ((padd_ba_rsp->
+ block_ack_param_set & BLOCKACKPARAM_AMSDU_SUPP_MASK) &&
+ priv->add_ba_param.rx_amsdu &&
+ (priv->aggr_prio_tbl[tid].amsdu != BA_STREAM_NOT_ALLOWED))
+ rx_reor_tbl_ptr->amsdu = MTRUE;
+ else
+ rx_reor_tbl_ptr->amsdu = MFALSE;
+ }
+ } else {
+ PRINTM(MERROR,
+ "ADDBA RSP: Failed(%02x:%02x:%02x:%02x:%02x:%02x tid=%d)\n",
+ padd_ba_rsp->peer_mac_addr[0], padd_ba_rsp->peer_mac_addr[1],
+ padd_ba_rsp->peer_mac_addr[2], padd_ba_rsp->peer_mac_addr[3],
+ padd_ba_rsp->peer_mac_addr[4], padd_ba_rsp->peer_mac_addr[5],
+ tid);
+ if ((rx_reor_tbl_ptr =
+ wlan_11n_get_rxreorder_tbl(priv, tid,
+ padd_ba_rsp->peer_mac_addr))) {
+ wlan_11n_delete_rxreorder_tbl_entry(priv, rx_reor_tbl_ptr);
+ }
+ }
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function handles ba_stream_timeout event
+ *
+ * @param priv A pointer to mlan_private
+ * @param event A pointer to structure HostCmd_DS_11N_BATIMEOUT
+ *
+ * @return N/A
+ */
+void
+wlan_11n_ba_stream_timeout(mlan_private * priv,
+ HostCmd_DS_11N_BATIMEOUT * event)
+{
+ HostCmd_DS_11N_DELBA delba;
+
+ ENTER();
+
+ DBG_HEXDUMP(MCMD_D, "Event:", (t_u8 *) event, 20);
+
+ memset(priv->adapter, &delba, 0, sizeof(HostCmd_DS_11N_DELBA));
+ memcpy(priv->adapter, delba.peer_mac_addr, event->peer_mac_addr,
+ MLAN_MAC_ADDR_LENGTH);
+
+ delba.del_ba_param_set |= (t_u16) event->tid << DELBA_TID_POS;
+ delba.del_ba_param_set |= (t_u16) event->origninator << DELBA_INITIATOR_POS;
+ delba.reason_code = REASON_CODE_STA_TIMEOUT;
+ wlan_prepare_cmd(priv, HostCmd_CMD_11N_DELBA, 0, 0, MNULL, &delba);
+
+ LEAVE();
+ return;
+}
+
+/**
+ * @brief This function cleans up reorder tbl
+ *
+ * @param priv A pointer to mlan_private
+ *
+ * @return N/A
+ */
+void
+wlan_11n_cleanup_reorder_tbl(mlan_private * priv)
+{
+ RxReorderTbl *del_tbl_ptr;
+
+ ENTER();
+
+ while ((del_tbl_ptr = (RxReorderTbl *)
+ util_peek_list(priv->adapter->pmoal_handle,
+ &priv->rx_reorder_tbl_ptr,
+ priv->adapter->callbacks.moal_spin_lock,
+ priv->adapter->callbacks.moal_spin_unlock))) {
+ wlan_11n_delete_rxreorder_tbl_entry(priv, del_tbl_ptr);
+ }
+
+ util_init_list((pmlan_linked_list) & priv->rx_reorder_tbl_ptr);
+
+ memset(priv->adapter, priv->rx_seq, 0xff, sizeof(priv->rx_seq));
+ LEAVE();
+}
+
+/**
+ * @brief This function handle the rxba_sync event
+ *
+ * @param priv A pointer to mlan_private
+ * @param event_buf A pointer to event buf
+ * @param len event_buf length
+ * @return N/A
+ */
+void
+wlan_11n_rxba_sync_event(mlan_private * priv, t_u8 * event_buf, t_u16 len)
+{
+ MrvlIEtypes_RxBaSync_t *tlv_rxba = (MrvlIEtypes_RxBaSync_t *) event_buf;
+ t_u16 tlv_type, tlv_len;
+ RxReorderTbl *rx_reor_tbl_ptr = MNULL;
+ t_u8 i, j;
+ t_u16 seq_num = 0;
+ int tlv_buf_left = len;
+ ENTER();
+ DBG_HEXDUMP(MEVT_D, "RXBA_SYNC_EVT", event_buf, len);
+ while (tlv_buf_left >= sizeof(MrvlIEtypes_RxBaSync_t)) {
+ tlv_type = wlan_le16_to_cpu(tlv_rxba->header.type);
+ tlv_len = wlan_le16_to_cpu(tlv_rxba->header.len);
+ if (tlv_type != TLV_TYPE_RXBA_SYNC) {
+ PRINTM(MERROR, "Wrong TLV id=0x%x\n", tlv_type);
+ goto done;
+ }
+ tlv_rxba->seq_num = wlan_le16_to_cpu(tlv_rxba->seq_num);
+ tlv_rxba->bitmap_len = wlan_le16_to_cpu(tlv_rxba->bitmap_len);
+ PRINTM(MEVENT,
+ "%02x:%02x:%02x:%02x:%02x:%02x tid=%d seq_num=%d bitmap_len=%d\n",
+ tlv_rxba->mac[0], tlv_rxba->mac[1], tlv_rxba->mac[2],
+ tlv_rxba->mac[3], tlv_rxba->mac[4], tlv_rxba->mac[5],
+ tlv_rxba->tid, tlv_rxba->seq_num, tlv_rxba->bitmap_len);
+ rx_reor_tbl_ptr =
+ wlan_11n_get_rxreorder_tbl(priv, tlv_rxba->tid, tlv_rxba->mac);
+ if (!rx_reor_tbl_ptr) {
+ PRINTM(MEVENT, "Can not find rx_reorder_tbl\n");
+ goto done;
+ }
+ for (i = 0; i < tlv_rxba->bitmap_len; i++) {
+ for (j = 0; j < 8; j++) {
+ if (tlv_rxba->bitmap[i] & (1 << j)) {
+ seq_num =
+ (tlv_rxba->seq_num + i * 8 + j) & (MAX_TID_VALUE - 1);
+ PRINTM(MEVENT,
+ "Fw dropped packet, seq=%d start_win=%d, win_size=%d\n",
+ seq_num, rx_reor_tbl_ptr->start_win,
+ rx_reor_tbl_ptr->win_size);
+ if (MLAN_STATUS_SUCCESS !=
+ mlan_11n_rxreorder_pkt(priv, seq_num, tlv_rxba->tid,
+ tlv_rxba->mac, 0,
+ (t_void *) RX_PKT_DROPPED_IN_FW))
+ {
+ PRINTM(MERROR,
+ "Fail to handle dropped packet, seq=%d\n",
+ seq_num);
+ }
+ }
+ }
+ }
+ tlv_buf_left -= (sizeof(MrvlIEtypesHeader_t) + tlv_len);
+ tlv_rxba =
+ (MrvlIEtypes_RxBaSync_t *) ((t_u8 *) tlv_rxba + tlv_len +
+ sizeof(MrvlIEtypesHeader_t));
+ }
+ done:
+ LEAVE();
+ return;
+}
+
+/**
+ * @brief This function will send a DELBA for each entry in the priv's
+ * rx reordering table
+ *
+ * @param priv A pointer to mlan_private
+ */
+t_void
+wlan_send_delba_to_all_in_reorder_tbl(pmlan_private priv)
+{
+ RxReorderTbl *rx_reor_tbl_ptr;
+
+ ENTER();
+
+ if (!
+ (rx_reor_tbl_ptr =
+ (RxReorderTbl *) util_peek_list(priv->adapter->pmoal_handle,
+ &priv->rx_reorder_tbl_ptr,
+ priv->adapter->callbacks.
+ moal_spin_lock,
+ priv->adapter->callbacks.
+ moal_spin_unlock))) {
+ LEAVE();
+ return;
+ }
+
+ while (rx_reor_tbl_ptr != (RxReorderTbl *) & priv->rx_reorder_tbl_ptr) {
+ if (rx_reor_tbl_ptr->ba_status == BA_STREAM_SETUP_COMPLETE) {
+ rx_reor_tbl_ptr->ba_status = BA_STREAM_SETUP_INPROGRESS;
+ wlan_send_delba(priv, rx_reor_tbl_ptr->tid, rx_reor_tbl_ptr->ta, 0);
+ }
+ rx_reor_tbl_ptr = rx_reor_tbl_ptr->pnext;
+ }
+ LEAVE();
+}
+
+/**
+ * @brief This function cleans up reorder tbl for specific station
+ *
+ * @param priv A pointer to mlan_private
+ * @param ta ta to find in reordering table
+ * @return N/A
+ */
+void
+wlan_cleanup_reorder_tbl(mlan_private * priv, t_u8 * ta)
+{
+ RxReorderTbl *rx_reor_tbl_ptr = MNULL;
+ t_u8 i;
+ ENTER();
+ for (i = 0; i < MAX_NUM_TID; ++i) {
+ if ((rx_reor_tbl_ptr = wlan_11n_get_rxreorder_tbl(priv, i, ta))) {
+ wlan_11n_delete_rxreorder_tbl_entry(priv, rx_reor_tbl_ptr);
+ }
+ }
+ LEAVE();
+ return;
+}
diff --git a/drivers/net/wireless/sd8797/mlan/mlan_11n_rxreorder.h b/drivers/net/wireless/sd8797/mlan/mlan_11n_rxreorder.h
new file mode 100644
index 000000000000..4ff15834c8a3
--- /dev/null
+++ b/drivers/net/wireless/sd8797/mlan/mlan_11n_rxreorder.h
@@ -0,0 +1,102 @@
+/** @file mlan_11n_rxreorder.h
+ *
+ * @brief This file contains related macros, enum, and struct
+ * of 11n RxReordering functionalities
+ *
+ * Copyright (C) 2008-2011, Marvell International Ltd.
+ *
+ * This software file (the "File") is distributed by Marvell International
+ * Ltd. under the terms of the GNU General Public License Version 2, June 1991
+ * (the "License"). You may use, redistribute and/or modify this File in
+ * accordance with the terms and conditions of the License, a copy of which
+ * is available by writing to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
+ * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
+ *
+ * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
+ * ARE EXPRESSLY DISCLAIMED. The License provides additional details about
+ * this warranty disclaimer.
+ */
+
+/********************************************************
+Change log:
+ 11/10/2008: initial version
+********************************************************/
+
+#ifndef _MLAN_11N_RXREORDER_H_
+#define _MLAN_11N_RXREORDER_H_
+
+/** Max value a TID can take = 2^12 = 4096 */
+#define MAX_TID_VALUE (2 << 11)
+/** 2^11 = 2048 */
+#define TWOPOW11 (2 << 10)
+
+/** Tid Mask used for extracting TID from BlockAckParamSet */
+#define BLOCKACKPARAM_TID_MASK 0x3C
+/** Tid position in BlockAckParamSet */
+#define BLOCKACKPARAM_TID_POS 2
+/** WinSize Mask used for extracting WinSize from BlockAckParamSet */
+#define BLOCKACKPARAM_WINSIZE_MASK 0xffc0
+/** WinSize Mask used for extracting WinSize from BlockAckParamSet */
+#define BLOCKACKPARAM_AMSDU_SUPP_MASK 0x1
+/** WinSize position in BlockAckParamSet */
+#define BLOCKACKPARAM_WINSIZE_POS 6
+/** Position of TID in DelBA Param set */
+#define DELBA_TID_POS 12
+/** Position of INITIATOR in DelBA Param set */
+#define DELBA_INITIATOR_POS 11
+/** Reason code: Requested from peer STA as it does not want to use the mechanism */
+#define REASON_CODE_STA_DONT_WANT 37
+/** Reason code: Requested from peer STA due to timeout*/
+#define REASON_CODE_STA_TIMEOUT 39
+/** Type: send delba command */
+#define TYPE_DELBA_SENT 1
+/** Type: recieve delba command */
+#define TYPE_DELBA_RECEIVE 2
+/** Set Initiator Bit */
+#define DELBA_INITIATOR(paramset) (paramset = (paramset | (1 << 11)))
+/** Reset Initiator Bit for recipient */
+#define DELBA_RECIPIENT(paramset) (paramset = (paramset & ~(1 << 11)))
+/** Immediate block ack */
+#define IMMEDIATE_BLOCK_ACK 0x2
+
+/** The request has been declined */
+#define ADDBA_RSP_STATUS_DECLINED 37
+/** ADDBA response status : Reject */
+#define ADDBA_RSP_STATUS_REJECT 1
+/** ADDBA response status : Accept */
+#define ADDBA_RSP_STATUS_ACCEPT 0
+
+/** DEFAULT SEQ NUM */
+#define DEFAULT_SEQ_NUM 0xffff
+
+/** Indicate packet has been dropped in FW */
+#define RX_PKT_DROPPED_IN_FW 0xffffffff
+
+mlan_status mlan_11n_rxreorder_pkt(void *priv, t_u16 seqNum, t_u16 tid,
+ t_u8 * ta, t_u8 pkttype, void *payload);
+void mlan_11n_delete_bastream_tbl(mlan_private * priv, int Tid,
+ t_u8 * PeerMACAddr, t_u8 type, int initiator);
+void wlan_11n_ba_stream_timeout(mlan_private * priv,
+ HostCmd_DS_11N_BATIMEOUT * event);
+mlan_status wlan_ret_11n_addba_resp(mlan_private * priv,
+ HostCmd_DS_COMMAND * resp);
+mlan_status wlan_cmd_11n_delba(mlan_private * priv, HostCmd_DS_COMMAND * cmd,
+ void *pdata_buf);
+mlan_status wlan_cmd_11n_addba_rspgen(mlan_private * priv,
+ HostCmd_DS_COMMAND * cmd,
+ void *pdata_buf);
+mlan_status wlan_cmd_11n_addba_req(mlan_private * priv,
+ HostCmd_DS_COMMAND * cmd, void *pdata_buf);
+void wlan_11n_cleanup_reorder_tbl(mlan_private * priv);
+RxReorderTbl *wlan_11n_get_rxreorder_tbl(mlan_private * priv, int tid,
+ t_u8 * ta);
+void wlan_11n_rxba_sync_event(mlan_private * priv, t_u8 * event_buf, t_u16 len);
+
+/** send delba for all entries in reorder_tbl */
+t_void wlan_send_delba_to_all_in_reorder_tbl(pmlan_private priv);
+
+/** clean up reorder_tbl */
+void wlan_cleanup_reorder_tbl(mlan_private * priv, t_u8 * ta);
+#endif /* _MLAN_11N_RXREORDER_H_ */
diff --git a/drivers/net/wireless/sd8797/mlan/mlan_cfp.c b/drivers/net/wireless/sd8797/mlan/mlan_cfp.c
new file mode 100644
index 000000000000..742c9cd368bc
--- /dev/null
+++ b/drivers/net/wireless/sd8797/mlan/mlan_cfp.c
@@ -0,0 +1,1148 @@
+/**
+ * @file mlan_cfp.c
+ *
+ * @brief This file contains WLAN client mode channel, frequency and power
+ * related code
+ *
+ * Copyright (C) 2009-2011, Marvell International Ltd.
+ *
+ * This software file (the "File") is distributed by Marvell International
+ * Ltd. under the terms of the GNU General Public License Version 2, June 1991
+ * (the "License"). You may use, redistribute and/or modify this File in
+ * accordance with the terms and conditions of the License, a copy of which
+ * is available by writing to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
+ * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
+ *
+ * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
+ * ARE EXPRESSLY DISCLAIMED. The License provides additional details about
+ * this warranty disclaimer.
+ */
+
+/*************************************************************
+Change Log:
+ 04/16/2009: initial version
+************************************************************/
+
+#include "mlan.h"
+#include "mlan_util.h"
+#include "mlan_fw.h"
+#include "mlan_join.h"
+#include "mlan_main.h"
+
+/********************************************************
+ Local Variables
+********************************************************/
+
+/** 100mW */
+#define WLAN_TX_PWR_DEFAULT 20
+/** 100mW */
+#define WLAN_TX_PWR_US_DEFAULT 20
+/** 100mW */
+#define WLAN_TX_PWR_JP_BG_DEFAULT 20
+/** 200mW */
+#define WLAN_TX_PWR_JP_A_DEFAULT 23
+/** 100mW */
+#define WLAN_TX_PWR_FR_100MW 20
+/** 10mW */
+#define WLAN_TX_PWR_FR_10MW 10
+/** 100mW */
+#define WLAN_TX_PWR_EMEA_DEFAULT 20
+/** 2000mW */
+#define WLAN_TX_PWR_CN_2000MW 33
+
+/**
+ * The structure for Channel-Frequency-Power table
+ */
+typedef struct _cfp_table
+{
+ /** Region or Code */
+ t_u8 code;
+ /** Frequency/Power */
+ chan_freq_power_t *cfp;
+ /** No of CFP flag */
+ int cfp_no;
+} cfp_table_t;
+
+/* Format { Channel, Frequency (MHz), MaxTxPower } */
+/** Band: 'B/G', Region: USA FCC/Canada IC */
+static chan_freq_power_t channel_freq_power_US_BG[] = {
+ {1, 2412, WLAN_TX_PWR_US_DEFAULT},
+ {2, 2417, WLAN_TX_PWR_US_DEFAULT},
+ {3, 2422, WLAN_TX_PWR_US_DEFAULT},
+ {4, 2427, WLAN_TX_PWR_US_DEFAULT},
+ {5, 2432, WLAN_TX_PWR_US_DEFAULT},
+ {6, 2437, WLAN_TX_PWR_US_DEFAULT},
+ {7, 2442, WLAN_TX_PWR_US_DEFAULT},
+ {8, 2447, WLAN_TX_PWR_US_DEFAULT},
+ {9, 2452, WLAN_TX_PWR_US_DEFAULT},
+ {10, 2457, WLAN_TX_PWR_US_DEFAULT},
+ {11, 2462, WLAN_TX_PWR_US_DEFAULT}
+};
+
+/** Band: 'B/G', Region: Europe ETSI/China */
+static chan_freq_power_t channel_freq_power_EU_BG[] = {
+ {1, 2412, WLAN_TX_PWR_EMEA_DEFAULT},
+ {2, 2417, WLAN_TX_PWR_EMEA_DEFAULT},
+ {3, 2422, WLAN_TX_PWR_EMEA_DEFAULT},
+ {4, 2427, WLAN_TX_PWR_EMEA_DEFAULT},
+ {5, 2432, WLAN_TX_PWR_EMEA_DEFAULT},
+ {6, 2437, WLAN_TX_PWR_EMEA_DEFAULT},
+ {7, 2442, WLAN_TX_PWR_EMEA_DEFAULT},
+ {8, 2447, WLAN_TX_PWR_EMEA_DEFAULT},
+ {9, 2452, WLAN_TX_PWR_EMEA_DEFAULT},
+ {10, 2457, WLAN_TX_PWR_EMEA_DEFAULT},
+ {11, 2462, WLAN_TX_PWR_EMEA_DEFAULT},
+ {12, 2467, WLAN_TX_PWR_EMEA_DEFAULT},
+ {13, 2472, WLAN_TX_PWR_EMEA_DEFAULT}
+};
+
+/** Band: 'B/G', Region: France */
+static chan_freq_power_t channel_freq_power_FR_BG[] = {
+ {1, 2412, WLAN_TX_PWR_FR_100MW},
+ {2, 2417, WLAN_TX_PWR_FR_100MW},
+ {3, 2422, WLAN_TX_PWR_FR_100MW},
+ {4, 2427, WLAN_TX_PWR_FR_100MW},
+ {5, 2432, WLAN_TX_PWR_FR_100MW},
+ {6, 2437, WLAN_TX_PWR_FR_100MW},
+ {7, 2442, WLAN_TX_PWR_FR_100MW},
+ {8, 2447, WLAN_TX_PWR_FR_100MW},
+ {9, 2452, WLAN_TX_PWR_FR_100MW},
+ {10, 2457, WLAN_TX_PWR_FR_10MW},
+ {11, 2462, WLAN_TX_PWR_FR_10MW},
+ {12, 2467, WLAN_TX_PWR_FR_10MW},
+ {13, 2472, WLAN_TX_PWR_FR_10MW}
+};
+
+/** Band: 'B/G', Region: Japan */
+static chan_freq_power_t channel_freq_power_JPN41_BG[] = {
+ {1, 2412, WLAN_TX_PWR_JP_BG_DEFAULT},
+ {2, 2417, WLAN_TX_PWR_JP_BG_DEFAULT},
+ {3, 2422, WLAN_TX_PWR_JP_BG_DEFAULT},
+ {4, 2427, WLAN_TX_PWR_JP_BG_DEFAULT},
+ {5, 2432, WLAN_TX_PWR_JP_BG_DEFAULT},
+ {6, 2437, WLAN_TX_PWR_JP_BG_DEFAULT},
+ {7, 2442, WLAN_TX_PWR_JP_BG_DEFAULT},
+ {8, 2447, WLAN_TX_PWR_JP_BG_DEFAULT},
+ {9, 2452, WLAN_TX_PWR_JP_BG_DEFAULT},
+ {10, 2457, WLAN_TX_PWR_JP_BG_DEFAULT},
+ {11, 2462, WLAN_TX_PWR_JP_BG_DEFAULT},
+ {12, 2467, WLAN_TX_PWR_JP_BG_DEFAULT},
+ {13, 2472, WLAN_TX_PWR_JP_BG_DEFAULT}
+};
+
+/** Band: 'B/G', Region: Japan */
+static chan_freq_power_t channel_freq_power_JPN40_BG[] = {
+ {14, 2484, WLAN_TX_PWR_JP_BG_DEFAULT}
+};
+
+/** Band : 'B/G', Region: Special */
+static chan_freq_power_t channel_freq_power_SPECIAL_BG[] = {
+ {1, 2412, WLAN_TX_PWR_JP_BG_DEFAULT},
+ {2, 2417, WLAN_TX_PWR_JP_BG_DEFAULT},
+ {3, 2422, WLAN_TX_PWR_JP_BG_DEFAULT},
+ {4, 2427, WLAN_TX_PWR_JP_BG_DEFAULT},
+ {5, 2432, WLAN_TX_PWR_JP_BG_DEFAULT},
+ {6, 2437, WLAN_TX_PWR_JP_BG_DEFAULT},
+ {7, 2442, WLAN_TX_PWR_JP_BG_DEFAULT},
+ {8, 2447, WLAN_TX_PWR_JP_BG_DEFAULT},
+ {9, 2452, WLAN_TX_PWR_JP_BG_DEFAULT},
+ {10, 2457, WLAN_TX_PWR_JP_BG_DEFAULT},
+ {11, 2462, WLAN_TX_PWR_JP_BG_DEFAULT},
+ {12, 2467, WLAN_TX_PWR_JP_BG_DEFAULT},
+ {13, 2472, WLAN_TX_PWR_JP_BG_DEFAULT},
+ {14, 2484, WLAN_TX_PWR_JP_BG_DEFAULT}
+};
+
+/**
+ * The 2.4GHz CFP tables
+ */
+static cfp_table_t cfp_table_BG[] = {
+ {0x10, /* US FCC */
+ channel_freq_power_US_BG,
+ sizeof(channel_freq_power_US_BG) / sizeof(chan_freq_power_t),
+ }
+ ,
+ {0x20, /* CANADA IC */
+ channel_freq_power_US_BG,
+ sizeof(channel_freq_power_US_BG) / sizeof(chan_freq_power_t),
+ }
+ ,
+ {0x30, /* EU */
+ channel_freq_power_EU_BG,
+ sizeof(channel_freq_power_EU_BG) / sizeof(chan_freq_power_t),
+ }
+ ,
+ {0x32, /* FRANCE */
+ channel_freq_power_FR_BG,
+ sizeof(channel_freq_power_FR_BG) / sizeof(chan_freq_power_t),
+ }
+ ,
+ {0x40, /* JAPAN */
+ channel_freq_power_JPN40_BG,
+ sizeof(channel_freq_power_JPN40_BG) / sizeof(chan_freq_power_t),
+ }
+ ,
+ {0x41, /* JAPAN */
+ channel_freq_power_JPN41_BG,
+ sizeof(channel_freq_power_JPN41_BG) / sizeof(chan_freq_power_t),
+ }
+ ,
+ {0x50, /* China */
+ channel_freq_power_EU_BG,
+ sizeof(channel_freq_power_EU_BG) / sizeof(chan_freq_power_t),
+ }
+ ,
+ {0xff, /* Special */
+ channel_freq_power_SPECIAL_BG,
+ sizeof(channel_freq_power_SPECIAL_BG) / sizeof(chan_freq_power_t),
+ }
+ ,
+/* Add new region here */
+};
+
+/** Number of the CFP tables for 2.4GHz */
+#define MLAN_CFP_TABLE_SIZE_BG (sizeof(cfp_table_BG)/sizeof(cfp_table_t))
+
+/* Format { Channel, Frequency (MHz), MaxTxPower, DFS } */
+/** Band: 'A', Region: USA FCC, Spain, France */
+static chan_freq_power_t channel_freq_power_A[] = {
+ {36, 5180, WLAN_TX_PWR_US_DEFAULT, MFALSE},
+ {40, 5200, WLAN_TX_PWR_US_DEFAULT, MFALSE},
+ {44, 5220, WLAN_TX_PWR_US_DEFAULT, MFALSE},
+ {48, 5240, WLAN_TX_PWR_US_DEFAULT, MFALSE},
+ {52, 5260, WLAN_TX_PWR_US_DEFAULT, MTRUE},
+ {56, 5280, WLAN_TX_PWR_US_DEFAULT, MTRUE},
+ {60, 5300, WLAN_TX_PWR_US_DEFAULT, MTRUE},
+ {64, 5320, WLAN_TX_PWR_US_DEFAULT, MTRUE},
+ {100, 5500, WLAN_TX_PWR_US_DEFAULT, MTRUE},
+ {104, 5520, WLAN_TX_PWR_US_DEFAULT, MTRUE},
+ {108, 5540, WLAN_TX_PWR_US_DEFAULT, MTRUE},
+ {112, 5560, WLAN_TX_PWR_US_DEFAULT, MTRUE},
+ {116, 5580, WLAN_TX_PWR_US_DEFAULT, MTRUE},
+ {120, 5600, WLAN_TX_PWR_US_DEFAULT, MTRUE},
+ {124, 5620, WLAN_TX_PWR_US_DEFAULT, MTRUE},
+ {128, 5640, WLAN_TX_PWR_US_DEFAULT, MTRUE},
+ {132, 5660, WLAN_TX_PWR_US_DEFAULT, MTRUE},
+ {136, 5680, WLAN_TX_PWR_US_DEFAULT, MTRUE},
+ {140, 5700, WLAN_TX_PWR_US_DEFAULT, MTRUE},
+ {149, 5745, WLAN_TX_PWR_US_DEFAULT, MFALSE},
+ {153, 5765, WLAN_TX_PWR_US_DEFAULT, MFALSE},
+ {157, 5785, WLAN_TX_PWR_US_DEFAULT, MFALSE},
+ {161, 5805, WLAN_TX_PWR_US_DEFAULT, MFALSE},
+ {165, 5825, WLAN_TX_PWR_US_DEFAULT, MFALSE}
+};
+
+/** Band: 'A', Region: Canada IC */
+static chan_freq_power_t channel_freq_power_CAN_A[] = {
+ {36, 5180, WLAN_TX_PWR_US_DEFAULT, MFALSE},
+ {40, 5200, WLAN_TX_PWR_US_DEFAULT, MFALSE},
+ {44, 5220, WLAN_TX_PWR_US_DEFAULT, MFALSE},
+ {48, 5240, WLAN_TX_PWR_US_DEFAULT, MFALSE},
+ {52, 5260, WLAN_TX_PWR_US_DEFAULT, MTRUE},
+ {56, 5280, WLAN_TX_PWR_US_DEFAULT, MTRUE},
+ {60, 5300, WLAN_TX_PWR_US_DEFAULT, MTRUE},
+ {64, 5320, WLAN_TX_PWR_US_DEFAULT, MTRUE},
+ {100, 5500, WLAN_TX_PWR_US_DEFAULT, MTRUE},
+ {104, 5520, WLAN_TX_PWR_US_DEFAULT, MTRUE},
+ {108, 5540, WLAN_TX_PWR_US_DEFAULT, MTRUE},
+ {112, 5560, WLAN_TX_PWR_US_DEFAULT, MTRUE},
+ {116, 5580, WLAN_TX_PWR_US_DEFAULT, MTRUE},
+ {132, 5660, WLAN_TX_PWR_US_DEFAULT, MTRUE},
+ {136, 5680, WLAN_TX_PWR_US_DEFAULT, MTRUE},
+ {140, 5700, WLAN_TX_PWR_US_DEFAULT, MTRUE},
+ {149, 5745, WLAN_TX_PWR_US_DEFAULT, MFALSE},
+ {153, 5765, WLAN_TX_PWR_US_DEFAULT, MFALSE},
+ {157, 5785, WLAN_TX_PWR_US_DEFAULT, MFALSE},
+ {161, 5805, WLAN_TX_PWR_US_DEFAULT, MFALSE},
+ {165, 5825, WLAN_TX_PWR_US_DEFAULT, MFALSE}
+};
+
+/** Band: 'A', Region: Europe ETSI */
+static chan_freq_power_t channel_freq_power_EU_A[] = {
+ {36, 5180, WLAN_TX_PWR_EMEA_DEFAULT, MFALSE},
+ {40, 5200, WLAN_TX_PWR_EMEA_DEFAULT, MFALSE},
+ {44, 5220, WLAN_TX_PWR_EMEA_DEFAULT, MFALSE},
+ {48, 5240, WLAN_TX_PWR_EMEA_DEFAULT, MFALSE},
+ {52, 5260, WLAN_TX_PWR_EMEA_DEFAULT, MTRUE},
+ {56, 5280, WLAN_TX_PWR_EMEA_DEFAULT, MTRUE},
+ {60, 5300, WLAN_TX_PWR_EMEA_DEFAULT, MTRUE},
+ {64, 5320, WLAN_TX_PWR_EMEA_DEFAULT, MTRUE},
+ {100, 5500, WLAN_TX_PWR_EMEA_DEFAULT, MTRUE},
+ {104, 5520, WLAN_TX_PWR_EMEA_DEFAULT, MTRUE},
+ {108, 5540, WLAN_TX_PWR_EMEA_DEFAULT, MTRUE},
+ {112, 5560, WLAN_TX_PWR_EMEA_DEFAULT, MTRUE},
+ {116, 5580, WLAN_TX_PWR_EMEA_DEFAULT, MTRUE},
+ {120, 5600, WLAN_TX_PWR_EMEA_DEFAULT, MTRUE},
+ {124, 5620, WLAN_TX_PWR_EMEA_DEFAULT, MTRUE},
+ {128, 5640, WLAN_TX_PWR_EMEA_DEFAULT, MTRUE},
+ {132, 5660, WLAN_TX_PWR_EMEA_DEFAULT, MTRUE},
+ {136, 5680, WLAN_TX_PWR_EMEA_DEFAULT, MTRUE},
+ {140, 5700, WLAN_TX_PWR_EMEA_DEFAULT, MTRUE}
+};
+
+/** Band: 'A', Region: Japan */
+static chan_freq_power_t channel_freq_power_JPN_A[] = {
+ {8, 5040, WLAN_TX_PWR_JP_A_DEFAULT, MFALSE},
+ {12, 5060, WLAN_TX_PWR_JP_A_DEFAULT, MFALSE},
+ {16, 5080, WLAN_TX_PWR_JP_A_DEFAULT, MFALSE},
+ {36, 5180, WLAN_TX_PWR_JP_A_DEFAULT, MFALSE},
+ {40, 5200, WLAN_TX_PWR_JP_A_DEFAULT, MFALSE},
+ {44, 5220, WLAN_TX_PWR_JP_A_DEFAULT, MFALSE},
+ {48, 5240, WLAN_TX_PWR_JP_A_DEFAULT, MFALSE},
+ {52, 5260, WLAN_TX_PWR_JP_A_DEFAULT, MTRUE},
+ {56, 5280, WLAN_TX_PWR_JP_A_DEFAULT, MTRUE},
+ {60, 5300, WLAN_TX_PWR_JP_A_DEFAULT, MTRUE},
+ {64, 5320, WLAN_TX_PWR_JP_A_DEFAULT, MTRUE},
+ {100, 5500, WLAN_TX_PWR_JP_A_DEFAULT, MTRUE},
+ {104, 5520, WLAN_TX_PWR_JP_A_DEFAULT, MTRUE},
+ {108, 5540, WLAN_TX_PWR_JP_A_DEFAULT, MTRUE},
+ {112, 5560, WLAN_TX_PWR_JP_A_DEFAULT, MTRUE},
+ {116, 5580, WLAN_TX_PWR_JP_A_DEFAULT, MTRUE},
+ {120, 5600, WLAN_TX_PWR_JP_A_DEFAULT, MTRUE},
+ {124, 5620, WLAN_TX_PWR_JP_A_DEFAULT, MTRUE},
+ {128, 5640, WLAN_TX_PWR_JP_A_DEFAULT, MTRUE},
+ {132, 5660, WLAN_TX_PWR_JP_A_DEFAULT, MTRUE},
+ {136, 5680, WLAN_TX_PWR_JP_A_DEFAULT, MTRUE},
+ {140, 5700, WLAN_TX_PWR_JP_A_DEFAULT, MTRUE}
+};
+
+/** Band: 'A', Region: China */
+static chan_freq_power_t channel_freq_power_CN_A[] = {
+ {149, 5745, WLAN_TX_PWR_CN_2000MW, MFALSE},
+ {153, 5765, WLAN_TX_PWR_CN_2000MW, MFALSE},
+ {157, 5785, WLAN_TX_PWR_CN_2000MW, MFALSE},
+ {161, 5805, WLAN_TX_PWR_CN_2000MW, MFALSE},
+ {165, 5825, WLAN_TX_PWR_CN_2000MW, MFALSE}
+};
+
+/**
+ * The 5GHz CFP tables
+ */
+static cfp_table_t cfp_table_A[] = {
+ {0x10, /* US FCC */
+ channel_freq_power_A,
+ sizeof(channel_freq_power_A) / sizeof(chan_freq_power_t),
+ }
+ ,
+ {0x20, /* CANADA IC */
+ channel_freq_power_CAN_A,
+ sizeof(channel_freq_power_CAN_A) / sizeof(chan_freq_power_t),
+ }
+ ,
+ {0x30, /* EU */
+ channel_freq_power_EU_A,
+ sizeof(channel_freq_power_EU_A) / sizeof(chan_freq_power_t),
+ }
+ ,
+ {0x32, /* FRANCE */
+ channel_freq_power_A,
+ sizeof(channel_freq_power_A) / sizeof(chan_freq_power_t),
+ }
+ ,
+ {0x40, /* JAPAN */
+ channel_freq_power_JPN_A,
+ sizeof(channel_freq_power_JPN_A) / sizeof(chan_freq_power_t),
+ }
+ ,
+ {0x41, /* JAPAN */
+ channel_freq_power_JPN_A,
+ sizeof(channel_freq_power_JPN_A) / sizeof(chan_freq_power_t),
+ }
+ ,
+ {0x50, /* China */
+ channel_freq_power_CN_A,
+ sizeof(channel_freq_power_CN_A) / sizeof(chan_freq_power_t),
+ }
+ ,
+ {0xff, /* Special */
+ channel_freq_power_JPN_A,
+ sizeof(channel_freq_power_JPN_A) / sizeof(chan_freq_power_t),
+ }
+ ,
+/* Add new region here */
+};
+
+/** Number of the CFP tables for 5GHz */
+#define MLAN_CFP_TABLE_SIZE_A (sizeof(cfp_table_A)/sizeof(cfp_table_t))
+
+/********************************************************
+ Global Variables
+********************************************************/
+/**
+ * The table to keep region code
+ */
+t_u16 region_code_index[MRVDRV_MAX_REGION_CODE] =
+ { 0x10, 0x20, 0x30, 0x32, 0x40, 0x41, 0x50, 0xff };
+
+/**
+ * The rates supported for ad-hoc B mode
+ */
+t_u8 AdhocRates_B[B_SUPPORTED_RATES] = { 0x82, 0x84, 0x8b, 0x96, 0 };
+
+/**
+ * The rates supported for ad-hoc G mode
+ */
+t_u8 AdhocRates_G[G_SUPPORTED_RATES] =
+ { 0x8c, 0x12, 0x98, 0x24, 0xb0, 0x48, 0x60, 0x6c, 0 };
+
+/**
+ * The rates supported for ad-hoc BG mode
+ */
+t_u8 AdhocRates_BG[BG_SUPPORTED_RATES] =
+ { 0x82, 0x84, 0x8b, 0x96, 0x0c, 0x12, 0x18, 0x24, 0x30, 0x48,
+ 0x60, 0x6c, 0
+};
+
+/**
+ * The rates supported in A mode for ad-hoc
+ */
+t_u8 AdhocRates_A[A_SUPPORTED_RATES] =
+ { 0x8c, 0x12, 0x98, 0x24, 0xb0, 0x48, 0x60, 0x6c, 0 };
+
+/**
+ * The rates supported in A mode (used for BAND_A)
+ */
+t_u8 SupportedRates_A[A_SUPPORTED_RATES] =
+ { 0x0c, 0x12, 0x18, 0x24, 0xb0, 0x48, 0x60, 0x6c, 0 };
+
+/**
+ * The rates supported by the card
+ */
+t_u16 WlanDataRates[WLAN_SUPPORTED_RATES_EXT] =
+ { 0x02, 0x04, 0x0B, 0x16, 0x00, 0x0C, 0x12,
+ 0x18, 0x24, 0x30, 0x48, 0x60, 0x6C, 0x90,
+ 0x0D, 0x1A, 0x27, 0x34, 0x4E, 0x68, 0x75,
+ 0x82, 0x0C, 0x1B, 0x36, 0x51, 0x6C, 0xA2,
+ 0xD8, 0xF3, 0x10E, 0x00
+};
+
+/**
+ * The rates supported in B mode
+ */
+t_u8 SupportedRates_B[B_SUPPORTED_RATES] = { 0x02, 0x04, 0x0b, 0x16, 0 };
+
+/**
+ * The rates supported in G mode (BAND_G, BAND_G|BAND_GN)
+ */
+t_u8 SupportedRates_G[G_SUPPORTED_RATES] =
+ { 0x0c, 0x12, 0x18, 0x24, 0x30, 0x48, 0x60, 0x6c, 0 };
+
+/**
+ * The rates supported in BG mode (BAND_B|BAND_G, BAND_B|BAND_G|BAND_GN)
+ */
+t_u8 SupportedRates_BG[BG_SUPPORTED_RATES] =
+ { 0x02, 0x04, 0x0b, 0x0c, 0x12, 0x16, 0x18, 0x24, 0x30, 0x48,
+ 0x60, 0x6c, 0
+};
+
+/**
+ * The rates supported in N mode
+ */
+t_u8 SupportedRates_N[N_SUPPORTED_RATES] = { 0x02, 0x04, 0 };
+
+/********************************************************
+ Local Functions
+********************************************************/
+/**
+ * @brief Find a character in a string.
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param s A pointer to string
+ * @param c Character to be located
+ * @param n The length of string
+ *
+ * @return A pointer to the first occurrence of c in string, or MNULL if c is not found.
+ */
+static void *
+wlan_memchr(pmlan_adapter pmadapter, void *s, int c, int n)
+{
+ const t_u8 *p = (t_u8 *) s;
+
+ ENTER();
+
+ while (n--) {
+ if ((t_u8) c == *p++) {
+ LEAVE();
+ return (void *) (p - 1);
+ }
+ }
+
+ LEAVE();
+ return MNULL;
+}
+
+/**
+ * @brief This function finds the CFP in
+ * cfp_table_BG/A based on region/code and band parameter.
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param region The region code
+ * @param band The band
+ * @param cfp_no A pointer to CFP number
+ *
+ * @return A pointer to CFP
+ */
+static chan_freq_power_t *
+wlan_get_region_cfp_table(pmlan_adapter pmadapter, t_u8 region, t_u8 band,
+ int *cfp_no)
+{
+ t_u32 i;
+ t_u8 cfp_bg, cfp_a;
+
+ ENTER();
+
+ cfp_bg = cfp_a = region;
+
+ if (band & (BAND_B | BAND_G | BAND_GN)) {
+ for (i = 0; i < MLAN_CFP_TABLE_SIZE_BG; i++) {
+ PRINTM(MINFO, "cfp_table_BG[%d].code=%d\n", i,
+ cfp_table_BG[i].code);
+ /* Check if region/code matches for BG bands */
+ if (cfp_table_BG[i].code == cfp_bg) {
+ /* Select by band */
+ *cfp_no = cfp_table_BG[i].cfp_no;
+ LEAVE();
+ return cfp_table_BG[i].cfp;
+ }
+ }
+ }
+ if (band & (BAND_A | BAND_AN)) {
+ for (i = 0; i < MLAN_CFP_TABLE_SIZE_A; i++) {
+ PRINTM(MINFO, "cfp_table_A[%d].code=%d\n", i, cfp_table_A[i].code);
+ /* Check if region/code matches for A bands */
+ if (cfp_table_A[i].code == cfp_a) {
+ /* Select by band */
+ *cfp_no = cfp_table_A[i].cfp_no;
+ LEAVE();
+ return cfp_table_A[i].cfp;
+ }
+ }
+ }
+
+ PRINTM(MERROR, "Error Band[0x%x] or region[%#x]\n", band, region);
+
+ LEAVE();
+ return MNULL;
+}
+
+/********************************************************
+ Global Functions
+********************************************************/
+
+#ifdef STA_SUPPORT
+#endif /* STA_SUPPORT */
+
+/**
+ * @brief Use index to get the data rate
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param index The index of data rate
+ * @param ht_info ht info
+ *
+ * @return Data rate or 0
+ */
+
+t_u32
+wlan_index_to_data_rate(pmlan_adapter pmadapter, t_u8 index, t_u8 ht_info)
+{
+#define MCS_NUM_SUPP 16
+ t_u16 mcs_rate[4][MCS_NUM_SUPP] =
+ { {0x1b, 0x36, 0x51, 0x6c, 0xa2, 0xd8, 0xf3, 0x10e, 0x36, 0x6c, 0xa2,
+ 0xd8, 0x144, 0x1b0, 0x1e6, 0x21c}
+ , /* LG 40M */
+ {0x1e, 0x3c, 0x5a, 0x78, 0xb4, 0xf0, 0x10e, 0x12c, 0x3c, 0x78, 0xb4, 0xf0,
+ 0x168, 0x1e0, 0x21c, 0x258}
+ , /* SG 40M */
+ {0x0d, 0x1a, 0x27, 0x34, 0x4e, 0x68, 0x75, 0x82, 0x1a, 0x34, 0x4e, 0x68,
+ 0x9c, 0xd0, 0xea, 0x104}
+ , /* LG 20M */
+ {0x0e, 0x1c, 0x2b, 0x39, 0x56, 0x73, 0x82, 0x90, 0x1c, 0x39, 0x56, 0x73,
+ 0xad, 0xe7, 0x104, 0x120}
+ }; /* SG 20M */
+
+ t_u32 rate = 0;
+ ENTER();
+
+ if (ht_info & MBIT(0)) {
+ if (index == MLAN_RATE_BITMAP_MCS0) {
+ if (ht_info & MBIT(2))
+ rate = 0x0D; /* MCS 32 SGI rate */
+ else
+ rate = 0x0C; /* MCS 32 LGI rate */
+ } else if (index < MCS_NUM_SUPP) {
+ if (ht_info & MBIT(1)) {
+ if (ht_info & MBIT(2))
+ rate = mcs_rate[1][index]; /* SGI, 40M */
+ else
+ rate = mcs_rate[0][index]; /* LGI, 40M */
+ } else {
+ if (ht_info & MBIT(2))
+ rate = mcs_rate[3][index]; /* SGI, 20M */
+ else
+ rate = mcs_rate[2][index]; /* LGI, 20M */
+ }
+ } else
+ rate = WlanDataRates[0];
+ } else {
+ /* 11n non HT rates */
+ if (index >= WLAN_SUPPORTED_RATES_EXT)
+ index = 0;
+ rate = WlanDataRates[index];
+ }
+ LEAVE();
+ return rate;
+}
+
+/**
+ * @brief Use rate to get the index
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param rate Data rate
+ *
+ * @return Index or 0
+ */
+t_u8
+wlan_data_rate_to_index(pmlan_adapter pmadapter, t_u32 rate)
+{
+ t_u16 *ptr;
+
+ ENTER();
+ if (rate)
+ if ((ptr = wlan_memchr(pmadapter, WlanDataRates, (t_u8) rate,
+ sizeof(WlanDataRates)))) {
+ LEAVE();
+ return (t_u8) (ptr - WlanDataRates);
+ }
+ LEAVE();
+ return 0;
+}
+
+/**
+ * @brief Get active data rates
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param bss_mode The specified BSS mode (Infra/IBSS)
+ * @param config_bands The specified band configuration
+ * @param rates The buf to return the active rates
+ *
+ * @return The number of Rates
+ */
+t_u32
+wlan_get_active_data_rates(mlan_private * pmpriv, t_u32 bss_mode,
+ t_u8 config_bands, WLAN_802_11_RATES rates)
+{
+ t_u32 k;
+
+ ENTER();
+
+ if (pmpriv->media_connected != MTRUE) {
+ k = wlan_get_supported_rates(pmpriv, bss_mode, config_bands, rates);
+ } else {
+ k = wlan_copy_rates(rates, 0, pmpriv->curr_bss_params.data_rates,
+ pmpriv->curr_bss_params.num_of_rates);
+ }
+
+ LEAVE();
+ return k;
+}
+
+#ifdef STA_SUPPORT
+/**
+ * @brief This function search through all the regions cfp table to find the channel,
+ * if the channel is found then gets the MIN txpower of the channel
+ * present in all the regions.
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param channel Channel number.
+ *
+ * @return The Tx power
+ */
+t_u8
+wlan_get_txpwr_of_chan_from_cfp(mlan_private * pmpriv, t_u8 channel)
+{
+ t_u8 i = 0;
+ t_u8 j = 0;
+ t_u8 tx_power = 0;
+ t_u32 cfp_no;
+ chan_freq_power_t *cfp = MNULL;
+ chan_freq_power_t *cfp_a = MNULL;
+ t_u32 cfp_no_a;
+
+ ENTER();
+
+ for (i = 0; i < MLAN_CFP_TABLE_SIZE_BG; i++) {
+ /* Get CFP */
+ cfp = cfp_table_BG[i].cfp;
+ cfp_no = cfp_table_BG[i].cfp_no;
+ /* Find matching channel and get Tx power */
+ for (j = 0; j < cfp_no; j++) {
+ if ((cfp + j)->channel == channel) {
+ if (tx_power != 0)
+ tx_power = MIN(tx_power, (cfp + j)->max_tx_power);
+ else
+ tx_power = (t_u8) (cfp + j)->max_tx_power;
+ break;
+ }
+ }
+ }
+
+ for (i = 0; i < MLAN_CFP_TABLE_SIZE_A; i++) {
+ /* Get CFP */
+ cfp_a = cfp_table_A[i].cfp;
+ cfp_no_a = cfp_table_A[i].cfp_no;
+ for (j = 0; j < cfp_no_a; j++) {
+ if ((cfp_a + j)->channel == channel) {
+ if (tx_power != 0)
+ tx_power = MIN(tx_power, (cfp_a + j)->max_tx_power);
+ else
+ tx_power = (t_u8) ((cfp_a + j)->max_tx_power);
+ break;
+ }
+ }
+ }
+
+ LEAVE();
+ return tx_power;
+}
+
+/**
+ * @brief Get the channel frequency power info for a specific channel
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param band It can be BAND_A, BAND_G or BAND_B
+ * @param channel The channel to search for
+ * @param region_channel A pointer to region_chan_t structure
+ *
+ * @return A pointer to chan_freq_power_t structure or MNULL if not found.
+ */
+
+chan_freq_power_t *
+wlan_get_cfp_by_band_and_channel(pmlan_adapter pmadapter,
+ t_u8 band,
+ t_u16 channel, region_chan_t * region_channel)
+{
+ region_chan_t *rc;
+ chan_freq_power_t *cfp = MNULL;
+ int i, j;
+
+ ENTER();
+
+ for (j = 0; !cfp && (j < MAX_REGION_CHANNEL_NUM); j++) {
+ rc = &region_channel[j];
+
+ if (!rc->valid || !rc->pcfp)
+ continue;
+ switch (rc->band) {
+ case BAND_A:
+ switch (band) {
+ case BAND_AN:
+ case BAND_A | BAND_AN:
+ case BAND_A: /* Matching BAND_A */
+ break;
+
+ default:
+ continue;
+ }
+ break;
+ case BAND_B:
+ case BAND_G:
+ switch (band) {
+ case BAND_GN:
+ case BAND_B | BAND_G | BAND_GN:
+ case BAND_G | BAND_GN:
+ case BAND_B | BAND_G:
+ case BAND_B: /* Matching BAND_B/G */
+ case BAND_G:
+ case 0:
+ break;
+ default:
+ continue;
+ }
+ break;
+ default:
+ continue;
+ }
+ if (channel == FIRST_VALID_CHANNEL)
+ cfp = &rc->pcfp[0];
+ else {
+ for (i = 0; i < rc->num_cfp; i++) {
+ if (rc->pcfp[i].channel == channel) {
+ cfp = &rc->pcfp[i];
+ break;
+ }
+ }
+ }
+ }
+
+ if (!cfp && channel)
+ PRINTM(MERROR, "wlan_get_cfp_by_band_and_channel(): cannot find "
+ "cfp by band %d & channel %d\n", band, channel);
+
+ LEAVE();
+ return cfp;
+}
+
+/**
+ * @brief Find the channel frequency power info for a specific channel
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param band It can be BAND_A, BAND_G or BAND_B
+ * @param channel The channel to search for
+ *
+ * @return A pointer to chan_freq_power_t structure or MNULL if not found.
+ */
+chan_freq_power_t *
+wlan_find_cfp_by_band_and_channel(mlan_adapter * pmadapter,
+ t_u8 band, t_u16 channel)
+{
+ chan_freq_power_t *cfp = MNULL;
+
+ ENTER();
+
+ /* Any station(s) with 11D enabled */
+ if (wlan_count_priv_cond(pmadapter, wlan_11d_is_enabled,
+ wlan_is_station) > 0)
+ cfp = wlan_get_cfp_by_band_and_channel(pmadapter, band, channel,
+ pmadapter->universal_channel);
+ else
+ cfp = wlan_get_cfp_by_band_and_channel(pmadapter, band, channel,
+ pmadapter->region_channel);
+
+ LEAVE();
+ return cfp;
+}
+
+/**
+ * @brief Find the channel frequency power info for a specific frequency
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param band It can be BAND_A, BAND_G or BAND_B
+ * @param freq The frequency to search for
+ *
+ * @return Pointer to chan_freq_power_t structure; MNULL if not found
+ */
+chan_freq_power_t *
+wlan_find_cfp_by_band_and_freq(mlan_adapter * pmadapter, t_u8 band, t_u32 freq)
+{
+ chan_freq_power_t *cfp = MNULL;
+ region_chan_t *rc;
+ int i, j;
+
+ ENTER();
+
+ for (j = 0; !cfp && (j < MAX_REGION_CHANNEL_NUM); j++) {
+ rc = &pmadapter->region_channel[j];
+
+ /* Any station(s) with 11D enabled */
+ if (wlan_count_priv_cond(pmadapter, wlan_11d_is_enabled,
+ wlan_is_station) > 0)
+ rc = &pmadapter->universal_channel[j];
+
+ if (!rc->valid || !rc->pcfp)
+ continue;
+ switch (rc->band) {
+ case BAND_A:
+ switch (band) {
+ case BAND_AN:
+ case BAND_A | BAND_AN:
+ case BAND_A: /* Matching BAND_A */
+ break;
+ default:
+ continue;
+ }
+ break;
+ case BAND_B:
+ case BAND_G:
+ switch (band) {
+ case BAND_GN:
+ case BAND_B | BAND_G | BAND_GN:
+ case BAND_G | BAND_GN:
+ case BAND_B | BAND_G:
+ case BAND_B:
+ case BAND_G:
+ case 0:
+ break;
+ default:
+ continue;
+ }
+ break;
+ default:
+ continue;
+ }
+ for (i = 0; i < rc->num_cfp; i++) {
+ if (rc->pcfp[i].freq == freq) {
+ cfp = &rc->pcfp[i];
+ break;
+ }
+ }
+ }
+
+ if (!cfp && freq)
+ PRINTM(MERROR, "wlan_find_cfp_by_band_and_freq(): cannot find cfp by "
+ "band %d & freq %d\n", band, freq);
+
+ LEAVE();
+ return cfp;
+}
+#endif /* STA_SUPPORT */
+
+/**
+ * @brief Check if Rate Auto
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ *
+ * @return MTRUE or MFALSE
+ */
+t_u8
+wlan_is_rate_auto(mlan_private * pmpriv)
+{
+ t_u32 i;
+ int rate_num = 0;
+
+ ENTER();
+
+ for (i = 0; i < NELEMENTS(pmpriv->bitmap_rates); i++)
+ if (pmpriv->bitmap_rates[i])
+ rate_num++;
+
+ LEAVE();
+ if (rate_num > 1)
+ return MTRUE;
+ else
+ return MFALSE;
+}
+
+/**
+ * @brief Covert Rate Bitmap to Rate index
+ *
+ * @param pmadapter Pointer to mlan_adapter structure
+ * @param rate_bitmap Pointer to rate bitmap
+ * @param size Size of the bitmap array
+ *
+ * @return Rate index
+ */
+int
+wlan_get_rate_index(pmlan_adapter pmadapter, t_u16 * rate_bitmap, int size)
+{
+ int i;
+
+ ENTER();
+
+ for (i = 0; i < size * 8; i++) {
+ if (rate_bitmap[i / 16] & (1 << (i % 16))) {
+ LEAVE();
+ return i;
+ }
+ }
+
+ LEAVE();
+ return -1;
+}
+
+/**
+ * @brief Get supported data rates
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param bss_mode The specified BSS mode (Infra/IBSS)
+ * @param config_bands The specified band configuration
+ * @param rates The buf to return the supported rates
+ *
+ * @return The number of Rates
+ */
+t_u32
+wlan_get_supported_rates(mlan_private * pmpriv, t_u32 bss_mode,
+ t_u8 config_bands, WLAN_802_11_RATES rates)
+{
+ t_u32 k = 0;
+
+ ENTER();
+
+ if (bss_mode == MLAN_BSS_MODE_INFRA) {
+ /* Infra. mode */
+ switch (config_bands) {
+ case BAND_B:
+ PRINTM(MINFO, "Infra Band=%d SupportedRates_B\n", config_bands);
+ k = wlan_copy_rates(rates, k, SupportedRates_B,
+ sizeof(SupportedRates_B));
+ break;
+ case BAND_G:
+ case BAND_G | BAND_GN:
+ PRINTM(MINFO, "Infra band=%d SupportedRates_G\n", config_bands);
+ k = wlan_copy_rates(rates, k, SupportedRates_G,
+ sizeof(SupportedRates_G));
+ break;
+ case BAND_B | BAND_G:
+ case BAND_A | BAND_B | BAND_G:
+ case BAND_A | BAND_B:
+ case BAND_A | BAND_B | BAND_G | BAND_GN | BAND_AN:
+ case BAND_B | BAND_G | BAND_GN:
+ PRINTM(MINFO, "Infra band=%d SupportedRates_BG\n", config_bands);
+#ifdef WIFI_DIRECT_SUPPORT
+ if (pmpriv->bss_type == MLAN_BSS_TYPE_WIFIDIRECT)
+ k = wlan_copy_rates(rates, k, SupportedRates_G,
+ sizeof(SupportedRates_G));
+ else
+ k = wlan_copy_rates(rates, k, SupportedRates_BG,
+ sizeof(SupportedRates_BG));
+#else
+ k = wlan_copy_rates(rates, k, SupportedRates_BG,
+ sizeof(SupportedRates_BG));
+#endif
+ break;
+ case BAND_A:
+ case BAND_A | BAND_G:
+ PRINTM(MINFO, "Infra band=%d SupportedRates_A\n", config_bands);
+ k = wlan_copy_rates(rates, k, SupportedRates_A,
+ sizeof(SupportedRates_A));
+ break;
+ case BAND_AN:
+ case BAND_A | BAND_AN:
+ case BAND_A | BAND_G | BAND_AN | BAND_GN:
+ PRINTM(MINFO, "Infra band=%d SupportedRates_A\n", config_bands);
+ k = wlan_copy_rates(rates, k, SupportedRates_A,
+ sizeof(SupportedRates_A));
+ break;
+ case BAND_GN:
+ PRINTM(MINFO, "Infra band=%d SupportedRates_N\n", config_bands);
+ k = wlan_copy_rates(rates, k, SupportedRates_N,
+ sizeof(SupportedRates_N));
+ break;
+ }
+ } else {
+ /* Ad-hoc mode */
+ switch (config_bands) {
+ case BAND_B:
+ PRINTM(MINFO, "Band: Adhoc B\n");
+ k = wlan_copy_rates(rates, k, AdhocRates_B, sizeof(AdhocRates_B));
+ break;
+ case BAND_G:
+ case BAND_G | BAND_GN:
+ PRINTM(MINFO, "Band: Adhoc G only\n");
+ k = wlan_copy_rates(rates, k, AdhocRates_G, sizeof(AdhocRates_G));
+ break;
+ case BAND_B | BAND_G:
+ case BAND_B | BAND_G | BAND_GN:
+ PRINTM(MINFO, "Band: Adhoc BG\n");
+ k = wlan_copy_rates(rates, k, AdhocRates_BG, sizeof(AdhocRates_BG));
+ break;
+ case BAND_A:
+ case BAND_AN:
+ case BAND_A | BAND_AN:
+ PRINTM(MINFO, "Band: Adhoc A\n");
+ k = wlan_copy_rates(rates, k, AdhocRates_A, sizeof(AdhocRates_A));
+ break;
+ }
+ }
+
+ LEAVE();
+ return k;
+}
+
+/**
+ * @brief This function sets region table.
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param region The region code
+ * @param band The band
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status
+wlan_set_regiontable(mlan_private * pmpriv, t_u8 region, t_u8 band)
+{
+ mlan_adapter *pmadapter = pmpriv->adapter;
+ int i = 0;
+ chan_freq_power_t *cfp;
+ int cfp_no;
+
+ ENTER();
+
+ memset(pmadapter, pmadapter->region_channel, 0,
+ sizeof(pmadapter->region_channel));
+
+ if (band & (BAND_B | BAND_G | BAND_GN)) {
+ cfp =
+ wlan_get_region_cfp_table(pmadapter, region,
+ BAND_G | BAND_B | BAND_GN, &cfp_no);
+ if (cfp) {
+ pmadapter->region_channel[i].num_cfp = (t_u8) cfp_no;
+ pmadapter->region_channel[i].pcfp = cfp;
+ } else {
+ PRINTM(MERROR, "wrong region code %#x in Band B-G\n", region);
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+ pmadapter->region_channel[i].valid = MTRUE;
+ pmadapter->region_channel[i].region = region;
+ if (band & BAND_GN)
+ pmadapter->region_channel[i].band = BAND_G;
+ else
+ pmadapter->region_channel[i].band =
+ (band & BAND_G) ? BAND_G : BAND_B;
+ i++;
+ }
+ if (band & (BAND_A | BAND_AN)) {
+ cfp = wlan_get_region_cfp_table(pmadapter, region, BAND_A, &cfp_no);
+ if (cfp) {
+ pmadapter->region_channel[i].num_cfp = (t_u8) cfp_no;
+ pmadapter->region_channel[i].pcfp = cfp;
+ } else {
+ PRINTM(MERROR, "wrong region code %#x in Band A\n", region);
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+ pmadapter->region_channel[i].valid = MTRUE;
+ pmadapter->region_channel[i].region = region;
+ pmadapter->region_channel[i].band = BAND_A;
+ }
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief Get if radar detection is enabled or not on a certain channel
+ *
+ * @param priv Private driver information structure
+ * @param chnl Channel to determine radar detection requirements
+ *
+ * @return
+ * - MTRUE if radar detection is required
+ * - MFALSE otherwise
+ */
+t_bool
+wlan_get_cfp_radar_detect(mlan_private * priv, t_u8 chnl)
+{
+ int i, j;
+ t_bool required = MFALSE;
+ chan_freq_power_t *pcfp = MNULL;
+
+ ENTER();
+
+ /* get the cfp table first */
+ for (i = 0; i < MAX_REGION_CHANNEL_NUM; i++) {
+ if (priv->adapter->region_channel[i].band == BAND_A) {
+ pcfp = priv->adapter->region_channel[i].pcfp;
+ break;
+ }
+ }
+
+ if (!pcfp) {
+ /* This means operation in BAND-A is not support, we can just return
+ false here, it's harmless */
+ goto done;
+ }
+
+ /* get the radar detection requirements according to chan num */
+ for (j = 0; j < priv->adapter->region_channel[i].num_cfp; j++) {
+ if (pcfp[j].channel == chnl) {
+ required = pcfp[j].radar_detect;
+ break;
+ }
+ }
+
+ done:
+ LEAVE();
+ return required;
+}
diff --git a/drivers/net/wireless/sd8797/mlan/mlan_cmdevt.c b/drivers/net/wireless/sd8797/mlan/mlan_cmdevt.c
new file mode 100644
index 000000000000..8b91ae2c43c2
--- /dev/null
+++ b/drivers/net/wireless/sd8797/mlan/mlan_cmdevt.c
@@ -0,0 +1,2927 @@
+/**
+ * @file mlan_cmdevt.c
+ *
+ * @brief This file contains the handling of CMD/EVENT in MLAN
+ *
+ * Copyright (C) 2009-2011, Marvell International Ltd.
+ *
+ * This software file (the "File") is distributed by Marvell International
+ * Ltd. under the terms of the GNU General Public License Version 2, June 1991
+ * (the "License"). You may use, redistribute and/or modify this File in
+ * accordance with the terms and conditions of the License, a copy of which
+ * is available by writing to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
+ * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
+ *
+ * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
+ * ARE EXPRESSLY DISCLAIMED. The License provides additional details about
+ * this warranty disclaimer.
+ */
+
+/*************************************************************
+Change Log:
+ 05/12/2009: initial version
+************************************************************/
+#include "mlan.h"
+#ifdef STA_SUPPORT
+#include "mlan_join.h"
+#endif
+#include "mlan_util.h"
+#include "mlan_fw.h"
+#include "mlan_main.h"
+#include "mlan_wmm.h"
+#include "mlan_11n.h"
+#include "mlan_11h.h"
+#include "mlan_sdio.h"
+/********************************************************
+ Local Variables
+********************************************************/
+
+/*******************************************************
+ Global Variables
+********************************************************/
+
+/********************************************************
+ Local Functions
+********************************************************/
+
+/**
+ * @brief This function convert a given character to hex
+ *
+ * @param chr Character to be converted
+ *
+ * @return The converted hex if chr is a valid hex, else 0
+ */
+static t_u32
+wlan_hexval(t_u8 chr)
+{
+ if (chr >= '0' && chr <= '9')
+ return chr - '0';
+ if (chr >= 'A' && chr <= 'F')
+ return chr - 'A' + 10;
+ if (chr >= 'a' && chr <= 'f')
+ return chr - 'a' + 10;
+
+ return 0;
+}
+
+/**
+ * @brief This function convert a given string to hex
+ *
+ * @param a A pointer to string to be converted
+ *
+ * @return The converted hex value if param a is a valid hex, else 0
+ */
+int
+wlan_atox(t_u8 * a)
+{
+ int i = 0;
+
+ ENTER();
+
+ while (wlan_isxdigit(*a))
+ i = i * 16 + wlan_hexval(*a++);
+
+ LEAVE();
+ return i;
+}
+
+/**
+ * @brief This function parse cal data from ASCII to hex
+ *
+ * @param src A pointer to source data
+ * @param len Source dara length
+ * @param dst A pointer to a buf to store the parsed data
+ *
+ * @return The parsed hex data length
+ */
+static t_u32
+wlan_parse_cal_cfg(t_u8 * src, t_size len, t_u8 * dst)
+{
+ t_u8 *ptr;
+ t_u8 *dptr;
+
+ ENTER();
+ ptr = src;
+ dptr = dst;
+
+ while (ptr - src < len) {
+ while (*ptr && (wlan_isspace(*ptr) || *ptr == '\t')) {
+ ptr++;
+ }
+
+ if (wlan_isxdigit(*ptr)) {
+ *dptr++ = wlan_atox(ptr);
+ ptr += 2;
+ } else {
+ ptr++;
+ }
+ }
+ LEAVE();
+ return (dptr - dst);
+}
+
+/**
+ * @brief This function initializes the command node.
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param pcmd_node A pointer to cmd_ctrl_node structure
+ * @param cmd_oid Cmd oid: treated as sub command
+ * @param pioctl_buf A pointer to MLAN IOCTL Request buffer
+ * @param pdata_buf A pointer to information buffer
+ *
+ * @return N/A
+ */
+static void
+wlan_init_cmd_node(IN pmlan_private pmpriv,
+ IN cmd_ctrl_node * pcmd_node,
+ IN t_u32 cmd_oid,
+ IN t_void * pioctl_buf, IN t_void * pdata_buf)
+{
+ mlan_adapter *pmadapter = pmpriv->adapter;
+
+ ENTER();
+
+ if (pcmd_node == MNULL) {
+ LEAVE();
+ return;
+ }
+ pcmd_node->priv = pmpriv;
+ pcmd_node->cmd_oid = cmd_oid;
+ pcmd_node->pioctl_buf = pioctl_buf;
+ pcmd_node->pdata_buf = pdata_buf;
+
+ pcmd_node->cmdbuf = pcmd_node->pmbuf;
+
+ /* Make sure head_ptr for cmd buf is Align */
+ pcmd_node->cmdbuf->data_offset = 0;
+ memset(pmadapter, pcmd_node->cmdbuf->pbuf, 0, MRVDRV_SIZE_OF_CMD_BUFFER);
+
+ /* Prepare mlan_buffer for command sending */
+ pcmd_node->cmdbuf->buf_type = MLAN_BUF_TYPE_CMD;
+ pcmd_node->cmdbuf->data_offset += INTF_HEADER_LEN;
+
+ LEAVE();
+}
+
+/**
+ * @brief This function gets a free command node if available in
+ * command free queue.
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ *
+ * @return cmd_ctrl_node A pointer to cmd_ctrl_node structure or MNULL
+ */
+static cmd_ctrl_node *
+wlan_get_cmd_node(mlan_adapter * pmadapter)
+{
+ cmd_ctrl_node *pcmd_node;
+
+ ENTER();
+
+ if (pmadapter == MNULL) {
+ LEAVE();
+ return MNULL;
+ }
+
+ if (util_peek_list(pmadapter->pmoal_handle, &pmadapter->cmd_free_q,
+ pmadapter->callbacks.moal_spin_lock,
+ pmadapter->callbacks.moal_spin_unlock)) {
+ pcmd_node = (cmd_ctrl_node *) util_dequeue_list(pmadapter->pmoal_handle,
+ &pmadapter->cmd_free_q,
+ pmadapter->callbacks.
+ moal_spin_lock,
+ pmadapter->callbacks.
+ moal_spin_unlock);
+ } else {
+ PRINTM(MERROR, "GET_CMD_NODE: cmd_ctrl_node is not available\n");
+ pcmd_node = MNULL;
+ }
+
+ LEAVE();
+ return pcmd_node;
+}
+
+/**
+ * @brief This function cleans command node.
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pcmd_node A pointer to cmd_ctrl_node structure
+ *
+ * @return N/A
+ */
+static t_void
+wlan_clean_cmd_node(pmlan_adapter pmadapter, cmd_ctrl_node * pcmd_node)
+{
+ ENTER();
+
+ if (pcmd_node == MNULL) {
+ LEAVE();
+ return;
+ }
+ pcmd_node->cmd_oid = 0;
+ pcmd_node->cmd_flag = 0;
+ pcmd_node->pioctl_buf = MNULL;
+ pcmd_node->pdata_buf = MNULL;
+
+ if (pcmd_node->respbuf) {
+ wlan_free_mlan_buffer(pmadapter, pcmd_node->respbuf);
+ pcmd_node->respbuf = MNULL;
+ }
+
+ LEAVE();
+ return;
+}
+
+/**
+ * @brief This function will return the pointer to the first entry in
+ * pending cmd which matches the given pioctl_req
+ *
+ * @param pmadapter A pointer to mlan_adapter
+ * @param pioctl_req A pointer to mlan_ioctl_req buf
+ *
+ * @return A pointer to first entry match pioctl_req
+ */
+static cmd_ctrl_node *
+wlan_get_pending_ioctl_cmd(pmlan_adapter pmadapter, pmlan_ioctl_req pioctl_req)
+{
+ cmd_ctrl_node *pcmd_node = MNULL;
+
+ ENTER();
+
+ if (!
+ (pcmd_node =
+ (cmd_ctrl_node *) util_peek_list(pmadapter->pmoal_handle,
+ &pmadapter->cmd_pending_q,
+ pmadapter->callbacks.moal_spin_lock,
+ pmadapter->callbacks.
+ moal_spin_unlock))) {
+ LEAVE();
+ return MNULL;
+ }
+ while (pcmd_node != (cmd_ctrl_node *) & pmadapter->cmd_pending_q) {
+ if (pcmd_node->pioctl_buf == pioctl_req) {
+ LEAVE();
+ return pcmd_node;
+ }
+ pcmd_node = pcmd_node->pnext;
+ }
+ LEAVE();
+ return MNULL;
+}
+
+/**
+ * @brief This function handles the command response of host_cmd
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param resp A pointer to HostCmd_DS_COMMAND
+ * @param pioctl_buf A pointer to mlan_ioctl_req structure
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+static mlan_status
+wlan_ret_host_cmd(IN pmlan_private pmpriv,
+ IN HostCmd_DS_COMMAND * resp, IN mlan_ioctl_req * pioctl_buf)
+{
+ mlan_ds_misc_cfg *misc;
+ t_u16 size = wlan_le16_to_cpu(resp->size);
+
+ ENTER();
+
+ PRINTM(MINFO, "host command response size = %d\n", size);
+ size = MIN(size, MRVDRV_SIZE_OF_CMD_BUFFER);
+ if (pioctl_buf) {
+ misc = (mlan_ds_misc_cfg *) pioctl_buf->pbuf;
+ misc->param.hostcmd.len = size;
+ memcpy(pmpriv->adapter, misc->param.hostcmd.cmd, (void *) resp, size);
+ }
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function sends host command to firmware.
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param cmd A pointer to HostCmd_DS_COMMAND structure
+ * @param pdata_buf A pointer to data buffer
+ * @return MLAN_STATUS_SUCCESS
+ */
+static mlan_status
+wlan_cmd_host_cmd(IN pmlan_private pmpriv,
+ IN HostCmd_DS_COMMAND * cmd, IN t_void * pdata_buf)
+{
+ mlan_ds_misc_cmd *pcmd_ptr = (mlan_ds_misc_cmd *) pdata_buf;
+
+ ENTER();
+
+ /* Copy the HOST command to command buffer */
+ memcpy(pmpriv->adapter, (void *) cmd, pcmd_ptr->cmd,
+ MIN(MRVDRV_SIZE_OF_CMD_BUFFER, pcmd_ptr->len));
+ PRINTM(MINFO, "Host command size = %d\n", pcmd_ptr->len);
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function downloads a command to firmware.
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param pcmd_node A pointer to cmd_ctrl_node structure
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+static mlan_status
+wlan_dnld_cmd_to_fw(IN mlan_private * pmpriv, IN cmd_ctrl_node * pcmd_node)
+{
+
+ mlan_adapter *pmadapter = pmpriv->adapter;
+ mlan_callbacks *pcb = (mlan_callbacks *) & pmadapter->callbacks;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ HostCmd_DS_COMMAND *pcmd;
+ mlan_ioctl_req *pioctl_buf = MNULL;
+ t_u16 cmd_code;
+ t_u16 cmd_size;
+ t_u32 sec, usec;
+
+ ENTER();
+
+ if (pcmd_node)
+ if (pcmd_node->pioctl_buf != MNULL)
+ pioctl_buf = (mlan_ioctl_req *) pcmd_node->pioctl_buf;
+ if (!pmadapter || !pcmd_node) {
+ if (pioctl_buf)
+ pioctl_buf->status_code = MLAN_ERROR_CMD_DNLD_FAIL;
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ pcmd =
+ (HostCmd_DS_COMMAND *) (pcmd_node->cmdbuf->pbuf +
+ pcmd_node->cmdbuf->data_offset);
+
+ /* Sanity test */
+ if (pcmd == MNULL || pcmd->size == 0) {
+ PRINTM(MERROR, "DNLD_CMD: pcmd is null or command size is zero, "
+ "Not sending\n");
+ if (pioctl_buf)
+ pioctl_buf->status_code = MLAN_ERROR_CMD_DNLD_FAIL;
+ wlan_insert_cmd_to_free_q(pmadapter, pcmd_node);
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ /* Set command sequence number */
+ pmadapter->seq_num++;
+ pcmd->seq_num =
+ wlan_cpu_to_le16(HostCmd_SET_SEQ_NO_BSS_INFO
+ (pmadapter->seq_num, pcmd_node->priv->bss_num,
+ pcmd_node->priv->bss_type));
+
+ wlan_request_cmd_lock(pmadapter);
+ pmadapter->curr_cmd = pcmd_node;
+ wlan_release_cmd_lock(pmadapter);
+
+ cmd_code = wlan_le16_to_cpu(pcmd->command);
+ cmd_size = wlan_le16_to_cpu(pcmd->size);
+
+ pcmd_node->cmdbuf->data_len = cmd_size;
+
+ pmadapter->callbacks.moal_get_system_time(pmadapter->pmoal_handle, &sec,
+ &usec);
+ PRINTM_NETINTF(MCMND, pmpriv);
+ PRINTM(MCMND, "DNLD_CMD (%lu.%06lu): 0x%x, act 0x%x, len %d, seqno 0x%x\n",
+ sec, usec, cmd_code,
+ wlan_le16_to_cpu(*(t_u16 *) ((t_u8 *) pcmd + S_DS_GEN)), cmd_size,
+ wlan_le16_to_cpu(pcmd->seq_num));
+ DBG_HEXDUMP(MCMD_D, "DNLD_CMD", (t_u8 *) pcmd, cmd_size);
+
+ /* Send the command to lower layer */
+
+ pcmd_node->cmdbuf->data_offset -= INTF_HEADER_LEN;
+ pcmd_node->cmdbuf->data_len += INTF_HEADER_LEN;
+ /* Extra header for SDIO is added here */
+ ret =
+ wlan_sdio_host_to_card(pmadapter, MLAN_TYPE_CMD, pcmd_node->cmdbuf,
+ MNULL);
+
+ if (ret == MLAN_STATUS_FAILURE) {
+ PRINTM(MERROR, "DNLD_CMD: Host to Card Failed\n");
+ if (pioctl_buf)
+ pioctl_buf->status_code = MLAN_ERROR_CMD_DNLD_FAIL;
+ wlan_insert_cmd_to_free_q(pmadapter, pmadapter->curr_cmd);
+
+ wlan_request_cmd_lock(pmadapter);
+ pmadapter->curr_cmd = MNULL;
+ wlan_release_cmd_lock(pmadapter);
+
+ pmadapter->dbg.num_cmd_host_to_card_failure++;
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ /* Save the last command id and action to debug log */
+ pmadapter->dbg.last_cmd_index =
+ (pmadapter->dbg.last_cmd_index + 1) % DBG_CMD_NUM;
+ pmadapter->dbg.last_cmd_id[pmadapter->dbg.last_cmd_index] = cmd_code;
+ pmadapter->dbg.last_cmd_act[pmadapter->dbg.last_cmd_index] =
+ wlan_le16_to_cpu(*(t_u16 *) ((t_u8 *) pcmd + S_DS_GEN));
+
+ /* Clear BSS_NO_BITS from HostCmd */
+ cmd_code &= HostCmd_CMD_ID_MASK;
+ /* soft_reset command has no command response, we should return here */
+ if (cmd_code == HostCmd_CMD_SOFT_RESET) {
+ PRINTM(MCMND, "DNLD_CMD: SoftReset\n");
+ if (pioctl_buf) {
+ wlan_request_cmd_lock(pmadapter);
+ pmadapter->curr_cmd->pioctl_buf = MNULL;
+ wlan_release_cmd_lock(pmadapter);
+ pcb->moal_ioctl_complete(pmadapter->pmoal_handle, pioctl_buf,
+ MLAN_STATUS_SUCCESS);
+ }
+ goto done;
+ }
+
+ /* Setup the timer after transmit command */
+ pcb->moal_start_timer(pmadapter->pmoal_handle, pmadapter->pmlan_cmd_timer,
+ MFALSE, MRVDRV_TIMER_60S);
+
+ pmadapter->cmd_timer_is_set = MTRUE;
+
+ ret = MLAN_STATUS_SUCCESS;
+
+ done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function sends sleep confirm command to firmware.
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+static mlan_status
+wlan_dnld_sleep_confirm_cmd(mlan_adapter * pmadapter)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ static t_u32 i = 0;
+ t_u16 cmd_len = 0;
+ opt_sleep_confirm_buffer *sleep_cfm_buf =
+ (opt_sleep_confirm_buffer *) (pmadapter->psleep_cfm->pbuf +
+ pmadapter->psleep_cfm->data_offset);
+
+ ENTER();
+
+ cmd_len = sizeof(OPT_Confirm_Sleep);
+ pmadapter->seq_num++;
+ sleep_cfm_buf->ps_cfm_sleep.seq_num =
+ wlan_cpu_to_le16(HostCmd_SET_SEQ_NO_BSS_INFO
+ (pmadapter->seq_num,
+ (wlan_get_priv(pmadapter, MLAN_BSS_ROLE_ANY))->
+ bss_num,
+ (wlan_get_priv(pmadapter, MLAN_BSS_ROLE_ANY))->
+ bss_type));
+ DBG_HEXDUMP(MCMD_D, "SLEEP_CFM", &sleep_cfm_buf->ps_cfm_sleep,
+ sizeof(OPT_Confirm_Sleep));
+
+ /* Send sleep confirm command to firmware */
+
+ pmadapter->psleep_cfm->data_len = cmd_len + INTF_HEADER_LEN;
+ ret = wlan_sdio_host_to_card(pmadapter, MLAN_TYPE_CMD,
+ pmadapter->psleep_cfm, MNULL);
+
+ if (ret == MLAN_STATUS_FAILURE) {
+ PRINTM(MERROR, "SLEEP_CFM: failed\n");
+ pmadapter->dbg.num_cmd_sleep_cfm_host_to_card_failure++;
+ goto done;
+ } else {
+ if (GET_BSS_ROLE(wlan_get_priv(pmadapter, MLAN_BSS_ROLE_ANY)) ==
+ MLAN_BSS_ROLE_UAP)
+ pmadapter->ps_state = PS_STATE_SLEEP_CFM;
+#ifdef STA_SUPPORT
+ if (GET_BSS_ROLE(wlan_get_priv(pmadapter, MLAN_BSS_ROLE_ANY)) ==
+ MLAN_BSS_ROLE_STA) {
+ if (!sleep_cfm_buf->ps_cfm_sleep.sleep_cfm.resp_ctrl) {
+ /* Response is not needed for sleep confirm command */
+ pmadapter->ps_state = PS_STATE_SLEEP;
+ } else {
+ pmadapter->ps_state = PS_STATE_SLEEP_CFM;
+ }
+
+ if (!sleep_cfm_buf->ps_cfm_sleep.sleep_cfm.resp_ctrl
+ && (pmadapter->is_hs_configured &&
+ !pmadapter->sleep_period.period)) {
+ pmadapter->pm_wakeup_card_req = MTRUE;
+ wlan_host_sleep_activated_event(wlan_get_priv
+ (pmadapter, MLAN_BSS_ROLE_STA),
+ MTRUE);
+ }
+ }
+#endif /* STA_SUPPORT */
+
+#define NUM_SC_PER_LINE 16
+ if (++i % NUM_SC_PER_LINE == 0)
+ PRINTM(MEVENT, "+\n");
+ else
+ PRINTM(MEVENT, "+");
+ }
+
+ done:
+ LEAVE();
+ return ret;
+}
+
+/********************************************************
+ Global Functions
+********************************************************/
+
+/**
+ * @brief Event handler
+ *
+ * @param priv A pointer to mlan_private structure
+ * @param event_id Event ID
+ * @param pmevent Event buffer
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+mlan_status
+wlan_recv_event(pmlan_private priv, mlan_event_id event_id, t_void * pmevent)
+{
+ pmlan_callbacks pcb = &priv->adapter->callbacks;
+
+ ENTER();
+
+ if (pmevent)
+ /* The caller has provided the event. */
+ pcb->moal_recv_event(priv->adapter->pmoal_handle,
+ (pmlan_event) pmevent);
+ else {
+ mlan_event mevent;
+
+ memset(priv->adapter, &mevent, 0, sizeof(mlan_event));
+ mevent.bss_index = priv->bss_index;
+ mevent.event_id = event_id;
+ mevent.event_len = 0;
+
+ pcb->moal_recv_event(priv->adapter->pmoal_handle, &mevent);
+ }
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function allocates the command buffer and links
+ * it to command free queue.
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status
+wlan_alloc_cmd_buffer(IN mlan_adapter * pmadapter)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_callbacks *pcb = (mlan_callbacks *) & pmadapter->callbacks;
+ cmd_ctrl_node *pcmd_array = MNULL;
+ t_u32 buf_size;
+ t_u32 i;
+
+ ENTER();
+
+ /* Allocate and initialize cmd_ctrl_node */
+ buf_size = sizeof(cmd_ctrl_node) * MRVDRV_NUM_OF_CMD_BUFFER;
+ ret =
+ pcb->moal_malloc(pmadapter->pmoal_handle, buf_size,
+ MLAN_MEM_DEF | MLAN_MEM_DMA, (t_u8 **) & pcmd_array);
+ if (ret != MLAN_STATUS_SUCCESS || !pcmd_array) {
+ PRINTM(MERROR, "ALLOC_CMD_BUF: Failed to allocate pcmd_array\n");
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ pmadapter->cmd_pool = pcmd_array;
+ memset(pmadapter, pmadapter->cmd_pool, 0, buf_size);
+
+ /* Allocate and initialize command buffers */
+ for (i = 0; i < MRVDRV_NUM_OF_CMD_BUFFER; i++) {
+ if (!(pcmd_array[i].pmbuf = wlan_alloc_mlan_buffer(pmadapter,
+ MRVDRV_SIZE_OF_CMD_BUFFER,
+ 0, MTRUE))) {
+ PRINTM(MERROR,
+ "ALLOC_CMD_BUF: Failed to allocate command buffer\n");
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ }
+
+ for (i = 0; i < MRVDRV_NUM_OF_CMD_BUFFER; i++) {
+ wlan_insert_cmd_to_free_q(pmadapter, &pcmd_array[i]);
+ }
+ ret = MLAN_STATUS_SUCCESS;
+ done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function frees the command buffer.
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+mlan_status
+wlan_free_cmd_buffer(IN mlan_adapter * pmadapter)
+{
+ mlan_callbacks *pcb = (mlan_callbacks *) & pmadapter->callbacks;
+ cmd_ctrl_node *pcmd_array;
+ t_u32 i;
+
+ ENTER();
+
+ /* Need to check if cmd pool is allocated or not */
+ if (pmadapter->cmd_pool == MNULL) {
+ PRINTM(MINFO, "FREE_CMD_BUF: cmd_pool is Null\n");
+ goto done;
+ }
+
+ pcmd_array = pmadapter->cmd_pool;
+
+ /* Release shared memory buffers */
+ for (i = 0; i < MRVDRV_NUM_OF_CMD_BUFFER; i++) {
+ if (pcmd_array[i].pmbuf) {
+ PRINTM(MINFO, "Free all the command buffer.\n");
+ wlan_free_mlan_buffer(pmadapter, pcmd_array[i].pmbuf);
+ pcmd_array[i].pmbuf = MNULL;
+ }
+ if (pcmd_array[i].respbuf) {
+ wlan_free_mlan_buffer(pmadapter, pcmd_array[i].respbuf);
+ pcmd_array[i].respbuf = MNULL;
+ }
+ }
+ /* Release cmd_ctrl_node */
+ if (pmadapter->cmd_pool) {
+ PRINTM(MINFO, "Free command pool.\n");
+ pcb->moal_mfree(pmadapter->pmoal_handle, (t_u8 *) pmadapter->cmd_pool);
+ pmadapter->cmd_pool = MNULL;
+ }
+
+ done:
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function handles events generated by firmware
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status
+wlan_process_event(pmlan_adapter pmadapter)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ pmlan_private priv = wlan_get_priv(pmadapter, MLAN_BSS_ROLE_ANY);
+ pmlan_buffer pmbuf = pmadapter->pmlan_buffer_event;
+ t_u32 eventcause = pmadapter->event_cause;
+ t_u32 in_ts_sec;
+ t_u32 in_ts_usec;
+ ENTER();
+
+ /* Save the last event to debug log */
+ pmadapter->dbg.last_event_index =
+ (pmadapter->dbg.last_event_index + 1) % DBG_CMD_NUM;
+ pmadapter->dbg.last_event[pmadapter->dbg.last_event_index] =
+ (t_u16) eventcause;
+
+ if ((eventcause & EVENT_ID_MASK) == EVENT_RADAR_DETECTED) {
+ if (wlan_11h_dfs_event_preprocessing(pmadapter) == MLAN_STATUS_SUCCESS) {
+ memcpy(pmadapter, (t_u8 *) & eventcause,
+ pmbuf->pbuf + pmbuf->data_offset, sizeof(eventcause));
+ }
+ }
+ /* Get BSS number and corresponding priv */
+ priv =
+ wlan_get_priv_by_id(pmadapter, EVENT_GET_BSS_NUM(eventcause),
+ EVENT_GET_BSS_TYPE(eventcause));
+ if (!priv)
+ priv = wlan_get_priv(pmadapter, MLAN_BSS_ROLE_ANY);
+
+ /* Clear BSS_NO_BITS from event */
+ eventcause &= EVENT_ID_MASK;
+ pmadapter->event_cause = eventcause;
+
+ if (pmbuf) {
+ pmbuf->bss_index = priv->bss_index;
+ memcpy(pmadapter,
+ pmbuf->pbuf + pmbuf->data_offset,
+ (t_u8 *) & eventcause, sizeof(eventcause));
+ }
+
+ if (MTRUE && (eventcause != EVENT_PS_SLEEP && eventcause != EVENT_PS_AWAKE)
+ ) {
+ pmadapter->callbacks.moal_get_system_time(pmadapter->pmoal_handle,
+ &in_ts_sec, &in_ts_usec);
+ PRINTM_NETINTF(MEVENT, priv);
+ PRINTM(MEVENT, "%lu.%06lu : Event: 0x%x\n", in_ts_sec, in_ts_usec,
+ eventcause);
+ }
+
+ ret = priv->ops.process_event(priv);
+
+ pmadapter->event_cause = 0;
+ pmadapter->pmlan_buffer_event = MNULL;
+ if (pmbuf) {
+ wlan_free_mlan_buffer(pmadapter, pmbuf);
+ }
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function requests a lock on command queue.
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ *
+ * @return N/A
+ */
+t_void
+wlan_request_cmd_lock(IN mlan_adapter * pmadapter)
+{
+ mlan_callbacks *pcb = (mlan_callbacks *) & pmadapter->callbacks;
+
+ ENTER();
+
+ /* Call MOAL spin lock callback function */
+ pcb->moal_spin_lock(pmadapter->pmoal_handle, pmadapter->pmlan_cmd_lock);
+
+ LEAVE();
+ return;
+}
+
+/**
+ * @brief This function releases a lock on command queue.
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ *
+ * @return N/A
+ */
+t_void
+wlan_release_cmd_lock(IN mlan_adapter * pmadapter)
+{
+ mlan_callbacks *pcb = (mlan_callbacks *) & pmadapter->callbacks;
+
+ ENTER();
+
+ /* Call MOAL spin unlock callback function */
+ pcb->moal_spin_unlock(pmadapter->pmoal_handle, pmadapter->pmlan_cmd_lock);
+
+ LEAVE();
+ return;
+}
+
+/**
+ * @brief This function prepare the command before sending to firmware.
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param cmd_no Command number
+ * @param cmd_action Command action: GET or SET
+ * @param cmd_oid Cmd oid: treated as sub command
+ * @param pioctl_buf A pointer to MLAN IOCTL Request buffer
+ * @param pdata_buf A pointer to information buffer
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status
+wlan_prepare_cmd(IN mlan_private * pmpriv,
+ IN t_u16 cmd_no,
+ IN t_u16 cmd_action,
+ IN t_u32 cmd_oid,
+ IN t_void * pioctl_buf, IN t_void * pdata_buf)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_adapter *pmadapter = pmpriv->adapter;
+ cmd_ctrl_node *pcmd_node = MNULL;
+ HostCmd_DS_COMMAND *cmd_ptr = MNULL;
+ pmlan_ioctl_req pioctl_req = (mlan_ioctl_req *) pioctl_buf;
+
+ ENTER();
+
+ /* Sanity test */
+ if (!pmadapter || pmadapter->surprise_removed) {
+ PRINTM(MERROR, "PREP_CMD: Card is Removed\n");
+ if (pioctl_req)
+ pioctl_req->status_code = MLAN_ERROR_FW_NOT_READY;
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ if (pmadapter->hw_status == WlanHardwareStatusReset) {
+ if ((cmd_no != HostCmd_CMD_FUNC_INIT)
+ ) {
+ PRINTM(MERROR, "PREP_CMD: FW is in reset state\n");
+ if (pioctl_req)
+ pioctl_req->status_code = MLAN_ERROR_FW_NOT_READY;
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ }
+
+ /* Get a new command node */
+ pcmd_node = wlan_get_cmd_node(pmadapter);
+
+ if (pcmd_node == MNULL) {
+ PRINTM(MERROR, "PREP_CMD: No free cmd node\n");
+ if (pioctl_req)
+ pioctl_req->status_code = MLAN_ERROR_NO_MEM;
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ /* Initialize the command node */
+ wlan_init_cmd_node(pmpriv, pcmd_node, cmd_oid, pioctl_buf, pdata_buf);
+
+ if (pcmd_node->cmdbuf == MNULL) {
+ PRINTM(MERROR, "PREP_CMD: No free cmd buf\n");
+ if (pioctl_req)
+ pioctl_req->status_code = MLAN_ERROR_NO_MEM;
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ cmd_ptr =
+ (HostCmd_DS_COMMAND *) (pcmd_node->cmdbuf->pbuf +
+ pcmd_node->cmdbuf->data_offset);
+ cmd_ptr->command = cmd_no;
+ cmd_ptr->result = 0;
+
+ /* Prepare command */
+ if (cmd_no)
+ ret =
+ pmpriv->ops.prepare_cmd(pmpriv, cmd_no, cmd_action, cmd_oid,
+ pioctl_buf, pdata_buf, cmd_ptr);
+ else {
+ ret = wlan_cmd_host_cmd(pmpriv, cmd_ptr, pdata_buf);
+ pcmd_node->cmd_flag |= CMD_F_HOSTCMD;
+ }
+
+ /* Return error, since the command preparation failed */
+ if (ret != MLAN_STATUS_SUCCESS) {
+ PRINTM(MERROR, "PREP_CMD: Command 0x%x preparation failed\n", cmd_no);
+ pcmd_node->pioctl_buf = MNULL;
+ wlan_insert_cmd_to_free_q(pmadapter, pcmd_node);
+ if (pioctl_req)
+ pioctl_req->status_code = MLAN_ERROR_CMD_DNLD_FAIL;
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ /* Send command */
+#ifdef STA_SUPPORT
+ if (cmd_no == HostCmd_CMD_802_11_SCAN
+ || cmd_no == HostCmd_CMD_802_11_SCAN_EXT)
+ wlan_queue_scan_cmd(pmpriv, pcmd_node);
+ else {
+#endif
+ if ((cmd_no == HostCmd_CMD_802_11_HS_CFG_ENH) &&
+ (cmd_action == HostCmd_ACT_GEN_SET) &&
+ (pmadapter->hs_cfg.conditions == HOST_SLEEP_CFG_CANCEL))
+ wlan_insert_cmd_to_pending_q(pmadapter, pcmd_node, MFALSE);
+ else
+ wlan_insert_cmd_to_pending_q(pmadapter, pcmd_node, MTRUE);
+#ifdef STA_SUPPORT
+ }
+#endif
+ done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function inserts command node to cmd_free_q
+ * after cleaning it.
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pcmd_node A pointer to cmd_ctrl_node structure
+ *
+ * @return N/A
+ */
+t_void
+wlan_insert_cmd_to_free_q(IN mlan_adapter * pmadapter,
+ IN cmd_ctrl_node * pcmd_node)
+{
+ mlan_callbacks *pcb = (mlan_callbacks *) & pmadapter->callbacks;
+ mlan_ioctl_req *pioctl_req = MNULL;
+ ENTER();
+
+ if (pcmd_node == MNULL)
+ goto done;
+ if (pcmd_node->pioctl_buf) {
+ pioctl_req = (mlan_ioctl_req *) pcmd_node->pioctl_buf;
+ if (pioctl_req->status_code != MLAN_ERROR_NO_ERROR)
+ pcb->moal_ioctl_complete(pmadapter->pmoal_handle,
+ pioctl_req, MLAN_STATUS_FAILURE);
+ else
+ pcb->moal_ioctl_complete(pmadapter->pmoal_handle,
+ pioctl_req, MLAN_STATUS_SUCCESS);
+ }
+ /* Clean the node */
+ wlan_clean_cmd_node(pmadapter, pcmd_node);
+
+ /* Insert node into cmd_free_q */
+ util_enqueue_list_tail(pmadapter->pmoal_handle, &pmadapter->cmd_free_q,
+ (pmlan_linked_list) pcmd_node,
+ pmadapter->callbacks.moal_spin_lock,
+ pmadapter->callbacks.moal_spin_unlock);
+ done:
+ LEAVE();
+}
+
+/**
+ * @brief This function queues the command to cmd list.
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pcmd_node A pointer to cmd_ctrl_node structure
+ * @param add_tail Specify if the cmd needs to be queued in the header or tail
+ *
+ * @return N/A
+ */
+t_void
+wlan_insert_cmd_to_pending_q(IN mlan_adapter * pmadapter,
+ IN cmd_ctrl_node * pcmd_node, IN t_u32 add_tail)
+{
+ HostCmd_DS_COMMAND *pcmd = MNULL;
+ t_u16 command;
+
+ ENTER();
+
+ if (pcmd_node == MNULL) {
+ PRINTM(MERROR, "QUEUE_CMD: pcmd_node is MNULL\n");
+ goto done;
+ }
+
+ pcmd =
+ (HostCmd_DS_COMMAND *) (pcmd_node->cmdbuf->pbuf +
+ pcmd_node->cmdbuf->data_offset);
+ if (pcmd == MNULL) {
+ PRINTM(MERROR, "QUEUE_CMD: pcmd is MNULL\n");
+ goto done;
+ }
+
+ command = wlan_le16_to_cpu(pcmd->command);
+
+ /* Exit_PS command needs to be queued in the header always. */
+ if (command == HostCmd_CMD_802_11_PS_MODE_ENH) {
+ HostCmd_DS_802_11_PS_MODE_ENH *pm = &pcmd->params.psmode_enh;
+ if (wlan_le16_to_cpu(pm->action) == DIS_AUTO_PS) {
+ if (pmadapter->ps_state != PS_STATE_AWAKE)
+ add_tail = MFALSE;
+ }
+ }
+
+ if (add_tail) {
+ util_enqueue_list_tail(pmadapter->pmoal_handle,
+ &pmadapter->cmd_pending_q,
+ (pmlan_linked_list) pcmd_node,
+ pmadapter->callbacks.moal_spin_lock,
+ pmadapter->callbacks.moal_spin_unlock);
+ } else {
+ util_enqueue_list_head(pmadapter->pmoal_handle,
+ &pmadapter->cmd_pending_q,
+ (pmlan_linked_list) pcmd_node,
+ pmadapter->callbacks.moal_spin_lock,
+ pmadapter->callbacks.moal_spin_unlock);
+ }
+
+ PRINTM_NETINTF(MCMND, pcmd_node->priv);
+ PRINTM(MCMND, "QUEUE_CMD: cmd=0x%x is queued\n", command);
+
+ done:
+ LEAVE();
+ return;
+}
+
+/**
+ * @brief This function executes next command in command
+ * pending queue. It will put firmware back to PS mode
+ * if applicable.
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status
+wlan_exec_next_cmd(mlan_adapter * pmadapter)
+{
+ mlan_private *priv = MNULL;
+ cmd_ctrl_node *pcmd_node = MNULL;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ HostCmd_DS_COMMAND *pcmd;
+
+ ENTER();
+
+ /* Sanity test */
+ if (pmadapter == MNULL) {
+ PRINTM(MERROR, "EXEC_NEXT_CMD: pmadapter is MNULL\n");
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ /* Check if already in processing */
+ if (pmadapter->curr_cmd) {
+ PRINTM(MERROR, "EXEC_NEXT_CMD: there is command in processing!\n");
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ wlan_request_cmd_lock(pmadapter);
+ /* Check if any command is pending */
+ pcmd_node =
+ (cmd_ctrl_node *) util_peek_list(pmadapter->pmoal_handle,
+ &pmadapter->cmd_pending_q,
+ pmadapter->callbacks.moal_spin_lock,
+ pmadapter->callbacks.moal_spin_unlock);
+
+ if (pcmd_node) {
+ pcmd =
+ (HostCmd_DS_COMMAND *) (pcmd_node->cmdbuf->pbuf +
+ pcmd_node->cmdbuf->data_offset);
+ priv = pcmd_node->priv;
+
+ if (pmadapter->ps_state != PS_STATE_AWAKE) {
+ PRINTM(MERROR,
+ "Cannot send command in sleep state, this should not happen\n");
+ wlan_release_cmd_lock(pmadapter);
+ goto done;
+ }
+
+ util_unlink_list(pmadapter->pmoal_handle,
+ &pmadapter->cmd_pending_q,
+ (pmlan_linked_list) pcmd_node,
+ pmadapter->callbacks.moal_spin_lock,
+ pmadapter->callbacks.moal_spin_unlock);
+ wlan_release_cmd_lock(pmadapter);
+ ret = wlan_dnld_cmd_to_fw(priv, pcmd_node);
+ priv = wlan_get_priv(pmadapter, MLAN_BSS_ROLE_ANY);
+ /* Any command sent to the firmware when host is in sleep mode, should
+ de-configure host sleep */
+ /* We should skip the host sleep configuration command itself though */
+ if (priv &&
+ (pcmd->command !=
+ wlan_cpu_to_le16(HostCmd_CMD_802_11_HS_CFG_ENH))) {
+ if (pmadapter->hs_activated == MTRUE) {
+ pmadapter->is_hs_configured = MFALSE;
+ wlan_host_sleep_activated_event(priv, MFALSE);
+ }
+ }
+ goto done;
+ } else {
+ wlan_release_cmd_lock(pmadapter);
+ }
+ ret = MLAN_STATUS_SUCCESS;
+ done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function handles the command response
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status
+wlan_process_cmdresp(mlan_adapter * pmadapter)
+{
+ HostCmd_DS_COMMAND *resp = MNULL;
+ mlan_private *pmpriv = wlan_get_priv(pmadapter, MLAN_BSS_ROLE_ANY);
+ mlan_private *pmpriv_next = MNULL;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ t_u16 orig_cmdresp_no;
+ t_u16 cmdresp_no;
+ t_u16 cmdresp_result;
+ mlan_ioctl_req *pioctl_buf = MNULL;
+ mlan_callbacks *pcb = (mlan_callbacks *) & pmadapter->callbacks;
+ t_u32 sec, usec, i;
+
+ ENTER();
+
+ /* Now we got response from FW, cancel the command timer */
+ if (pmadapter->cmd_timer_is_set) {
+ /* Cancel command timeout timer */
+ pcb->moal_stop_timer(pmadapter->pmoal_handle,
+ pmadapter->pmlan_cmd_timer);
+ /* Cancel command timeout timer */
+ pmadapter->cmd_timer_is_set = MFALSE;
+ }
+
+ if (pmadapter->curr_cmd)
+ if (pmadapter->curr_cmd->pioctl_buf != MNULL) {
+ pioctl_buf = (mlan_ioctl_req *) pmadapter->curr_cmd->pioctl_buf;
+ }
+
+ if (!pmadapter->curr_cmd || !pmadapter->curr_cmd->respbuf) {
+ resp = (HostCmd_DS_COMMAND *) pmadapter->upld_buf;
+ resp->command = wlan_le16_to_cpu(resp->command);
+ PRINTM(MERROR, "CMD_RESP: No curr_cmd, 0x%x\n", resp->command);
+ if (pioctl_buf)
+ pioctl_buf->status_code = MLAN_ERROR_CMD_RESP_FAIL;
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ pmadapter->num_cmd_timeout = 0;
+
+ DBG_HEXDUMP(MCMD_D, "CMD_RESP",
+ pmadapter->curr_cmd->respbuf->pbuf +
+ pmadapter->curr_cmd->respbuf->data_offset,
+ pmadapter->curr_cmd->respbuf->data_len);
+
+ resp =
+ (HostCmd_DS_COMMAND *) (pmadapter->curr_cmd->respbuf->pbuf +
+ pmadapter->curr_cmd->respbuf->data_offset);
+ wlan_request_cmd_lock(pmadapter);
+ if (pmadapter->curr_cmd->cmd_flag & CMD_F_CANCELED) {
+ cmd_ctrl_node *free_cmd = pmadapter->curr_cmd;
+ pmadapter->curr_cmd = MNULL;
+ wlan_release_cmd_lock(pmadapter);
+ PRINTM(MERROR, "CMD_RESP: 0x%x been canceled!\n",
+ wlan_le16_to_cpu(resp->command));
+ wlan_insert_cmd_to_free_q(pmadapter, free_cmd);
+ if (pioctl_buf)
+ pioctl_buf->status_code = MLAN_ERROR_CMD_CANCEL;
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ } else {
+ wlan_release_cmd_lock(pmadapter);
+ }
+ if (pmadapter->curr_cmd->cmd_flag & CMD_F_HOSTCMD) {
+ /* Copy original response back to response buffer */
+ wlan_ret_host_cmd(pmpriv, resp, pioctl_buf);
+ }
+ orig_cmdresp_no = wlan_le16_to_cpu(resp->command);
+ resp->size = wlan_le16_to_cpu(resp->size);
+ resp->seq_num = wlan_le16_to_cpu(resp->seq_num);
+ resp->result = wlan_le16_to_cpu(resp->result);
+
+ /* Get BSS number and corresponding priv */
+ pmpriv =
+ wlan_get_priv_by_id(pmadapter, HostCmd_GET_BSS_NO(resp->seq_num),
+ HostCmd_GET_BSS_TYPE(resp->seq_num));
+ if (!pmpriv)
+ pmpriv = wlan_get_priv(pmadapter, MLAN_BSS_ROLE_ANY);
+ /* Clear RET_BIT from HostCmd */
+ resp->command = (orig_cmdresp_no & HostCmd_CMD_ID_MASK);
+ cmdresp_no = resp->command;
+
+ cmdresp_result = resp->result;
+
+ /* Save the last command response to debug log */
+ pmadapter->dbg.last_cmd_resp_index =
+ (pmadapter->dbg.last_cmd_resp_index + 1) % DBG_CMD_NUM;
+ pmadapter->dbg.last_cmd_resp_id[pmadapter->dbg.last_cmd_resp_index] =
+ orig_cmdresp_no;
+
+ pmadapter->callbacks.moal_get_system_time(pmadapter->pmoal_handle, &sec,
+ &usec);
+ PRINTM_NETINTF(MCMND, pmadapter->curr_cmd->priv);
+ PRINTM(MCMND, "CMD_RESP (%lu.%06lu): 0x%x, result %d, len %d, seqno 0x%x\n",
+ sec, usec, orig_cmdresp_no, cmdresp_result, resp->size,
+ resp->seq_num);
+
+ if (!(orig_cmdresp_no & HostCmd_RET_BIT)) {
+ PRINTM(MERROR, "CMD_RESP: Invalid response to command!\n");
+ if (pioctl_buf) {
+ pioctl_buf->status_code = MLAN_ERROR_FW_CMDRESP;
+ }
+ wlan_insert_cmd_to_free_q(pmadapter, pmadapter->curr_cmd);
+ wlan_request_cmd_lock(pmadapter);
+ pmadapter->curr_cmd = MNULL;
+ wlan_release_cmd_lock(pmadapter);
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ if (pmadapter->curr_cmd->cmd_flag & CMD_F_HOSTCMD) {
+ pmadapter->curr_cmd->cmd_flag &= ~CMD_F_HOSTCMD;
+ if ((cmdresp_result == HostCmd_RESULT_OK)
+ && (cmdresp_no == HostCmd_CMD_802_11_HS_CFG_ENH))
+ ret = wlan_ret_802_11_hs_cfg(pmpriv, resp, pioctl_buf);
+ } else {
+ /* handle response */
+ ret = pmpriv->ops.process_cmdresp(pmpriv, cmdresp_no, resp, pioctl_buf);
+ }
+
+ /* Check init command response */
+ if (pmadapter->hw_status == WlanHardwareStatusInitializing) {
+ if (ret == MLAN_STATUS_FAILURE) {
+#if defined(STA_SUPPORT)
+ if (pmadapter->pwarm_reset_ioctl_req) {
+ /* warm reset failure */
+ pmadapter->pwarm_reset_ioctl_req->status_code =
+ MLAN_ERROR_CMD_RESP_FAIL;
+ pcb->moal_ioctl_complete(pmadapter->pmoal_handle,
+ pmadapter->pwarm_reset_ioctl_req,
+ MLAN_STATUS_FAILURE);
+ pmadapter->pwarm_reset_ioctl_req = MNULL;
+ goto done;
+ }
+#endif
+ PRINTM(MERROR, "cmd 0x%02x failed during initialization\n",
+ cmdresp_no);
+ wlan_init_fw_complete(pmadapter);
+ goto done;
+ }
+ }
+
+ wlan_request_cmd_lock(pmadapter);
+ if (pmadapter->curr_cmd) {
+ cmd_ctrl_node *free_cmd = pmadapter->curr_cmd;
+ pioctl_buf = (mlan_ioctl_req *) pmadapter->curr_cmd->pioctl_buf;
+ pmadapter->curr_cmd = MNULL;
+ wlan_release_cmd_lock(pmadapter);
+
+ if (pioctl_buf && (ret == MLAN_STATUS_SUCCESS))
+ pioctl_buf->status_code = MLAN_ERROR_NO_ERROR;
+ else if (pioctl_buf && (ret == MLAN_STATUS_FAILURE))
+ pioctl_buf->status_code = MLAN_ERROR_CMD_RESP_FAIL;
+
+ /* Clean up and put current command back to cmd_free_q */
+ wlan_insert_cmd_to_free_q(pmadapter, free_cmd);
+ } else {
+ wlan_release_cmd_lock(pmadapter);
+ }
+
+ if ((pmadapter->hw_status == WlanHardwareStatusInitializing) &&
+ (pmadapter->last_init_cmd == cmdresp_no)) {
+ i = pmpriv->bss_index + 1;
+ while (!(pmpriv_next = pmadapter->priv[i]) && i < pmadapter->priv_num)
+ i++;
+ if (!pmpriv_next || i >= pmadapter->priv_num) {
+#if defined(STA_SUPPORT)
+ if (pmadapter->pwarm_reset_ioctl_req) {
+ /* warm reset complete */
+ pmadapter->hw_status = WlanHardwareStatusReady;
+ pcb->moal_ioctl_complete(pmadapter->pmoal_handle,
+ pmadapter->pwarm_reset_ioctl_req,
+ MLAN_STATUS_SUCCESS);
+ pmadapter->pwarm_reset_ioctl_req = MNULL;
+ goto done;
+ }
+#endif
+ pmadapter->hw_status = WlanHardwareStatusInitdone;
+ } else {
+ /* Issue init commands for the next interface */
+ ret = pmpriv_next->ops.init_cmd(pmpriv_next, MFALSE);
+ }
+ }
+
+ done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function handles the timeout of command sending.
+ * It will re-send the same command again.
+ *
+ * @param function_context A pointer to function_context
+ * @return N/A
+ */
+t_void
+wlan_cmd_timeout_func(t_void * function_context)
+{
+ mlan_adapter *pmadapter = (mlan_adapter *) function_context;
+ cmd_ctrl_node *pcmd_node = MNULL;
+ mlan_ioctl_req *pioctl_buf = MNULL;
+ t_u32 sec, usec;
+ t_u8 i;
+ mlan_private *pmpriv = MNULL;
+
+ ENTER();
+
+ pmadapter->cmd_timer_is_set = MFALSE;
+ pmadapter->num_cmd_timeout++;
+ pmadapter->dbg.num_cmd_timeout++;
+ if (!pmadapter->curr_cmd) {
+ PRINTM(MWARN, "CurCmd Empty\n");
+ goto exit;
+ }
+ pcmd_node = pmadapter->curr_cmd;
+ if (pcmd_node->pioctl_buf != MNULL) {
+ pioctl_buf = (mlan_ioctl_req *) pcmd_node->pioctl_buf;
+ pioctl_buf->status_code = MLAN_ERROR_CMD_TIMEOUT;
+ }
+
+ if (pcmd_node) {
+ pmadapter->dbg.timeout_cmd_id =
+ pmadapter->dbg.last_cmd_id[pmadapter->dbg.last_cmd_index];
+ pmadapter->dbg.timeout_cmd_act =
+ pmadapter->dbg.last_cmd_act[pmadapter->dbg.last_cmd_index];
+ pmadapter->callbacks.moal_get_system_time(pmadapter->pmoal_handle, &sec,
+ &usec);
+ PRINTM(MERROR, "Timeout cmd id (%lu.%06lu) = 0x%x, act = 0x%x \n", sec,
+ usec, pmadapter->dbg.timeout_cmd_id,
+ pmadapter->dbg.timeout_cmd_act);
+ if (pcmd_node->cmdbuf) {
+ t_u8 *pcmd_buf;
+ pcmd_buf =
+ pcmd_node->cmdbuf->pbuf + pcmd_node->cmdbuf->data_offset +
+ INTF_HEADER_LEN;
+ for (i = 0; i < 16; i++) {
+ PRINTM(MERROR, "%02x ", *pcmd_buf++);
+ }
+ PRINTM(MERROR, "\n");
+ }
+
+ pmpriv = pcmd_node->priv;
+ if (pmpriv) {
+ PRINTM(MERROR, "BSS type = %d BSS role= %d\n", pmpriv->bss_type,
+ pmpriv->bss_role);
+ }
+
+ PRINTM(MERROR, "num_cmd_timeout = %d\n",
+ pmadapter->dbg.num_cmd_timeout);
+ PRINTM(MERROR, "last_cmd_index = %d\n", pmadapter->dbg.last_cmd_index);
+ PRINTM(MERROR, "last_cmd_id = ");
+ for (i = 0; i < DBG_CMD_NUM; i++) {
+ PRINTM(MERROR, "0x%x ", pmadapter->dbg.last_cmd_id[i]);
+ }
+ PRINTM(MERROR, "\n");
+ PRINTM(MERROR, "last_cmd_act = ");
+ for (i = 0; i < DBG_CMD_NUM; i++) {
+ PRINTM(MERROR, "0x%x ", pmadapter->dbg.last_cmd_act[i]);
+ }
+ PRINTM(MERROR, "\n");
+ PRINTM(MERROR, "last_cmd_resp_index = %d\n",
+ pmadapter->dbg.last_cmd_resp_index);
+ PRINTM(MERROR, "last_cmd_resp_id = ");
+ for (i = 0; i < DBG_CMD_NUM; i++) {
+ PRINTM(MERROR, "0x%x ", pmadapter->dbg.last_cmd_resp_id[i]);
+ }
+ PRINTM(MERROR, "\n");
+ PRINTM(MERROR, "last_event_index = %d\n",
+ pmadapter->dbg.last_event_index);
+ PRINTM(MERROR, "last_event = ");
+ for (i = 0; i < DBG_CMD_NUM; i++) {
+ PRINTM(MERROR, "0x%x ", pmadapter->dbg.last_event[i]);
+ }
+ PRINTM(MERROR, "\n");
+
+ PRINTM(MERROR, "num_data_h2c_failure = %d\n",
+ pmadapter->dbg.num_tx_host_to_card_failure);
+ PRINTM(MERROR, "num_cmd_h2c_failure = %d\n",
+ pmadapter->dbg.num_cmd_host_to_card_failure);
+ PRINTM(MERROR, "num_data_c2h_failure = %d\n",
+ pmadapter->dbg.num_rx_card_to_host_failure);
+ PRINTM(MERROR, "num_cmdevt_c2h_failure = %d\n",
+ pmadapter->dbg.num_cmdevt_card_to_host_failure);
+ PRINTM(MERROR, "num_int_read_failure = %d\n",
+ pmadapter->dbg.num_int_read_failure);
+ PRINTM(MERROR, "last_int_status = %d\n",
+ pmadapter->dbg.last_int_status);
+
+ PRINTM(MERROR, "num_event_deauth = %d\n",
+ pmadapter->dbg.num_event_deauth);
+ PRINTM(MERROR, "num_event_disassoc = %d\n",
+ pmadapter->dbg.num_event_disassoc);
+ PRINTM(MERROR, "num_event_link_lost = %d\n",
+ pmadapter->dbg.num_event_link_lost);
+ PRINTM(MERROR, "num_cmd_deauth = %d\n", pmadapter->dbg.num_cmd_deauth);
+ PRINTM(MERROR, "num_cmd_assoc_success = %d\n",
+ pmadapter->dbg.num_cmd_assoc_success);
+ PRINTM(MERROR, "num_cmd_assoc_failure = %d\n",
+ pmadapter->dbg.num_cmd_assoc_failure);
+ PRINTM(MERROR, "cmd_resp_received=%d\n", pmadapter->cmd_resp_received);
+ PRINTM(MERROR, "event_received=%d\n", pmadapter->event_received);
+
+ PRINTM(MERROR, "max_tx_buf_size=%d\n", pmadapter->max_tx_buf_size);
+ PRINTM(MERROR, "tx_buf_size=%d\n", pmadapter->tx_buf_size);
+ PRINTM(MERROR, "curr_tx_buf_size=%d\n", pmadapter->curr_tx_buf_size);
+
+ PRINTM(MERROR, "data_sent=%d cmd_sent=%d\n", pmadapter->data_sent,
+ pmadapter->cmd_sent);
+
+ PRINTM(MERROR, "ps_mode=%d ps_state=%d\n", pmadapter->ps_mode,
+ pmadapter->ps_state);
+ PRINTM(MERROR, "wakeup_dev_req=%d wakeup_tries=%d\n",
+ pmadapter->pm_wakeup_card_req, pmadapter->pm_wakeup_fw_try);
+ PRINTM(MERROR, "hs_configured=%d hs_activated=%d\n",
+ pmadapter->is_hs_configured, pmadapter->hs_activated);
+ PRINTM(MERROR, "pps_uapsd_mode=%d sleep_pd=%d\n",
+ pmadapter->pps_uapsd_mode, pmadapter->sleep_period.period);
+ PRINTM(MERROR, "tx_lock_flag = %d\n", pmadapter->tx_lock_flag);
+ PRINTM(MERROR, "scan_processing = %d\n", pmadapter->scan_processing);
+
+ PRINTM(MERROR, "mp_rd_bitmap=0x%x curr_rd_port=0x%x\n",
+ pmadapter->mp_rd_bitmap, pmadapter->curr_rd_port);
+ PRINTM(MERROR, "mp_wr_bitmap=0x%x curr_wr_port=0x%x\n",
+ pmadapter->mp_wr_bitmap, pmadapter->curr_wr_port);
+ }
+ if (pmadapter->hw_status == WlanHardwareStatusInitializing)
+ wlan_init_fw_complete(pmadapter);
+ else
+ /* Signal MOAL to perform extra handling for debugging */
+ if (pmpriv) {
+ wlan_recv_event(pmpriv, MLAN_EVENT_ID_DRV_DBG_DUMP, MNULL);
+ } else {
+ wlan_recv_event(wlan_get_priv(pmadapter, MLAN_BSS_ROLE_ANY),
+ MLAN_EVENT_ID_DRV_DBG_DUMP, MNULL);
+ }
+
+ exit:
+ LEAVE();
+ return;
+}
+
+#ifdef STA_SUPPORT
+/**
+ * @brief Internal function used to flush the scan pending queue
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ *
+ * @return N/A
+ */
+t_void
+wlan_flush_scan_queue(IN pmlan_adapter pmadapter)
+{
+ mlan_callbacks *pcb = (pmlan_callbacks) & pmadapter->callbacks;
+ cmd_ctrl_node *pcmd_node = MNULL;
+
+ ENTER();
+
+ while ((pcmd_node =
+ (cmd_ctrl_node *) util_peek_list(pmadapter->pmoal_handle,
+ &pmadapter->scan_pending_q,
+ pcb->moal_spin_lock,
+ pcb->moal_spin_unlock))) {
+ util_unlink_list(pmadapter->pmoal_handle, &pmadapter->scan_pending_q,
+ (pmlan_linked_list) pcmd_node, pcb->moal_spin_lock,
+ pcb->moal_spin_unlock);
+ pcmd_node->pioctl_buf = MNULL;
+ wlan_insert_cmd_to_free_q(pmadapter, pcmd_node);
+ }
+ wlan_request_cmd_lock(pmadapter);
+ pmadapter->scan_processing = MFALSE;
+ wlan_release_cmd_lock(pmadapter);
+
+ LEAVE();
+}
+#endif
+
+/**
+ * @brief Cancel all pending cmd.
+ *
+ * @param pmadapter A pointer to mlan_adapter
+ *
+ * @return N/A
+ */
+t_void
+wlan_cancel_all_pending_cmd(pmlan_adapter pmadapter)
+{
+ cmd_ctrl_node *pcmd_node = MNULL;
+ pmlan_callbacks pcb = &pmadapter->callbacks;
+ mlan_ioctl_req *pioctl_buf = MNULL;
+
+ ENTER();
+ /* Cancel current cmd */
+ wlan_request_cmd_lock(pmadapter);
+ if ((pmadapter->curr_cmd) && (pmadapter->curr_cmd->pioctl_buf)) {
+ pioctl_buf = (mlan_ioctl_req *) pmadapter->curr_cmd->pioctl_buf;
+ pmadapter->curr_cmd->pioctl_buf = MNULL;
+ wlan_release_cmd_lock(pmadapter);
+ pioctl_buf->status_code = MLAN_ERROR_CMD_CANCEL;
+ pcb->moal_ioctl_complete(pmadapter->pmoal_handle, pioctl_buf,
+ MLAN_STATUS_FAILURE);
+ } else {
+ wlan_release_cmd_lock(pmadapter);
+ }
+ /* Cancel all pending command */
+ while ((pcmd_node =
+ (cmd_ctrl_node *) util_peek_list(pmadapter->pmoal_handle,
+ &pmadapter->cmd_pending_q,
+ pcb->moal_spin_lock,
+ pcb->moal_spin_unlock))) {
+ util_unlink_list(pmadapter->pmoal_handle, &pmadapter->cmd_pending_q,
+ (pmlan_linked_list) pcmd_node, pcb->moal_spin_lock,
+ pcb->moal_spin_unlock);
+ if (pcmd_node->pioctl_buf) {
+ pioctl_buf = (mlan_ioctl_req *) pcmd_node->pioctl_buf;
+ pioctl_buf->status_code = MLAN_ERROR_CMD_CANCEL;
+ pcb->moal_ioctl_complete(pmadapter->pmoal_handle, pioctl_buf,
+ MLAN_STATUS_FAILURE);
+ pcmd_node->pioctl_buf = MNULL;
+ }
+ wlan_insert_cmd_to_free_q(pmadapter, pcmd_node);
+ }
+#ifdef STA_SUPPORT
+ /* Cancel all pending scan command */
+ wlan_flush_scan_queue(pmadapter);
+#endif
+ LEAVE();
+}
+
+/**
+ * @brief Cancel pending ioctl cmd.
+ *
+ * @param pmadapter A pointer to mlan_adapter
+ * @param pioctl_req A pointer to mlan_ioctl_req buf
+ *
+ * @return N/A
+ */
+t_void
+wlan_cancel_pending_ioctl(pmlan_adapter pmadapter, pmlan_ioctl_req pioctl_req)
+{
+ pmlan_callbacks pcb = &pmadapter->callbacks;
+ cmd_ctrl_node *pcmd_node = MNULL;
+
+ ENTER();
+
+ PRINTM(MIOCTL, "MOAL Cancel IOCTL: 0x%x sub_id=0x%x action=%d\n",
+ pioctl_req->req_id, *((t_u32 *) pioctl_req->pbuf),
+ (int) pioctl_req->action);
+
+ wlan_request_cmd_lock(pmadapter);
+ if ((pmadapter->curr_cmd) &&
+ (pmadapter->curr_cmd->pioctl_buf == pioctl_req)) {
+ pcmd_node = pmadapter->curr_cmd;
+ pcmd_node->pioctl_buf = MNULL;
+ pcmd_node->cmd_flag |= CMD_F_CANCELED;
+ }
+
+ while ((pcmd_node =
+ wlan_get_pending_ioctl_cmd(pmadapter, pioctl_req)) != MNULL) {
+ util_unlink_list(pmadapter->pmoal_handle, &pmadapter->cmd_pending_q,
+ (pmlan_linked_list) pcmd_node,
+ pmadapter->callbacks.moal_spin_lock,
+ pmadapter->callbacks.moal_spin_unlock);
+ pcmd_node->pioctl_buf = MNULL;
+ wlan_release_cmd_lock(pmadapter);
+ wlan_insert_cmd_to_free_q(pmadapter, pcmd_node);
+ wlan_request_cmd_lock(pmadapter);
+ }
+ wlan_release_cmd_lock(pmadapter);
+#ifdef STA_SUPPORT
+ if (pioctl_req->req_id == MLAN_IOCTL_SCAN) {
+ /* IOCTL will be completed, avoid calling IOCTL complete again from
+ EVENT */
+ if (pmadapter->pext_scan_ioctl_req == pioctl_req)
+ pmadapter->pext_scan_ioctl_req = MNULL;
+ /* Cancel all pending scan command */
+ wlan_flush_scan_queue(pmadapter);
+ }
+#endif
+ pioctl_req->status_code = MLAN_ERROR_CMD_CANCEL;
+ pcb->moal_ioctl_complete(pmadapter->pmoal_handle, pioctl_req,
+ MLAN_STATUS_FAILURE);
+
+ LEAVE();
+ return;
+}
+
+/**
+ * @brief Handle the version_ext resp
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param resp A pointer to HostCmd_DS_COMMAND
+ * @param pioctl_buf A pointer to mlan_ioctl_req structure
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+mlan_status
+wlan_ret_ver_ext(IN pmlan_private pmpriv,
+ IN HostCmd_DS_COMMAND * resp, IN mlan_ioctl_req * pioctl_buf)
+{
+ HostCmd_DS_VERSION_EXT *ver_ext = &resp->params.verext;
+ mlan_ds_get_info *info;
+ ENTER();
+ if (pioctl_buf) {
+ info = (mlan_ds_get_info *) pioctl_buf->pbuf;
+ info->param.ver_ext.version_str_sel = ver_ext->version_str_sel;
+ memcpy(pmpriv->adapter, info->param.ver_ext.version_str,
+ ver_ext->version_str, sizeof(char) * 128);
+ }
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief Handle the rx mgmt forward registration resp
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param resp A pointer to HostCmd_DS_COMMAND
+ * @param pioctl_buf A pointer to mlan_ioctl_req structure
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+mlan_status
+wlan_ret_rx_mgmt_ind(IN pmlan_private pmpriv,
+ IN HostCmd_DS_COMMAND * resp,
+ IN mlan_ioctl_req * pioctl_buf)
+{
+ mlan_ds_misc_cfg *misc = MNULL;
+ ENTER();
+
+ if (pioctl_buf) {
+ misc = (mlan_ds_misc_cfg *) pioctl_buf->pbuf;
+ misc->param.mgmt_subtype_mask =
+ wlan_le32_to_cpu(resp->params.rx_mgmt_ind.mgmt_subtype_mask);
+ }
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function checks conditions and prepares to
+ * send sleep confirm command to firmware if OK.
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ *
+ * @return N/A
+ */
+t_void
+wlan_check_ps_cond(mlan_adapter * pmadapter)
+{
+ ENTER();
+
+ if (!pmadapter->cmd_sent &&
+ !pmadapter->curr_cmd && !IS_CARD_RX_RCVD(pmadapter)) {
+ wlan_dnld_sleep_confirm_cmd(pmadapter);
+ } else {
+ PRINTM(MCMND, "Delay Sleep Confirm (%s%s%s)\n",
+ (pmadapter->cmd_sent) ? "D" : "",
+ (pmadapter->curr_cmd) ? "C" : "",
+ (IS_CARD_RX_RCVD(pmadapter)) ? "R" : "");
+ }
+
+ LEAVE();
+}
+
+/**
+ * @brief This function sends the HS_ACTIVATED event to the application
+ *
+ * @param priv A pointer to mlan_private structure
+ * @param activated MTRUE if activated, MFALSE if de-activated
+ *
+ * @return N/A
+ */
+t_void
+wlan_host_sleep_activated_event(pmlan_private priv, t_u8 activated)
+{
+ ENTER();
+
+ if (activated) {
+ if (priv->adapter->is_hs_configured) {
+ priv->adapter->hs_activated = MTRUE;
+ PRINTM(MEVENT, "hs_activated\n");
+ wlan_recv_event(priv, MLAN_EVENT_ID_DRV_HS_ACTIVATED, MNULL);
+ } else
+ PRINTM(MWARN, "hs_activated: HS not configured !!!\n");
+ } else {
+ PRINTM(MEVENT, "hs_deactived\n");
+ priv->adapter->hs_activated = MFALSE;
+ wlan_recv_event(priv, MLAN_EVENT_ID_DRV_HS_DEACTIVATED, MNULL);
+ }
+
+ LEAVE();
+}
+
+/**
+ * @brief This function sends the HS_WAKEUP event to the application
+ *
+ * @param priv A pointer to mlan_private structure
+ *
+ * @return N/A
+ */
+t_void
+wlan_host_sleep_wakeup_event(pmlan_private priv)
+{
+ ENTER();
+
+ if (priv->adapter->is_hs_configured) {
+ wlan_recv_event(priv, MLAN_EVENT_ID_FW_HS_WAKEUP, MNULL);
+ } else {
+ PRINTM(MWARN, "hs_wakeup: Host Sleep not configured !!!\n");
+ }
+
+ LEAVE();
+}
+
+/**
+ * @brief This function handles the command response of hs_cfg
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param resp A pointer to HostCmd_DS_COMMAND
+ * @param pioctl_buf A pointer to mlan_ioctl_req structure
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+mlan_status
+wlan_ret_802_11_hs_cfg(IN pmlan_private pmpriv,
+ IN HostCmd_DS_COMMAND * resp,
+ IN mlan_ioctl_req * pioctl_buf)
+{
+ pmlan_adapter pmadapter = pmpriv->adapter;
+ HostCmd_DS_802_11_HS_CFG_ENH *phs_cfg = &resp->params.opt_hs_cfg;
+
+ ENTER();
+
+ if (wlan_le16_to_cpu(phs_cfg->action) == HS_ACTIVATE) {
+ /* clean up curr_cmd to allow suspend */
+ if (pioctl_buf)
+ pioctl_buf->status_code = MLAN_ERROR_NO_ERROR;
+ /* Clean up and put current command back to cmd_free_q */
+ wlan_insert_cmd_to_free_q(pmadapter, pmadapter->curr_cmd);
+ wlan_request_cmd_lock(pmadapter);
+ pmadapter->curr_cmd = MNULL;
+ wlan_release_cmd_lock(pmadapter);
+ wlan_host_sleep_activated_event(pmpriv, MTRUE);
+ goto done;
+ } else {
+ phs_cfg->params.hs_config.conditions =
+ wlan_le32_to_cpu(phs_cfg->params.hs_config.conditions);
+ PRINTM(MCMND,
+ "CMD_RESP: HS_CFG cmd reply result=%#x,"
+ " conditions=0x%x gpio=0x%x gap=0x%x\n", resp->result,
+ phs_cfg->params.hs_config.conditions,
+ phs_cfg->params.hs_config.gpio, phs_cfg->params.hs_config.gap);
+ }
+ if (phs_cfg->params.hs_config.conditions != HOST_SLEEP_CFG_CANCEL) {
+ pmadapter->is_hs_configured = MTRUE;
+ } else {
+ pmadapter->is_hs_configured = MFALSE;
+ if (pmadapter->hs_activated)
+ wlan_host_sleep_activated_event(pmpriv, MFALSE);
+ }
+
+ done:
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief Perform hs related activities on receiving the power up interrupt
+ *
+ * @param pmadapter A pointer to the adapter structure
+ * @return N/A
+ */
+t_void
+wlan_process_hs_config(pmlan_adapter pmadapter)
+{
+ ENTER();
+ PRINTM(MINFO, "Recevie interrupt/data in HS mode\n");
+ if (pmadapter->hs_cfg.gap == HOST_SLEEP_CFG_GAP_FF)
+ wlan_pm_wakeup_card(pmadapter);
+ LEAVE();
+ return;
+}
+
+/**
+ * @brief Check sleep confirm command response and set the state to ASLEEP
+ *
+ * @param pmadapter A pointer to the adapter structure
+ * @param pbuf A pointer to the command response buffer
+ * @param upld_len Command response buffer length
+ * @return N/A
+ */
+void
+wlan_process_sleep_confirm_resp(pmlan_adapter pmadapter, t_u8 * pbuf,
+ t_u32 upld_len)
+{
+ HostCmd_DS_COMMAND *cmd;
+
+ ENTER();
+
+ if (!upld_len) {
+ PRINTM(MERROR, "Command size is 0\n");
+ LEAVE();
+ return;
+ }
+ cmd = (HostCmd_DS_COMMAND *) pbuf;
+ cmd->result = wlan_le16_to_cpu(cmd->result);
+ cmd->command = wlan_le16_to_cpu(cmd->command);
+ cmd->seq_num = wlan_le16_to_cpu(cmd->seq_num);
+
+ /* Update sequence number */
+ cmd->seq_num = HostCmd_GET_SEQ_NO(cmd->seq_num);
+ /* Clear RET_BIT from HostCmd */
+ cmd->command &= HostCmd_CMD_ID_MASK;
+
+ if (cmd->command != HostCmd_CMD_802_11_PS_MODE_ENH) {
+ PRINTM(MERROR,
+ "Received unexpected response for command %x, result = %x\n",
+ cmd->command, cmd->result);
+ LEAVE();
+ return;
+ }
+ PRINTM(MEVENT, "#\n");
+ if (cmd->result != MLAN_STATUS_SUCCESS) {
+ PRINTM(MERROR, "Sleep confirm command failed\n");
+ pmadapter->pm_wakeup_card_req = MFALSE;
+ pmadapter->ps_state = PS_STATE_AWAKE;
+ LEAVE();
+ return;
+ }
+ pmadapter->pm_wakeup_card_req = MTRUE;
+
+ if (pmadapter->is_hs_configured) {
+ wlan_host_sleep_activated_event(wlan_get_priv
+ (pmadapter, MLAN_BSS_ROLE_ANY), MTRUE);
+ }
+ pmadapter->ps_state = PS_STATE_SLEEP;
+ LEAVE();
+}
+
+/**
+ * @brief This function prepares command of power mode
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param cmd A pointer to HostCmd_DS_COMMAND structure
+ * @param cmd_action the action: GET or SET
+ * @param ps_bitmap PS bitmap
+ * @param pdata_buf A pointer to data buffer
+ * @return MLAN_STATUS_SUCCESS
+ */
+mlan_status
+wlan_cmd_enh_power_mode(pmlan_private pmpriv,
+ IN HostCmd_DS_COMMAND * cmd,
+ IN t_u16 cmd_action,
+ IN t_u16 ps_bitmap, IN t_void * pdata_buf)
+{
+ HostCmd_DS_802_11_PS_MODE_ENH *psmode_enh = &cmd->params.psmode_enh;
+ t_u8 *tlv = MNULL;
+ t_u16 cmd_size = 0;
+
+ ENTER();
+
+ PRINTM(MCMND, "PS Command: action = 0x%x, bitmap = 0x%x\n", cmd_action,
+ ps_bitmap);
+
+ cmd->command = wlan_cpu_to_le16(HostCmd_CMD_802_11_PS_MODE_ENH);
+ if (cmd_action == DIS_AUTO_PS) {
+ psmode_enh->action = wlan_cpu_to_le16(DIS_AUTO_PS);
+ psmode_enh->params.ps_bitmap = wlan_cpu_to_le16(ps_bitmap);
+ cmd->size = wlan_cpu_to_le16(S_DS_GEN + AUTO_PS_FIX_SIZE);
+ } else if (cmd_action == GET_PS) {
+ psmode_enh->action = wlan_cpu_to_le16(GET_PS);
+ psmode_enh->params.ps_bitmap = wlan_cpu_to_le16(ps_bitmap);
+ cmd->size = wlan_cpu_to_le16(S_DS_GEN + AUTO_PS_FIX_SIZE);
+ } else if (cmd_action == EN_AUTO_PS) {
+ psmode_enh->action = wlan_cpu_to_le16(EN_AUTO_PS);
+ psmode_enh->params.auto_ps.ps_bitmap = wlan_cpu_to_le16(ps_bitmap);
+ cmd_size = S_DS_GEN + AUTO_PS_FIX_SIZE;
+ tlv = (t_u8 *) cmd + cmd_size;
+ if (ps_bitmap & BITMAP_STA_PS) {
+ pmlan_adapter pmadapter = pmpriv->adapter;
+ MrvlIEtypes_ps_param_t *ps_tlv = (MrvlIEtypes_ps_param_t *) tlv;
+ ps_param *ps_mode = &ps_tlv->param;
+ ps_tlv->header.type = wlan_cpu_to_le16(TLV_TYPE_PS_PARAM);
+ ps_tlv->header.len =
+ wlan_cpu_to_le16(sizeof(MrvlIEtypes_ps_param_t) -
+ sizeof(MrvlIEtypesHeader_t));
+ cmd_size += sizeof(MrvlIEtypes_ps_param_t);
+ tlv += sizeof(MrvlIEtypes_ps_param_t);
+ ps_mode->null_pkt_interval =
+ wlan_cpu_to_le16(pmadapter->null_pkt_interval);
+ ps_mode->multiple_dtims =
+ wlan_cpu_to_le16(pmadapter->multiple_dtim);
+ ps_mode->bcn_miss_timeout =
+ wlan_cpu_to_le16(pmadapter->bcn_miss_time_out);
+ ps_mode->local_listen_interval =
+ wlan_cpu_to_le16(pmadapter->local_listen_interval);
+ ps_mode->adhoc_wake_period =
+ wlan_cpu_to_le16(pmadapter->adhoc_awake_period);
+ ps_mode->delay_to_ps = wlan_cpu_to_le16(pmadapter->delay_to_ps);
+ ps_mode->mode = wlan_cpu_to_le16(pmadapter->enhanced_ps_mode);
+ }
+ if (ps_bitmap & BITMAP_AUTO_DS) {
+ MrvlIEtypes_auto_ds_param_t *auto_ps_tlv =
+ (MrvlIEtypes_auto_ds_param_t *) tlv;
+ auto_ds_param *auto_ds = &auto_ps_tlv->param;
+ t_u16 idletime = 0;
+ auto_ps_tlv->header.type = wlan_cpu_to_le16(TLV_TYPE_AUTO_DS_PARAM);
+ auto_ps_tlv->header.len =
+ wlan_cpu_to_le16(sizeof(MrvlIEtypes_auto_ds_param_t) -
+ sizeof(MrvlIEtypesHeader_t));
+ cmd_size += sizeof(MrvlIEtypes_auto_ds_param_t);
+ tlv += sizeof(MrvlIEtypes_auto_ds_param_t);
+ if (pdata_buf)
+ idletime = ((mlan_ds_auto_ds *) pdata_buf)->idletime;
+ auto_ds->deep_sleep_timeout = wlan_cpu_to_le16(idletime);
+ }
+#if defined(UAP_SUPPORT)
+ if (pdata_buf &&
+ (ps_bitmap & (BITMAP_UAP_INACT_PS | BITMAP_UAP_DTIM_PS))) {
+ mlan_ds_ps_mgmt *ps_mgmt = (mlan_ds_ps_mgmt *) pdata_buf;
+ MrvlIEtypes_sleep_param_t *sleep_tlv = MNULL;
+ MrvlIEtypes_inact_sleep_param_t *inact_tlv = MNULL;
+ if (ps_mgmt->flags & PS_FLAG_SLEEP_PARAM) {
+ sleep_tlv = (MrvlIEtypes_sleep_param_t *) tlv;
+ sleep_tlv->header.type =
+ wlan_cpu_to_le16(TLV_TYPE_AP_SLEEP_PARAM);
+ sleep_tlv->header.len =
+ wlan_cpu_to_le16(sizeof(MrvlIEtypes_sleep_param_t) -
+ sizeof(MrvlIEtypesHeader_t));
+ sleep_tlv->ctrl_bitmap =
+ wlan_cpu_to_le32(ps_mgmt->sleep_param.ctrl_bitmap);
+ sleep_tlv->min_sleep =
+ wlan_cpu_to_le32(ps_mgmt->sleep_param.min_sleep);
+ sleep_tlv->max_sleep =
+ wlan_cpu_to_le32(ps_mgmt->sleep_param.max_sleep);
+ cmd_size += sizeof(MrvlIEtypes_sleep_param_t);
+ tlv += sizeof(MrvlIEtypes_sleep_param_t);
+ }
+ if (ps_mgmt->flags & PS_FLAG_INACT_SLEEP_PARAM) {
+ inact_tlv = (MrvlIEtypes_inact_sleep_param_t *) tlv;
+ inact_tlv->header.type =
+ wlan_cpu_to_le16(TLV_TYPE_AP_INACT_SLEEP_PARAM);
+ inact_tlv->header.len =
+ wlan_cpu_to_le16(sizeof(MrvlIEtypes_inact_sleep_param_t)
+ - sizeof(MrvlIEtypesHeader_t));
+ inact_tlv->inactivity_to =
+ wlan_cpu_to_le32(ps_mgmt->inact_param.inactivity_to);
+ inact_tlv->min_awake =
+ wlan_cpu_to_le32(ps_mgmt->inact_param.min_awake);
+ inact_tlv->max_awake =
+ wlan_cpu_to_le32(ps_mgmt->inact_param.max_awake);
+ cmd_size += sizeof(MrvlIEtypes_inact_sleep_param_t);
+ tlv += sizeof(MrvlIEtypes_inact_sleep_param_t);
+ }
+ }
+#endif
+ cmd->size = wlan_cpu_to_le16(cmd_size);
+ }
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function handles the command response of ps_mode_enh
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param resp A pointer to HostCmd_DS_COMMAND
+ * @param pioctl_buf A pointer to mlan_ioctl_req structure
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+mlan_status
+wlan_ret_enh_power_mode(IN pmlan_private pmpriv,
+ IN HostCmd_DS_COMMAND * resp,
+ IN mlan_ioctl_req * pioctl_buf)
+{
+ pmlan_adapter pmadapter = pmpriv->adapter;
+ MrvlIEtypesHeader_t *mrvl_tlv = MNULL;
+ MrvlIEtypes_auto_ds_param_t *auto_ds_tlv = MNULL;
+ HostCmd_DS_802_11_PS_MODE_ENH *ps_mode = &resp->params.psmode_enh;
+
+ ENTER();
+
+ ps_mode->action = wlan_le16_to_cpu(ps_mode->action);
+ PRINTM(MINFO, "CMD_RESP: PS_MODE cmd reply result=%#x action=0x%X\n",
+ resp->result, ps_mode->action);
+ if (ps_mode->action == EN_AUTO_PS) {
+ ps_mode->params.auto_ps.ps_bitmap =
+ wlan_le16_to_cpu(ps_mode->params.auto_ps.ps_bitmap);
+ if (ps_mode->params.auto_ps.ps_bitmap & BITMAP_AUTO_DS) {
+ PRINTM(MCMND, "Enabled auto deep sleep\n");
+ pmpriv->adapter->is_deep_sleep = MTRUE;
+ mrvl_tlv =
+ (MrvlIEtypesHeader_t *) ((t_u8 *) ps_mode + AUTO_PS_FIX_SIZE);
+ while (wlan_le16_to_cpu(mrvl_tlv->type) != TLV_TYPE_AUTO_DS_PARAM) {
+ mrvl_tlv =
+ (MrvlIEtypesHeader_t *) ((t_u8 *) mrvl_tlv +
+ wlan_le16_to_cpu(mrvl_tlv->len)
+ + sizeof(MrvlIEtypesHeader_t));
+ }
+ auto_ds_tlv = (MrvlIEtypes_auto_ds_param_t *) mrvl_tlv;
+ pmpriv->adapter->idle_time =
+ wlan_le16_to_cpu(auto_ds_tlv->param.deep_sleep_timeout);
+ }
+ if (ps_mode->params.auto_ps.ps_bitmap & BITMAP_STA_PS) {
+ PRINTM(MCMND, "Enabled STA power save\n");
+ if (pmadapter->sleep_period.period) {
+ PRINTM(MCMND, "Setting uapsd/pps mode to TRUE\n");
+ }
+ }
+#if defined(UAP_SUPPORT)
+ if (ps_mode->params.auto_ps.
+ ps_bitmap & (BITMAP_UAP_INACT_PS | BITMAP_UAP_DTIM_PS)) {
+ pmadapter->ps_mode = Wlan802_11PowerModePSP;
+ PRINTM(MCMND, "Enabled uAP power save\n");
+ }
+#endif
+ } else if (ps_mode->action == DIS_AUTO_PS) {
+ ps_mode->params.ps_bitmap = wlan_cpu_to_le16(ps_mode->params.ps_bitmap);
+ if (ps_mode->params.ps_bitmap & BITMAP_AUTO_DS) {
+ pmpriv->adapter->is_deep_sleep = MFALSE;
+ PRINTM(MCMND, "Disabled auto deep sleep\n");
+ }
+ if (ps_mode->params.ps_bitmap & BITMAP_STA_PS) {
+ PRINTM(MCMND, "Disabled STA power save\n");
+ if (pmadapter->sleep_period.period) {
+ pmadapter->delay_null_pkt = MFALSE;
+ pmadapter->tx_lock_flag = MFALSE;
+ pmadapter->pps_uapsd_mode = MFALSE;
+ }
+ }
+#if defined(UAP_SUPPORT)
+ if (ps_mode->params.
+ ps_bitmap & (BITMAP_UAP_INACT_PS | BITMAP_UAP_DTIM_PS)) {
+ pmadapter->ps_mode = Wlan802_11PowerModeCAM;
+ PRINTM(MCMND, "Disabled uAP power save\n");
+ }
+#endif
+ } else if (ps_mode->action == GET_PS) {
+ ps_mode->params.ps_bitmap = wlan_le16_to_cpu(ps_mode->params.ps_bitmap);
+ if (ps_mode->params.auto_ps.
+ ps_bitmap & (BITMAP_STA_PS | BITMAP_UAP_INACT_PS |
+ BITMAP_UAP_DTIM_PS))
+ pmadapter->ps_mode = Wlan802_11PowerModePSP;
+ else
+ pmadapter->ps_mode = Wlan802_11PowerModeCAM;
+ PRINTM(MCMND, "ps_bitmap=0x%x\n", ps_mode->params.ps_bitmap);
+ if (pioctl_buf) {
+ mlan_ds_pm_cfg *pm_cfg = (mlan_ds_pm_cfg *) pioctl_buf->pbuf;
+ if (pm_cfg->sub_command == MLAN_OID_PM_CFG_IEEE_PS) {
+ if (ps_mode->params.auto_ps.ps_bitmap & BITMAP_STA_PS)
+ pm_cfg->param.ps_mode = 1;
+ else
+ pm_cfg->param.ps_mode = 0;
+ }
+#if defined(UAP_SUPPORT)
+ if (pm_cfg->sub_command == MLAN_OID_PM_CFG_PS_MODE) {
+ MrvlIEtypes_sleep_param_t *sleep_tlv = MNULL;
+ MrvlIEtypes_inact_sleep_param_t *inact_tlv = MNULL;
+ MrvlIEtypesHeader_t *tlv = MNULL;
+ t_u16 tlv_type = 0;
+ t_u16 tlv_len = 0;
+ t_u16 tlv_buf_left = 0;
+ pm_cfg->param.ps_mgmt.flags = PS_FLAG_PS_MODE;
+ if (ps_mode->params.ps_bitmap & BITMAP_UAP_INACT_PS)
+ pm_cfg->param.ps_mgmt.ps_mode = PS_MODE_INACTIVITY;
+ else if (ps_mode->params.ps_bitmap & BITMAP_UAP_DTIM_PS)
+ pm_cfg->param.ps_mgmt.ps_mode = PS_MODE_PERIODIC_DTIM;
+ else
+ pm_cfg->param.ps_mgmt.ps_mode = PS_MODE_DISABLE;
+ tlv_buf_left = resp->size - (S_DS_GEN + AUTO_PS_FIX_SIZE);
+ tlv =
+ (MrvlIEtypesHeader_t *) ((t_u8 *) ps_mode +
+ AUTO_PS_FIX_SIZE);
+ while (tlv_buf_left >= sizeof(MrvlIEtypesHeader_t)) {
+ tlv_type = wlan_le16_to_cpu(tlv->type);
+ tlv_len = wlan_le16_to_cpu(tlv->len);
+ switch (tlv_type) {
+ case TLV_TYPE_AP_SLEEP_PARAM:
+ sleep_tlv = (MrvlIEtypes_sleep_param_t *) tlv;
+ pm_cfg->param.ps_mgmt.flags |= PS_FLAG_SLEEP_PARAM;
+ pm_cfg->param.ps_mgmt.sleep_param.ctrl_bitmap =
+ wlan_le32_to_cpu(sleep_tlv->ctrl_bitmap);
+ pm_cfg->param.ps_mgmt.sleep_param.min_sleep =
+ wlan_le32_to_cpu(sleep_tlv->min_sleep);
+ pm_cfg->param.ps_mgmt.sleep_param.max_sleep =
+ wlan_le32_to_cpu(sleep_tlv->max_sleep);
+ break;
+ case TLV_TYPE_AP_INACT_SLEEP_PARAM:
+ inact_tlv = (MrvlIEtypes_inact_sleep_param_t *) tlv;
+ pm_cfg->param.ps_mgmt.flags |=
+ PS_FLAG_INACT_SLEEP_PARAM;
+ pm_cfg->param.ps_mgmt.inact_param.inactivity_to =
+ wlan_le32_to_cpu(inact_tlv->inactivity_to);
+ pm_cfg->param.ps_mgmt.inact_param.min_awake =
+ wlan_le32_to_cpu(inact_tlv->min_awake);
+ pm_cfg->param.ps_mgmt.inact_param.max_awake =
+ wlan_le32_to_cpu(inact_tlv->max_awake);
+ break;
+ }
+ tlv_buf_left -= tlv_len + sizeof(MrvlIEtypesHeader_t);
+ tlv =
+ (MrvlIEtypesHeader_t *) ((t_u8 *) tlv + tlv_len +
+ sizeof(MrvlIEtypesHeader_t));
+ }
+ }
+#endif
+ }
+ }
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function handles the command response of tx rate query
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param resp A pointer to HostCmd_DS_COMMAND
+ * @param pioctl_buf A pointer to mlan_ioctl_req structure
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+mlan_status
+wlan_ret_802_11_tx_rate_query(IN pmlan_private pmpriv,
+ IN HostCmd_DS_COMMAND * resp,
+ IN mlan_ioctl_req * pioctl_buf)
+{
+ mlan_adapter *pmadapter = pmpriv->adapter;
+ mlan_ds_rate *rate = MNULL;
+ ENTER();
+
+ pmpriv->tx_rate = resp->params.tx_rate.tx_rate;
+ pmpriv->tx_htinfo = resp->params.tx_rate.ht_info;
+ if (!pmpriv->is_data_rate_auto) {
+ pmpriv->data_rate = wlan_index_to_data_rate(pmadapter,
+ pmpriv->tx_rate,
+ pmpriv->tx_htinfo);
+ }
+
+ if (pioctl_buf) {
+ rate = (mlan_ds_rate *) pioctl_buf->pbuf;
+ if (rate->sub_command == MLAN_OID_RATE_CFG) {
+ if (rate->param.rate_cfg.rate_type == MLAN_RATE_INDEX) {
+ if (pmpriv->tx_htinfo & MBIT(0))
+ rate->param.rate_cfg.rate =
+ pmpriv->tx_rate + MLAN_RATE_INDEX_MCS0;
+ else
+ /* For HostCmd_CMD_802_11_TX_RATE_QUERY, there is a hole in
+ rate table between HR/DSSS and OFDM rates, so minus 1
+ for OFDM rate index */
+ rate->param.rate_cfg.rate =
+ (pmpriv->tx_rate >
+ MLAN_RATE_INDEX_OFDM0) ? pmpriv->tx_rate -
+ 1 : pmpriv->tx_rate;
+ } else {
+ rate->param.rate_cfg.rate =
+ wlan_index_to_data_rate(pmadapter, pmpriv->tx_rate,
+ pmpriv->tx_htinfo);
+ }
+ } else if (rate->sub_command == MLAN_OID_GET_DATA_RATE) {
+ if (pmpriv->tx_htinfo & MBIT(0)) {
+ rate->param.data_rate.tx_data_rate =
+ pmpriv->tx_rate + MLAN_RATE_INDEX_MCS0;
+ if (pmpriv->tx_htinfo & MBIT(1))
+ rate->param.data_rate.tx_ht_bw = MLAN_HT_BW40;
+ else
+ rate->param.data_rate.tx_ht_bw = MLAN_HT_BW20;
+ if (pmpriv->tx_htinfo & MBIT(2))
+ rate->param.data_rate.tx_ht_gi = MLAN_HT_SGI;
+ else
+ rate->param.data_rate.tx_ht_gi = MLAN_HT_LGI;
+ } else
+ /* For HostCmd_CMD_802_11_TX_RATE_QUERY, there is a hole in
+ rate table between HR/DSSS and OFDM rates, so minus 1 for
+ OFDM rate index */
+ rate->param.data_rate.tx_data_rate =
+ (pmpriv->tx_rate >
+ MLAN_RATE_INDEX_OFDM0) ? pmpriv->tx_rate -
+ 1 : pmpriv->tx_rate;
+ if (pmpriv->rxpd_htinfo & MBIT(0)) {
+ rate->param.data_rate.rx_data_rate =
+ pmpriv->rxpd_rate + MLAN_RATE_INDEX_MCS0;
+ if (pmpriv->rxpd_htinfo & MBIT(1))
+ rate->param.data_rate.rx_ht_bw = MLAN_HT_BW40;
+ else
+ rate->param.data_rate.rx_ht_bw = MLAN_HT_BW20;
+ if (pmpriv->tx_htinfo & MBIT(2))
+ rate->param.data_rate.rx_ht_gi = MLAN_HT_SGI;
+ else
+ rate->param.data_rate.rx_ht_gi = MLAN_HT_LGI;
+ } else
+ /* For rate index in RxPD, there is a hole in rate table
+ between HR/DSSS and OFDM rates, so minus 1 for OFDM rate
+ index */
+ rate->param.data_rate.rx_data_rate =
+ (pmpriv->rxpd_rate >
+ MLAN_RATE_INDEX_OFDM0) ? pmpriv->rxpd_rate -
+ 1 : pmpriv->rxpd_rate;
+ }
+ pioctl_buf->data_read_written =
+ sizeof(mlan_multicast_list) + MLAN_SUB_COMMAND_SIZE;
+ }
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function prepares command of tx_rate_cfg.
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param cmd A pointer to HostCmd_DS_COMMAND structure
+ * @param cmd_action The action: GET or SET
+ * @param pdata_buf A pointer to data buffer
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+mlan_status
+wlan_cmd_tx_rate_cfg(IN pmlan_private pmpriv,
+ IN HostCmd_DS_COMMAND * cmd,
+ IN t_u16 cmd_action, IN t_void * pdata_buf)
+{
+ HostCmd_DS_TX_RATE_CFG *rate_cfg = &cmd->params.tx_rate_cfg;
+ MrvlRateScope_t *rate_scope;
+ MrvlRateDropPattern_t *rate_drop;
+ t_u16 *pbitmap_rates = (t_u16 *) pdata_buf;
+
+ t_u32 i;
+
+ ENTER();
+
+ cmd->command = wlan_cpu_to_le16(HostCmd_CMD_TX_RATE_CFG);
+
+ rate_cfg->action = wlan_cpu_to_le16(cmd_action);
+ rate_cfg->cfg_index = 0;
+
+ rate_scope = (MrvlRateScope_t *) ((t_u8 *) rate_cfg +
+ sizeof(HostCmd_DS_TX_RATE_CFG));
+ rate_scope->type = wlan_cpu_to_le16(TLV_TYPE_RATE_SCOPE);
+ rate_scope->length = wlan_cpu_to_le16(sizeof(MrvlRateScope_t) -
+ sizeof(MrvlIEtypesHeader_t));
+ if (pbitmap_rates != MNULL) {
+ rate_scope->hr_dsss_rate_bitmap = wlan_cpu_to_le16(pbitmap_rates[0]);
+ rate_scope->ofdm_rate_bitmap = wlan_cpu_to_le16(pbitmap_rates[1]);
+ for (i = 0; i < sizeof(rate_scope->ht_mcs_rate_bitmap) / sizeof(t_u16);
+ i++)
+ rate_scope->ht_mcs_rate_bitmap[i] =
+ wlan_cpu_to_le16(pbitmap_rates[2 + i]);
+ } else {
+ rate_scope->hr_dsss_rate_bitmap =
+ wlan_cpu_to_le16(pmpriv->bitmap_rates[0]);
+ rate_scope->ofdm_rate_bitmap =
+ wlan_cpu_to_le16(pmpriv->bitmap_rates[1]);
+ for (i = 0; i < sizeof(rate_scope->ht_mcs_rate_bitmap) / sizeof(t_u16);
+ i++)
+ rate_scope->ht_mcs_rate_bitmap[i] =
+ wlan_cpu_to_le16(pmpriv->bitmap_rates[2 + i]);
+ }
+
+ rate_drop = (MrvlRateDropPattern_t *) ((t_u8 *) rate_scope +
+ sizeof(MrvlRateScope_t));
+ rate_drop->type = wlan_cpu_to_le16(TLV_TYPE_RATE_DROP_PATTERN);
+ rate_drop->length = wlan_cpu_to_le16(sizeof(rate_drop->rate_drop_mode));
+ rate_drop->rate_drop_mode = 0;
+
+ cmd->size = wlan_cpu_to_le16(S_DS_GEN + sizeof(HostCmd_DS_TX_RATE_CFG) +
+ sizeof(MrvlRateScope_t) +
+ sizeof(MrvlRateDropPattern_t));
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function handles the command response of tx_rate_cfg
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param resp A pointer to HostCmd_DS_COMMAND
+ * @param pioctl_buf A pointer to mlan_ioctl_req structure
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status
+wlan_ret_tx_rate_cfg(IN pmlan_private pmpriv,
+ IN HostCmd_DS_COMMAND * resp,
+ IN mlan_ioctl_req * pioctl_buf)
+{
+ mlan_adapter *pmadapter = pmpriv->adapter;
+ mlan_ds_rate *ds_rate = MNULL;
+ HostCmd_DS_TX_RATE_CFG *prate_cfg = MNULL;
+ MrvlRateScope_t *prate_scope;
+ MrvlIEtypesHeader_t *head = MNULL;
+ t_u16 tlv, tlv_buf_len;
+ t_u8 *tlv_buf;
+ t_u32 i;
+ t_s32 index;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ if (resp == MNULL) {
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+ prate_cfg = &resp->params.tx_rate_cfg;
+
+ tlv_buf = (t_u8 *) ((t_u8 *) prate_cfg) + sizeof(HostCmd_DS_TX_RATE_CFG);
+ tlv_buf_len = *(t_u16 *) (tlv_buf + sizeof(t_u16));
+ tlv_buf_len = wlan_le16_to_cpu(tlv_buf_len);
+
+ while (tlv_buf && tlv_buf_len > 0) {
+ tlv = (*tlv_buf);
+ tlv = tlv | (*(tlv_buf + 1) << 8);
+
+ switch (tlv) {
+ case TLV_TYPE_RATE_SCOPE:
+ prate_scope = (MrvlRateScope_t *) tlv_buf;
+ pmpriv->bitmap_rates[0] =
+ wlan_le16_to_cpu(prate_scope->hr_dsss_rate_bitmap);
+ pmpriv->bitmap_rates[1] =
+ wlan_le16_to_cpu(prate_scope->ofdm_rate_bitmap);
+ for (i = 0;
+ i < sizeof(prate_scope->ht_mcs_rate_bitmap) / sizeof(t_u16);
+ i++)
+ pmpriv->bitmap_rates[2 + i] =
+ wlan_le16_to_cpu(prate_scope->ht_mcs_rate_bitmap[i]);
+ break;
+ /* Add RATE_DROP tlv here */
+ }
+
+ head = (MrvlIEtypesHeader_t *) tlv_buf;
+ head->len = wlan_le16_to_cpu(head->len);
+ tlv_buf += head->len + sizeof(MrvlIEtypesHeader_t);
+ tlv_buf_len -= head->len;
+ }
+
+ pmpriv->is_data_rate_auto = wlan_is_rate_auto(pmpriv);
+
+ if (pmpriv->is_data_rate_auto) {
+ pmpriv->data_rate = 0;
+ } else {
+ ret = wlan_prepare_cmd(pmpriv,
+ HostCmd_CMD_802_11_TX_RATE_QUERY,
+ HostCmd_ACT_GEN_GET, 0, MNULL, MNULL);
+
+ }
+
+ if (pioctl_buf) {
+ ds_rate = (mlan_ds_rate *) pioctl_buf->pbuf;
+ if (ds_rate == MNULL) {
+ PRINTM(MERROR, "Request buffer not found!\n");
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+ if (pmpriv->is_data_rate_auto) {
+ ds_rate->param.rate_cfg.is_rate_auto = MTRUE;
+ } else {
+ ds_rate->param.rate_cfg.is_rate_auto = MFALSE;
+ /* check the LG rate */
+ index = wlan_get_rate_index(pmadapter, &pmpriv->bitmap_rates[0], 4);
+ if (index != -1) {
+ if ((index >= MLAN_RATE_BITMAP_OFDM0) &&
+ (index <= MLAN_RATE_BITMAP_OFDM7))
+ index -= (MLAN_RATE_BITMAP_OFDM0 - MLAN_RATE_INDEX_OFDM0);
+ ds_rate->param.rate_cfg.rate = index;
+ }
+ /* check the HT rate */
+ index = wlan_get_rate_index(pmadapter,
+ &pmpriv->bitmap_rates[2], 16);
+ if (index != -1) {
+ ds_rate->param.rate_cfg.rate = index + MLAN_RATE_INDEX_MCS0;
+ }
+ PRINTM(MINFO, "Rate index is %d\n", ds_rate->param.rate_cfg.rate);
+ }
+ for (i = 0; i < MAX_BITMAP_RATES_SIZE; i++) {
+ ds_rate->param.rate_cfg.bitmap_rates[i] = pmpriv->bitmap_rates[i];
+ }
+
+ }
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function issues adapter specific commands
+ * to initialize firmware
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ *
+ * @return MLAN_STATUS_PENDING or MLAN_STATUS_FAILURE
+ */
+mlan_status
+wlan_adapter_init_cmd(IN pmlan_adapter pmadapter)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ pmlan_private pmpriv = MNULL;
+#ifdef STA_SUPPORT
+ pmlan_private pmpriv_sta = MNULL;
+#endif
+
+ ENTER();
+
+ pmpriv = wlan_get_priv(pmadapter, MLAN_BSS_ROLE_ANY);
+#ifdef STA_SUPPORT
+ pmpriv_sta = wlan_get_priv(pmadapter, MLAN_BSS_ROLE_STA);
+#endif
+
+ /*
+ * This should be issued in the very first to config
+ * SDIO_GPIO interrupt mode.
+ */
+ if (wlan_set_sdio_gpio_int(pmpriv) != MLAN_STATUS_SUCCESS) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_FUNC_INIT,
+ HostCmd_ACT_GEN_SET, 0, MNULL, MNULL);
+ if (ret) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ /** Cal data dnld cmd prepare */
+ if ((pmadapter->pcal_data) && (pmadapter->cal_data_len > 0)) {
+ ret =
+ wlan_prepare_cmd(pmpriv, HostCmd_CMD_CFG_DATA, HostCmd_ACT_GEN_SET,
+ 0, MNULL, MNULL);
+ if (ret) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ pmadapter->pcal_data = MNULL;
+ pmadapter->cal_data_len = 0;
+ }
+
+ /*
+ * Get HW spec
+ */
+ ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_GET_HW_SPEC,
+ HostCmd_ACT_GEN_GET, 0, MNULL, MNULL);
+ if (ret) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ /* Reconfigure tx buf size */
+ ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_RECONFIGURE_TX_BUFF,
+ HostCmd_ACT_GEN_SET, 0, MNULL,
+ &pmadapter->max_tx_buf_size);
+ if (ret) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+#if defined(STA_SUPPORT)
+ if (pmpriv_sta && (pmpriv_sta->state_11d.user_enable_11d == ENABLE_11D)) {
+ /* Send command to FW to enable 11d */
+ ret = wlan_prepare_cmd(pmpriv_sta,
+ HostCmd_CMD_802_11_SNMP_MIB,
+ HostCmd_ACT_GEN_SET,
+ Dot11D_i,
+ MNULL, &pmpriv_sta->state_11d.user_enable_11d);
+ if (ret) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ }
+#endif
+
+#if defined(STA_SUPPORT)
+ if (pmpriv_sta && (pmadapter->ps_mode == Wlan802_11PowerModePSP)) {
+ ret = wlan_prepare_cmd(pmpriv_sta, HostCmd_CMD_802_11_PS_MODE_ENH,
+ EN_AUTO_PS, BITMAP_STA_PS, MNULL, MNULL);
+ if (ret) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ }
+#endif
+
+ if (pmadapter->init_auto_ds) {
+ mlan_ds_auto_ds auto_ds;
+ /* Enable auto deep sleep */
+ auto_ds.idletime = pmadapter->idle_time;
+ ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_802_11_PS_MODE_ENH,
+ EN_AUTO_PS, BITMAP_AUTO_DS, MNULL, &auto_ds);
+ if (ret) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ }
+
+ ret = MLAN_STATUS_PENDING;
+ done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function prepares command of get_hw_spec.
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param pcmd A pointer to HostCmd_DS_COMMAND structure
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+mlan_status
+wlan_cmd_get_hw_spec(IN pmlan_private pmpriv, IN HostCmd_DS_COMMAND * pcmd)
+{
+ HostCmd_DS_GET_HW_SPEC *hw_spec = &pcmd->params.hw_spec;
+
+ ENTER();
+
+ pcmd->command = wlan_cpu_to_le16(HostCmd_CMD_GET_HW_SPEC);
+ pcmd->size = wlan_cpu_to_le16(sizeof(HostCmd_DS_GET_HW_SPEC) + S_DS_GEN);
+ memcpy(pmpriv->adapter, hw_spec->permanent_addr, pmpriv->curr_addr,
+ MLAN_MAC_ADDR_LENGTH);
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function prepares command of set_cfg_data.
+ *
+ * @param pmpriv A pointer to mlan_private strcture
+ * @param pcmd A pointer to HostCmd_DS_COMMAND structure
+ * @param cmd_action Command action: GET or SET
+ * @param pdata_buf A pointer to cal_data buf
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+mlan_status
+wlan_cmd_cfg_data(IN pmlan_private pmpriv,
+ IN HostCmd_DS_COMMAND * pcmd,
+ IN t_u16 cmd_action, IN t_void * pdata_buf)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ HostCmd_DS_802_11_CFG_DATA *pcfg_data = &(pcmd->params.cfg_data);
+ pmlan_adapter pmadapter = pmpriv->adapter;
+ t_u32 len;
+ t_u32 cal_data_offset;
+ t_u8 *temp_pcmd = (t_u8 *) pcmd;
+
+ ENTER();
+
+ cal_data_offset = S_DS_GEN + sizeof(HostCmd_DS_802_11_CFG_DATA);
+ if ((pmadapter->pcal_data) && (pmadapter->cal_data_len > 0)) {
+ len = wlan_parse_cal_cfg((t_u8 *) pmadapter->pcal_data,
+ pmadapter->cal_data_len,
+ (t_u8 *) (temp_pcmd + cal_data_offset));
+ } else {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ pcfg_data->action = cmd_action;
+ pcfg_data->type = 2; /* cal data type */
+ pcfg_data->data_len = len;
+
+ pcmd->command = HostCmd_CMD_CFG_DATA;
+ pcmd->size = pcfg_data->data_len + cal_data_offset;
+
+ pcmd->command = wlan_cpu_to_le16(pcmd->command);
+ pcmd->size = wlan_cpu_to_le16(pcmd->size);
+
+ pcfg_data->action = wlan_cpu_to_le16(pcfg_data->action);
+ pcfg_data->type = wlan_cpu_to_le16(pcfg_data->type);
+ pcfg_data->data_len = wlan_cpu_to_le16(pcfg_data->data_len);
+
+ done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function handles the command response of set_cfg_data
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param resp A pointer to HostCmd_DS_COMMAND
+ * @param pioctl_buf A pointer to A pointer to mlan_ioctl_req
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status
+wlan_ret_cfg_data(IN pmlan_private pmpriv,
+ IN HostCmd_DS_COMMAND * resp, IN t_void * pioctl_buf)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ if (resp->result != HostCmd_RESULT_OK) {
+ PRINTM(MERROR, "Cal data cmd resp failed\n");
+ ret = MLAN_STATUS_FAILURE;
+ }
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function handles the command response of get_hw_spec
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param resp A pointer to HostCmd_DS_COMMAND
+ * @param pioctl_buf A pointer to command buffer
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status
+wlan_ret_get_hw_spec(IN pmlan_private pmpriv,
+ IN HostCmd_DS_COMMAND * resp, IN t_void * pioctl_buf)
+{
+ HostCmd_DS_GET_HW_SPEC *hw_spec = &resp->params.hw_spec;
+ mlan_adapter *pmadapter = pmpriv->adapter;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ t_u32 i;
+ pmlan_ioctl_req pioctl_req = (mlan_ioctl_req *) pioctl_buf;
+
+ ENTER();
+
+ pmadapter->fw_cap_info = wlan_le32_to_cpu(hw_spec->fw_cap_info);
+#ifdef STA_SUPPORT
+ if (IS_SUPPORT_MULTI_BANDS(pmadapter)) {
+ pmadapter->fw_bands = (t_u8) GET_FW_DEFAULT_BANDS(pmadapter);
+ } else {
+ pmadapter->fw_bands = BAND_B;
+ }
+
+ pmadapter->config_bands = pmadapter->fw_bands;
+ for (i = 0; i < pmadapter->priv_num; i++) {
+ if (pmadapter->priv[i])
+ pmadapter->priv[i]->config_bands = pmadapter->fw_bands;
+ }
+
+ if (pmadapter->fw_bands & BAND_A) {
+ if (pmadapter->fw_bands & BAND_GN) {
+ pmadapter->config_bands |= BAND_AN;
+ for (i = 0; i < pmadapter->priv_num; i++) {
+ if (pmadapter->priv[i])
+ pmadapter->priv[i]->config_bands |= BAND_AN;
+ }
+
+ pmadapter->fw_bands |= BAND_AN;
+ }
+ if ((pmadapter->fw_bands & BAND_AN)
+ ) {
+ pmadapter->adhoc_start_band = BAND_A | BAND_AN;
+ pmadapter->adhoc_11n_enabled = MTRUE;
+ } else
+ pmadapter->adhoc_start_band = BAND_A;
+ pmpriv->adhoc_channel = DEFAULT_AD_HOC_CHANNEL_A;
+ } else if ((pmadapter->fw_bands & BAND_GN)
+ ) {
+ pmadapter->adhoc_start_band = BAND_G | BAND_B | BAND_GN;
+ pmpriv->adhoc_channel = DEFAULT_AD_HOC_CHANNEL;
+ pmadapter->adhoc_11n_enabled = MTRUE;
+ } else if (pmadapter->fw_bands & BAND_G) {
+ pmadapter->adhoc_start_band = BAND_G | BAND_B;
+ pmpriv->adhoc_channel = DEFAULT_AD_HOC_CHANNEL;
+ } else if (pmadapter->fw_bands & BAND_B) {
+ pmadapter->adhoc_start_band = BAND_B;
+ pmpriv->adhoc_channel = DEFAULT_AD_HOC_CHANNEL;
+ }
+#endif /* STA_SUPPORT */
+
+ pmadapter->fw_release_number = hw_spec->fw_release_number;
+ pmadapter->number_of_antenna = wlan_le16_to_cpu(hw_spec->number_of_antenna);
+
+ PRINTM(MINFO, "GET_HW_SPEC: fw_release_number- 0x%X\n",
+ wlan_le32_to_cpu(pmadapter->fw_release_number));
+ PRINTM(MINFO, "GET_HW_SPEC: Permanent addr- %2x:%2x:%2x:%2x:%2x:%2x\n",
+ hw_spec->permanent_addr[0], hw_spec->permanent_addr[1],
+ hw_spec->permanent_addr[2], hw_spec->permanent_addr[3],
+ hw_spec->permanent_addr[4], hw_spec->permanent_addr[5]);
+ PRINTM(MINFO, "GET_HW_SPEC: hw_if_version=0x%X version=0x%X\n",
+ wlan_le16_to_cpu(hw_spec->hw_if_version),
+ wlan_le16_to_cpu(hw_spec->version));
+
+ if (pmpriv->curr_addr[0] == 0xff)
+ memmove(pmadapter, pmpriv->curr_addr, hw_spec->permanent_addr,
+ MLAN_MAC_ADDR_LENGTH);
+
+ pmadapter->hw_dot_11n_dev_cap = wlan_le32_to_cpu(hw_spec->dot_11n_dev_cap);
+ pmadapter->usr_dot_11n_dev_cap_bg = pmadapter->hw_dot_11n_dev_cap &
+ DEFAULT_11N_CAP_MASK_BG;
+ pmadapter->usr_dot_11n_dev_cap_a = pmadapter->hw_dot_11n_dev_cap &
+ DEFAULT_11N_CAP_MASK_A;
+ pmadapter->usr_dev_mcs_support = pmadapter->hw_dev_mcs_support =
+ hw_spec->dev_mcs_support;
+ wlan_show_dot11ndevcap(pmadapter, pmadapter->hw_dot_11n_dev_cap);
+ wlan_show_devmcssupport(pmadapter, pmadapter->hw_dev_mcs_support);
+ pmadapter->mp_end_port = wlan_le16_to_cpu(hw_spec->mp_end_port);
+
+ for (i = 1; i <= (unsigned) (MAX_PORT - pmadapter->mp_end_port); i++) {
+ pmadapter->mp_data_port_mask &= ~(1 << (MAX_PORT - i));
+ }
+
+ pmadapter->max_mgmt_ie_index = wlan_le16_to_cpu(hw_spec->mgmt_buf_count);
+ PRINTM(MINFO, "GET_HW_SPEC: mgmt IE count=%d\n",
+ pmadapter->max_mgmt_ie_index);
+ if (!pmadapter->max_mgmt_ie_index)
+ pmadapter->max_mgmt_ie_index = MAX_MGMT_IE_INDEX;
+
+ pmadapter->region_code = wlan_le16_to_cpu(hw_spec->region_code);
+ for (i = 0; i < MRVDRV_MAX_REGION_CODE; i++) {
+ /* Use the region code to search for the index */
+ if (pmadapter->region_code == region_code_index[i])
+ break;
+ }
+ /* If it's unidentified region code, use the default */
+ if (i >= MRVDRV_MAX_REGION_CODE) {
+ pmadapter->region_code = MRVDRV_DEFAULT_REGION_CODE;
+ PRINTM(MWARN, "unidentified region code, use the default (0x%02x)\n",
+ MRVDRV_DEFAULT_REGION_CODE);
+ }
+
+ if (wlan_set_regiontable(pmpriv, (t_u8) pmadapter->region_code,
+ pmadapter->fw_bands)) {
+ if (pioctl_req)
+ pioctl_req->status_code = MLAN_ERROR_CMD_SCAN_FAIL;
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+#ifdef STA_SUPPORT
+ if (wlan_11d_set_universaltable(pmpriv, pmadapter->fw_bands)) {
+ if (pioctl_req)
+ pioctl_req->status_code = MLAN_ERROR_CMD_SCAN_FAIL;
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+#endif /* STA_SUPPORT */
+
+ done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function prepares command of radio_control.
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param cmd A pointer to HostCmd_DS_COMMAND structure
+ * @param cmd_action The action: GET or SET
+ * @param pdata_buf A pointer to data buffer
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+mlan_status
+wlan_cmd_802_11_radio_control(IN pmlan_private pmpriv,
+ IN HostCmd_DS_COMMAND * cmd,
+ IN t_u16 cmd_action, IN t_void * pdata_buf)
+{
+ HostCmd_DS_802_11_RADIO_CONTROL *pradio_control = &cmd->params.radio;
+ t_u32 radio_ctl;
+ ENTER();
+ cmd->size = wlan_cpu_to_le16((sizeof(HostCmd_DS_802_11_RADIO_CONTROL))
+ + S_DS_GEN);
+ cmd->command = wlan_cpu_to_le16(HostCmd_CMD_802_11_RADIO_CONTROL);
+ pradio_control->action = wlan_cpu_to_le16(cmd_action);
+ memcpy(pmpriv->adapter, &radio_ctl, pdata_buf, sizeof(t_u32));
+ pradio_control->control = wlan_cpu_to_le16((t_u16) radio_ctl);
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function handles the command response of radio_control
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param resp A pointer to HostCmd_DS_COMMAND
+ * @param pioctl_buf A pointer to mlan_ioctl_req structure
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+mlan_status
+wlan_ret_802_11_radio_control(IN pmlan_private pmpriv,
+ IN HostCmd_DS_COMMAND * resp,
+ IN mlan_ioctl_req * pioctl_buf)
+{
+ HostCmd_DS_802_11_RADIO_CONTROL *pradio_ctrl =
+ (HostCmd_DS_802_11_RADIO_CONTROL *) & resp->params.radio;
+ mlan_ds_radio_cfg *radio_cfg = MNULL;
+ mlan_adapter *pmadapter = pmpriv->adapter;
+
+ ENTER();
+ pmadapter->radio_on = wlan_le16_to_cpu(pradio_ctrl->control);
+ if (pioctl_buf) {
+ radio_cfg = (mlan_ds_radio_cfg *) pioctl_buf->pbuf;
+ radio_cfg->param.radio_on_off = (t_u32) pmadapter->radio_on;
+ pioctl_buf->data_read_written = sizeof(mlan_ds_radio_cfg);
+ }
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+#ifdef WIFI_DIRECT_SUPPORT
+/**
+ * @brief This function prepares command of remain_on_channel.
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param cmd A pointer to HostCmd_DS_COMMAND structure
+ * @param cmd_action The action: GET or SET
+ * @param pdata_buf A pointer to data buffer
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+mlan_status
+wlan_cmd_remain_on_channel(IN pmlan_private pmpriv,
+ IN HostCmd_DS_COMMAND * cmd,
+ IN t_u16 cmd_action, IN t_void * pdata_buf)
+{
+ HostCmd_DS_REMAIN_ON_CHANNEL *remain_channel = &cmd->params.remain_on_chan;
+ mlan_ds_remain_chan *cfg = (mlan_ds_remain_chan *) pdata_buf;
+ ENTER();
+ cmd->size = wlan_cpu_to_le16((sizeof(HostCmd_DS_REMAIN_ON_CHANNEL))
+ + S_DS_GEN);
+ cmd->command = wlan_cpu_to_le16(HostCmd_CMD_802_11_REMAIN_ON_CHANNEL);
+ remain_channel->action = cmd_action;
+ if (cmd_action == HostCmd_ACT_GEN_SET) {
+ if (cfg->remove) {
+ remain_channel->action = HostCmd_ACT_GEN_REMOVE;
+ } else {
+ remain_channel->bandcfg = cfg->bandcfg;
+ remain_channel->channel = cfg->channel;
+ remain_channel->remain_period =
+ wlan_cpu_to_le32(cfg->remain_period);
+ }
+ }
+ remain_channel->action = wlan_cpu_to_le16(remain_channel->action);
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function handles the command response of remain_on_channel
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param resp A pointer to HostCmd_DS_COMMAND
+ * @param pioctl_buf A pointer to mlan_ioctl_req structure
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+mlan_status
+wlan_ret_remain_on_channel(IN pmlan_private pmpriv,
+ IN HostCmd_DS_COMMAND * resp,
+ IN mlan_ioctl_req * pioctl_buf)
+{
+ HostCmd_DS_REMAIN_ON_CHANNEL *remain_channel = &resp->params.remain_on_chan;
+ mlan_ds_radio_cfg *radio_cfg = MNULL;
+
+ ENTER();
+ if (pioctl_buf) {
+ radio_cfg = (mlan_ds_radio_cfg *) pioctl_buf->pbuf;
+ radio_cfg->param.remain_chan.status = remain_channel->status;
+ radio_cfg->param.remain_chan.bandcfg = remain_channel->bandcfg;
+ radio_cfg->param.remain_chan.channel = remain_channel->channel;
+ radio_cfg->param.remain_chan.remain_period =
+ wlan_le32_to_cpu(remain_channel->remain_period);
+ pioctl_buf->data_read_written = sizeof(mlan_ds_radio_cfg);
+ }
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function prepares command of wifi direct mode.
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param cmd A pointer to HostCmd_DS_COMMAND structure
+ * @param cmd_action The action: GET or SET
+ * @param pdata_buf A pointer to data buffer
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+mlan_status
+wlan_cmd_wifi_direct_mode(IN pmlan_private pmpriv,
+ IN HostCmd_DS_COMMAND * cmd,
+ IN t_u16 cmd_action, IN t_void * pdata_buf)
+{
+ HostCmd_DS_WIFI_DIRECT_MODE *wfd_mode = &cmd->params.wifi_direct_mode;
+ t_u16 mode = *((t_u16 *) pdata_buf);
+ ENTER();
+ cmd->size = wlan_cpu_to_le16((sizeof(HostCmd_DS_WIFI_DIRECT_MODE))
+ + S_DS_GEN);
+ cmd->command = wlan_cpu_to_le16(HOST_CMD_WIFI_DIRECT_MODE_CONFIG);
+ wfd_mode->action = wlan_cpu_to_le16(cmd_action);
+ if (cmd_action == HostCmd_ACT_GEN_SET)
+ wfd_mode->mode = wlan_cpu_to_le16(mode);
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function handles the command response of wifi direct mode
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param resp A pointer to HostCmd_DS_COMMAND
+ * @param pioctl_buf A pointer to mlan_ioctl_req structure
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+mlan_status
+wlan_ret_wifi_direct_mode(IN pmlan_private pmpriv,
+ IN HostCmd_DS_COMMAND * resp,
+ IN mlan_ioctl_req * pioctl_buf)
+{
+ HostCmd_DS_WIFI_DIRECT_MODE *wfd_mode = &resp->params.wifi_direct_mode;
+ mlan_ds_bss *bss = MNULL;
+
+ ENTER();
+ if (pioctl_buf) {
+ bss = (mlan_ds_bss *) pioctl_buf->pbuf;
+ bss->param.wfd_mode = wlan_le16_to_cpu(wfd_mode->mode);
+ pioctl_buf->data_read_written = sizeof(mlan_ds_bss);
+ }
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+#endif
diff --git a/drivers/net/wireless/sd8797/mlan/mlan_decl.h b/drivers/net/wireless/sd8797/mlan/mlan_decl.h
new file mode 100644
index 000000000000..d0ca7acae937
--- /dev/null
+++ b/drivers/net/wireless/sd8797/mlan/mlan_decl.h
@@ -0,0 +1,883 @@
+/** @file mlan_decl.h
+ *
+ * @brief This file declares the generic data structures and APIs.
+ *
+ * Copyright (C) 2008-2011, Marvell International Ltd.
+ *
+ * This software file (the "File") is distributed by Marvell International
+ * Ltd. under the terms of the GNU General Public License Version 2, June 1991
+ * (the "License"). You may use, redistribute and/or modify this File in
+ * accordance with the terms and conditions of the License, a copy of which
+ * is available by writing to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
+ * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
+ *
+ * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
+ * ARE EXPRESSLY DISCLAIMED. The License provides additional details about
+ * this warranty disclaimer.
+ */
+
+/******************************************************
+Change log:
+ 11/07/2008: initial version
+******************************************************/
+
+#ifndef _MLAN_DECL_H_
+#define _MLAN_DECL_H_
+
+/** MLAN release version */
+#define MLAN_RELEASE_VERSION "303"
+
+/** Re-define generic data types for MLAN/MOAL */
+/** Signed char (1-byte) */
+typedef char t_s8;
+/** Unsigned char (1-byte) */
+typedef unsigned char t_u8;
+/** Signed short (2-bytes) */
+typedef short t_s16;
+/** Unsigned short (2-bytes) */
+typedef unsigned short t_u16;
+/** Signed long (4-bytes) */
+typedef int t_s32;
+/** Unsigned long (4-bytes) */
+typedef unsigned int t_u32;
+/** Signed long long 8-bytes) */
+typedef long long t_s64;
+/** Unsigned long long 8-bytes) */
+typedef unsigned long long t_u64;
+/** Void pointer (4-bytes) */
+typedef void t_void;
+/** Size type */
+typedef t_u32 t_size;
+/** Boolean type */
+typedef t_u8 t_bool;
+
+#ifdef MLAN_64BIT
+/** Pointer type (64-bit) */
+typedef t_u64 t_ptr;
+/** Signed value (64-bit) */
+typedef t_s64 t_sval;
+#else
+/** Pointer type (32-bit) */
+typedef t_u32 t_ptr;
+/** Signed value (32-bit) */
+typedef t_s32 t_sval;
+#endif
+
+/** Constants below */
+
+#ifdef __GNUC__
+/** Structure packing begins */
+#define MLAN_PACK_START
+/** Structure packeing end */
+#define MLAN_PACK_END __attribute__ ((packed))
+#else /* !__GNUC__ */
+#ifdef PRAGMA_PACK
+/** Structure packing begins */
+#define MLAN_PACK_START
+/** Structure packeing end */
+#define MLAN_PACK_END
+#else /* !PRAGMA_PACK */
+/** Structure packing begins */
+#define MLAN_PACK_START __packed
+/** Structure packing end */
+#define MLAN_PACK_END
+#endif /* PRAGMA_PACK */
+#endif /* __GNUC__ */
+
+#ifndef INLINE
+#ifdef __GNUC__
+/** inline directive */
+#define INLINE inline
+#else
+/** inline directive */
+#define INLINE __inline
+#endif
+#endif
+
+/** MLAN TRUE */
+#define MTRUE (1)
+/** MLAN FALSE */
+#define MFALSE (0)
+
+/** Macros for Data Alignment : size */
+#define ALIGN_SZ(p, a) \
+ (((p) + ((a) - 1)) & ~((a) - 1))
+
+/** Macros for Data Alignment : address */
+#define ALIGN_ADDR(p, a) \
+ ((((t_ptr)(p)) + (((t_ptr)(a)) - 1)) & ~(((t_ptr)(a)) - 1))
+
+/** Return the byte offset of a field in the given structure */
+#define MLAN_FIELD_OFFSET(type, field) ((t_u32)(t_ptr)&(((type *)0)->field))
+/** Return aligned offset */
+#define OFFSET_ALIGN_ADDR(p, a) (t_u32)(ALIGN_ADDR(p, a) - (t_ptr)p)
+
+/** Maximum BSS numbers */
+#define MLAN_MAX_BSS_NUM (16)
+
+/** NET IP alignment */
+#define MLAN_NET_IP_ALIGN 0
+
+/** DMA alignment */
+#define DMA_ALIGNMENT 64
+/** max size of TxPD */
+#define MAX_TXPD_SIZE 32
+
+/** Minimum data header length */
+#define MLAN_MIN_DATA_HEADER_LEN (DMA_ALIGNMENT+MAX_TXPD_SIZE)
+
+/** rx data header length */
+#define MLAN_RX_HEADER_LEN MLAN_MIN_DATA_HEADER_LEN
+
+/** This is current limit on Maximum Tx AMPDU allowed */
+#define MLAN_MAX_TX_BASTREAM_SUPPORTED 2
+/** This is current limit on Maximum Rx AMPDU allowed */
+#define MLAN_MAX_RX_BASTREAM_SUPPORTED 16
+
+/** Default Win size attached during ADDBA request */
+#define MLAN_AMPDU_DEF_TXWINSIZE 32
+/** Default Win size attached during ADDBA response */
+#define MLAN_AMPDU_DEF_RXWINSIZE 16
+/** Block ack timeout value */
+#define MLAN_DEFAULT_BLOCK_ACK_TIMEOUT 0xffff
+/** Maximum Tx Win size configured for ADDBA request [10 bits] */
+#define MLAN_AMPDU_MAX_TXWINSIZE 0x3ff
+/** Maximum Rx Win size configured for ADDBA request [10 bits] */
+#define MLAN_AMPDU_MAX_RXWINSIZE 0x3ff
+
+/** Rate index for HR/DSSS 0 */
+#define MLAN_RATE_INDEX_HRDSSS0 0
+/** Rate index for HR/DSSS 3 */
+#define MLAN_RATE_INDEX_HRDSSS3 3
+/** Rate index for OFDM 0 */
+#define MLAN_RATE_INDEX_OFDM0 4
+/** Rate index for OFDM 7 */
+#define MLAN_RATE_INDEX_OFDM7 11
+/** Rate index for MCS 0 */
+#define MLAN_RATE_INDEX_MCS0 12
+/** Rate index for MCS 7 */
+#define MLAN_RATE_INDEX_MCS7 19
+/** Rate index for MCS 9 */
+#define MLAN_RATE_INDEX_MCS9 21
+/** Rate index for MCS15 */
+#define MLAN_RATE_INDEX_MCS15 27
+/** Rate index for MCS 32 */
+#define MLAN_RATE_INDEX_MCS32 44
+/** Rate index for MCS 127 */
+#define MLAN_RATE_INDEX_MCS127 139
+
+/** Rate bitmap for OFDM 0 */
+#define MLAN_RATE_BITMAP_OFDM0 16
+/** Rate bitmap for OFDM 7 */
+#define MLAN_RATE_BITMAP_OFDM7 23
+/** Rate bitmap for MCS 0 */
+#define MLAN_RATE_BITMAP_MCS0 32
+/** Rate bitmap for MCS 127 */
+#define MLAN_RATE_BITMAP_MCS127 159
+
+/** Size of rx data buffer */
+#define MLAN_RX_DATA_BUF_SIZE (4 * 1024)
+/** Size of rx command buffer */
+#define MLAN_RX_CMD_BUF_SIZE (2 * 1024)
+
+/** MLAN MAC Address Length */
+#define MLAN_MAC_ADDR_LENGTH (6)
+/** MLAN 802.11 MAC Address */
+typedef t_u8 mlan_802_11_mac_addr[MLAN_MAC_ADDR_LENGTH];
+
+/** MLAN Maximum SSID Length */
+#define MLAN_MAX_SSID_LENGTH (32)
+
+/** RTS/FRAG related defines */
+/** Minimum RTS value */
+#define MLAN_RTS_MIN_VALUE (0)
+/** Maximum RTS value */
+#define MLAN_RTS_MAX_VALUE (2347)
+/** Minimum FRAG value */
+#define MLAN_FRAG_MIN_VALUE (256)
+/** Maximum FRAG value */
+#define MLAN_FRAG_MAX_VALUE (2346)
+
+/** Minimum tx retry count */
+#define MLAN_TX_RETRY_MIN (0)
+/** Maximum tx retry count */
+#define MLAN_TX_RETRY_MAX (14)
+
+/** define SDIO block size for data Tx/Rx */
+/* We support up to 480-byte block size due to FW buffer limitation. */
+#define MLAN_SDIO_BLOCK_SIZE 256
+
+/** define SDIO block size for firmware download */
+#define MLAN_SDIO_BLOCK_SIZE_FW_DNLD MLAN_SDIO_BLOCK_SIZE
+
+/** define allocated buffer size */
+#define ALLOC_BUF_SIZE (4 * 1024)
+
+/** SDIO IO Port mask */
+#define MLAN_SDIO_IO_PORT_MASK 0xfffff
+/** SDIO Block/Byte mode mask */
+#define MLAN_SDIO_BYTE_MODE_MASK 0x80000000
+
+/** Max retry number of IO write */
+#define MAX_WRITE_IOMEM_RETRY 2
+
+/** IN parameter */
+#define IN
+/** OUT parameter */
+#define OUT
+
+/** BIT value */
+#define MBIT(x) (((t_u32)1) << (x))
+
+/** Buffer flag for requeued packet */
+#define MLAN_BUF_FLAG_REQUEUED_PKT MBIT(0)
+/** Buffer flag for transmit buf from moal */
+#define MLAN_BUF_FLAG_MOAL_TX_BUF MBIT(1)
+/** Buffer flag for malloc mlan_buffer */
+#define MLAN_BUF_FLAG_MALLOC_BUF MBIT(2)
+
+/** Buffer flag for bridge packet */
+#define MLAN_BUF_FLAG_BRIDGE_BUF MBIT(3)
+
+#ifdef DEBUG_LEVEL1
+/** Debug level bit definition */
+#define MMSG MBIT(0)
+#define MFATAL MBIT(1)
+#define MERROR MBIT(2)
+#define MDATA MBIT(3)
+#define MCMND MBIT(4)
+#define MEVENT MBIT(5)
+#define MINTR MBIT(6)
+#define MIOCTL MBIT(7)
+
+#define MDAT_D MBIT(16)
+#define MCMD_D MBIT(17)
+#define MEVT_D MBIT(18)
+#define MFW_D MBIT(19)
+#define MIF_D MBIT(20)
+
+#define MENTRY MBIT(28)
+#define MWARN MBIT(29)
+#define MINFO MBIT(30)
+#define MHEX_DUMP MBIT(31)
+#endif /* DEBUG_LEVEL1 */
+
+/** Memory allocation type: DMA */
+#define MLAN_MEM_DMA MBIT(0)
+
+/** Default memory allocation flag */
+#define MLAN_MEM_DEF 0
+
+/** mlan_status */
+typedef enum _mlan_status
+{
+ MLAN_STATUS_FAILURE = 0xffffffff,
+ MLAN_STATUS_SUCCESS = 0,
+ MLAN_STATUS_PENDING,
+ MLAN_STATUS_RESOURCE,
+} mlan_status;
+
+/** mlan_error_code */
+typedef enum _mlan_error_code
+{
+ /** No error */
+ MLAN_ERROR_NO_ERROR = 0,
+ /** Firmware/device errors below (MSB=0) */
+ MLAN_ERROR_FW_NOT_READY = 0x00000001,
+ MLAN_ERROR_FW_BUSY,
+ MLAN_ERROR_FW_CMDRESP,
+ MLAN_ERROR_DATA_TX_FAIL,
+ MLAN_ERROR_DATA_RX_FAIL,
+ /** Driver errors below (MSB=1) */
+ MLAN_ERROR_PKT_SIZE_INVALID = 0x80000001,
+ MLAN_ERROR_PKT_TIMEOUT,
+ MLAN_ERROR_PKT_INVALID,
+ MLAN_ERROR_CMD_INVALID,
+ MLAN_ERROR_CMD_TIMEOUT,
+ MLAN_ERROR_CMD_DNLD_FAIL,
+ MLAN_ERROR_CMD_CANCEL,
+ MLAN_ERROR_CMD_RESP_FAIL,
+ MLAN_ERROR_CMD_ASSOC_FAIL,
+ MLAN_ERROR_CMD_SCAN_FAIL,
+ MLAN_ERROR_IOCTL_INVALID,
+ MLAN_ERROR_IOCTL_FAIL,
+ MLAN_ERROR_EVENT_UNKNOWN,
+ MLAN_ERROR_INVALID_PARAMETER,
+ MLAN_ERROR_NO_MEM,
+ /** More to add */
+} mlan_error_code;
+
+/** mlan_buf_type */
+typedef enum _mlan_buf_type
+{
+ MLAN_BUF_TYPE_CMD = 1,
+ MLAN_BUF_TYPE_DATA,
+ MLAN_BUF_TYPE_EVENT,
+ MLAN_BUF_TYPE_RAW_DATA,
+} mlan_buf_type;
+
+/** MLAN BSS type */
+typedef enum _mlan_bss_type
+{
+ MLAN_BSS_TYPE_STA = 0,
+ MLAN_BSS_TYPE_UAP = 1,
+#ifdef WIFI_DIRECT_SUPPORT
+ MLAN_BSS_TYPE_WIFIDIRECT = 2,
+#endif
+ MLAN_BSS_TYPE_ANY = 0xff,
+} mlan_bss_type;
+
+/** MLAN BSS role */
+typedef enum _mlan_bss_role
+{
+ MLAN_BSS_ROLE_STA = 0,
+ MLAN_BSS_ROLE_UAP = 1,
+ MLAN_BSS_ROLE_ANY = 0xff,
+} mlan_bss_role;
+
+/** BSS role bit mask */
+#define BSS_ROLE_BIT_MASK MBIT(0)
+
+/** Get BSS role */
+#define GET_BSS_ROLE(priv) ((priv)->bss_role & BSS_ROLE_BIT_MASK)
+
+/** mlan_data_frame_type */
+typedef enum _mlan_data_frame_type
+{
+ MLAN_DATA_FRAME_TYPE_ETH_II = 0,
+ MLAN_DATA_FRAME_TYPE_802_11,
+} mlan_data_frame_type;
+
+/** mlan_event_id */
+typedef enum _mlan_event_id
+{
+ /* Event generated by firmware (MSB=0) */
+ MLAN_EVENT_ID_FW_UNKNOWN = 0x00000001,
+ MLAN_EVENT_ID_FW_ADHOC_LINK_SENSED,
+ MLAN_EVENT_ID_FW_ADHOC_LINK_LOST,
+ MLAN_EVENT_ID_FW_DISCONNECTED,
+ MLAN_EVENT_ID_FW_MIC_ERR_UNI,
+ MLAN_EVENT_ID_FW_MIC_ERR_MUL,
+ MLAN_EVENT_ID_FW_BCN_RSSI_LOW,
+ MLAN_EVENT_ID_FW_BCN_RSSI_HIGH,
+ MLAN_EVENT_ID_FW_BCN_SNR_LOW,
+ MLAN_EVENT_ID_FW_BCN_SNR_HIGH,
+ MLAN_EVENT_ID_FW_MAX_FAIL,
+ MLAN_EVENT_ID_FW_DATA_RSSI_LOW,
+ MLAN_EVENT_ID_FW_DATA_RSSI_HIGH,
+ MLAN_EVENT_ID_FW_DATA_SNR_LOW,
+ MLAN_EVENT_ID_FW_DATA_SNR_HIGH,
+ MLAN_EVENT_ID_FW_LINK_QUALITY,
+ MLAN_EVENT_ID_FW_PORT_RELEASE,
+ MLAN_EVENT_ID_FW_PRE_BCN_LOST,
+ MLAN_EVENT_ID_FW_WMM_CONFIG_CHANGE,
+ MLAN_EVENT_ID_FW_HS_WAKEUP,
+ MLAN_EVENT_ID_FW_BG_SCAN,
+ MLAN_EVENT_ID_FW_WEP_ICV_ERR,
+ MLAN_EVENT_ID_FW_STOP_TX,
+ MLAN_EVENT_ID_FW_START_TX,
+ MLAN_EVENT_ID_FW_CHANNEL_SWITCH_ANN,
+ MLAN_EVENT_ID_FW_RADAR_DETECTED,
+ MLAN_EVENT_ID_FW_CHANNEL_REPORT_RDY,
+ MLAN_EVENT_ID_FW_BW_CHANGED,
+#ifdef WIFI_DIRECT_SUPPORT
+ MLAN_EVENT_ID_FW_REMAIN_ON_CHAN_EXPIRED,
+#endif
+#ifdef UAP_SUPPORT
+ MLAN_EVENT_ID_UAP_FW_BSS_START,
+ MLAN_EVENT_ID_UAP_FW_BSS_ACTIVE,
+ MLAN_EVENT_ID_UAP_FW_BSS_IDLE,
+ MLAN_EVENT_ID_UAP_FW_STA_CONNECT,
+ MLAN_EVENT_ID_UAP_FW_STA_DISCONNECT,
+#endif
+
+ /* Event generated by MLAN driver (MSB=1) */
+ MLAN_EVENT_ID_DRV_CONNECTED = 0x80000001,
+ MLAN_EVENT_ID_DRV_DEFER_HANDLING,
+ MLAN_EVENT_ID_DRV_HS_ACTIVATED,
+ MLAN_EVENT_ID_DRV_HS_DEACTIVATED,
+ MLAN_EVENT_ID_DRV_MGMT_FRAME,
+ MLAN_EVENT_ID_DRV_OBSS_SCAN_PARAM,
+ MLAN_EVENT_ID_DRV_PASSTHRU,
+ MLAN_EVENT_ID_DRV_SCAN_REPORT,
+ MLAN_EVENT_ID_DRV_MEAS_REPORT,
+ MLAN_EVENT_ID_DRV_REPORT_STRING,
+ MLAN_EVENT_ID_DRV_DBG_DUMP,
+} mlan_event_id;
+
+/** Data Structures */
+/** mlan_image data structure */
+typedef struct _mlan_fw_image
+{
+ /** Helper image buffer pointer */
+ t_u8 *phelper_buf;
+ /** Helper image length */
+ t_u32 helper_len;
+ /** Firmware image buffer pointer */
+ t_u8 *pfw_buf;
+ /** Firmware image length */
+ t_u32 fw_len;
+} mlan_fw_image, *pmlan_fw_image;
+
+/** Custom data structure */
+typedef struct _mlan_init_param
+{
+ /** Cal data buffer pointer */
+ t_u8 *pcal_data_buf;
+ /** Cal data length */
+ t_u32 cal_data_len;
+ /** Other custom data */
+} mlan_init_param, *pmlan_init_param;
+
+/** mlan_event data structure */
+typedef struct _mlan_event
+{
+ /** BSS index number for multiple BSS support */
+ t_u32 bss_index;
+ /** Event ID */
+ mlan_event_id event_id;
+ /** Event length */
+ t_u32 event_len;
+ /** Event buffer */
+ t_u8 event_buf[1];
+} mlan_event, *pmlan_event;
+
+/** mlan_event_scan_result data structure */
+typedef MLAN_PACK_START struct _mlan_event_scan_result
+{
+ /** Event ID */
+ t_u16 event_id;
+ /** BSS index number for multiple BSS support */
+ t_u8 bss_index;
+ /** BSS type */
+ t_u8 bss_type;
+ /** More event available or not */
+ t_u8 more_event;
+ /** Reserved */
+ t_u8 reserved[3];
+ /** Size of the response buffer */
+ t_u16 buf_size;
+ /** Number of BSS in scan response */
+ t_u8 num_of_set;
+} MLAN_PACK_END mlan_event_scan_result, *pmlan_event_scan_result;
+
+/** mlan_ioctl_req data structure */
+typedef struct _mlan_ioctl_req
+{
+ /** Status code from firmware/driver */
+ t_u32 status_code;
+ /** BSS index number for multiple BSS support */
+ t_u32 bss_index;
+ /** Request id */
+ t_u32 req_id;
+ /** Action: set or get */
+ t_u32 action;
+ /** Pointer to buffer */
+ t_u8 *pbuf;
+ /** Length of buffer */
+ t_u32 buf_len;
+ /** Length of the data read/written in buffer */
+ t_u32 data_read_written;
+ /** Length of buffer needed */
+ t_u32 buf_len_needed;
+ /** Reserved for MOAL module */
+ t_ptr reserved_1;
+} mlan_ioctl_req, *pmlan_ioctl_req;
+
+/** mlan_buffer data structure */
+typedef struct _mlan_buffer
+{
+ /** Pointer to previous mlan_buffer */
+ struct _mlan_buffer *pprev;
+ /** Pointer to next mlan_buffer */
+ struct _mlan_buffer *pnext;
+ /** Status code from firmware/driver */
+ t_u32 status_code;
+ /** Flags for this buffer */
+ t_u32 flags;
+ /** BSS index number for multiple BSS support */
+ t_u32 bss_index;
+ /** Buffer descriptor, e.g. skb in Linux */
+ t_void *pdesc;
+ /** Pointer to buffer */
+ t_u8 *pbuf;
+ /** Offset to data */
+ t_u32 data_offset;
+ /** Data length */
+ t_u32 data_len;
+ /** Buffer type: data, cmd, event etc. */
+ mlan_buf_type buf_type;
+
+ /** Fields below are valid for data packet only */
+ /** QoS priority */
+ t_u32 priority;
+ /** Time stamp when packet is received (seconds) */
+ t_u32 in_ts_sec;
+ /** Time stamp when packet is received (micro seconds) */
+ t_u32 in_ts_usec;
+ /** Time stamp when packet is processed (seconds) */
+ t_u32 out_ts_sec;
+ /** Time stamp when packet is processed (micro seconds) */
+ t_u32 out_ts_usec;
+
+ /** Fields below are valid for MLAN module only */
+ /** Pointer to parent mlan_buffer */
+ struct _mlan_buffer *pparent;
+ /** Use count for this buffer */
+ t_u32 use_count;
+} mlan_buffer, *pmlan_buffer;
+
+/** mlan_bss_attr data structure */
+typedef struct _mlan_bss_attr
+{
+ /** BSS type */
+ t_u32 bss_type;
+ /** Data frame type: Ethernet II, 802.11, etc. */
+ t_u32 frame_type;
+ /** The BSS is active (non-0) or not (0). */
+ t_u32 active;
+ /** BSS Priority */
+ t_u32 bss_priority;
+ /** BSS number */
+ t_u32 bss_num;
+} mlan_bss_attr, *pmlan_bss_attr;
+
+#ifdef PRAGMA_PACK
+#pragma pack(push, 1)
+#endif
+
+/** Type enumeration for the command result */
+typedef MLAN_PACK_START enum _mlan_cmd_result_e
+{
+ MLAN_CMD_RESULT_SUCCESS = 0,
+ MLAN_CMD_RESULT_FAILURE = 1,
+ MLAN_CMD_RESULT_TIMEOUT = 2,
+ MLAN_CMD_RESULT_INVALID_DATA = 3
+} MLAN_PACK_END mlan_cmd_result_e;
+
+/** Type enumeration of WMM AC_QUEUES */
+typedef MLAN_PACK_START enum _mlan_wmm_ac_e
+{
+ WMM_AC_BK,
+ WMM_AC_BE,
+ WMM_AC_VI,
+ WMM_AC_VO
+} MLAN_PACK_END mlan_wmm_ac_e;
+
+/** Type enumeration for the action field in the Queue Config command */
+typedef MLAN_PACK_START enum _mlan_wmm_queue_config_action_e
+{
+ MLAN_WMM_QUEUE_CONFIG_ACTION_GET = 0,
+ MLAN_WMM_QUEUE_CONFIG_ACTION_SET = 1,
+ MLAN_WMM_QUEUE_CONFIG_ACTION_DEFAULT = 2,
+ MLAN_WMM_QUEUE_CONFIG_ACTION_MAX
+} MLAN_PACK_END mlan_wmm_queue_config_action_e;
+
+/** Type enumeration for the action field in the queue stats command */
+typedef MLAN_PACK_START enum _mlan_wmm_queue_stats_action_e
+{
+ MLAN_WMM_STATS_ACTION_START = 0,
+ MLAN_WMM_STATS_ACTION_STOP = 1,
+ MLAN_WMM_STATS_ACTION_GET_CLR = 2,
+ MLAN_WMM_STATS_ACTION_SET_CFG = 3, /* Not currently used */
+ MLAN_WMM_STATS_ACTION_GET_CFG = 4, /* Not currently used */
+ MLAN_WMM_STATS_ACTION_MAX
+} MLAN_PACK_END mlan_wmm_queue_stats_action_e;
+
+/**
+ * @brief IOCTL structure for a Traffic stream status.
+ *
+ */
+typedef MLAN_PACK_START struct
+{
+ /** TSID: Range: 0->7 */
+ t_u8 tid;
+ /** TSID specified is valid */
+ t_u8 valid;
+ /** AC TSID is active on */
+ t_u8 access_category;
+ /** UP specified for the TSID */
+ t_u8 user_priority;
+ /** Power save mode for TSID: 0 (legacy), 1 (UAPSD) */
+ t_u8 psb;
+ /** Upstream(0), Downlink(1), Bidirectional(3) */
+ t_u8 flow_dir;
+ /** Medium time granted for the TSID */
+ t_u16 medium_time;
+} MLAN_PACK_END wlan_ioctl_wmm_ts_status_t,
+/** Type definition of mlan_ds_wmm_ts_status for MLAN_OID_WMM_CFG_TS_STATUS */
+ mlan_ds_wmm_ts_status, *pmlan_ds_wmm_ts_status;
+
+/** Max Ie length */
+#define MAX_IE_SIZE 256
+
+/** custom IE */
+typedef MLAN_PACK_START struct _custom_ie
+{
+ /** IE Index */
+ t_u16 ie_index;
+ /** Mgmt Subtype Mask */
+ t_u16 mgmt_subtype_mask;
+ /** IE Length */
+ t_u16 ie_length;
+ /** IE buffer */
+ t_u8 ie_buffer[MAX_IE_SIZE];
+} MLAN_PACK_END custom_ie;
+
+/** Max IE index per BSS */
+#define MAX_MGMT_IE_INDEX 16
+
+/** custom IE info */
+typedef MLAN_PACK_START struct _custom_ie_info
+{
+ /** size of buffer */
+ t_u16 buf_size;
+ /** no of buffers of buf_size */
+ t_u16 buf_count;
+} MLAN_PACK_END custom_ie_info;
+
+/** TLV buffer : Max Mgmt IE */
+typedef MLAN_PACK_START struct _tlvbuf_max_mgmt_ie
+{
+ /** Type */
+ t_u16 type;
+ /** Length */
+ t_u16 len;
+ /** No of tuples */
+ t_u16 count;
+ /** custom IE info tuples */
+ custom_ie_info info[MAX_MGMT_IE_INDEX];
+} MLAN_PACK_END tlvbuf_max_mgmt_ie;
+
+/** TLV buffer : custom IE */
+typedef MLAN_PACK_START struct _tlvbuf_custom_ie
+{
+ /** Type */
+ t_u16 type;
+ /** Length */
+ t_u16 len;
+ /** IE data */
+ custom_ie ie_data_list[MAX_MGMT_IE_INDEX];
+ /** Max mgmt IE TLV */
+ tlvbuf_max_mgmt_ie max_mgmt_ie;
+} MLAN_PACK_END mlan_ds_misc_custom_ie;
+
+#ifdef PRAGMA_PACK
+#pragma pack(pop)
+#endif
+
+/** mlan_callbacks data structure */
+typedef struct _mlan_callbacks
+{
+ /** moal_get_fw_data */
+ mlan_status(*moal_get_fw_data) (IN t_void * pmoal_handle,
+ IN t_u32 offset,
+ IN t_u32 len, OUT t_u8 * pbuf);
+ /** moal_init_fw_complete */
+ mlan_status(*moal_init_fw_complete) (IN t_void * pmoal_handle,
+ IN mlan_status status);
+ /** moal_shutdown_fw_complete */
+ mlan_status(*moal_shutdown_fw_complete) (IN t_void * pmoal_handle,
+ IN mlan_status status);
+ /** moal_send_packet_complete */
+ mlan_status(*moal_send_packet_complete) (IN t_void * pmoal_handle,
+ IN pmlan_buffer pmbuf,
+ IN mlan_status status);
+ /** moal_recv_complete */
+ mlan_status(*moal_recv_complete) (IN t_void * pmoal_handle,
+ IN pmlan_buffer pmbuf,
+ IN t_u32 port, IN mlan_status status);
+ /** moal_recv_packet */
+ mlan_status(*moal_recv_packet) (IN t_void * pmoal_handle,
+ IN pmlan_buffer pmbuf);
+ /** moal_recv_event */
+ mlan_status(*moal_recv_event) (IN t_void * pmoal_handle,
+ IN pmlan_event pmevent);
+ /** moal_ioctl_complete */
+ mlan_status(*moal_ioctl_complete) (IN t_void * pmoal_handle,
+ IN pmlan_ioctl_req pioctl_req,
+ IN mlan_status status);
+ /** moal_alloc_mlan_buffer */
+ mlan_status(*moal_alloc_mlan_buffer) (IN t_void * pmoal_handle,
+ IN t_u32 size,
+ OUT pmlan_buffer * pmbuf);
+ /** moal_free_mlan_buffer */
+ mlan_status(*moal_free_mlan_buffer) (IN t_void * pmoal_handle,
+ IN pmlan_buffer pmbuf);
+ /** moal_write_reg */
+ mlan_status(*moal_write_reg) (IN t_void * pmoal_handle,
+ IN t_u32 reg, IN t_u32 data);
+ /** moal_read_reg */
+ mlan_status(*moal_read_reg) (IN t_void * pmoal_handle,
+ IN t_u32 reg, OUT t_u32 * data);
+ /** moal_write_data_sync */
+ mlan_status(*moal_write_data_sync) (IN t_void * pmoal_handle,
+ IN pmlan_buffer pmbuf,
+ IN t_u32 port, IN t_u32 timeout);
+ /** moal_read_data_sync */
+ mlan_status(*moal_read_data_sync) (IN t_void * pmoal_handle,
+ IN OUT pmlan_buffer pmbuf,
+ IN t_u32 port, IN t_u32 timeout);
+ /** moal_malloc */
+ mlan_status(*moal_malloc) (IN t_void * pmoal_handle,
+ IN t_u32 size, IN t_u32 flag, OUT t_u8 ** ppbuf);
+ /** moal_mfree */
+ mlan_status(*moal_mfree) (IN t_void * pmoal_handle, IN t_u8 * pbuf);
+ /** moal_memset */
+ t_void *(*moal_memset) (IN t_void * pmoal_handle,
+ IN t_void * pmem, IN t_u8 byte, IN t_u32 num);
+ /** moal_memcpy */
+ t_void *(*moal_memcpy) (IN t_void * pmoal_handle,
+ IN t_void * pdest,
+ IN const t_void * psrc, IN t_u32 num);
+ /** moal_memmove */
+ t_void *(*moal_memmove) (IN t_void * pmoal_handle,
+ IN t_void * pdest,
+ IN const t_void * psrc, IN t_u32 num);
+ /** moal_memcmp */
+ t_s32(*moal_memcmp) (IN t_void * pmoal_handle,
+ IN const t_void * pmem1,
+ IN const t_void * pmem2, IN t_u32 num);
+ /** moal_udelay */
+ t_void(*moal_udelay) (IN t_void * pmoal_handle, IN t_u32 udelay);
+ /** moal_get_system_time */
+ mlan_status(*moal_get_system_time) (IN t_void * pmoal_handle,
+ OUT t_u32 * psec, OUT t_u32 * pusec);
+ /** moal_init_timer*/
+ mlan_status(*moal_init_timer) (IN t_void * pmoal_handle,
+ OUT t_void ** pptimer,
+ IN t_void(*callback) (t_void * pcontext),
+ IN t_void * pcontext);
+ /** moal_free_timer */
+ mlan_status(*moal_free_timer) (IN t_void * pmoal_handle,
+ IN t_void * ptimer);
+ /** moal_start_timer*/
+ mlan_status(*moal_start_timer) (IN t_void * pmoal_handle,
+ IN t_void * ptimer,
+ IN t_u8 periodic, IN t_u32 msec);
+ /** moal_stop_timer*/
+ mlan_status(*moal_stop_timer) (IN t_void * pmoal_handle,
+ IN t_void * ptimer);
+ /** moal_init_lock */
+ mlan_status(*moal_init_lock) (IN t_void * pmoal_handle,
+ OUT t_void ** pplock);
+ /** moal_free_lock */
+ mlan_status(*moal_free_lock) (IN t_void * pmoal_handle,
+ IN t_void * plock);
+ /** moal_spin_lock */
+ mlan_status(*moal_spin_lock) (IN t_void * pmoal_handle,
+ IN t_void * plock);
+ /** moal_spin_unlock */
+ mlan_status(*moal_spin_unlock) (IN t_void * pmoal_handle,
+ IN t_void * plock);
+ /** moal_print */
+ t_void(*moal_print) (IN t_void * pmoal_handle,
+ IN t_u32 level, IN t_s8 * pformat, IN ...);
+ /** moal_print_netintf */
+ t_void(*moal_print_netintf) (IN t_void * pmoal_handle,
+ IN t_u32 bss_index, IN t_u32 level);
+ /** moal_assert */
+ t_void(*moal_assert) (IN t_void * pmoal_handle, IN t_u32 cond);
+} mlan_callbacks, *pmlan_callbacks;
+
+/** Interrupt Mode SDIO */
+#define INT_MODE_SDIO 0
+/** Interrupt Mode GPIO */
+#define INT_MODE_GPIO 1
+
+/** Parameter unchanged, use MLAN default setting */
+#define MLAN_INIT_PARA_UNCHANGED 0
+/** Parameter enabled, override MLAN default setting */
+#define MLAN_INIT_PARA_ENABLED 1
+/** Parameter disabled, override MLAN default setting */
+#define MLAN_INIT_PARA_DISABLED 2
+
+/** mlan_device data structure */
+typedef struct _mlan_device
+{
+ /** MOAL Handle */
+ t_void *pmoal_handle;
+ /** BSS Attributes */
+ mlan_bss_attr bss_attr[MLAN_MAX_BSS_NUM];
+ /** Callbacks */
+ mlan_callbacks callbacks;
+#ifdef MFG_CMD_SUPPORT
+ /** MFG mode */
+ t_u32 mfg_mode;
+#endif
+ /** SDIO interrupt mode (0: INT_MODE_SDIO, 1: INT_MODE_GPIO) */
+ t_u32 int_mode;
+ /** GPIO interrupt pin number */
+ t_u32 gpio_pin;
+#ifdef DEBUG_LEVEL1
+ /** Driver debug bit masks */
+ t_u32 drvdbg;
+#endif
+#ifdef SDIO_MULTI_PORT_TX_AGGR
+ /** SDIO MPA Tx */
+ t_u32 mpa_tx_cfg;
+#endif
+#ifdef SDIO_MULTI_PORT_RX_AGGR
+ /** SDIO MPA Rx */
+ t_u32 mpa_rx_cfg;
+#endif
+ /** Auto deep sleep */
+ t_u32 auto_ds;
+ /** IEEE PS mode */
+ t_u32 ps_mode;
+ /** Max Tx buffer size */
+ t_u32 max_tx_buf;
+#if defined(STA_SUPPORT)
+ /** 802.11d configuration */
+ t_u32 cfg_11d;
+#endif
+} mlan_device, *pmlan_device;
+
+/** MLAN API function prototype */
+#define MLAN_API
+
+/** Registration */
+MLAN_API mlan_status mlan_register(IN pmlan_device pmdevice,
+ OUT t_void ** ppmlan_adapter);
+
+/** Un-registration */
+MLAN_API mlan_status mlan_unregister(IN t_void * pmlan_adapter);
+
+/** Firmware Downloading */
+MLAN_API mlan_status mlan_dnld_fw(IN t_void * pmlan_adapter,
+ IN pmlan_fw_image pmfw);
+
+/** Custom data pass API */
+MLAN_API mlan_status mlan_set_init_param(IN t_void * pmlan_adapter,
+ IN pmlan_init_param pparam);
+
+/** Firmware Initialization */
+MLAN_API mlan_status mlan_init_fw(IN t_void * pmlan_adapter);
+
+/** Firmware Shutdown */
+MLAN_API mlan_status mlan_shutdown_fw(IN t_void * pmlan_adapter);
+
+/** Main Process */
+MLAN_API mlan_status mlan_main_process(IN t_void * pmlan_adapter);
+
+/** Packet Transmission */
+MLAN_API mlan_status mlan_send_packet(IN t_void * pmlan_adapter,
+ IN pmlan_buffer pmbuf);
+
+/** Packet Reception complete callback */
+MLAN_API mlan_status mlan_recv_packet_complete(IN t_void * pmlan_adapter,
+ IN pmlan_buffer pmbuf,
+ IN mlan_status status);
+
+/** interrupt handler */
+MLAN_API t_void mlan_interrupt(IN t_void * pmlan_adapter);
+
+/** mlan ioctl */
+MLAN_API mlan_status mlan_ioctl(IN t_void * pmlan_adapter,
+ IN pmlan_ioctl_req pioctl_req);
+/** mlan select wmm queue */
+MLAN_API t_u8 mlan_select_wmm_queue(IN t_void * pmlan_adapter,
+ IN t_u8 bss_num, IN t_u8 tid);
+#endif /* !_MLAN_DECL_H_ */
diff --git a/drivers/net/wireless/sd8797/mlan/mlan_fw.h b/drivers/net/wireless/sd8797/mlan/mlan_fw.h
new file mode 100644
index 000000000000..4b15b43711b5
--- /dev/null
+++ b/drivers/net/wireless/sd8797/mlan/mlan_fw.h
@@ -0,0 +1,4630 @@
+/** @file mlan_fw.h
+ *
+ * @brief This file contains firmware specific defines.
+ * structures and declares global function prototypes used
+ * in MLAN module.
+ *
+ * Copyright (C) 2008-2011, Marvell International Ltd.
+ *
+ * This software file (the "File") is distributed by Marvell International
+ * Ltd. under the terms of the GNU General Public License Version 2, June 1991
+ * (the "License"). You may use, redistribute and/or modify this File in
+ * accordance with the terms and conditions of the License, a copy of which
+ * is available by writing to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
+ * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
+ *
+ * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
+ * ARE EXPRESSLY DISCLAIMED. The License provides additional details about
+ * this warranty disclaimer.
+ */
+
+/******************************************************
+Change log:
+ 10/27/2008: initial version
+******************************************************/
+
+#ifndef _MLAN_FW_H_
+#define _MLAN_FW_H_
+
+/** Interface header length */
+#define INTF_HEADER_LEN 4
+
+/** Ethernet header */
+typedef struct
+{
+ /** Ethernet header destination address */
+ t_u8 dest_addr[MLAN_MAC_ADDR_LENGTH];
+ /** Ethernet header source address */
+ t_u8 src_addr[MLAN_MAC_ADDR_LENGTH];
+ /** Ethernet header length */
+ t_u16 h803_len;
+
+} Eth803Hdr_t;
+
+/** RFC 1042 header */
+typedef struct
+{
+ /** LLC DSAP */
+ t_u8 llc_dsap;
+ /** LLC SSAP */
+ t_u8 llc_ssap;
+ /** LLC CTRL */
+ t_u8 llc_ctrl;
+ /** SNAP OUI */
+ t_u8 snap_oui[3];
+ /** SNAP type */
+ t_u16 snap_type;
+
+} Rfc1042Hdr_t;
+
+#ifdef PRAGMA_PACK
+#pragma pack(push, 1)
+#endif
+
+/** Rx packet header */
+typedef MLAN_PACK_START struct
+{
+ /** Etherner header */
+ Eth803Hdr_t eth803_hdr;
+ /** RFC 1042 header */
+ Rfc1042Hdr_t rfc1042_hdr;
+
+} MLAN_PACK_END RxPacketHdr_t;
+
+/** Rates supported in band B */
+#define B_SUPPORTED_RATES 5
+/** Rates supported in band G */
+#define G_SUPPORTED_RATES 9
+/** Rates supported in band BG */
+#define BG_SUPPORTED_RATES 13
+
+/** Setup the number of rates passed in the driver/firmware API */
+#define A_SUPPORTED_RATES 9
+
+/** CapInfo Short Slot Time Disabled */
+//#define SHORT_SLOT_TIME_DISABLED(CapInfo) ((IEEEtypes_CapInfo_t)(CapInfo).short_slot_time = 0)
+#define SHORT_SLOT_TIME_DISABLED(CapInfo) (CapInfo &= ~MBIT(10))
+/** CapInfo Short Slot Time Enabled */
+#define SHORT_SLOT_TIME_ENABLED(CapInfo) (CapInfo |= MBIT(10))
+
+/** Setup the number of rates passed in the driver/firmware API */
+#define HOSTCMD_SUPPORTED_RATES 14
+
+/** Rates supported in band N */
+#define N_SUPPORTED_RATES 3
+#ifdef STA_SUPPORT
+/** All bands (B, G, N) */
+#define ALL_802_11_BANDS (BAND_A | BAND_B | BAND_G | BAND_GN)
+#else
+/** All bands (B, G, A) */
+#define ALL_802_11_BANDS (BAND_B | BAND_G | BAND_A)
+#endif /* STA_SUPPORT */
+
+#ifdef STA_SUPPORT
+/** Firmware multiple bands support */
+#define FW_MULTI_BANDS_SUPPORT (MBIT(8) | MBIT(9) | MBIT(10) | MBIT(11))
+#else
+/** Firmware multiple bands support */
+#define FW_MULTI_BANDS_SUPPORT (MBIT(8) | MBIT(9) | MBIT(10))
+#endif /* STA_SUPPORT */
+/** Check if multiple bands support is enabled in firmware */
+#define IS_SUPPORT_MULTI_BANDS(_adapter) \
+ (_adapter->fw_cap_info & FW_MULTI_BANDS_SUPPORT)
+/** Get default bands of the firmware */
+#define GET_FW_DEFAULT_BANDS(_adapter) \
+ ((_adapter->fw_cap_info >> 8) & ALL_802_11_BANDS)
+
+extern t_u8 SupportedRates_B[B_SUPPORTED_RATES];
+extern t_u8 SupportedRates_G[G_SUPPORTED_RATES];
+extern t_u8 SupportedRates_BG[BG_SUPPORTED_RATES];
+extern t_u8 SupportedRates_A[A_SUPPORTED_RATES];
+extern t_u8 SupportedRates_N[N_SUPPORTED_RATES];
+extern t_u8 AdhocRates_G[G_SUPPORTED_RATES];
+extern t_u8 AdhocRates_B[B_SUPPORTED_RATES];
+extern t_u8 AdhocRates_BG[BG_SUPPORTED_RATES];
+extern t_u8 AdhocRates_A[A_SUPPORTED_RATES];
+
+/** Default auto deep sleep mode */
+#define DEFAULT_AUTO_DS_MODE MTRUE
+/** Default power save mode */
+#define DEFAULT_PS_MODE Wlan802_11PowerModePSP
+
+/** WEP Key index mask */
+#define HostCmd_WEP_KEY_INDEX_MASK 0x3fff
+
+/** Key information enabled */
+#define KEY_INFO_ENABLED 0x01
+/** KEY_TYPE_ID */
+typedef enum _KEY_TYPE_ID
+{
+ /** Key type : WEP */
+ KEY_TYPE_ID_WEP = 0,
+ /** Key type : TKIP */
+ KEY_TYPE_ID_TKIP,
+ /** Key type : AES */
+ KEY_TYPE_ID_AES,
+ KEY_TYPE_ID_WAPI,
+} KEY_TYPE_ID;
+
+/** KEY_INFO_WEP*/
+typedef enum _KEY_INFO_WEP
+{
+ KEY_INFO_WEP_MCAST = 0x01,
+ KEY_INFO_WEP_UNICAST = 0x02,
+ KEY_INFO_WEP_ENABLED = 0x04
+} KEY_INFO_WEP;
+
+/** KEY_INFO_TKIP */
+typedef enum _KEY_INFO_TKIP
+{
+ KEY_INFO_TKIP_MCAST = 0x01,
+ KEY_INFO_TKIP_UNICAST = 0x02,
+ KEY_INFO_TKIP_ENABLED = 0x04
+} KEY_INFO_TKIP;
+
+/** KEY_INFO_AES*/
+typedef enum _KEY_INFO_AES
+{
+ KEY_INFO_AES_MCAST = 0x01,
+ KEY_INFO_AES_UNICAST = 0x02,
+ KEY_INFO_AES_ENABLED = 0x04
+} KEY_INFO_AES;
+
+/** WPA AES key length */
+#define WPA_AES_KEY_LEN 16
+/** WPA TKIP key length */
+#define WPA_TKIP_KEY_LEN 32
+
+/** WAPI key length */
+#define WAPI_KEY_LEN 50
+/** KEY_INFO_WAPI*/
+typedef enum _KEY_INFO_WAPI
+{
+ KEY_INFO_WAPI_MCAST = 0x01,
+ KEY_INFO_WAPI_UNICAST = 0x02,
+ KEY_INFO_WAPI_ENABLED = 0x04
+} KEY_INFO_WAPI;
+
+/** Maximum ethernet frame length sans FCS */
+#define MV_ETH_FRAME_LEN 1514
+
+/** Length of SNAP header */
+#define MRVDRV_SNAP_HEADER_LEN 8
+
+/** The number of times to try when polling for status bits */
+#define MAX_POLL_TRIES 100
+
+/** The number of times to try when waiting for downloaded firmware to
+ become active when multiple interface is present */
+#define MAX_MULTI_INTERFACE_POLL_TRIES 1000
+
+/** The number of times to try when waiting for downloaded firmware to
+ become active. (polling the scratch register). */
+#define MAX_FIRMWARE_POLL_TRIES 100
+
+/** This is for firmware specific length */
+#define EXTRA_LEN 36
+
+/** Buffer size for ethernet Tx packets */
+#define MRVDRV_ETH_TX_PACKET_BUFFER_SIZE \
+ (MV_ETH_FRAME_LEN + sizeof(TxPD) + EXTRA_LEN)
+
+/** Buffer size for ethernet Rx packets */
+#define MRVDRV_ETH_RX_PACKET_BUFFER_SIZE \
+ (MV_ETH_FRAME_LEN + sizeof(RxPD) \
+ + MRVDRV_SNAP_HEADER_LEN + EXTRA_LEN)
+
+/* Macros in interface module */
+/** Firmware ready */
+#define FIRMWARE_READY 0xfedc
+
+/** Number of firmware blocks to transfer */
+#define FIRMWARE_TRANSFER_NBLOCK 2
+
+/** Enumeration definition*/
+/** WLAN_802_11_PRIVACY_FILTER */
+typedef enum _WLAN_802_11_PRIVACY_FILTER
+{
+ Wlan802_11PrivFilterAcceptAll,
+ Wlan802_11PrivFilter8021xWEP
+} WLAN_802_11_PRIVACY_FILTER;
+
+/** WLAN_802_11_WEP_STATUS */
+typedef enum _WLAN_802_11_WEP_STATUS
+{
+ Wlan802_11WEPEnabled,
+ Wlan802_11WEPDisabled,
+ Wlan802_11WEPKeyAbsent,
+ Wlan802_11WEPNotSupported
+} WLAN_802_11_WEP_STATUS;
+
+/** SNR calculation */
+#define CAL_SNR(RSSI, NF) ((t_s16)((t_s16)(RSSI)-(t_s16)(NF)))
+
+/** 2K buf size */
+#define MLAN_TX_DATA_BUF_SIZE_2K 2048
+
+/** TLV type ID definition */
+#define PROPRIETARY_TLV_BASE_ID 0x0100
+
+/** Terminating TLV Type */
+#define MRVL_TERMINATE_TLV_ID 0xffff
+
+/** TLV type : SSID */
+#define TLV_TYPE_SSID 0x0000
+/** TLV type : Rates */
+#define TLV_TYPE_RATES 0x0001
+/** TLV type : PHY FH */
+#define TLV_TYPE_PHY_FH 0x0002
+/** TLV type : PHY DS */
+#define TLV_TYPE_PHY_DS 0x0003
+/** TLV type : CF */
+#define TLV_TYPE_CF 0x0004
+/** TLV type : IBSS */
+#define TLV_TYPE_IBSS 0x0006
+
+/** TLV type : Domain */
+#define TLV_TYPE_DOMAIN 0x0007
+
+/** TLV type : Power constraint */
+#define TLV_TYPE_POWER_CONSTRAINT 0x0020
+
+/** TLV type : Power capability */
+#define TLV_TYPE_POWER_CAPABILITY 0x0021
+
+/** TLV type : Vendor Specific IE */
+#define TLV_TYPE_VENDOR_SPECIFIC_IE 0xdd
+
+/** TLV type : Key material */
+#define TLV_TYPE_KEY_MATERIAL (PROPRIETARY_TLV_BASE_ID + 0x00) // 0x0100
+/** TLV type : Channel list */
+#define TLV_TYPE_CHANLIST (PROPRIETARY_TLV_BASE_ID + 0x01) // 0x0101
+/** TLV type : Number of probes */
+#define TLV_TYPE_NUMPROBES (PROPRIETARY_TLV_BASE_ID + 0x02) // 0x0102
+/** TLV type : Beacon RSSI low */
+#define TLV_TYPE_RSSI_LOW (PROPRIETARY_TLV_BASE_ID + 0x04) // 0x0104
+/** TLV type : Beacon SNR low */
+#define TLV_TYPE_SNR_LOW (PROPRIETARY_TLV_BASE_ID + 0x05) // 0x0105
+/** TLV type : Fail count */
+#define TLV_TYPE_FAILCOUNT (PROPRIETARY_TLV_BASE_ID + 0x06) // 0x0106
+/** TLV type : BCN miss */
+#define TLV_TYPE_BCNMISS (PROPRIETARY_TLV_BASE_ID + 0x07) // 0x0107
+/** TLV type : LED behavior */
+#define TLV_TYPE_LEDBEHAVIOR (PROPRIETARY_TLV_BASE_ID + 0x09) // 0x0109
+/** TLV type : Passthrough */
+#define TLV_TYPE_PASSTHROUGH (PROPRIETARY_TLV_BASE_ID + 0x0a) // 0x010a
+/** TLV type : Power TBL 2.4 Ghz */
+#define TLV_TYPE_POWER_TBL_2_4GHZ (PROPRIETARY_TLV_BASE_ID + 0x0c) // 0x010c
+/** TLV type : Power TBL 5 GHz */
+#define TLV_TYPE_POWER_TBL_5GHZ (PROPRIETARY_TLV_BASE_ID + 0x0d) // 0x010d
+/** TLV type : WMM queue status */
+#define TLV_TYPE_WMMQSTATUS (PROPRIETARY_TLV_BASE_ID + 0x10) // 0x0110
+/** TLV type : Wildcard SSID */
+#define TLV_TYPE_WILDCARDSSID (PROPRIETARY_TLV_BASE_ID + 0x12) // 0x0112
+/** TLV type : TSF timestamp */
+#define TLV_TYPE_TSFTIMESTAMP (PROPRIETARY_TLV_BASE_ID + 0x13) // 0x0113
+/** TLV type : ARP filter */
+#define TLV_TYPE_ARP_FILTER (PROPRIETARY_TLV_BASE_ID + 0x15) // 0x0115
+/** TLV type : Beacon RSSI high */
+#define TLV_TYPE_RSSI_HIGH (PROPRIETARY_TLV_BASE_ID + 0x16) // 0x0116
+/** TLV type : Beacon SNR high */
+#define TLV_TYPE_SNR_HIGH (PROPRIETARY_TLV_BASE_ID + 0x17) // 0x0117
+
+/** TLV type : Start BG scan later */
+#define TLV_TYPE_STARTBGSCANLATER (PROPRIETARY_TLV_BASE_ID + 0x1e) // 0x011e
+/** TLV type : Authentication type */
+#define TLV_TYPE_AUTH_TYPE (PROPRIETARY_TLV_BASE_ID + 0x1f) // 0x011f
+/** TLV type : BSSID */
+#define TLV_TYPE_BSSID (PROPRIETARY_TLV_BASE_ID + 0x23) // 0x0123
+
+/** TLV type : Link Quality */
+#define TLV_TYPE_LINK_QUALITY (PROPRIETARY_TLV_BASE_ID + 0x24) // 0x0124
+
+/** TLV type : Data RSSI low */
+#define TLV_TYPE_RSSI_LOW_DATA (PROPRIETARY_TLV_BASE_ID + 0x26) // 0x0126
+/** TLV type : Data SNR low */
+#define TLV_TYPE_SNR_LOW_DATA (PROPRIETARY_TLV_BASE_ID + 0x27) // 0x0127
+/** TLV type : Data RSSI high */
+#define TLV_TYPE_RSSI_HIGH_DATA (PROPRIETARY_TLV_BASE_ID + 0x28) // 0x0128
+/** TLV type : Data SNR high */
+#define TLV_TYPE_SNR_HIGH_DATA (PROPRIETARY_TLV_BASE_ID + 0x29) // 0x0129
+
+/** TLV type : Channel band list */
+#define TLV_TYPE_CHANNELBANDLIST (PROPRIETARY_TLV_BASE_ID + 0x2a) // 0x012a
+
+/** TLV type : Passphrase */
+#define TLV_TYPE_PASSPHRASE (PROPRIETARY_TLV_BASE_ID + 0x3c) // 0x013c
+
+/** TLV type : Encryption Protocol TLV */
+#define TLV_TYPE_ENCRYPTION_PROTO (PROPRIETARY_TLV_BASE_ID + 0x40) // 0x0140
+/** TLV type : Cipher TLV */
+#define TLV_TYPE_CIPHER (PROPRIETARY_TLV_BASE_ID + 0x42) // 0x0142
+/** TLV type : PMK */
+#define TLV_TYPE_PMK (PROPRIETARY_TLV_BASE_ID + 0x44) // 0x0144
+
+/** TLV type : BCN miss */
+#define TLV_TYPE_PRE_BCNMISS (PROPRIETARY_TLV_BASE_ID + 0x49) // 0x0149
+
+/** TLV type: WAPI IE */
+#define TLV_TYPE_WAPI_IE (PROPRIETARY_TLV_BASE_ID + 0x5e) // 0x015e
+
+/** TLV type: MGMT IE */
+#define TLV_TYPE_MGMT_IE (PROPRIETARY_TLV_BASE_ID + 0x69) // 0x0169
+/** TLV type: MAX_MGMT_IE */
+#define TLV_TYPE_MAX_MGMT_IE (PROPRIETARY_TLV_BASE_ID + 0xaa) // 0x01aa
+
+/** TLV type : HT Capabilities */
+#define TLV_TYPE_HT_CAP (PROPRIETARY_TLV_BASE_ID + 0x4a) // 0x014a
+/** TLV type : HT Information */
+#define TLV_TYPE_HT_INFO (PROPRIETARY_TLV_BASE_ID + 0x4b) // 0x014b
+/** TLV type : Secondary Channel Offset */
+#define TLV_SECONDARY_CHANNEL_OFFSET (PROPRIETARY_TLV_BASE_ID + 0x4c) // 0x014c
+/** TLV type : 20/40 BSS Coexistence */
+#define TLV_TYPE_2040BSS_COEXISTENCE (PROPRIETARY_TLV_BASE_ID + 0x4d) // 0x014d
+/** TLV type : Overlapping BSS Scan Parameters */
+#define TLV_TYPE_OVERLAP_BSS_SCAN_PARAM (PROPRIETARY_TLV_BASE_ID + 0x4e) // 0x014e
+/** TLV type : Extended capabilities */
+#define TLV_TYPE_EXTCAP (PROPRIETARY_TLV_BASE_ID + 0x4f) // 0x014f
+/** TLV type : Set of MCS values that STA desires to use within the BSS */
+#define TLV_TYPE_HT_OPERATIONAL_MCS_SET (PROPRIETARY_TLV_BASE_ID + 0x50) // 0x0150
+/** TLV type : RXBA_SYNC */
+#define TLV_TYPE_RXBA_SYNC (PROPRIETARY_TLV_BASE_ID + 0x99) // 0x0199
+/** ADDBA TID mask */
+#define ADDBA_TID_MASK (MBIT(2) | MBIT(3) | MBIT(4) | MBIT(5))
+/** DELBA TID mask */
+#define DELBA_TID_MASK (MBIT(12) | MBIT(13) | MBIT(14) | MBIT(15))
+/** ADDBA Starting Sequence Number Mask */
+#define SSN_MASK 0xfff0
+
+/** Block Ack result status */
+/** Block Ack Result : Success */
+#define BA_RESULT_SUCCESS 0x0
+/** Block Ack Result : Execution failure */
+#define BA_RESULT_FAILURE 0x1
+/** Block Ack Result : Timeout */
+#define BA_RESULT_TIMEOUT 0x2
+/** Block Ack Result : Data invalid */
+#define BA_RESULT_DATA_INVALID 0x3
+
+/** Get the baStatus (NOT_SETUP, COMPLETE, IN_PROGRESS)
+ * in Tx BA stream table */
+#define IS_BASTREAM_SETUP(ptr) (ptr->ba_status)
+
+/** An AMPDU/AMSDU could be disallowed for certain TID. 0xff means
+ * no aggregation is enabled for the assigned TID */
+#define BA_STREAM_NOT_ALLOWED 0xff
+
+/** Test if 11n is enabled by checking the HTCap IE */
+#define IS_11N_ENABLED(priv) ((priv->adapter->config_bands & BAND_GN ||priv->adapter->config_bands & BAND_AN) \
+ && priv->curr_bss_params.bss_descriptor.pht_cap)
+/** Find out if we are the initiator or not */
+#define INITIATOR_BIT(DelBAParamSet) (((DelBAParamSet) & \
+ MBIT(DELBA_INITIATOR_POS)) >> DELBA_INITIATOR_POS)
+
+/** 4K buf size */
+#define MLAN_TX_DATA_BUF_SIZE_4K 4096
+/** 8K buf size */
+#define MLAN_TX_DATA_BUF_SIZE_8K 8192
+/** Max Rx AMPDU Size */
+#define MAX_RX_AMPDU_SIZE_64K 0x03
+/** Non green field station */
+#define NON_GREENFIELD_STAS 0x04
+
+/** Greenfield support */
+#define HWSPEC_GREENFIELD_SUPP MBIT(29)
+/** RX STBC support */
+#define HWSPEC_RXSTBC_SUPP MBIT(26)
+/** ShortGI @ 40Mhz support */
+#define HWSPEC_SHORTGI40_SUPP MBIT(24)
+/** ShortGI @ 20Mhz support */
+#define HWSPEC_SHORTGI20_SUPP MBIT(23)
+/** Channel width 40Mhz support */
+#define HWSPEC_CHANBW40_SUPP MBIT(17)
+/** 40Mhz intolarent enable */
+#define CAPINFO_40MHZ_INTOLARENT MBIT(8)
+
+/** Default 11n capability mask for 2.4GHz */
+#define DEFAULT_11N_CAP_MASK_BG (HWSPEC_SHORTGI20_SUPP | HWSPEC_RXSTBC_SUPP)
+/** Default 11n capability mask for 5GHz */
+#define DEFAULT_11N_CAP_MASK_A (HWSPEC_CHANBW40_SUPP | HWSPEC_SHORTGI20_SUPP | \
+ HWSPEC_SHORTGI40_SUPP | HWSPEC_RXSTBC_SUPP)
+/** Bits to ignore in hw_dev_cap as these bits are set in get_hw_spec */
+#define IGN_HW_DEV_CAP (CAPINFO_40MHZ_INTOLARENT)
+
+/** HW_SPEC FwCapInfo */
+#define ISSUPP_11NENABLED(FwCapInfo) (FwCapInfo & MBIT(11))
+
+/** HW_SPEC Dot11nDevCap : MAX AMSDU supported */
+#define ISSUPP_MAXAMSDU(Dot11nDevCap) (Dot11nDevCap & MBIT(31))
+/** HW_SPEC Dot11nDevCap : Beamforming support */
+#define ISSUPP_BEAMFORMING(Dot11nDevCap) (Dot11nDevCap & MBIT(30))
+/** HW_SPEC Dot11nDevCap : Green field support */
+#define ISSUPP_GREENFIELD(Dot11nDevCap) (Dot11nDevCap & MBIT(29))
+/** HW_SPEC Dot11nDevCap : AMPDU support */
+#define ISSUPP_AMPDU(Dot11nDevCap) (Dot11nDevCap & MBIT(28))
+/** HW_SPEC Dot11nDevCap : MIMO PS support */
+#define ISSUPP_MIMOPS(Dot11nDevCap) (Dot11nDevCap & MBIT(27))
+/** HW_SPEC Dot11nDevCap : Rx STBC support */
+#define ISSUPP_RXSTBC(Dot11nDevCap) (Dot11nDevCap & MBIT(26))
+/** HW_SPEC Dot11nDevCap : Tx STBC support */
+#define ISSUPP_TXSTBC(Dot11nDevCap) (Dot11nDevCap & MBIT(25))
+/** HW_SPEC Dot11nDevCap : Short GI @ 40Mhz support */
+#define ISSUPP_SHORTGI40(Dot11nDevCap) (Dot11nDevCap & MBIT(24))
+/** HW_SPEC Dot11nDevCap : Short GI @ 20Mhz support */
+#define ISSUPP_SHORTGI20(Dot11nDevCap) (Dot11nDevCap & MBIT(23))
+/** HW_SPEC Dot11nDevCap : Rx LDPC support */
+#define ISSUPP_RXLDPC(Dot11nDevCap) (Dot11nDevCap & MBIT(22))
+/** HW_SPEC Dot11nDevCap : Delayed ACK */
+#define GET_DELAYEDBACK(Dot11nDevCap) (((Dot11nDevCap >> 20) & 0x03))
+/** HW_SPEC Dot11nDevCap : Immediate ACK */
+#define GET_IMMEDIATEBACK(Dot11nDevCap) (((Dot11nDevCap >> 18) & 0x03))
+/** HW_SPEC Dot11nDevCap : Channel BW support @ 40Mhz support */
+#define ISSUPP_CHANWIDTH40(Dot11nDevCap) (Dot11nDevCap & MBIT(17))
+/** HW_SPEC Dot11nDevCap : Channel BW support @ 20Mhz support */
+#define ISSUPP_CHANWIDTH20(Dot11nDevCap) (Dot11nDevCap & MBIT(16))
+/** HW_SPEC Dot11nDevCap : Channel BW support @ 10Mhz support */
+#define ISSUPP_CHANWIDTH10(Dot11nDevCap) (Dot11nDevCap & MBIT(15))
+/** Dot11nUsrCap : 40Mhz intolarance enabled */
+#define ISENABLED_40MHZ_INTOLARENT(Dot11nDevCap) (Dot11nDevCap & MBIT(8))
+/** HW_SPEC Dot11nDevCap : Rx AntennaD support */
+#define ISSUPP_RXANTENNAD(Dot11nDevCap) (Dot11nDevCap & MBIT(7))
+/** HW_SPEC Dot11nDevCap : Rx AntennaC support */
+#define ISSUPP_RXANTENNAC(Dot11nDevCap) (Dot11nDevCap & MBIT(6))
+/** HW_SPEC Dot11nDevCap : Rx AntennaB support */
+#define ISSUPP_RXANTENNAB(Dot11nDevCap) (Dot11nDevCap & MBIT(5))
+/** HW_SPEC Dot11nDevCap : Rx AntennaA support */
+#define ISSUPP_RXANTENNAA(Dot11nDevCap) (Dot11nDevCap & MBIT(4))
+/** HW_SPEC Dot11nDevCap : Tx AntennaD support */
+#define ISSUPP_TXANTENNAD(Dot11nDevCap) (Dot11nDevCap & MBIT(3))
+/** HW_SPEC Dot11nDevCap : Tx AntennaC support */
+#define ISSUPP_TXANTENNAC(Dot11nDevCap) (Dot11nDevCap & MBIT(2))
+/** HW_SPEC Dot11nDevCap : Tx AntennaB support */
+#define ISSUPP_TXANTENNAB(Dot11nDevCap) (Dot11nDevCap & MBIT(1))
+/** HW_SPEC Dot11nDevCap : Tx AntennaA support */
+#define ISSUPP_TXANTENNAA(Dot11nDevCap) (Dot11nDevCap & MBIT(0))
+
+/** HW_SPEC Dot11nDevCap : Set support of channel bw @ 40Mhz */
+#define SETSUPP_CHANWIDTH40(Dot11nDevCap) (Dot11nDevCap |= MBIT(17))
+/** HW_SPEC Dot11nDevCap : Reset support of channel bw @ 40Mhz */
+#define RESETSUPP_CHANWIDTH40(Dot11nDevCap) (Dot11nDevCap &= ~MBIT(17))
+
+/** DevMCSSupported : Tx MCS supported */
+#define GET_TXMCSSUPP(DevMCSSupported) (DevMCSSupported >> 4)
+/** DevMCSSupported : Rx MCS supported */
+#define GET_RXMCSSUPP(DevMCSSupported) (DevMCSSupported & 0x0f)
+
+/** GET HTCapInfo : Supported Channel BW */
+#define GETHT_SUPPCHANWIDTH(HTCapInfo) (HTCapInfo & MBIT(1))
+/** GET HTCapInfo : Support for Greenfield */
+#define GETHT_GREENFIELD(HTCapInfo) (HTCapInfo & MBIT(4))
+/** GET HTCapInfo : Support for Short GI @ 20Mhz */
+#define GETHT_SHORTGI20(HTCapInfo) (HTCapInfo & MBIT(5))
+/** GET HTCapInfo : Support for Short GI @ 40Mhz */
+#define GETHT_SHORTGI40(HTCapInfo) (HTCapInfo & MBIT(6))
+/** GET HTCapInfo : Support for Tx STBC */
+#define GETHT_TXSTBC(HTCapInfo) (HTCapInfo & MBIT(7))
+
+/** GET HTCapInfo : Support for Rx STBC */
+#define GETHT_RXSTBC(HTCapInfo) ((HTCapInfo >> 8) & 0x03)
+/** GET HTCapInfo : Support for Delayed ACK */
+#define GETHT_DELAYEDBACK(HTCapInfo) (HTCapInfo & MBIT(10))
+/** GET HTCapInfo : Support for Max AMSDU */
+#define GETHT_MAXAMSDU(HTCapInfo) (HTCapInfo & MBIT(11))
+
+/** SET HTCapInfo : Set support for LDPC coding capability */
+#define SETHT_LDPCCODINGCAP(HTCapInfo) (HTCapInfo |= MBIT(0))
+/** SET HTCapInfo : Set support for Channel BW */
+#define SETHT_SUPPCHANWIDTH(HTCapInfo) (HTCapInfo |= MBIT(1))
+/** SET HTCapInfo : Set support for Greenfield */
+#define SETHT_GREENFIELD(HTCapInfo) (HTCapInfo |= MBIT(4))
+/** SET HTCapInfo : Set support for Short GI @ 20Mhz */
+#define SETHT_SHORTGI20(HTCapInfo) (HTCapInfo |= MBIT(5))
+/** SET HTCapInfo : Set support for Short GI @ 40Mhz */
+#define SETHT_SHORTGI40(HTCapInfo) (HTCapInfo |= MBIT(6))
+/** SET HTCapInfo : Set support for Tx STBC */
+#define SETHT_TXSTBC(HTCapInfo) (HTCapInfo |= MBIT(7))
+/** SET HTCapInfo : Set support for Rx STBC */
+#define SETHT_RXSTBC(HTCapInfo, value) (HTCapInfo |= (value << 8))
+/** SET HTCapInfo : Set support for delayed block ack */
+#define SETHT_DELAYEDBACK(HTCapInfo) (HTCapInfo |= MBIT(10))
+/** SET HTCapInfo : Set support for Max size AMSDU */
+#define SETHT_MAXAMSDU(HTCapInfo) (HTCapInfo |= MBIT(11))
+/** SET HTCapInfo : Set support for DSSS/CCK Rates @ 40Mhz */
+#define SETHT_DSSSCCK40(HTCapInfo) (HTCapInfo |= MBIT(12))
+/** SET HTCapInfo : Enable 40Mhz Intolarence */
+#define SETHT_40MHZ_INTOLARANT(HTCapInfo) (HTCapInfo |= MBIT(14))
+
+/** RESET HTCapInfo : Set support for LDPC coding capability */
+#define RESETHT_LDPCCODINGCAP(HTCapInfo) (HTCapInfo &= ~MBIT(0))
+/** RESET HTCapInfo : Set support for Channel BW */
+#define RESETHT_SUPPCHANWIDTH(HTCapInfo) (HTCapInfo &= ~MBIT(1))
+/** RESET HTCapInfo : Set support for Greenfield */
+#define RESETHT_GREENFIELD(HTCapInfo) (HTCapInfo &= ~MBIT(4))
+/** RESET HTCapInfo : Set support for Short GI @ 20Mhz */
+#define RESETHT_SHORTGI20(HTCapInfo) (HTCapInfo &= ~MBIT(5))
+/** RESET HTCapInfo : Set support for Short GI @ 40Mhz */
+#define RESETHT_SHORTGI40(HTCapInfo) (HTCapInfo &= ~MBIT(6))
+/** RESET HTCapInfo : Set support for Tx STBC */
+#define RESETHT_TXSTBC(HTCapInfo) (HTCapInfo &= ~MBIT(7))
+/** RESET HTCapInfo : Set support for Rx STBC */
+#define RESETHT_RXSTBC(HTCapInfo) (HTCapInfo &= ~(0x03 << 8))
+/** RESET HTCapInfo : Set support for delayed block ack */
+#define RESETHT_DELAYEDBACK(HTCapInfo) (HTCapInfo &= ~MBIT(10))
+/** RESET HTCapInfo : Set support for Max size AMSDU */
+#define RESETHT_MAXAMSDU(HTCapInfo) (HTCapInfo &= ~MBIT(11))
+/** RESET HTCapInfo : Disable 40Mhz Intolarence */
+#define RESETHT_40MHZ_INTOLARANT(HTCapInfo) (HTCapInfo &= ~MBIT(14))
+/** RESET HTExtCap : Clear RD Responder bit */
+#define RESETHT_EXTCAP_RDG(HTExtCap) (HTExtCap &= ~MBIT(11))
+/** SET MCS32 */
+#define SETHT_MCS32(x) (x[4] |= 1)
+/** Set mcs set defined bit */
+#define SETHT_MCS_SET_DEFINED(x) (x[12] |= 1)
+/** Set the highest Rx data rate */
+#define SETHT_RX_HIGHEST_DT_SUPP(x, y) ((*(t_u16 *) (x + 10)) = y)
+/** AMPDU factor size */
+#define AMPDU_FACTOR_64K 0x03
+/** Set AMPDU size in A-MPDU paramter field */
+#define SETAMPDU_SIZE(x, y) do { \
+ x = x & ~0x03; \
+ x |= y & 0x03; \
+} while (0) \
+/** Set AMPDU spacing in A-MPDU paramter field */
+#define SETAMPDU_SPACING(x, y) do { \
+ x = x & ~0x1c; \
+ x |= (y & 0x07) << 2; \
+} while (0) \
+
+/** RadioType : Support for Band A */
+#define ISSUPP_BANDA(FwCapInfo) (FwCapInfo & MBIT(10))
+/** RadioType : Support for 40Mhz channel BW */
+#define ISALLOWED_CHANWIDTH40(Field2) (Field2 & MBIT(2))
+/** RadioType : Set support 40Mhz channel */
+#define SET_CHANWIDTH40(Field2) (Field2 |= MBIT(2))
+/** RadioType : Reset support 40Mhz channel */
+#define RESET_CHANWIDTH40(Field2) (Field2 &= ~(MBIT(0) | MBIT(1) | MBIT(2)))
+/** RadioType : Get secondary channel */
+#define GET_SECONDARYCHAN(Field2) (Field2 & (MBIT(0) | MBIT(1)))
+/** RadioType : Set secondary channel */
+#define SET_SECONDARYCHAN(RadioType, SECCHAN) (RadioType |= (SECCHAN << 4))
+
+/** LLC/SNAP header len */
+#define LLC_SNAP_LEN 8
+
+/** TLV type : Rate scope */
+#define TLV_TYPE_RATE_DROP_PATTERN (PROPRIETARY_TLV_BASE_ID + 0x51) // 0x0151
+/** TLV type : Rate drop pattern */
+#define TLV_TYPE_RATE_DROP_CONTROL (PROPRIETARY_TLV_BASE_ID + 0x52) // 0x0152
+/** TLV type : Rate scope */
+#define TLV_TYPE_RATE_SCOPE (PROPRIETARY_TLV_BASE_ID + 0x53) // 0x0153
+
+/** TLV type : Power group */
+#define TLV_TYPE_POWER_GROUP (PROPRIETARY_TLV_BASE_ID + 0x54) // 0x0154
+
+/** Modulation class for DSSS Rates */
+#define MOD_CLASS_HR_DSSS 0x03
+/** Modulation class for OFDM Rates */
+#define MOD_CLASS_OFDM 0x07
+/** Modulation class for HT Rates */
+#define MOD_CLASS_HT 0x08
+/** HT bandwidth 20 MHz */
+#define HT_BW_20 0
+/** HT bandwidth 40 MHz */
+#define HT_BW_40 1
+
+/** TLV type : Scan Response */
+#define TLV_TYPE_BSS_SCAN_RSP (PROPRIETARY_TLV_BASE_ID + 0x56) // 0x0156
+/** TLV type : Scan Response Stats */
+#define TLV_TYPE_BSS_SCAN_INFO (PROPRIETARY_TLV_BASE_ID + 0x57) // 0x0157
+
+/** TLV type : 11h Basic Rpt */
+#define TLV_TYPE_CHANRPT_11H_BASIC (PROPRIETARY_TLV_BASE_ID + 0x5b) // 0x015b
+
+/** TLV type : Action frame */
+#define TLV_TYPE_IEEE_ACTION_FRAME (PROPRIETARY_TLV_BASE_ID + 0x8c) // 0x018c
+
+/** Firmware Host Command ID Constants */
+/** Host Command ID : Get hardware specifications */
+#define HostCmd_CMD_GET_HW_SPEC 0x0003
+/** Host Command ID : 802.11 scan */
+#define HostCmd_CMD_802_11_SCAN 0x0006
+/** Host Command ID : 802.11 get log */
+#define HostCmd_CMD_802_11_GET_LOG 0x000b
+/** Host Command ID : MAC multicast address */
+#define HostCmd_CMD_MAC_MULTICAST_ADR 0x0010
+/** Host Command ID : 802.11 EEPROM access */
+#define HostCmd_CMD_802_11_EEPROM_ACCESS 0x0059
+/** Host Command ID : 802.11 associate */
+#define HostCmd_CMD_802_11_ASSOCIATE 0x0012
+
+/** Host Command ID : 802.11 SNMP MIB */
+#define HostCmd_CMD_802_11_SNMP_MIB 0x0016
+/** Host Command ID : MAC register access */
+#define HostCmd_CMD_MAC_REG_ACCESS 0x0019
+/** Host Command ID : BBP register access */
+#define HostCmd_CMD_BBP_REG_ACCESS 0x001a
+/** Host Command ID : RF register access */
+#define HostCmd_CMD_RF_REG_ACCESS 0x001b
+
+/** Host Command ID : 802.11 radio control */
+#define HostCmd_CMD_802_11_RADIO_CONTROL 0x001c
+/** Host Command ID : 802.11 RF channel */
+#define HostCmd_CMD_802_11_RF_CHANNEL 0x001d
+/** Host Command ID : 802.11 RF Tx power */
+#define HostCmd_CMD_802_11_RF_TX_POWER 0x001e
+
+/** Host Command ID : 802.11 RF antenna */
+#define HostCmd_CMD_802_11_RF_ANTENNA 0x0020
+
+/** Host Command ID : 802.11 deauthenticate */
+#define HostCmd_CMD_802_11_DEAUTHENTICATE 0x0024
+/** Host Command ID : MAC control */
+#define HostCmd_CMD_MAC_CONTROL 0x0028
+/** Host Command ID : 802.11 Ad-Hoc start */
+#define HostCmd_CMD_802_11_AD_HOC_START 0x002b
+/** Host Command ID : 802.11 Ad-Hoc join */
+#define HostCmd_CMD_802_11_AD_HOC_JOIN 0x002c
+
+/** Host Command ID : 802.11 key material */
+#define HostCmd_CMD_802_11_KEY_MATERIAL 0x005e
+
+/** Host Command ID : 802.11 Ad-Hoc stop */
+#define HostCmd_CMD_802_11_AD_HOC_STOP 0x0040
+
+/** Host Command ID : 802.22 MAC address */
+#define HostCmd_CMD_802_11_MAC_ADDRESS 0x004D
+
+/** Host Command ID : WMM Traffic Stream Status */
+#define HostCmd_CMD_WMM_TS_STATUS 0x005d
+
+/** Host Command ID : 802.11 D domain information */
+#define HostCmd_CMD_802_11D_DOMAIN_INFO 0x005b
+
+/** Host Command ID : 802.11 TPC information */
+#define HostCmd_CMD_802_11_TPC_INFO 0x005f
+/** Host Command ID : 802.11 TPC adapt req */
+#define HostCmd_CMD_802_11_TPC_ADAPT_REQ 0x0060
+/** Host Command ID : 802.11 channel SW ann */
+#define HostCmd_CMD_802_11_CHAN_SW_ANN 0x0061
+
+/** Host Command ID : Measurement request */
+#define HostCmd_CMD_MEASUREMENT_REQUEST 0x0062
+/** Host Command ID : Measurement report */
+#define HostCmd_CMD_MEASUREMENT_REPORT 0x0063
+
+/** Host Command ID : 802.11 sleep parameters */
+#define HostCmd_CMD_802_11_SLEEP_PARAMS 0x0066
+
+/** Host Command ID : 802.11 sleep period */
+#define HostCmd_CMD_802_11_SLEEP_PERIOD 0x0068
+
+/** Host Command ID: 802.11 BG scan config */
+#define HostCmd_CMD_802_11_BG_SCAN_CONFIG 0x006b
+/** Host Command ID : 802.11 BG scan query */
+#define HostCmd_CMD_802_11_BG_SCAN_QUERY 0x006c
+
+/** Host Command ID : WMM ADDTS req */
+#define HostCmd_CMD_WMM_ADDTS_REQ 0x006E
+/** Host Command ID : WMM DELTS req */
+#define HostCmd_CMD_WMM_DELTS_REQ 0x006F
+/** Host Command ID : WMM queue configuration */
+#define HostCmd_CMD_WMM_QUEUE_CONFIG 0x0070
+/** Host Command ID : 802.11 get status */
+#define HostCmd_CMD_WMM_GET_STATUS 0x0071
+
+/** Host Command ID : 802.11 subscribe event */
+#define HostCmd_CMD_802_11_SUBSCRIBE_EVENT 0x0075
+
+/** Host Command ID : 802.11 Tx rate query */
+#define HostCmd_CMD_802_11_TX_RATE_QUERY 0x007f
+
+/** Host Command ID : WMM queue stats */
+#define HostCmd_CMD_WMM_QUEUE_STATS 0x0081
+
+/** Host Command ID : 802.11 IBSS coalescing status */
+#define HostCmd_CMD_802_11_IBSS_COALESCING_STATUS 0x0083
+
+/** Host Command ID : Memory access */
+#define HostCmd_CMD_MEM_ACCESS 0x0086
+
+/** Host Command ID : SDIO GPIO interrupt configuration */
+#define HostCmd_CMD_SDIO_GPIO_INT_CONFIG 0x0088
+
+#ifdef MFG_CMD_SUPPORT
+/** Host Command ID : Mfg command */
+#define HostCmd_CMD_MFG_COMMAND 0x0089
+#endif
+/** Host Command ID : Inactivity timeout ext */
+#define HostCmd_CMD_INACTIVITY_TIMEOUT_EXT 0x008a
+
+/** Host Command ID : DBGS configuration */
+#define HostCmd_CMD_DBGS_CFG 0x008b
+/** Host Command ID : Get memory */
+#define HostCmd_CMD_GET_MEM 0x008c
+
+/** Host Command ID : Cal data dnld */
+#define HostCmd_CMD_CFG_DATA 0x008f
+
+/** Host Command ID : SDIO pull control */
+#define HostCmd_CMD_SDIO_PULL_CTRL 0x0093
+
+/** Host Command ID : ECL system clock configuration */
+#define HostCmd_CMD_ECL_SYSTEM_CLOCK_CONFIG 0x0094
+
+/** Host Command ID : Extended version */
+#define HostCmd_CMD_VERSION_EXT 0x0097
+
+/** Host Command ID : MEF configuration */
+#define HostCmd_CMD_MEF_CFG 0x009a
+
+/** Host Command ID : 802.11 RSSI INFO*/
+#define HostCmd_CMD_RSSI_INFO 0x00a4
+
+/** Host Command ID : Function initialization */
+#define HostCmd_CMD_FUNC_INIT 0x00a9
+/** Host Command ID : Function shutdown */
+#define HostCmd_CMD_FUNC_SHUTDOWN 0x00aa
+
+/** Host Command ID : Channel report request */
+#define HostCmd_CMD_CHAN_REPORT_REQUEST 0x00dd
+
+/** Host Command ID: SUPPLICANT_PMK */
+#define HostCmd_CMD_SUPPLICANT_PMK 0x00c4
+/** Host Command ID: SUPPLICANT_PROFILE */
+#define HostCmd_CMD_SUPPLICANT_PROFILE 0x00c5
+
+/** Host Command ID : Add Block Ack Request */
+#define HostCmd_CMD_11N_ADDBA_REQ 0x00ce
+/** Host Command ID : Delete a Block Ack Request */
+#define HostCmd_CMD_11N_CFG 0x00cd
+/** Host Command ID : Add Block Ack Response */
+#define HostCmd_CMD_11N_ADDBA_RSP 0x00cf
+/** Host Command ID : Delete a Block Ack Request */
+#define HostCmd_CMD_11N_DELBA 0x00d0
+/** Host Command ID: Configure Tx Buf size */
+#define HostCmd_CMD_RECONFIGURE_TX_BUFF 0x00d9
+/** Host Command ID: AMSDU Aggr Ctrl */
+#define HostCmd_CMD_AMSDU_AGGR_CTRL 0x00df
+/** Host Command ID: Configure TX Beamforming capability */
+#define HostCmd_CMD_TX_BF_CFG 0x0104
+
+/** Host Command ID : 802.11 TX power configuration */
+#define HostCmd_CMD_TXPWR_CFG 0x00d1
+
+/** Host Command ID : Soft Reset */
+#define HostCmd_CMD_SOFT_RESET 0x00d5
+
+/** Host Command ID : 802.11 b/g/n rate configration */
+#define HostCmd_CMD_TX_RATE_CFG 0x00d6
+
+/** Host Command ID : Enhanced PS mode */
+#define HostCmd_CMD_802_11_PS_MODE_ENH 0x00e4
+
+/** Host command action : Host sleep configuration */
+#define HostCmd_CMD_802_11_HS_CFG_ENH 0x00e5
+
+/** Host Command ID : CAU register access */
+#define HostCmd_CMD_CAU_REG_ACCESS 0x00ed
+
+/** Host Command ID : mgmt IE list */
+#define HostCmd_CMD_MGMT_IE_LIST 0x00f2
+
+/** Host Command ID : Extended scan support */
+#define HostCmd_CMD_802_11_SCAN_EXT 0x0107
+
+/** Host Command ID : Forward mgmt frame */
+#define HostCmd_CMD_RX_MGMT_IND 0x010c
+
+/** Host Command ID : Set BSS_MODE */
+#define HostCmd_CMD_SET_BSS_MODE 0x00f7
+
+#ifdef UAP_SUPPORT
+/** Host Command id: SYS_INFO */
+#define HOST_CMD_APCMD_SYS_INFO 0x00ae
+/** Host Command id: sys_reset */
+#define HOST_CMD_APCMD_SYS_RESET 0x00af
+/** Host Command id: SYS_CONFIGURE */
+#define HOST_CMD_APCMD_SYS_CONFIGURE 0x00b0
+/** Host Command id: BSS_START */
+#define HOST_CMD_APCMD_BSS_START 0x00b1
+/** Host Command id: BSS_STOP */
+#define HOST_CMD_APCMD_BSS_STOP 0x00b2
+/** Host Command id: sta_list */
+#define HOST_CMD_APCMD_STA_LIST 0x00b3
+/** Host Command id: STA_DEAUTH */
+#define HOST_CMD_APCMD_STA_DEAUTH 0x00b5
+
+#endif /* UAP_SUPPORT */
+
+/** Host Command ID: Tx data pause */
+#define HostCmd_CMD_CFG_TX_DATA_PAUSE 0x0103
+
+#ifdef WIFI_DIRECT_SUPPORT
+/** Host Command ID: WIFI_DIRECT_MODE_CONFIG */
+#define HOST_CMD_WIFI_DIRECT_MODE_CONFIG 0x00eb
+/** Host Command ID: Remain On Channel */
+#define HostCmd_CMD_802_11_REMAIN_ON_CHANNEL 0x010d
+#endif
+
+/** Enhanced PS modes */
+typedef enum _ENH_PS_MODES
+{
+ GET_PS = 0,
+ SLEEP_CONFIRM = 5,
+ DIS_AUTO_PS = 0xfe,
+ EN_AUTO_PS = 0xff,
+} ENH_PS_MODES;
+
+/** Command RET code, MSB is set to 1 */
+#define HostCmd_RET_BIT 0x8000
+
+/** General purpose action : Get */
+#define HostCmd_ACT_GEN_GET 0x0000
+/** General purpose action : Set */
+#define HostCmd_ACT_GEN_SET 0x0001
+/** General purpose action : Get_Current */
+#define HostCmd_ACT_GEN_GET_CURRENT 0x0003
+/** General purpose action : Remove */
+#define HostCmd_ACT_GEN_REMOVE 0x0004
+
+/** Host command action : Set Rx */
+#define HostCmd_ACT_SET_RX 0x0001
+/** Host command action : Set Tx */
+#define HostCmd_ACT_SET_TX 0x0002
+/** Host command action : Set both Rx and Tx */
+#define HostCmd_ACT_SET_BOTH 0x0003
+/** Host command action : Get Rx */
+#define HostCmd_ACT_GET_RX 0x0004
+/** Host command action : Get Tx */
+#define HostCmd_ACT_GET_TX 0x0008
+/** Host command action : Get both Rx and Tx */
+#define HostCmd_ACT_GET_BOTH 0x000c
+
+/** General Result Code*/
+/** General result code OK */
+#define HostCmd_RESULT_OK 0x0000
+/** Genenral error */
+#define HostCmd_RESULT_ERROR 0x0001
+/** Command is not valid */
+#define HostCmd_RESULT_NOT_SUPPORT 0x0002
+/** Command is pending */
+#define HostCmd_RESULT_PENDING 0x0003
+/** System is busy (command ignored) */
+#define HostCmd_RESULT_BUSY 0x0004
+/** Data buffer is not big enough */
+#define HostCmd_RESULT_PARTIAL_DATA 0x0005
+
+/* Define action or option for HostCmd_CMD_MAC_CONTROL */
+/** MAC action : Rx on */
+#define HostCmd_ACT_MAC_RX_ON 0x0001
+/** MAC action : Tx on */
+#define HostCmd_ACT_MAC_TX_ON 0x0002
+/** MAC action : WEP enable */
+#define HostCmd_ACT_MAC_WEP_ENABLE 0x0008
+/** MAC action : EthernetII enable */
+#define HostCmd_ACT_MAC_ETHERNETII_ENABLE 0x0010
+/** MAC action : Promiscous mode enable */
+#define HostCmd_ACT_MAC_PROMISCUOUS_ENABLE 0x0080
+/** MAC action : All multicast enable */
+#define HostCmd_ACT_MAC_ALL_MULTICAST_ENABLE 0x0100
+/** MAC action : RTS/CTS enable */
+#define HostCmd_ACT_MAC_RTS_CTS_ENABLE 0x0200
+/** MAC action : Strict protection enable */
+#define HostCmd_ACT_MAC_STRICT_PROTECTION_ENABLE 0x0400
+/** MAC action : Force 11n protection disable */
+#define HostCmd_ACT_MAC_FORCE_11N_PROTECTION_OFF 0x0800
+/** MAC action : Ad-Hoc G protection on */
+#define HostCmd_ACT_MAC_ADHOC_G_PROTECTION_ON 0x2000
+
+/* Define action or option for HostCmd_CMD_802_11_SCAN */
+/** Scan type : BSS */
+#define HostCmd_BSS_MODE_BSS 0x0001
+/** Scan type : IBSS */
+#define HostCmd_BSS_MODE_IBSS 0x0002
+/** Scan type : Any */
+#define HostCmd_BSS_MODE_ANY 0x0003
+
+/* Radio type definitions for the channel TLV */
+/** Radio type BG */
+#define HostCmd_SCAN_RADIO_TYPE_BG 0
+/** Radio type A */
+#define HostCmd_SCAN_RADIO_TYPE_A 1
+
+/** Define bitmap conditions for HOST_SLEEP_CFG : GPIO FF */
+#define HOST_SLEEP_CFG_GPIO_FF 0xff
+/** Define bitmap conditions for HOST_SLEEP_CFG : GAP FF */
+#define HOST_SLEEP_CFG_GAP_FF 0xff
+
+/** Buffer Constants */
+/** Number of command buffers */
+#define MRVDRV_NUM_OF_CMD_BUFFER 20
+/** Size of command buffer */
+#define MRVDRV_SIZE_OF_CMD_BUFFER (2 * 1024)
+
+/** Maximum number of BSS Descriptors */
+#define MRVDRV_MAX_BSSID_LIST 64
+
+/** Host command flag in command */
+#define CMD_F_HOSTCMD (1 << 0)
+/** command cancel flag in command */
+#define CMD_F_CANCELED (1 << 1)
+
+/** Host Command ID bit mask (bit 11:0) */
+#define HostCmd_CMD_ID_MASK 0x0fff
+
+/** Host Command Sequence number mask (bit 7:0) */
+#define HostCmd_SEQ_NUM_MASK 0x00ff
+
+/** Host Command BSS number mask (bit 11:8) */
+#define HostCmd_BSS_NUM_MASK 0x0f00
+
+/** Host Command BSS type mask (bit 15:12) */
+#define HostCmd_BSS_TYPE_MASK 0xf000
+
+/** Set BSS information to Host Command */
+#define HostCmd_SET_SEQ_NO_BSS_INFO(seq, num, type) \
+ (((seq) & 0x00ff) | \
+ (((num) & 0x000f) << 8)) | \
+ (((type) & 0x000f) << 12)
+
+/** Get Sequence Number from Host Command (bit 7:0) */
+#define HostCmd_GET_SEQ_NO(seq) \
+ ((seq) & HostCmd_SEQ_NUM_MASK)
+
+/** Get BSS number from Host Command (bit 11:8) */
+#define HostCmd_GET_BSS_NO(seq) \
+ (((seq) & HostCmd_BSS_NUM_MASK) >> 8)
+
+/** Get BSS type from Host Command (bit 15:12) */
+#define HostCmd_GET_BSS_TYPE(seq) \
+ (((seq) & HostCmd_BSS_TYPE_MASK) >> 12)
+
+/** Card Event definition : Dummy host wakeup signal */
+#define EVENT_DUMMY_HOST_WAKEUP_SIGNAL 0x00000001
+/** Card Event definition : Link lost */
+#define EVENT_LINK_LOST 0x00000003
+/** Card Event definition : Link sensed */
+#define EVENT_LINK_SENSED 0x00000004
+/** Card Event definition : MIB changed */
+#define EVENT_MIB_CHANGED 0x00000006
+/** Card Event definition : Init done */
+#define EVENT_INIT_DONE 0x00000007
+/** Card Event definition : Deauthenticated */
+#define EVENT_DEAUTHENTICATED 0x00000008
+/** Card Event definition : Disassociated */
+#define EVENT_DISASSOCIATED 0x00000009
+/** Card Event definition : Power save awake */
+#define EVENT_PS_AWAKE 0x0000000a
+/** Card Event definition : Power save sleep */
+#define EVENT_PS_SLEEP 0x0000000b
+/** Card Event definition : MIC error multicast */
+#define EVENT_MIC_ERR_MULTICAST 0x0000000d
+/** Card Event definition : MIC error unicast */
+#define EVENT_MIC_ERR_UNICAST 0x0000000e
+
+/** Card Event definition : Ad-Hoc BCN lost */
+#define EVENT_ADHOC_BCN_LOST 0x00000011
+
+/** Card Event definition : Stop Tx */
+#define EVENT_STOP_TX 0x00000013
+/** Card Event definition : Start Tx */
+#define EVENT_START_TX 0x00000014
+/** Card Event definition : Channel switch */
+#define EVENT_CHANNEL_SWITCH 0x00000015
+
+/** Card Event definition : MEAS report ready */
+#define EVENT_MEAS_REPORT_RDY 0x00000016
+
+/** Card Event definition : WMM status change */
+#define EVENT_WMM_STATUS_CHANGE 0x00000017
+
+/** Card Event definition : BG scan report */
+#define EVENT_BG_SCAN_REPORT 0x00000018
+
+/** Card Event definition : Beacon RSSI low */
+#define EVENT_RSSI_LOW 0x00000019
+/** Card Event definition : Beacon SNR low */
+#define EVENT_SNR_LOW 0x0000001a
+/** Card Event definition : Maximum fail */
+#define EVENT_MAX_FAIL 0x0000001b
+/** Card Event definition : Beacon RSSI high */
+#define EVENT_RSSI_HIGH 0x0000001c
+/** Card Event definition : Beacon SNR high */
+#define EVENT_SNR_HIGH 0x0000001d
+
+/** Card Event definition : IBSS coalsced */
+#define EVENT_IBSS_COALESCED 0x0000001e
+
+/** Card Event definition : Data RSSI low */
+#define EVENT_DATA_RSSI_LOW 0x00000024
+/** Card Event definition : Data SNR low */
+#define EVENT_DATA_SNR_LOW 0x00000025
+/** Card Event definition : Data RSSI high */
+#define EVENT_DATA_RSSI_HIGH 0x00000026
+/** Card Event definition : Data SNR high */
+#define EVENT_DATA_SNR_HIGH 0x00000027
+
+/** Card Event definition : Link Quality */
+#define EVENT_LINK_QUALITY 0x00000028
+
+/** Card Event definition : Port release event */
+#define EVENT_PORT_RELEASE 0x0000002b
+
+/** Card Event definition : Pre-Beacon Lost */
+#define EVENT_PRE_BEACON_LOST 0x00000031
+
+/** Card Event definition : Add BA event */
+#define EVENT_ADDBA 0x00000033
+/** Card Event definition : Del BA event */
+#define EVENT_DELBA 0x00000034
+/** Card Event definition: BA stream timeout*/
+#define EVENT_BA_STREAM_TIMEOUT 0x00000037
+
+/** Card Event definition : AMSDU aggr control */
+#define EVENT_AMSDU_AGGR_CTRL 0x00000042
+
+/** Card Event definition: WEP ICV error */
+#define EVENT_WEP_ICV_ERR 0x00000046
+
+/** Card Event definition : Host sleep enable */
+#define EVENT_HS_ACT_REQ 0x00000047
+
+/** Card Event definition : BW changed */
+#define EVENT_BW_CHANGE 0x00000048
+
+#ifdef WIFI_DIRECT_SUPPORT
+/** WIFIDIRECT generic event */
+#define EVENT_WIFIDIRECT_GENERIC_EVENT 0x00000049
+/** WIFIDIRECT service discovery event */
+#define EVENT_WIFIDIRECT_SERVICE_DISCOVERY 0x0000004a
+/** Remain on Channel expired event */
+#define EVENT_REMAIN_ON_CHANNEL_EXPIRED 0x0000005f
+#endif
+
+/** Card Event definition: Channel switch pending announcment */
+#define EVENT_CHANNEL_SWITCH_ANN 0x00000050
+
+/** Event definition: Radar Detected by card */
+#define EVENT_RADAR_DETECTED 0x00000053
+
+/** Event definition: Radar Detected by card */
+#define EVENT_CHANNEL_REPORT_RDY 0x00000054
+
+/** Event definition: Scan results through event */
+#define EVENT_EXT_SCAN_REPORT 0x00000058
+
+/** Event definition: RXBA_SYNC */
+#define EVENT_RXBA_SYNC 0x00000059
+
+#ifdef UAP_SUPPORT
+/** Event ID: STA deauth */
+#define EVENT_MICRO_AP_STA_DEAUTH 0x0000002c
+/** Event ID: STA assoicated */
+#define EVENT_MICRO_AP_STA_ASSOC 0x0000002d
+/** Event ID: BSS started */
+#define EVENT_MICRO_AP_BSS_START 0x0000002e
+/** Event ID: BSS idle event */
+#define EVENT_MICRO_AP_BSS_IDLE 0x00000043
+/** Event ID: BSS active event */
+#define EVENT_MICRO_AP_BSS_ACTIVE 0x00000044
+
+#endif /* UAP_SUPPORT */
+
+/** Event ID: TX data pause event */
+#define EVENT_TX_DATA_PAUSE 0x00000055
+
+/** Event ID mask */
+#define EVENT_ID_MASK 0xffff
+
+/** BSS number mask */
+#define BSS_NUM_MASK 0xf
+
+/** Get BSS number from event cause (bit 23:16) */
+#define EVENT_GET_BSS_NUM(event_cause) \
+ (((event_cause) >> 16) & BSS_NUM_MASK)
+
+/** Get BSS type from event cause (bit 31:24) */
+#define EVENT_GET_BSS_TYPE(event_cause) \
+ (((event_cause) >> 24) & 0x00ff)
+
+/** Event_WEP_ICV_ERR structure */
+typedef MLAN_PACK_START struct _Event_WEP_ICV_ERR
+{
+ /** Reason code */
+ t_u16 reason_code;
+ /** Source MAC address */
+ t_u8 src_mac_addr[MLAN_MAC_ADDR_LENGTH];
+ /** WEP decryption used key */
+ t_u8 wep_key_index;
+ /** WEP key length */
+ t_u8 wep_key_length;
+ /** WEP key */
+ t_u8 key[MAX_WEP_KEY_SIZE];
+} MLAN_PACK_END Event_WEP_ICV_ERR;
+
+/** WLAN_802_11_FIXED_IEs */
+typedef MLAN_PACK_START struct _WLAN_802_11_FIXED_IEs
+{
+ /** Timestamp */
+ t_u8 time_stamp[8];
+ /** Beacon interval */
+ t_u16 beacon_interval;
+ /** Capabilities*/
+ t_u16 capabilities;
+} MLAN_PACK_END WLAN_802_11_FIXED_IEs;
+
+/** WLAN_802_11_VARIABLE_IEs */
+typedef MLAN_PACK_START struct _WLAN_802_11_VARIABLE_IEs
+{
+ /** Element ID */
+ t_u8 element_id;
+ /** Length */
+ t_u8 length;
+ /** IE data */
+ t_u8 data[1];
+} MLAN_PACK_END WLAN_802_11_VARIABLE_IEs;
+
+/** TLV related data structures*/
+/** MrvlIEtypesHeader_t */
+typedef MLAN_PACK_START struct _MrvlIEtypesHeader
+{
+ /** Header type */
+ t_u16 type;
+ /** Header length */
+ t_u16 len;
+} MLAN_PACK_END MrvlIEtypesHeader_t;
+
+/** MrvlIEtypes_Data_t */
+typedef MLAN_PACK_START struct _MrvlIEtypes_Data_t
+{
+ /** Header */
+ MrvlIEtypesHeader_t header;
+ /** Data */
+ t_u8 data[1];
+} MLAN_PACK_END MrvlIEtypes_Data_t;
+
+/** Bit mask for TxPD status field for null packet */
+#define MRVDRV_TxPD_POWER_MGMT_NULL_PACKET 0x01
+/** Bit mask for TxPD status field for last packet */
+#define MRVDRV_TxPD_POWER_MGMT_LAST_PACKET 0x08
+
+/** Packet type: 802.11 */
+#define PKT_TYPE_802DOT11 0x05
+#define PKT_TYPE_MGMT_FRAME 0xE5
+/** Packet type: AMSDU */
+#define PKT_TYPE_AMSDU 0xE6
+/** Packet type: BAR */
+#define PKT_TYPE_BAR 0xE7
+/** Packet type: debugging */
+#define PKT_TYPE_DEBUG 0xEF
+
+/** TxPD descriptor */
+typedef MLAN_PACK_START struct _TxPD
+{
+ /** BSS type */
+ t_u8 bss_type;
+ /** BSS number */
+ t_u8 bss_num;
+ /** Tx packet length */
+ t_u16 tx_pkt_length;
+ /** Tx packet offset */
+ t_u16 tx_pkt_offset;
+ /** Tx packet type */
+ t_u16 tx_pkt_type;
+ /** Tx Control */
+ t_u32 tx_control;
+ /** Pkt Priority */
+ t_u8 priority;
+ /** Transmit Pkt Flags*/
+ t_u8 flags;
+ /** Amount of time the packet has been queued in the driver (units = 2ms)*/
+ t_u8 pkt_delay_2ms;
+ /** Reserved */
+ t_u8 reserved1;
+} MLAN_PACK_END TxPD, *PTxPD;
+
+/** RxPD Descriptor */
+typedef MLAN_PACK_START struct _RxPD
+{
+ /** BSS type */
+ t_u8 bss_type;
+ /** BSS number */
+ t_u8 bss_num;
+ /** Rx Packet Length */
+ t_u16 rx_pkt_length;
+ /** Rx Pkt offset */
+ t_u16 rx_pkt_offset;
+ /** Rx packet type */
+ t_u16 rx_pkt_type;
+ /** Sequence number */
+ t_u16 seq_num;
+ /** Packet Priority */
+ t_u8 priority;
+ /** Rx Packet Rate */
+ t_u8 rx_rate;
+ /** SNR */
+ t_s8 snr;
+ /** Noise Floor */
+ t_s8 nf;
+ /** Ht Info [Bit 0] RxRate format: LG=0, HT=1
+ * [Bit 1] HT Bandwidth: BW20 = 0, BW40 = 1
+ * [Bit 2] HT Guard Interval: LGI = 0, SGI = 1 */
+ t_u8 ht_info;
+ /** Reserved */
+ t_u8 reserved;
+} MLAN_PACK_END RxPD, *PRxPD;
+
+#ifdef UAP_SUPPORT
+/** TxPD descriptor */
+typedef MLAN_PACK_START struct _UapTxPD
+{
+ /** BSS type */
+ t_u8 bss_type;
+ /** BSS number */
+ t_u8 bss_num;
+ /** Tx packet length */
+ t_u16 tx_pkt_length;
+ /** Tx packet offset */
+ t_u16 tx_pkt_offset;
+ /** Tx packet type */
+ t_u16 tx_pkt_type;
+ /** Tx Control */
+ t_u32 tx_control;
+ /** Pkt Priority */
+ t_u8 priority;
+ /** Transmit Pkt Flags*/
+ t_u8 flags;
+ /** Amount of time the packet has been queued in the driver (units = 2ms)*/
+ t_u8 pkt_delay_2ms;
+ /** Reserved */
+ t_u8 reserved1;
+ /** Reserved */
+ t_u32 reserved;
+} MLAN_PACK_END UapTxPD, *PUapTxPD;
+
+/** RxPD Descriptor */
+typedef MLAN_PACK_START struct _UapRxPD
+{
+ /** BSS Type */
+ t_u8 bss_type;
+ /** BSS number*/
+ t_u8 bss_num;
+ /** Rx packet length */
+ t_u16 rx_pkt_length;
+ /** Rx packet offset */
+ t_u16 rx_pkt_offset;
+ /** Rx packet type */
+ t_u16 rx_pkt_type;
+ /** Sequence number */
+ t_u16 seq_num;
+ /** Packet Priority */
+ t_u8 priority;
+ /** reserved */
+ t_u8 reserved1;
+} MLAN_PACK_END UapRxPD, *PUapRxPD;
+
+/** Fixed size of station association event */
+#define ASSOC_EVENT_FIX_SIZE 12
+
+/** IEEEtypes_FrameCtl_t*/
+#ifdef BIG_ENDIAN_SUPPORT
+typedef MLAN_PACK_START struct _IEEEtypes_FrameCtl_t
+{
+ /** Order */
+ t_u8 order:1;
+ /** Wep */
+ t_u8 wep:1;
+ /** More Data */
+ t_u8 more_data:1;
+ /** Power Mgmt */
+ t_u8 pwr_mgmt:1;
+ /** Retry */
+ t_u8 retry:1;
+ /** More Frag */
+ t_u8 more_frag:1;
+ /** From DS */
+ t_u8 from_ds:1;
+ /** To DS */
+ t_u8 to_ds:1;
+ /** Sub Type */
+ t_u8 sub_type:4;
+ /** Type */
+ t_u8 type:2;
+ /** Protocol Version */
+ t_u8 protocol_version:2;
+} MLAN_PACK_END IEEEtypes_FrameCtl_t;
+#else
+typedef MLAN_PACK_START struct _IEEEtypes_FrameCtl_t
+{
+ /** Protocol Version */
+ t_u8 protocol_version:2;
+ /** Type */
+ t_u8 type:2;
+ /** Sub Type */
+ t_u8 sub_type:4;
+ /** To DS */
+ t_u8 to_ds:1;
+ /** From DS */
+ t_u8 from_ds:1;
+ /** More Frag */
+ t_u8 more_frag:1;
+ /** Retry */
+ t_u8 retry:1;
+ /** Power Mgmt */
+ t_u8 pwr_mgmt:1;
+ /** More Data */
+ t_u8 more_data:1;
+ /** Wep */
+ t_u8 wep:1;
+ /** Order */
+ t_u8 order:1;
+} MLAN_PACK_END IEEEtypes_FrameCtl_t;
+#endif
+
+/** MrvlIETypes_MgmtFrameSet_t */
+typedef MLAN_PACK_START struct _MrvlIETypes_MgmtFrameSet_t
+{
+ /** Type */
+ t_u16 type;
+ /** Length */
+ t_u16 len;
+ /** Frame Control */
+ IEEEtypes_FrameCtl_t frame_control;
+ /* t_u8 frame_contents[0]; */
+} MLAN_PACK_END MrvlIETypes_MgmtFrameSet_t;
+
+/** IEEEtypes_AssocRqst_t */
+typedef MLAN_PACK_START struct _IEEEtypes_AssocRqst_t
+{
+ /** Capability Info */
+ t_u16 cap_info;
+ /** Listen Interval */
+ t_u16 listen_interval;
+ /* t_u8 ie_buffer[0]; */
+} MLAN_PACK_END IEEEtypes_AssocRqst_t;
+
+/** IEEEtypes_ReAssocRqst_t */
+typedef MLAN_PACK_START struct _IEEEtypes_ReAssocRqst_t
+{
+ /** Capability Info */
+ t_u16 cap_info;
+ /** Listen Interval */
+ t_u16 listen_interval;
+ /** Current AP Address */
+ t_u8 current_ap_addr[MLAN_MAC_ADDR_LENGTH];
+ /* t_u8 ie_buffer[0]; */
+} MLAN_PACK_END IEEEtypes_ReAssocRqst_t;
+#endif /* UAP_SUPPORT */
+
+/** wlan_802_11_header */
+typedef MLAN_PACK_START struct _wlan_802_11_header
+{
+ /** Frame Control */
+ t_u16 frm_ctl;
+ /** Duration ID */
+ t_u16 duration_id;
+ /** Address1 */
+ mlan_802_11_mac_addr addr1;
+ /** Address2 */
+ mlan_802_11_mac_addr addr2;
+ /** Address3 */
+ mlan_802_11_mac_addr addr3;
+ /** Sequence Control */
+ t_u16 seq_ctl;
+ /** Address4 */
+ mlan_802_11_mac_addr addr4;
+} MLAN_PACK_END wlan_802_11_header;
+
+/** wlan_802_11_header packet from FW with length */
+typedef MLAN_PACK_START struct _wlan_mgmt_pkt
+{
+ /** Packet Length */
+ t_u16 frm_len;
+ /** wlan_802_11_header */
+ wlan_802_11_header wlan_header;
+} MLAN_PACK_END wlan_mgmt_pkt;
+
+#ifdef STA_SUPPORT
+/** (Beaconsize(256)-5(IEId,len,contrystr(3))/3(FirstChan,NoOfChan,MaxPwr) */
+#define MAX_NO_OF_CHAN 40
+
+/** Channel-power table entries */
+typedef MLAN_PACK_START struct _chan_power_11d
+{
+ /** 11D channel */
+ t_u8 chan;
+ /** Band for channel */
+ t_u8 band;
+ /** 11D channel power */
+ t_u8 pwr;
+ /** AP seen on channel */
+ t_u8 ap_seen;
+} MLAN_PACK_END chan_power_11d_t;
+
+/** Region channel info */
+typedef MLAN_PACK_START struct _parsed_region_chan_11d
+{
+ /** 11D channel power per channel */
+ chan_power_11d_t chan_pwr[MAX_NO_OF_CHAN];
+ /** 11D number of channels */
+ t_u8 no_of_chan;
+} MLAN_PACK_END parsed_region_chan_11d_t;
+#endif /* STA_SUPPORT */
+
+/** ChanScanMode_t */
+typedef MLAN_PACK_START struct _ChanScanMode_t
+{
+#ifdef BIG_ENDIAN_SUPPORT
+ /** Reserved */
+ t_u8 reserved_2_7:6;
+ /** Disble channel filtering flag */
+ t_u8 disable_chan_filt:1;
+ /** Channel scan mode passive flag */
+ t_u8 passive_scan:1;
+#else
+ /** Channel scan mode passive flag */
+ t_u8 passive_scan:1;
+ /** Disble channel filtering flag */
+ t_u8 disable_chan_filt:1;
+ /** Reserved */
+ t_u8 reserved_2_7:6;
+#endif
+} MLAN_PACK_END ChanScanMode_t;
+
+/** secondary channel is below */
+#define SECOND_CHANNEL_BELOW 0x30
+/** secondary channel is above */
+#define SECOND_CHANNEL_ABOVE 0x10
+/** channel offset */
+enum
+{
+ SEC_CHAN_NONE = 0,
+ SEC_CHAN_ABOVE = 1,
+ SEC_CHAN_BELOW = 3
+};
+/** channel bandwidth */
+enum
+{
+ CHAN_BW_20MHZ = 0,
+ CHAN_BW_10MHZ,
+ CHAN_BW_40MHZ,
+};
+/** ChanScanParamSet_t */
+typedef MLAN_PACK_START struct _ChanScanParamSet_t
+{
+ /** Channel scan parameter : Radio type */
+ t_u8 radio_type;
+ /** Channel scan parameter : Channel number */
+ t_u8 chan_number;
+ /** Channel scan parameter : Channel scan mode */
+ ChanScanMode_t chan_scan_mode;
+ /** Channel scan parameter : Minimum scan time */
+ t_u16 min_scan_time;
+ /** Channel scan parameter : Maximum scan time */
+ t_u16 max_scan_time;
+} MLAN_PACK_END ChanScanParamSet_t;
+
+/** MrvlIEtypes_ChanListParamSet_t */
+typedef MLAN_PACK_START struct _MrvlIEtypes_ChanListParamSet_t
+{
+ /** Header */
+ MrvlIEtypesHeader_t header;
+ /** Channel scan parameters */
+ ChanScanParamSet_t chan_scan_param[1];
+} MLAN_PACK_END MrvlIEtypes_ChanListParamSet_t;
+
+/** ChanBandParamSet_t */
+typedef struct _ChanBandParamSet_t
+{
+ /** Channel scan parameter : Radio type */
+ t_u8 radio_type;
+ /** Channel number */
+ t_u8 chan_number;
+} ChanBandParamSet_t;
+
+/** MrvlIEtypes_ChanBandListParamSet_t */
+typedef MLAN_PACK_START struct _MrvlIEtypes_ChanBandListParamSet_t
+{
+ /** Header */
+ MrvlIEtypesHeader_t header;
+ /** Channel Band parameters */
+ ChanBandParamSet_t chan_band_param[1];
+} MLAN_PACK_END MrvlIEtypes_ChanBandListParamSet_t;
+
+/** MrvlIEtypes_RatesParamSet_t */
+typedef MLAN_PACK_START struct _MrvlIEtypes_RatesParamSet_t
+{
+ /** Header */
+ MrvlIEtypesHeader_t header;
+ /** Rates */
+ t_u8 rates[1];
+} MLAN_PACK_END MrvlIEtypes_RatesParamSet_t;
+
+/** MrvlIEtypes_SsIdParamSet_t */
+typedef MLAN_PACK_START struct _MrvlIEtypes_SsIdParamSet_t
+{
+ /** Header */
+ MrvlIEtypesHeader_t header;
+ /** SSID */
+ t_u8 ssid[1];
+} MLAN_PACK_END MrvlIEtypes_SsIdParamSet_t;
+
+/** MrvlIEtypes_NumProbes_t */
+typedef MLAN_PACK_START struct _MrvlIEtypes_NumProbes_t
+{
+ /** Header */
+ MrvlIEtypesHeader_t header;
+ /** Number of probes */
+ t_u16 num_probes;
+} MLAN_PACK_END MrvlIEtypes_NumProbes_t;
+
+/** MrvlIEtypes_WildCardSsIdParamSet_t */
+typedef MLAN_PACK_START struct _MrvlIEtypes_WildCardSsIdParamSet_t
+{
+ /** Header */
+ MrvlIEtypesHeader_t header;
+ /** Maximum SSID length */
+ t_u8 max_ssid_length;
+ /** SSID */
+ t_u8 ssid[1];
+} MLAN_PACK_END MrvlIEtypes_WildCardSsIdParamSet_t;
+
+/**TSF data size */
+#define TSF_DATA_SIZE 8
+/** Table of TSF values returned in the scan result */
+typedef MLAN_PACK_START struct _MrvlIEtypes_TsfTimestamp_t
+{
+ /** Header */
+ MrvlIEtypesHeader_t header;
+ /** the length of each TSF data is 8 bytes, could be multiple TSF here */
+ t_u8 tsf_data[1];
+} MLAN_PACK_END MrvlIEtypes_TsfTimestamp_t;
+
+/** CfParamSet_t */
+typedef MLAN_PACK_START struct _CfParamSet_t
+{
+ /** CF parameter : Count */
+ t_u8 cfp_cnt;
+ /** CF parameter : Period */
+ t_u8 cfp_period;
+ /** CF parameter : Duration */
+ t_u16 cfp_max_duration;
+ /** CF parameter : Duration remaining */
+ t_u16 cfp_duration_remaining;
+} MLAN_PACK_END CfParamSet_t;
+
+/** IbssParamSet_t */
+typedef MLAN_PACK_START struct _IbssParamSet_t
+{
+ /** ATIM window value */
+ t_u16 atim_window;
+} MLAN_PACK_END IbssParamSet_t;
+
+/** MrvlIEtypes_SsParamSet_t */
+typedef MLAN_PACK_START struct _MrvlIEtypes_SsParamSet_t
+{
+ /** Header */
+ MrvlIEtypesHeader_t header;
+ /** CF/IBSS parameters sets */
+ union
+ {
+ /** CF parameter set */
+ CfParamSet_t cf_param_set[1];
+ /** IBSS parameter set */
+ IbssParamSet_t ibss_param_set[1];
+ } cf_ibss;
+} MLAN_PACK_END MrvlIEtypes_SsParamSet_t;
+
+/** FhParamSet_t */
+typedef MLAN_PACK_START struct _FhParamSet_t
+{
+ /** FH parameter : Dwell time */
+ t_u16 dwell_time;
+ /** FH parameter : Hop set */
+ t_u8 hop_set;
+ /** FH parameter : Hop pattern */
+ t_u8 hop_pattern;
+ /** FH parameter : Hop index */
+ t_u8 hop_index;
+} MLAN_PACK_END FhParamSet_t;
+
+/** DsParamSet_t */
+typedef MLAN_PACK_START struct _DsParamSet_t
+{
+ /** Current channel number */
+ t_u8 current_chan;
+} MLAN_PACK_END DsParamSet_t;
+
+/** MrvlIEtypes_PhyParamSet_t */
+typedef MLAN_PACK_START struct _MrvlIEtypes_PhyParamSet_t
+{
+ /** Header */
+ MrvlIEtypesHeader_t header;
+ /** FH/DS parameters */
+ union
+ {
+ /** FH parameter set */
+ FhParamSet_t fh_param_set[1];
+ /** DS parameter set */
+ DsParamSet_t ds_param_set[1];
+ } fh_ds;
+} MLAN_PACK_END MrvlIEtypes_PhyParamSet_t;
+
+/* Auth type to be used in the Authentication portion of an Assoc seq */
+/** MrvlIEtypes_AuthType_t */
+typedef MLAN_PACK_START struct _MrvlIEtypes_AuthType_t
+{
+ /** Header */
+ MrvlIEtypesHeader_t header;
+ /** Authentication type */
+ t_u16 auth_type;
+} MLAN_PACK_END MrvlIEtypes_AuthType_t;
+
+/** MrvlIETypes_ActionFrame_t */
+typedef MLAN_PACK_START struct
+{
+ MrvlIEtypesHeader_t header; /**< Header */
+
+ t_u8 srcAddr[MLAN_MAC_ADDR_LENGTH];
+ t_u8 dstAddr[MLAN_MAC_ADDR_LENGTH];
+
+ IEEEtypes_ActionFrame_t actionFrame;
+
+} MLAN_PACK_END MrvlIETypes_ActionFrame_t;
+
+/** MrvlIEtypes_RxBaSync_t */
+typedef MLAN_PACK_START struct _MrvlIEtypes_RxBaSync_t
+{
+ /** Header */
+ MrvlIEtypesHeader_t header;
+ /** mac address */
+ t_u8 mac[MLAN_MAC_ADDR_LENGTH];
+ /** tid */
+ t_u8 tid;
+ /** reserved field */
+ t_u8 reserved;
+ /** start seq num */
+ t_u16 seq_num;
+ /** bitmap len */
+ t_u16 bitmap_len;
+ /** bitmap */
+ t_u8 bitmap[1];
+} MLAN_PACK_END MrvlIEtypes_RxBaSync_t;
+
+/** MrvlIEtypes_RsnParamSet_t */
+typedef MLAN_PACK_START struct _MrvlIEtypes_RsnParamSet_t
+{
+ /** Header */
+ MrvlIEtypesHeader_t header;
+ /** RSN IE */
+ t_u8 rsn_ie[1];
+} MLAN_PACK_END MrvlIEtypes_RsnParamSet_t;
+
+/** Key_param_set fixed length */
+#define KEYPARAMSET_FIXED_LEN 6
+
+/** MrvlIEtype_KeyParamSet_t */
+typedef MLAN_PACK_START struct _MrvlIEtype_KeyParamSet_t
+{
+ /** Type ID */
+ t_u16 type;
+ /** Length of Payload */
+ t_u16 length;
+ /** Type of Key: WEP=0, TKIP=1, AES=2 */
+ t_u16 key_type_id;
+ /** Key Control Info specific to a key_type_id */
+ t_u16 key_info;
+ /** Length of key */
+ t_u16 key_len;
+ /** Key material of size key_len */
+ t_u8 key[50];
+} MLAN_PACK_END MrvlIEtype_KeyParamSet_t;
+
+/** HostCmd_DS_802_11_KEY_MATERIAL */
+typedef MLAN_PACK_START struct _HostCmd_DS_802_11_KEY_MATERIAL
+{
+ /** Action */
+ t_u16 action;
+ /** Key parameter set */
+ MrvlIEtype_KeyParamSet_t key_param_set;
+} MLAN_PACK_END HostCmd_DS_802_11_KEY_MATERIAL;
+
+/** Data structure of WMM QoS information */
+typedef MLAN_PACK_START struct _WmmQosInfo_t
+{
+#ifdef BIG_ENDIAN_SUPPORT
+ /** QoS UAPSD */
+ t_u8 qos_uapsd:1;
+ /** Reserved */
+ t_u8 reserved:3;
+ /** Parameter set count */
+ t_u8 para_set_count:4;
+#else
+ /** Parameter set count */
+ t_u8 para_set_count:4;
+ /** Reserved */
+ t_u8 reserved:3;
+ /** QoS UAPSD */
+ t_u8 qos_uapsd:1;
+#endif /* BIG_ENDIAN_SUPPORT */
+} MLAN_PACK_END WmmQosInfo_t, *pWmmQosInfo_t;
+
+/** Data structure of WMM ECW */
+typedef MLAN_PACK_START struct _WmmEcw_t
+{
+#ifdef BIG_ENDIAN_SUPPORT
+ /** Maximum Ecw */
+ t_u8 ecw_max:4;
+ /** Minimum Ecw */
+ t_u8 ecw_min:4;
+#else
+ /** Minimum Ecw */
+ t_u8 ecw_min:4;
+ /** Maximum Ecw */
+ t_u8 ecw_max:4;
+#endif /* BIG_ENDIAN_SUPPORT */
+} MLAN_PACK_END WmmEcw_t, *pWmmEcw_t;
+
+/** Data structure of WMM Aci/Aifsn */
+typedef MLAN_PACK_START struct _WmmAciAifsn_t
+{
+#ifdef BIG_ENDIAN_SUPPORT
+ /** Reserved */
+ t_u8 reserved:1;
+ /** Aci */
+ t_u8 aci:2;
+ /** Acm */
+ t_u8 acm:1;
+ /** Aifsn */
+ t_u8 aifsn:4;
+#else
+ /** Aifsn */
+ t_u8 aifsn:4;
+ /** Acm */
+ t_u8 acm:1;
+ /** Aci */
+ t_u8 aci:2;
+ /** Reserved */
+ t_u8 reserved:1;
+#endif /* BIG_ENDIAN_SUPPORT */
+} MLAN_PACK_END WmmAciAifsn_t, *pWmmAciAifsn_t;
+
+/** Data structure of WMM AC parameters */
+typedef MLAN_PACK_START struct _WmmAcParameters_t
+{
+ WmmAciAifsn_t aci_aifsn; /**< AciAifSn */
+ WmmEcw_t ecw; /**< Ecw */
+ t_u16 tx_op_limit; /**< Tx op limit */
+} MLAN_PACK_END WmmAcParameters_t, *pWmmAcParameters_t;
+
+/** Data structure of WMM parameter */
+typedef MLAN_PACK_START struct _WmmParameter_t
+{
+ /** OuiType: 00:50:f2:02 */
+ t_u8 ouitype[4];
+ /** Oui subtype: 01 */
+ t_u8 ouisubtype;
+ /** version: 01 */
+ t_u8 version;
+ /** QoS information */
+ t_u8 qos_info;
+ /** Reserved */
+ t_u8 reserved;
+ /** AC Parameters Record WMM_AC_BE, WMM_AC_BK, WMM_AC_VI, WMM_AC_VO */
+ WmmAcParameters_t ac_params[MAX_AC_QUEUES];
+} MLAN_PACK_END WmmParameter_t, *pWmmParameter_t;
+
+/* Definition of firmware host command */
+/** HostCmd_DS_GEN */
+typedef MLAN_PACK_START struct _HostCmd_DS_GEN
+{
+ /** Command */
+ t_u16 command;
+ /** Size */
+ t_u16 size;
+ /** Sequence number */
+ t_u16 seq_num;
+ /** Result */
+ t_u16 result;
+} MLAN_PACK_END HostCmd_DS_GEN;
+
+/** Size of HostCmd_DS_GEN */
+#define S_DS_GEN sizeof(HostCmd_DS_GEN)
+
+/** Address type: broadcast */
+#define ADDR_TYPE_BROADCAST 1
+/* Address type: unicast */
+#define ADDR_TYPE_UNICAST 2
+/* Address type: multicast */
+#define ADDR_TYPE_MULTICAST 3
+
+/** Ether type: any */
+#define ETHER_TYPE_ANY 0xffff
+/** Ether type: ARP */
+#define ETHER_TYPE_ARP 0x0608
+
+/** IPv4 address any */
+#define IPV4_ADDR_ANY 0xffffffff
+
+/** Header structure for ARP filter */
+typedef MLAN_PACK_START struct _arpfilter_header
+{
+ /** Type */
+ t_u16 type;
+ /** TLV length */
+ t_u16 len;
+} MLAN_PACK_END arpfilter_header;
+
+/** Filter entry structure */
+typedef MLAN_PACK_START struct _filter_entry
+{
+ /** Address type */
+ t_u16 addr_type;
+ /** Ether type */
+ t_u16 eth_type;
+ /** IPv4 address */
+ t_u32 ipv4_addr;
+} MLAN_PACK_END filter_entry;
+
+typedef MLAN_PACK_START struct _HostCmd_DS_MEF_CFG
+{
+ /** Criteria */
+ t_u32 criteria;
+ /** Number of entries */
+ t_u16 nentries;
+} MLAN_PACK_END HostCmd_DS_MEF_CFG;
+
+/* HostCmd_DS_802_11_SLEEP_PERIOD */
+typedef MLAN_PACK_START struct _HostCmd_DS_802_11_SLEEP_PERIOD
+{
+ /** ACT_GET/ACT_SET */
+ t_u16 action;
+
+ /** Sleep Period in msec */
+ t_u16 sleep_pd;
+} MLAN_PACK_END HostCmd_DS_802_11_SLEEP_PERIOD;
+
+/* HostCmd_DS_802_11_SLEEP_PARAMS */
+typedef MLAN_PACK_START struct _HostCmd_DS_802_11_SLEEP_PARAMS
+{
+ /** ACT_GET/ACT_SET */
+ t_u16 action;
+ /** Sleep clock error in ppm */
+ t_u16 error;
+ /** Wakeup offset in usec */
+ t_u16 offset;
+ /** Clock stabilization time in usec */
+ t_u16 stable_time;
+ /** Control periodic calibration */
+ t_u8 cal_control;
+ /** Control the use of external sleep clock */
+ t_u8 external_sleep_clk;
+ /** Reserved field, should be set to zero */
+ t_u16 reserved;
+} MLAN_PACK_END HostCmd_DS_802_11_SLEEP_PARAMS;
+
+/** Sleep response control */
+typedef enum _sleep_resp_ctrl
+{
+ RESP_NOT_NEEDED = 0,
+ RESP_NEEDED,
+} sleep_resp_ctrl;
+
+/** Structure definition for the new ieee power save parameters*/
+typedef struct __ps_param
+{
+ /** Null packet interval */
+ t_u16 null_pkt_interval;
+ /** Num dtims */
+ t_u16 multiple_dtims;
+ /** becaon miss interval */
+ t_u16 bcn_miss_timeout;
+ /** local listen interval */
+ t_u16 local_listen_interval;
+ /** Adhoc awake period */
+ t_u16 adhoc_wake_period;
+ /** mode - (0x01 - firmware to automatically choose PS_POLL or NULL mode, 0x02 - PS_POLL, 0x03 - NULL mode ) */
+ t_u16 mode;
+ /** Delay to PS in milliseconds */
+ t_u16 delay_to_ps;
+} ps_param;
+
+/** Structure definition for the new auto deep sleep command */
+typedef struct __auto_ds_param
+{
+ /** Deep sleep inactivity timeout */
+ t_u16 deep_sleep_timeout;
+} auto_ds_param;
+
+/** Structure definition for sleep confirmation in the new ps command */
+typedef struct __sleep_confirm_param
+{
+ /** response control 0x00 - response not needed, 0x01 - response needed */
+ t_u16 resp_ctrl;
+} sleep_confirm_param;
+
+/** bitmap for get auto deepsleep */
+#define BITMAP_AUTO_DS 0x01
+/** bitmap for sta power save */
+#define BITMAP_STA_PS 0x10
+/** bitmap for uap inactivity based PS */
+#define BITMAP_UAP_INACT_PS 0x100
+/** bitmap for uap DTIM PS */
+#define BITMAP_UAP_DTIM_PS 0x200
+/** Structure definition for the new ieee power save parameters*/
+typedef struct _auto_ps_param
+{
+ /** bitmap for enable power save mode */
+ t_u16 ps_bitmap;
+ /* auto deep sleep parameter, sta power save parameter uap inactivity
+ parameter uap DTIM parameter */
+} auto_ps_param;
+
+/** fix size for auto ps */
+#define AUTO_PS_FIX_SIZE 4
+
+/** TLV type : auto ds param */
+#define TLV_TYPE_AUTO_DS_PARAM (PROPRIETARY_TLV_BASE_ID + 0x71) // 0x0171
+/** TLV type : ps param */
+#define TLV_TYPE_PS_PARAM (PROPRIETARY_TLV_BASE_ID + 0x72) // 0x0172
+
+/** MrvlIEtypes_auto_ds_param_t */
+typedef MLAN_PACK_START struct _MrvlIEtypes_auto_ds_param_t
+{
+ /** Header */
+ MrvlIEtypesHeader_t header;
+ /** auto ds param */
+ auto_ds_param param;
+} MLAN_PACK_END MrvlIEtypes_auto_ds_param_t;
+
+/** MrvlIEtypes_ps_param_t */
+typedef MLAN_PACK_START struct _MrvlIEtypes_ps_param_t
+{
+ /** Header */
+ MrvlIEtypesHeader_t header;
+ /** ps param */
+ ps_param param;
+} MLAN_PACK_END MrvlIEtypes_ps_param_t;
+
+/** Structure definition for new power save command */
+typedef MLAN_PACK_START struct _HostCmd_DS_PS_MODE_ENH
+{
+ /** Action */
+ t_u16 action;
+ /** Data speciifc to action */
+ /* For IEEE power save data will be as UINT16 mode (0x01 - firmware to
+ automatically choose PS_POLL or NULL mode, 0x02 - PS_POLL, 0x03 - NULL
+ mode ) UINT16 NullpacketInterval UINT16 NumDtims UINT16
+ BeaconMissInterval UINT16 locallisteninterval UINT16 adhocawakeperiod */
+
+ /* For auto deep sleep */
+ /* UINT16 Deep sleep inactivity timeout */
+
+ /* For PS sleep confirm UINT16 responeCtrl - 0x00 - reponse from fw not
+ needed, 0x01 - response from fw is needed */
+
+ union
+ {
+ /** PS param definition */
+ ps_param opt_ps;
+ /** Auto ds param definition */
+ auto_ds_param auto_ds;
+ /** Sleep comfirm param definition */
+ sleep_confirm_param sleep_cfm;
+ /** bitmap for get PS info and Disable PS mode */
+ t_u16 ps_bitmap;
+ /** auto ps param */
+ auto_ps_param auto_ps;
+ } params;
+} MLAN_PACK_END HostCmd_DS_802_11_PS_MODE_ENH;
+
+/** HostCmd_DS_GET_HW_SPEC */
+typedef MLAN_PACK_START struct _HostCmd_DS_GET_HW_SPEC
+{
+ /** HW Interface version number */
+ t_u16 hw_if_version;
+ /** HW version number */
+ t_u16 version;
+ /** Reserved field */
+ t_u16 reserved;
+ /** Max no of Multicast address */
+ t_u16 num_of_mcast_adr;
+ /** MAC address */
+ t_u8 permanent_addr[MLAN_MAC_ADDR_LENGTH];
+ /** Region Code */
+ t_u16 region_code;
+ /** Number of antenna used */
+ t_u16 number_of_antenna;
+ /** FW release number, example 0x1234=1.2.3.4 */
+ t_u32 fw_release_number;
+ /** Reserved field */
+ t_u32 reserved_1;
+ /** Reserved field */
+ t_u32 reserved_2;
+ /** Reserved field */
+ t_u32 reserved_3;
+ /** FW/HW Capability */
+ t_u32 fw_cap_info;
+ /** 802.11n Device Capabilities */
+ t_u32 dot_11n_dev_cap;
+ /** MIMO abstraction of MCSs supported by device */
+ t_u8 dev_mcs_support;
+ /** Valid end port at init */
+ t_u16 mp_end_port;
+ /** mgmt IE buffer count */
+ t_u16 mgmt_buf_count;
+} MLAN_PACK_END HostCmd_DS_GET_HW_SPEC;
+
+/** HostCmd_DS_802_11_CFG_DATA */
+typedef MLAN_PACK_START struct _HostCmd_DS_802_11_CFG_DATA
+{
+ /** Action */
+ t_u16 action;
+ /** Type */
+ t_u16 type;
+ /** Data length */
+ t_u16 data_len;
+ /** Data */
+} MLAN_PACK_END HostCmd_DS_802_11_CFG_DATA;
+
+/** HostCmd_DS_CMD_802_11_RSSI_INFO */
+typedef MLAN_PACK_START struct _HostCmd_DS_802_11_RSSI_INFO
+{
+ /** Action */
+ t_u16 action;
+ /** Parameter used for exponential averaging for Data */
+ t_u16 ndata;
+ /** Parameter used for exponential averaging for Beacon */
+ t_u16 nbcn;
+ /** Reserved field 0 */
+ t_u16 reserved[9];
+ /** Reserved field 1 */
+ t_u64 reserved_1;
+} MLAN_PACK_END HostCmd_DS_802_11_RSSI_INFO;
+
+/** HostCmd_DS_802_11_RSSI_INFO_RSP */
+typedef MLAN_PACK_START struct _HostCmd_DS_802_11_RSSI_INFO_RSP
+{
+ /** Action */
+ t_u16 action;
+ /** Parameter used for exponential averaging for Data */
+ t_u16 ndata;
+ /** Parameter used for exponential averaging for beacon */
+ t_u16 nbcn;
+ /** Last Data RSSI in dBm */
+ t_s16 data_rssi_last;
+ /** Last Data NF in dBm */
+ t_s16 data_nf_last;
+ /** AVG DATA RSSI in dBm */
+ t_s16 data_rssi_avg;
+ /** AVG DATA NF in dBm */
+ t_s16 data_nf_avg;
+ /** Last BEACON RSSI in dBm */
+ t_s16 bcn_rssi_last;
+ /** Last BEACON NF in dBm */
+ t_s16 bcn_nf_last;
+ /** AVG BEACON RSSI in dBm */
+ t_s16 bcn_rssi_avg;
+ /** AVG BEACON NF in dBm */
+ t_s16 bcn_nf_avg;
+ /** Last RSSI Beacon TSF */
+ t_u64 tsf_bcn;
+} MLAN_PACK_END HostCmd_DS_802_11_RSSI_INFO_RSP;
+
+/** HostCmd_DS_802_11_MAC_ADDRESS */
+typedef MLAN_PACK_START struct _HostCmd_DS_802_11_MAC_ADDRESS
+{
+ /** Action */
+ t_u16 action;
+ /** MAC address */
+ t_u8 mac_addr[MLAN_MAC_ADDR_LENGTH];
+} MLAN_PACK_END HostCmd_DS_802_11_MAC_ADDRESS;
+
+/** HostCmd_DS_MAC_CONTROL */
+typedef MLAN_PACK_START struct _HostCmd_DS_MAC_CONTROL
+{
+ /** Action */
+ t_u16 action;
+ /** Reserved field */
+ t_u16 reserved;
+} MLAN_PACK_END HostCmd_DS_MAC_CONTROL;
+
+/** HostCmd_DS_CMD_TX_DATA_PAUSE */
+typedef MLAN_PACK_START struct _HostCmd_DS_CMD_TX_DATA_PAUSE
+{
+ /** Action */
+ t_u16 action;
+ /** Enable/disable Tx data pause */
+ t_u8 enable_tx_pause;
+ /** Max number of TX buffers allowed for all PS clients*/
+ t_u8 pause_tx_count;
+} MLAN_PACK_END HostCmd_DS_CMD_TX_DATA_PAUSE;
+
+/** TLV type : TX pause TLV */
+#define TLV_TYPE_TX_PAUSE (PROPRIETARY_TLV_BASE_ID + 0x94) // 0x0194
+/** MrvlIEtypes_SsIdParamSet_t */
+typedef MLAN_PACK_START struct _MrvlIEtypes_tx_pause_t
+{
+ /** Header */
+ MrvlIEtypesHeader_t header;
+ /** peer mac address */
+ t_u8 peermac[MLAN_MAC_ADDR_LENGTH];
+ /** Tx pause state, 1--pause, 0--free flowing */
+ t_u8 tx_pause;
+ /** total packets queued for the client */
+ t_u8 pkt_cnt;
+} MLAN_PACK_END MrvlIEtypes_tx_pause_t;
+
+/** HostCmd_CMD_MAC_MULTICAST_ADR */
+typedef MLAN_PACK_START struct _HostCmd_DS_MAC_MULTICAST_ADR
+{
+ /** Action */
+ t_u16 action;
+ /** Number of addresses */
+ t_u16 num_of_adrs;
+ /** List of MAC */
+ t_u8 mac_list[MLAN_MAC_ADDR_LENGTH * MLAN_MAX_MULTICAST_LIST_SIZE];
+} MLAN_PACK_END HostCmd_DS_MAC_MULTICAST_ADR;
+
+/** HostCmd_CMD_802_11_DEAUTHENTICATE */
+typedef MLAN_PACK_START struct _HostCmd_DS_802_11_DEAUTHENTICATE
+{
+ /** MAC address */
+ t_u8 mac_addr[MLAN_MAC_ADDR_LENGTH];
+ /** Deauthentication resaon code */
+ t_u16 reason_code;
+} MLAN_PACK_END HostCmd_DS_802_11_DEAUTHENTICATE;
+
+/** HostCmd_DS_802_11_ASSOCIATE */
+typedef MLAN_PACK_START struct _HostCmd_DS_802_11_ASSOCIATE
+{
+ /** Peer STA address */
+ t_u8 peer_sta_addr[MLAN_MAC_ADDR_LENGTH];
+ /** Capability information */
+ IEEEtypes_CapInfo_t cap_info;
+ /** Listen interval */
+ t_u16 listen_interval;
+ /** Beacon period */
+ t_u16 beacon_period;
+ /** DTIM period */
+ t_u8 dtim_period;
+
+ /**
+ * MrvlIEtypes_SsIdParamSet_t SsIdParamSet;
+ * MrvlIEtypes_PhyParamSet_t PhyParamSet;
+ * MrvlIEtypes_SsParamSet_t SsParamSet;
+ * MrvlIEtypes_RatesParamSet_t RatesParamSet;
+ */
+} MLAN_PACK_END HostCmd_DS_802_11_ASSOCIATE;
+
+/** HostCmd_CMD_802_11_ASSOCIATE response */
+typedef MLAN_PACK_START struct _HostCmd_DS_802_11_ASSOCIATE_RSP
+{
+ /** Association response structure */
+ IEEEtypes_AssocRsp_t assoc_rsp;
+} MLAN_PACK_END HostCmd_DS_802_11_ASSOCIATE_RSP;
+
+/** HostCmd_DS_802_11_AD_HOC_START*/
+typedef MLAN_PACK_START struct _HostCmd_DS_802_11_AD_HOC_START
+{
+ /** AdHoc SSID */
+ t_u8 ssid[MLAN_MAX_SSID_LENGTH];
+ /** BSS mode */
+ t_u8 bss_mode;
+ /** Beacon period */
+ t_u16 beacon_period;
+ /** DTIM period */
+ t_u8 dtim_period;
+ /** SS parameter set */
+ IEEEtypes_SsParamSet_t ss_param_set;
+ /** PHY parameter set */
+ IEEEtypes_PhyParamSet_t phy_param_set;
+ /** Reserved field */
+ t_u16 reserved1;
+ /** Capability information */
+ IEEEtypes_CapInfo_t cap;
+ /** Supported data rates */
+ t_u8 DataRate[HOSTCMD_SUPPORTED_RATES];
+} MLAN_PACK_END HostCmd_DS_802_11_AD_HOC_START;
+
+/** HostCmd_CMD_802_11_AD_HOC_START response */
+typedef MLAN_PACK_START struct _HostCmd_DS_802_11_AD_HOC_START_RESULT
+{
+ /** Padding */
+ t_u8 pad[3];
+ /** AdHoc BSSID */
+ t_u8 bssid[MLAN_MAC_ADDR_LENGTH];
+ /** Padding to sync with FW structure*/
+ t_u8 pad2[2];
+ /** Result */
+ t_u8 result;
+} MLAN_PACK_END HostCmd_DS_802_11_AD_HOC_START_RESULT;
+
+/** HostCmd_CMD_802_11_AD_HOC_START response */
+typedef MLAN_PACK_START struct _HostCmd_DS_802_11_AD_HOC_JOIN_RESULT
+{
+ /** Result */
+ t_u8 result;
+} MLAN_PACK_END HostCmd_DS_802_11_AD_HOC_JOIN_RESULT;
+
+/** AdHoc_BssDesc_t */
+typedef MLAN_PACK_START struct _AdHoc_BssDesc_t
+{
+ /** BSSID */
+ t_u8 bssid[MLAN_MAC_ADDR_LENGTH];
+ /** SSID */
+ t_u8 ssid[MLAN_MAX_SSID_LENGTH];
+ /** BSS mode */
+ t_u8 bss_mode;
+ /** Beacon period */
+ t_u16 beacon_period;
+ /** DTIM period */
+ t_u8 dtim_period;
+ /** Timestamp */
+ t_u8 time_stamp[8];
+ /** Local time */
+ t_u8 local_time[8];
+ /** PHY parameter set */
+ IEEEtypes_PhyParamSet_t phy_param_set;
+ /** SS parameter set */
+ IEEEtypes_SsParamSet_t ss_param_set;
+ /** Capability information */
+ IEEEtypes_CapInfo_t cap;
+ /** Supported data rates */
+ t_u8 data_rates[HOSTCMD_SUPPORTED_RATES];
+
+ /*
+ * DO NOT ADD ANY FIELDS TO THIS STRUCTURE.
+ * It is used in the Adhoc join command and will cause a
+ * binary layout mismatch with the firmware
+ */
+} MLAN_PACK_END AdHoc_BssDesc_t;
+
+/** HostCmd_DS_802_11_AD_HOC_JOIN */
+typedef MLAN_PACK_START struct _HostCmd_DS_802_11_AD_HOC_JOIN
+{
+ /** AdHoc BSS descriptor */
+ AdHoc_BssDesc_t bss_descriptor;
+ /** Reserved field */
+ t_u16 reserved1;
+ /** Reserved field */
+ t_u16 reserved2;
+} MLAN_PACK_END HostCmd_DS_802_11_AD_HOC_JOIN;
+
+/** Interrupt Raising Edge */
+#define INT_RASING_EDGE 0
+/** Interrupt Falling Edge */
+#define INT_FALLING_EDGE 1
+
+/** Delay 1 usec */
+#define DELAY_1_US 1
+
+typedef MLAN_PACK_START struct _HostCmd_DS_SDIO_GPIO_INT_CONFIG
+{
+ /** Action */
+ t_u16 action;
+ /** GPIO interrupt pin */
+ t_u16 gpio_pin;
+ /** GPIO interrupt edge, 1: failing edge; 0: raising edge */
+ t_u16 gpio_int_edge;
+ /** GPIO interrupt pulse widthin usec units */
+ t_u16 gpio_pulse_width;
+} MLAN_PACK_END HostCmd_DS_SDIO_GPIO_INT_CONFIG;
+
+typedef MLAN_PACK_START struct _HostCmd_DS_SDIO_PULL_CTRL
+{
+ /** Action */
+ t_u16 action;
+ /** The delay of pulling up in us */
+ t_u16 pull_up;
+ /** The delay of pulling down in us */
+ t_u16 pull_down;
+} MLAN_PACK_END HostCmd_DS_SDIO_PULL_CTRL;
+
+/** HostCmd_DS_802_11_GET_LOG */
+typedef MLAN_PACK_START struct _HostCmd_DS_802_11_GET_LOG
+{
+ /** Number of multicast transmitted frames */
+ t_u32 mcast_tx_frame;
+ /** Number of failures */
+ t_u32 failed;
+ /** Number of retries */
+ t_u32 retry;
+ /** Number of multiretries */
+ t_u32 multiretry;
+ /** Number of duplicate frames */
+ t_u32 frame_dup;
+ /** Number of RTS success */
+ t_u32 rts_success;
+ /** Number of RTS failure */
+ t_u32 rts_failure;
+ /** Number of acknowledgement failure */
+ t_u32 ack_failure;
+ /** Number of fragmented packets received */
+ t_u32 rx_frag;
+ /** Number of multicast frames received */
+ t_u32 mcast_rx_frame;
+ /** FCS error */
+ t_u32 fcs_error;
+ /** Number of transmitted frames */
+ t_u32 tx_frame;
+ /** Reserved field */
+ t_u32 reserved;
+ /** Number of WEP icv error for each key */
+ t_u32 wep_icv_err_cnt[4];
+} MLAN_PACK_END HostCmd_DS_802_11_GET_LOG;
+
+/**_HostCmd_TX_RATE_QUERY */
+typedef MLAN_PACK_START struct _HostCmd_TX_RATE_QUERY
+{
+ /** Tx rate */
+ t_u8 tx_rate;
+ /** Ht Info [Bit 0] RxRate format: LG=0, HT=1
+ * [Bit 1] HT Bandwidth: BW20 = 0, BW40 = 1
+ * [Bit 2] HT Guard Interval: LGI = 0, SGI = 1 */
+ t_u8 ht_info;
+} MLAN_PACK_END HostCmd_TX_RATE_QUERY;
+
+typedef MLAN_PACK_START struct _hs_config_param
+{
+ /** bit0=1: broadcast data
+ * bit1=1: unicast data
+ * bit2=1: mac events
+ * bit3=1: multicast data
+ */
+ t_u32 conditions;
+ /** GPIO pin or 0xff for interface */
+ t_u8 gpio;
+ /** gap in milliseconds or or 0xff for special setting when GPIO is used to wakeup host */
+ t_u8 gap;
+} MLAN_PACK_END hs_config_param;
+
+/** HS Action 0x0001 - Configure enhanced host sleep mode, 0x0002 - Activate enhanced host sleep mode */
+typedef enum _Host_Sleep_Action
+{
+ HS_CONFIGURE = 0x0001,
+ HS_ACTIVATE = 0x0002,
+} Host_Sleep_Action;
+
+/** Structure definition for activating enhanced hs */
+typedef MLAN_PACK_START struct __hs_activate_param
+{
+ /** response control 0x00 - response not needed, 0x01 - response needed */
+ t_u16 resp_ctrl;
+} MLAN_PACK_END hs_activate_param;
+
+/** HostCmd_DS_802_11_HS_CFG_ENH */
+typedef MLAN_PACK_START struct _HostCmd_DS_802_11_HS_CFG_ENH
+{
+ /** Action 0x0001 - Configure enhanced host sleep mode, 0x0002 - Activate enhanced host sleep mode */
+ t_u16 action;
+
+ union
+ {
+ /** Configure enhanced hs */
+ hs_config_param hs_config;
+ /** Activate enhanced hs */
+ hs_activate_param hs_activate;
+ } params;
+} MLAN_PACK_END HostCmd_DS_802_11_HS_CFG_ENH;
+
+/** SNMP_MIB_INDEX */
+typedef enum _SNMP_MIB_INDEX
+{
+ OpRateSet_i = 1,
+ DtimPeriod_i = 3,
+ RtsThresh_i = 5,
+ ShortRetryLim_i = 6,
+ LongRetryLim_i = 7,
+ FragThresh_i = 8,
+ Dot11D_i = 9,
+ Dot11H_i = 10,
+ WwsMode_i = 17,
+ Thermal_i = 34,
+} SNMP_MIB_INDEX;
+
+/** max SNMP buf size */
+#define MAX_SNMP_BUF_SIZE 128
+
+/** HostCmd_CMD_802_11_SNMP_MIB */
+typedef MLAN_PACK_START struct _HostCmd_DS_802_11_SNMP_MIB
+{
+ /** SNMP query type */
+ t_u16 query_type;
+ /** SNMP object ID */
+ t_u16 oid;
+ /** SNMP buffer size */
+ t_u16 buf_size;
+ /** Value */
+ t_u8 value[1];
+} MLAN_PACK_END HostCmd_DS_802_11_SNMP_MIB;
+
+/** Radio on */
+#define RADIO_ON 0x01
+/** Radio off */
+#define RADIO_OFF 0x00
+
+/** HostCmd_CMD_802_11_RADIO_CONTROL */
+typedef MLAN_PACK_START struct _HostCmd_DS_802_11_RADIO_CONTROL
+{
+ /** Action */
+ t_u16 action;
+ /** Control */
+ t_u16 control;
+} MLAN_PACK_END HostCmd_DS_802_11_RADIO_CONTROL;
+
+/** MrvlRateScope_t */
+typedef MLAN_PACK_START struct _MrvlRateScope_t
+{
+ /** Header Type */
+ t_u16 type;
+ /** Header Length */
+ t_u16 length;
+ /** Bitmap of HR/DSSS rates */
+ t_u16 hr_dsss_rate_bitmap;
+ /** Bitmap of OFDM rates */
+ t_u16 ofdm_rate_bitmap;
+ /** Bitmap of HT-MCSs allowed for initial rate */
+ t_u16 ht_mcs_rate_bitmap[8];
+} MLAN_PACK_END MrvlRateScope_t;
+
+/** MrvlRateDropControl_t */
+typedef MLAN_PACK_START struct _MrvlRateDropControl_t
+{
+ /** Header Length */
+ t_u16 length;
+ /** Rate Information */
+ t_u32 rate_info[1];
+} MLAN_PACK_END MrvlRateDropControl_t;
+
+/** MrvlRateDropPattern_t */
+typedef MLAN_PACK_START struct _MrvlRateDropPattern_t
+{
+ /** Header Type */
+ t_u16 type;
+ /** Header Length */
+ t_u16 length;
+ /** Rate Drop Mode */
+ t_u32 rate_drop_mode;
+ /* MrvlRateDropControl_t RateDropControl[0]; */
+} MLAN_PACK_END MrvlRateDropPattern_t;
+
+/** HostCmd_DS_TX_RATE_CFG */
+typedef MLAN_PACK_START struct _HostCmd_DS_TX_RATE_CFG
+{
+ /** Action */
+ t_u16 action;
+ /** Tx Rate Configuration Index */
+ t_u16 cfg_index;
+ /* MrvlRateScope_t RateScope; MrvlRateDropPattern_t RateDrop; */
+} MLAN_PACK_END HostCmd_DS_TX_RATE_CFG;
+
+/** Power_Group_t */
+typedef MLAN_PACK_START struct _Power_Group_t
+{
+ /** Modulation Class */
+ t_u8 modulation_class;
+ /** MCS Code or Legacy RateID */
+ t_u8 first_rate_code;
+ /** MCS Code or Legacy RateID */
+ t_u8 last_rate_code;
+ /** Power Adjustment Step */
+ t_s8 power_step;
+ /** Minimal Tx Power Level [dBm] */
+ t_s8 power_min;
+ /** Maximal Tx Power Level [dBm] */
+ t_s8 power_max;
+ /** 0: HTBW20, 1: HTBW40 */
+ t_u8 ht_bandwidth;
+ /** Reserved */
+ t_u8 reserved;
+} MLAN_PACK_END Power_Group_t;
+
+/** MrvlTypes_Power_Group_t */
+typedef MLAN_PACK_START struct _MrvlTypes_Power_Group_t
+{
+ /** Header Type */
+ t_u16 type;
+ /** Header Length */
+ t_u16 length;
+ /* Power_Group_t PowerGroups */
+} MLAN_PACK_END MrvlTypes_Power_Group_t;
+
+/** HostCmd_CMD_TXPWR_CFG */
+typedef MLAN_PACK_START struct _HostCmd_DS_TXPWR_CFG
+{
+ /** Action */
+ t_u16 action;
+ /** Power group configuration index */
+ t_u16 cfg_index;
+ /** Power group configuration mode */
+ t_u32 mode;
+ /* MrvlTypes_Power_Group_t PowerGrpCfg[0] */
+} MLAN_PACK_END HostCmd_DS_TXPWR_CFG;
+
+/** HostCmd_CMD_802_11_RF_TX_POWER */
+typedef MLAN_PACK_START struct _HostCmd_DS_802_11_RF_TX_POWER
+{
+ /** Action */
+ t_u16 action;
+ /** Current power level */
+ t_u16 current_level;
+ /** Maximum power */
+ t_u8 max_power;
+ /** Minimum power */
+ t_u8 min_power;
+} MLAN_PACK_END HostCmd_DS_802_11_RF_TX_POWER;
+
+/** Connection type infra */
+#define CONNECTION_TYPE_INFRA 0
+/** Connection type adhoc */
+#define CONNECTION_TYPE_ADHOC 1
+#ifdef WIFI_DIRECT_SUPPORT
+/** BSS Mode: WIFIDIRECT Client */
+#define BSS_MODE_WIFIDIRECT_CLIENT 0
+/** BSS Mode: WIFIDIRECT GO */
+#define BSS_MODE_WIFIDIRECT_GO 2
+#endif
+/** HostCmd_DS_SET_BSS_MODE */
+typedef MLAN_PACK_START struct _HostCmd_DS_SET_BSS_MODE
+{
+ /** connection type */
+ t_u8 con_type;
+} MLAN_PACK_END HostCmd_DS_SET_BSS_MODE;
+
+#ifdef WIFI_DIRECT_SUPPORT
+/** HostCmd_DS_REMAIN_ON_CHANNEL */
+typedef MLAN_PACK_START struct _HostCmd_DS_REMAIN_ON_CHANNEL
+{
+ /** Action 0-GET, 1-SET, 4 CLEAR*/
+ t_u16 action;
+ /** Not used set to zero */
+ t_u8 status;
+ /** Not used set to zero */
+ t_u8 reserved;
+ /** Band cfg */
+ t_u8 bandcfg;
+ /** channel */
+ t_u8 channel;
+ /** remain time: Unit ms*/
+ t_u32 remain_period;
+} MLAN_PACK_END HostCmd_DS_REMAIN_ON_CHANNEL;
+
+/** HostCmd_DS_WIFI_DIRECT_MODE */
+typedef MLAN_PACK_START struct _HostCmd_DS_WIFI_DIRECT_MODE
+{
+ /** Action 0-GET, 1-SET*/
+ t_u16 action;
+ /**0:disable 1:listen 2:GO 3:p2p client 4:find 5:stop find*/
+ t_u16 mode;
+} MLAN_PACK_END HostCmd_DS_WIFI_DIRECT_MODE;
+#endif
+
+#ifdef STA_SUPPORT
+
+/**
+ * @brief Structure used internally in the wlan driver to configure a scan.
+ *
+ * Sent to the command process module to configure the firmware
+ * scan command prepared by wlan_cmd_802_11_scan.
+ *
+ * @sa wlan_scan_networks
+ *
+ */
+typedef MLAN_PACK_START struct _wlan_scan_cmd_config
+{
+ /**
+ * BSS Type to be sent in the firmware command
+ *
+ * Field can be used to restrict the types of networks returned in the
+ * scan. Valid settings are:
+ *
+ * - MLAN_SCAN_MODE_BSS (infrastructure)
+ * - MLAN_SCAN_MODE_IBSS (adhoc)
+ * - MLAN_SCAN_MODE_ANY (unrestricted, adhoc and infrastructure)
+ */
+ t_u8 bss_mode;
+
+ /**
+ * Specific BSSID used to filter scan results in the firmware
+ */
+ t_u8 specific_bssid[MLAN_MAC_ADDR_LENGTH];
+
+ /**
+ * Length of TLVs sent in command starting at tlvBuffer
+ */
+ t_u32 tlv_buf_len;
+
+ /**
+ * SSID TLV(s) and ChanList TLVs to be sent in the firmware command
+ *
+ * TLV_TYPE_CHANLIST, MrvlIEtypes_ChanListParamSet_t
+ * TLV_TYPE_SSID, MrvlIEtypes_SsIdParamSet_t
+ */
+ t_u8 tlv_buf[1]; /* SSID TLV(s) and ChanList TLVs are stored
+ here */
+} MLAN_PACK_END wlan_scan_cmd_config;
+
+/**
+ * Sructure to retrieve the scan table
+ */
+typedef MLAN_PACK_START struct
+{
+ /**
+ * - Zero based scan entry to start retrieval in command request
+ * - Number of scans entries returned in command response
+ */
+ t_u32 scan_number;
+ /**
+ * Buffer marker for multiple wlan_ioctl_get_scan_table_entry structures.
+ * Each struct is padded to the nearest 32 bit boundary.
+ */
+ t_u8 scan_table_entry_buf[1];
+} MLAN_PACK_END wlan_get_scan_table_info;
+
+/** Generic structure defined for parsing WPA/RSN IEs for GTK/PTK OUIs */
+typedef MLAN_PACK_START struct
+{
+ /** Group key oui */
+ t_u8 GrpKeyOui[4];
+ /** Number of PTKs */
+ t_u8 PtkCnt[2];
+ /** Ptk body starts here */
+ t_u8 PtkBody[4];
+} MLAN_PACK_END IEBody;
+#endif /* STA_SUPPORT */
+
+/*
+ * This scan handle Country Information IE(802.11d compliant)
+ * Define data structure for HostCmd_CMD_802_11_SCAN
+ */
+/** HostCmd_DS_802_11_SCAN */
+typedef MLAN_PACK_START struct _HostCmd_DS_802_11_SCAN
+{
+ /** BSS mode */
+ t_u8 bss_mode;
+ /** BSSID */
+ t_u8 bssid[MLAN_MAC_ADDR_LENGTH];
+ /** TLV buffer */
+ t_u8 tlv_buffer[1];
+ /** MrvlIEtypes_SsIdParamSet_t SsIdParamSet;
+ * MrvlIEtypes_ChanListParamSet_t ChanListParamSet;
+ * MrvlIEtypes_RatesParamSet_t OpRateSet;
+ */
+} MLAN_PACK_END HostCmd_DS_802_11_SCAN;
+
+/*
+ * This scan handle Country Information IE(802.11d compliant)
+ * Define data structure for HostCmd_CMD_802_11_SCAN_EXT
+ */
+/** HostCmd_DS_802_11_SCAN_EXT */
+typedef MLAN_PACK_START struct _HostCmd_DS_802_11_SCAN_EXT
+{
+ /** Reserved */
+ t_u32 reserved;
+ /** TLV buffer */
+ t_u8 tlv_buffer[1];
+ /** MrvlIEtypes_Bssid_List_t BssIdList;
+ * MrvlIEtypes_SsIdParamSet_t SSIDParamSet;
+ * MrvlIEtypes_ChanListParamSet_t ChanListParamSet;
+ * MrvlIEtypes_RatesParamSet_t OpRateSet;
+ * MrvlIEtypes_NumProbes_t NumProbes;
+ * MrvlIEtypes_WildCardSsIdParamSet_t WildCardSSIDParamSet;
+ */
+} MLAN_PACK_END HostCmd_DS_802_11_SCAN_EXT;
+
+typedef MLAN_PACK_START struct _MrvlIEtypes_Bss_Scan_Rsp_t
+{
+ /** Header */
+ MrvlIEtypesHeader_t header;
+ /** BSSID of the BSS descriptor */
+ t_u8 bssid[MLAN_MAC_ADDR_LENGTH];
+ /** Beacon/Probe response buffer */
+ t_u8 frame_body[1];
+} MLAN_PACK_END MrvlIEtypes_Bss_Scan_Rsp_t;
+
+typedef MLAN_PACK_START struct _MrvlIEtypes_Bss_Scan_Info_t
+{
+ /** Header */
+ MrvlIEtypesHeader_t header;
+ /** RSSI for scan entry */
+ t_s16 rssi;
+ /** Channel ANPI */
+ t_s16 anpi;
+ /** Channel load (parts per 255) */
+ t_u8 cca_busy_fraction;
+ /** Band */
+ t_u8 band;
+ /** Channel */
+ t_u8 channel;
+ /** Reserved */
+ t_u8 reserved;
+ /** TSF data */
+ t_u64 tsf;
+} MLAN_PACK_END MrvlIEtypes_Bss_Scan_Info_t;
+
+/** HostCmd_DS_RX_MGMT_IND */
+typedef MLAN_PACK_START struct _HostCmd_DS_RX_MGMT_IND
+{
+ /** Action */
+ t_u16 action;
+ /** Mgmt frame subtype mask */
+ t_u32 mgmt_subtype_mask;
+} MLAN_PACK_END HostCmd_DS_RX_MGMT_IND;
+
+/** HostCmd_DS_802_11_SCAN_RSP */
+typedef MLAN_PACK_START struct _HostCmd_DS_802_11_SCAN_RSP
+{
+ /** Size of BSS descriptor */
+ t_u16 bss_descript_size;
+ /** Numner of sets */
+ t_u8 number_of_sets;
+ /** BSS descriptor and TLV buffer */
+ t_u8 bss_desc_and_tlv_buffer[1];
+} MLAN_PACK_END HostCmd_DS_802_11_SCAN_RSP;
+
+/** HostCmd_DS_802_11_BG_SCAN_CONFIG */
+typedef MLAN_PACK_START struct _HostCmd_DS_802_11_BG_SCAN_CONFIG
+{
+ /** action */
+ t_u16 action;
+ /** 0: disable, 1: enable */
+ t_u8 enable;
+ /** bss type */
+ t_u8 bss_type;
+ /** num of channel per scan */
+ t_u8 chan_per_scan;
+ /** reserved field */
+ t_u8 reserved;
+ /** reserved field */
+ t_u16 reserved1;
+ /** interval between consecutive scans */
+ t_u32 scan_interval;
+ /** reserved field */
+ t_u32 reserved2;
+ /** condition to trigger report to host */
+ t_u32 report_condition;
+ /** reserved field */
+ t_u16 reserved3;
+} MLAN_PACK_END HostCmd_DS_802_11_BG_SCAN_CONFIG;
+
+/** HostCmd_DS_802_11_BG_SCAN_QUERY */
+typedef MLAN_PACK_START struct _HostCmd_DS_802_11_BG_SCAN_QUERY
+{
+ /** Flush */
+ t_u8 flush;
+} MLAN_PACK_END HostCmd_DS_802_11_BG_SCAN_QUERY;
+
+/** HostCmd_DS_802_11_BG_SCAN_QUERY_RSP */
+typedef MLAN_PACK_START struct _HostCmd_DS_802_11_BG_SCAN_QUERY_RSP
+{
+ /** Report condition */
+ t_u32 report_condition;
+ /** Scan response */
+ HostCmd_DS_802_11_SCAN_RSP scan_resp;
+} MLAN_PACK_END HostCmd_DS_802_11_BG_SCAN_QUERY_RSP;
+
+/** MrvlIEtypes_DomainParamSet_t */
+typedef MLAN_PACK_START struct _MrvlIEtypes_DomainParamSet
+{
+ /** Header */
+ MrvlIEtypesHeader_t header;
+ /** Country code */
+ t_u8 country_code[COUNTRY_CODE_LEN];
+ /** Set of subbands */
+ IEEEtypes_SubbandSet_t sub_band[1];
+} MLAN_PACK_END MrvlIEtypes_DomainParamSet_t;
+
+/** HostCmd_DS_802_11D_DOMAIN_INFO */
+typedef MLAN_PACK_START struct _HostCmd_DS_802_11D_DOMAIN_INFO
+{
+ /** Action */
+ t_u16 action;
+ /** Domain parameter set */
+ MrvlIEtypes_DomainParamSet_t domain;
+} MLAN_PACK_END HostCmd_DS_802_11D_DOMAIN_INFO;
+
+/** HostCmd_DS_802_11D_DOMAIN_INFO_RSP */
+typedef MLAN_PACK_START struct _HostCmd_DS_802_11D_DOMAIN_INFO_RSP
+{
+ /** Action */
+ t_u16 action;
+ /** Domain parameter set */
+ MrvlIEtypes_DomainParamSet_t domain;
+} MLAN_PACK_END HostCmd_DS_802_11D_DOMAIN_INFO_RSP;
+
+/** HostCmd_DS_11N_ADDBA_REQ */
+typedef MLAN_PACK_START struct _HostCmd_DS_11N_ADDBA_REQ
+{
+ /** Result of the ADDBA Request Operation */
+ t_u8 add_req_result;
+ /** Peer MAC address */
+ t_u8 peer_mac_addr[MLAN_MAC_ADDR_LENGTH];
+ /** Dialog Token */
+ t_u8 dialog_token;
+ /** Block Ack Parameter Set */
+ t_u16 block_ack_param_set;
+ /** Block Act Timeout Value */
+ t_u16 block_ack_tmo;
+ /** Starting Sequence Number */
+ t_u16 ssn;
+} MLAN_PACK_END HostCmd_DS_11N_ADDBA_REQ;
+
+/** HostCmd_DS_11N_ADDBA_RSP */
+typedef MLAN_PACK_START struct _HostCmd_DS_11N_ADDBA_RSP
+{
+ /** Result of the ADDBA Response Operation */
+ t_u8 add_rsp_result;
+ /** Peer MAC address */
+ t_u8 peer_mac_addr[MLAN_MAC_ADDR_LENGTH];
+ /** Dialog Token */
+ t_u8 dialog_token;
+ /** Status Code */
+ t_u16 status_code;
+ /** Block Ack Parameter Set */
+ t_u16 block_ack_param_set;
+ /** Block Act Timeout Value */
+ t_u16 block_ack_tmo;
+ /** Starting Sequence Number */
+ t_u16 ssn;
+} MLAN_PACK_END HostCmd_DS_11N_ADDBA_RSP;
+
+/** HostCmd_DS_11N_DELBA */
+typedef MLAN_PACK_START struct _HostCmd_DS_11N_DELBA
+{
+ /** Result of the ADDBA Request Operation */
+ t_u8 del_result;
+ /** Peer MAC address */
+ t_u8 peer_mac_addr[MLAN_MAC_ADDR_LENGTH];
+ /** Delete Block Ack Parameter Set */
+ t_u16 del_ba_param_set;
+ /** Reason Code sent for DELBA */
+ t_u16 reason_code;
+ /** Reserved */
+ t_u8 reserved;
+} MLAN_PACK_END HostCmd_DS_11N_DELBA;
+
+/** HostCmd_DS_11N_BATIMEOUT */
+typedef MLAN_PACK_START struct _HostCmd_DS_11N_BATIMEOUT
+{
+ /** TID */
+ t_u8 tid;
+ /** Peer MAC address */
+ t_u8 peer_mac_addr[MLAN_MAC_ADDR_LENGTH];
+ /** Delete Block Ack Parameter Set */
+ t_u8 origninator;
+} MLAN_PACK_END HostCmd_DS_11N_BATIMEOUT;
+
+/** HostCmd_DS_11N_CFG */
+typedef MLAN_PACK_START struct _HostCmd_DS_11N_CFG
+{
+ /** Action */
+ t_u16 action;
+ /** HTTxCap */
+ t_u16 ht_tx_cap;
+ /** HTTxInfo */
+ t_u16 ht_tx_info;
+ /** Misc configuration */
+ t_u16 misc_config;
+} MLAN_PACK_END HostCmd_DS_11N_CFG;
+
+/** HostCmd_DS_TXBUF_CFG*/
+typedef MLAN_PACK_START struct _HostCmd_DS_TXBUF_CFG
+{
+ /** Action */
+ t_u16 action;
+ /** Buffer Size */
+ t_u16 buff_size;
+ /** End Port_for Multiport */
+ t_u16 mp_end_port;
+ /** Reserved */
+ t_u16 reserved3;
+} MLAN_PACK_END HostCmd_DS_TXBUF_CFG;
+
+/** HostCmd_DS_AMSDU_AGGR_CTRL */
+typedef MLAN_PACK_START struct _HostCmd_DS_AMSDU_AGGR_CTRL
+{
+ /** Action */
+ t_u16 action;
+ /** Enable */
+ t_u16 enable;
+ /** Get the current Buffer Size valid */
+ t_u16 curr_buf_size;
+} MLAN_PACK_END HostCmd_DS_AMSDU_AGGR_CTRL;
+
+/** HostCmd_DS_ECL_SYSTEM_CLOCK_CONFIG */
+typedef MLAN_PACK_START struct _HostCmd_DS_ECL_SYSTEM_CLOCK_CONFIG
+{
+ /** Action */
+ t_u16 action;
+ /** Current system clock */
+ t_u16 cur_sys_clk;
+ /** Clock type */
+ t_u16 sys_clk_type;
+ /** Length of clocks */
+ t_u16 sys_clk_len;
+ /** System clocks */
+ t_u16 sys_clk[16];
+} MLAN_PACK_END HostCmd_DS_ECL_SYSTEM_CLOCK_CONFIG;
+
+/** MrvlIEtypes_WmmParamSet_t */
+typedef MLAN_PACK_START struct _MrvlIEtypes_WmmParamSet_t
+{
+ /** Header */
+ MrvlIEtypesHeader_t header;
+ /** WMM IE */
+ t_u8 wmm_ie[1];
+} MLAN_PACK_END MrvlIEtypes_WmmParamSet_t;
+
+/** MrvlIEtypes_WmmQueueStatus_t */
+typedef MLAN_PACK_START struct
+{
+ /** Header */
+ MrvlIEtypesHeader_t header;
+ /** Queue index */
+ t_u8 queue_index;
+ /** Disabled flag */
+ t_u8 disabled;
+ /** Medium time allocation in 32us units*/
+ t_u16 medium_time;
+ /** Flow required flag */
+ t_u8 flow_required;
+ /** Flow created flag */
+ t_u8 flow_created;
+ /** Reserved */
+ t_u32 reserved;
+} MLAN_PACK_END MrvlIEtypes_WmmQueueStatus_t;
+
+/** Size of a TSPEC. Used to allocate necessary buffer space in commands */
+#define WMM_TSPEC_SIZE 63
+
+/** Maximum number of AC QOS queues available in the driver/firmware */
+#define MAX_AC_QUEUES 4
+
+/** Extra IE bytes allocated in messages for appended IEs after a TSPEC */
+#define WMM_ADDTS_EXTRA_IE_BYTES 256
+
+/** Extra TLV bytes allocated in messages for configuring WMM Queues */
+#define WMM_QUEUE_CONFIG_EXTRA_TLV_BYTES 64
+
+/** Number of bins in the histogram for the HostCmd_DS_WMM_QUEUE_STATS */
+#define WMM_STATS_PKTS_HIST_BINS 7
+
+/**
+ * @brief Firmware command structure to retrieve the firmware WMM status.
+ *
+ * Used to retrieve the status of each WMM AC Queue in TLV
+ * format (MrvlIEtypes_WmmQueueStatus_t) as well as the current WMM
+ * parameter IE advertised by the AP.
+ *
+ * Used in response to a EVENT_WMM_STATUS_CHANGE event signaling
+ * a QOS change on one of the ACs or a change in the WMM Parameter in
+ * the Beacon.
+ *
+ * TLV based command, byte arrays used for max sizing purpose. There are no
+ * arguments sent in the command, the TLVs are returned by the firmware.
+ */
+typedef MLAN_PACK_START struct
+{
+ /** Queue status TLV */
+ t_u8 queue_status_tlv[sizeof(MrvlIEtypes_WmmQueueStatus_t)
+ * MAX_AC_QUEUES];
+ /** WMM parameter TLV */
+ t_u8 wmm_param_tlv[sizeof(IEEEtypes_WmmParameter_t) + 2];
+}
+MLAN_PACK_END HostCmd_DS_WMM_GET_STATUS;
+
+/**
+ * @brief Command structure for the HostCmd_CMD_WMM_ADDTS_REQ firmware command
+ */
+typedef MLAN_PACK_START struct
+{
+ mlan_cmd_result_e command_result; /**< Command result */
+ t_u32 timeout_ms; /**< Timeout value in milliseconds */
+ t_u8 dialog_token; /**< Dialog token */
+ t_u8 ieee_status_code; /**< IEEE status code */
+ t_u8 tspec_data[WMM_TSPEC_SIZE]; /**< TSPEC data */
+ t_u8 addts_extra_ie_buf[WMM_ADDTS_EXTRA_IE_BYTES]; /**< Extra IE buffer */
+} MLAN_PACK_END HostCmd_DS_WMM_ADDTS_REQ;
+
+/**
+ * @brief Command structure for the HostCmd_CMD_WMM_DELTS_REQ firmware command
+ */
+typedef MLAN_PACK_START struct
+{
+ mlan_cmd_result_e command_result; /**< Command result */
+ t_u8 dialog_token; /**< Dialog token */
+ t_u8 ieee_reason_code; /**< IEEE reason code */
+ t_u8 tspec_data[WMM_TSPEC_SIZE]; /**< TSPEC data */
+} MLAN_PACK_END HostCmd_DS_WMM_DELTS_REQ;
+
+/**
+ * @brief Command structure for the HostCmd_CMD_WMM_QUEUE_CONFIG firmware cmd
+ *
+ * Set/Get/Default the Queue parameters for a specific AC in the firmware.
+ */
+typedef MLAN_PACK_START struct
+{
+ mlan_wmm_queue_config_action_e action; /**< Set, Get, or Default */
+ mlan_wmm_ac_e access_category; /**< WMM_AC_BK(0) to WMM_AC_VO(3) */
+ /** @brief MSDU lifetime expiry per 802.11e
+ *
+ * - Ignored if 0 on a set command
+ * - Set to the 802.11e specified 500 TUs when defaulted
+ */
+ t_u16 msdu_lifetime_expiry;
+ t_u8 tlv_buffer[WMM_QUEUE_CONFIG_EXTRA_TLV_BYTES]; /**< Not supported */
+} MLAN_PACK_END HostCmd_DS_WMM_QUEUE_CONFIG;
+
+/**
+ * @brief Command structure for the HostCmd_CMD_WMM_QUEUE_STATS firmware cmd
+ *
+ * Turn statistical collection on/off for a given AC or retrieve the
+ * accumulated stats for an AC and clear them in the firmware.
+ */
+typedef MLAN_PACK_START struct
+{
+ mlan_wmm_queue_stats_action_e action; /**< Start, Stop, or Get */
+#ifdef BIG_ENDIAN_SUPPORT
+ t_u8 select_bin:7; /**< WMM_AC_BK(0) to WMM_AC_VO(3), or TID */
+ t_u8 select_is_userpri:1; /**< Set if select_bin is UP, Clear for AC */
+#else
+ t_u8 select_is_userpri:1; /**< Set if select_bin is UP, Clear for AC */
+ t_u8 select_bin:7; /**< WMM_AC_BK(0) to WMM_AC_VO(3), or TID */
+#endif
+ t_u16 pkt_count; /**< Number of successful packets transmitted */
+ t_u16 pkt_loss; /**< Packets lost; not included in pktCount */
+ t_u32 avg_queue_delay; /**< Average Queue delay in microsec */
+ t_u32 avg_tx_delay; /**< Average Transmission delay in microsec */
+ t_u16 used_time; /**< Calc used time - units of 32 microsec */
+ t_u16 policed_time; /**< Calc policed time - units of 32 microsec */
+ /** @brief Queue Delay Histogram; number of packets per queue delay range
+ *
+ * [0] - 0ms <= delay < 5ms
+ * [1] - 5ms <= delay < 10ms
+ * [2] - 10ms <= delay < 20ms
+ * [3] - 20ms <= delay < 30ms
+ * [4] - 30ms <= delay < 40ms
+ * [5] - 40ms <= delay < 50ms
+ * [6] - 50ms <= delay < msduLifetime (TUs)
+ */
+ t_u16 delay_histogram[WMM_STATS_PKTS_HIST_BINS];
+ /** Reserved */
+ t_u16 reserved_1;
+} MLAN_PACK_END HostCmd_DS_WMM_QUEUE_STATS;
+
+/**
+ * @brief Command structure for the HostCmd_CMD_WMM_TS_STATUS firmware cmd
+ *
+ * Query the firmware to get the status of the WMM Traffic Streams
+ */
+typedef MLAN_PACK_START struct
+{
+ /** TSID: Range: 0->7 */
+ t_u8 tid;
+ /** TSID specified is valid */
+ t_u8 valid;
+ /** AC TSID is active on */
+ t_u8 access_category;
+ /** UP specified for the TSID */
+ t_u8 user_priority;
+ /** Power save mode for TSID: 0 (legacy), 1 (UAPSD) */
+ t_u8 psb;
+ /** Uplink(1), Downlink(2), Bidirectional(3) */
+ t_u8 flow_dir;
+ /** Medium time granted for the TSID */
+ t_u16 medium_time;
+} MLAN_PACK_END HostCmd_DS_WMM_TS_STATUS;
+
+/** Firmware status for a specific AC */
+typedef MLAN_PACK_START struct
+{
+ /** Disabled flag */
+ t_u8 disabled;
+ /** Flow required flag */
+ t_u8 flow_required;
+ /** Flow created flag */
+ t_u8 flow_created;
+} MLAN_PACK_END WmmAcStatus_t;
+
+/** Local Power Capability */
+typedef MLAN_PACK_START struct _MrvlIEtypes_PowerCapability_t
+{
+ /** Header */
+ MrvlIEtypesHeader_t header;
+ /** Minmum power */
+ t_s8 min_power;
+ /** Maximum power */
+ t_s8 max_power;
+} MLAN_PACK_END MrvlIEtypes_PowerCapability_t;
+
+/** HT Capabilities element */
+typedef MLAN_PACK_START struct _MrvlIETypes_HTCap_t
+{
+ /** Header */
+ MrvlIEtypesHeader_t header;
+
+ /** HTCap struct */
+ HTCap_t ht_cap;
+} MLAN_PACK_END MrvlIETypes_HTCap_t;
+
+/** HT Information element */
+typedef MLAN_PACK_START struct _MrvlIETypes_HTInfo_t
+{
+ /** Header */
+ MrvlIEtypesHeader_t header;
+
+ /** HTInfo struct */
+ HTInfo_t ht_info;
+} MLAN_PACK_END MrvlIETypes_HTInfo_t;
+
+/** 20/40 BSS Coexistence element */
+typedef MLAN_PACK_START struct _MrvlIETypes_2040BSSCo_t
+{
+ /** Header */
+ MrvlIEtypesHeader_t header;
+
+ /** BSSCo2040_t struct */
+ BSSCo2040_t bss_co_2040;
+} MLAN_PACK_END MrvlIETypes_2040BSSCo_t;
+
+/** Extended Capabilities element */
+typedef MLAN_PACK_START struct _MrvlIETypes_ExtCap_t
+{
+ /** Header */
+ MrvlIEtypesHeader_t header;
+
+ /** ExtCap_t struct */
+ ExtCap_t ext_cap;
+} MLAN_PACK_END MrvlIETypes_ExtCap_t;
+
+/** Overlapping BSS Scan Parameters element */
+typedef MLAN_PACK_START struct _MrvlIETypes_OverlapBSSScanParam_t
+{
+ /** Header */
+ MrvlIEtypesHeader_t header;
+
+ /** OBSSScanParam_t struct */
+ OBSSScanParam_t obss_scan_param;
+} MLAN_PACK_END MrvlIETypes_OverlapBSSScanParam_t;
+
+/** Set of MCS values that STA desires to use within the BSS */
+typedef MLAN_PACK_START struct _MrvlIETypes_HTOperationalMCSSet_t
+{
+ /** Header */
+ MrvlIEtypesHeader_t header;
+
+ /** Bitmap indicating MCSs that STA desires to use within the BSS */
+ t_u8 ht_operational_mcs_bitmap[16];
+} MLAN_PACK_END MrvlIETypes_HTOperationalMCSSet_t;
+
+/** bf global args */
+typedef struct MLAN_PACK_START _bf_global_cfg_args
+{
+ /** Global enable/disable bf */
+ t_u8 bf_enbl;
+ /** Global enable/disable sounding */
+ t_u8 sounding_enbl;
+ /** FB Type */
+ t_u8 fb_type;
+ /** SNR Threshold */
+ t_u8 snr_threshold;
+ /** Sounding interval */
+ t_u16 sounding_interval;
+ /** BF mode */
+ t_u8 bf_mode;
+ /** Reserved */
+ t_u8 reserved;
+} MLAN_PACK_END bf_global_cfg_args;
+
+/** bf_trigger_sound_args_t */
+typedef MLAN_PACK_START struct _bf_trigger_sound_args_t
+{
+ /** Peer MAC address */
+ t_u8 peer_mac[MLAN_MAC_ADDR_LENGTH];
+ /** Status */
+ t_u8 status;
+} MLAN_PACK_END bf_trigger_sound_args_t;
+
+/** bf periodicity args */
+typedef MLAN_PACK_START struct _bf_periodicity_args
+{
+ /** Peer MAC address */
+ t_u8 peer_mac[MLAN_MAC_ADDR_LENGTH];
+ /** Current Tx BF Interval */
+ t_u16 interval;
+ /** Status */
+ t_u8 status;
+} MLAN_PACK_END bf_periodicity_args;
+
+/** bf peer configuration args */
+typedef struct MLAN_PACK_START _bf_peer_args
+{
+ /** Peer MAC address */
+ t_u8 peer_mac[MLAN_MAC_ADDR_LENGTH];
+ /** Reserved */
+ t_u16 reserved;
+ /** Enable/Disable Beamforming */
+ t_u8 bf_enbl;
+ /** Enable/Disable sounding */
+ t_u8 sounding_enbl;
+ /** FB Type */
+ t_u8 fb_type;
+} MLAN_PACK_END bf_peer_args;
+
+/** bf_snr_thr_t */
+typedef MLAN_PACK_START struct _bf_snr_thr_t
+{
+ /** Peer MAC address */
+ t_u8 peer_mac[MLAN_MAC_ADDR_LENGTH];
+ /** SNR */
+ t_u8 snr;
+} MLAN_PACK_END bf_snr_thr_t;
+
+/** HostCmd_DS_TX_BF_CFG */
+typedef MLAN_PACK_START struct _HostCmd_DS_TX_BF_CFG
+{
+ /* Beamforming action */
+ t_u16 bf_action;
+ /* action - SET/GET */
+ t_u16 action;
+
+ MLAN_PACK_START union
+ {
+ bf_global_cfg_args bf_global_cfg;
+ bf_trigger_sound_args_t bf_sound_args;
+ bf_periodicity_args bf_periodicity;
+ bf_peer_args tx_bf_peer;
+ bf_snr_thr_t bf_snr;
+ } MLAN_PACK_END body;
+} MLAN_PACK_END HostCmd_DS_TX_BF_CFG;
+
+#ifdef WIFI_DIRECT_SUPPORT
+/** MrvlIEtypes_psk_t */
+typedef MLAN_PACK_START struct _MrvlIEtypes_psk_t
+{
+ /** Header */
+ MrvlIEtypesHeader_t header;
+ /** PSK */
+ t_u8 psk[MLAN_MAX_KEY_LENGTH];
+} MLAN_PACK_END MrvlIEtypes_psk_t;
+#endif /* WIFI_DIRECT_SUPPORT */
+
+/** MrvlIEtypes_PMK_t */
+typedef MLAN_PACK_START struct _MrvlIEtypes_PMK_t
+{
+ /** Header */
+ MrvlIEtypesHeader_t header;
+ /** PMK */
+ t_u8 pmk[1];
+} MLAN_PACK_END MrvlIEtypes_PMK_t;
+
+/** MrvlIEtypes_Passphrase_t */
+typedef MLAN_PACK_START struct _MrvlIEtypes_Passphrase_t
+{
+ /** Header */
+ MrvlIEtypesHeader_t header;
+ /** Passphrase */
+ char passphrase[1];
+} MLAN_PACK_END MrvlIEtypes_Passphrase_t;
+
+/* unicastCipher -
+ * Bit 0 : RFU
+ * Bit 1 : RFU
+ * Bit 2 : TKIP
+ * Bit 3 : AES CCKM
+ * Bit 2-7 : RFU
+ * multicastCipher -
+ * Bit 0 : WEP40
+ * Bit 1 : WEP104
+ * Bit 2 : TKIP
+ * Bit 3 : AES
+ * Bit 4-7 : Reserved for now
+ */
+/** MrvlIEtypes_Cipher_t */
+typedef MLAN_PACK_START struct _MrvlIEtypes_Cipher_t
+{
+ /** Header */
+ MrvlIEtypesHeader_t header;
+ /** PairCipher */
+ t_u8 pair_cipher;
+ /** GroupCipher */
+ t_u8 group_cipher;
+} MLAN_PACK_END MrvlIEtypes_Cipher_t;
+
+/* rsnMode -
+ * Bit 0 : No RSN
+ * Bit 1-2 : RFU
+ * Bit 3 : WPA
+ * Bit 4 : WPA-NONE
+ * Bit 5 : WPA2
+ * Bit 6 : AES CCKM
+ * Bit 7-15 : RFU
+ */
+/** MrvlIEtypes_EncrProto_t */
+typedef MLAN_PACK_START struct _MrvlIEtypes_EncrProto_t
+{
+ /** Header */
+ MrvlIEtypesHeader_t header;
+ /** EncrProto */
+ t_u16 rsn_mode;
+} MLAN_PACK_END MrvlIEtypes_EncrProto_t;
+
+/** MrvlIEtypes_Bssid_t */
+typedef MLAN_PACK_START struct _MrvlIEtypes_Bssid_t
+{
+ /** Header */
+ MrvlIEtypesHeader_t header;
+ /** Bssid */
+ t_u8 bssid[MLAN_MAC_ADDR_LENGTH];
+} MLAN_PACK_END MrvlIEtypes_Bssid_t;
+
+/*
+ * This struct will handle GET,SET,CLEAR function for embedded
+ * supplicant.
+ * Define data structure for HostCmd_CMD_802_11_SUPPLICANT_PMK
+ */
+/** HostCmd_DS_802_11_SUPPLICANT_PMK */
+typedef MLAN_PACK_START struct _HostCmd_DS_802_11_SUPPLICANT_PMK
+{
+ /** CMD Action GET/SET/CLEAR */
+ t_u16 action;
+ /** CacheResult initialized to 0 */
+ t_u16 cache_result;
+ /** TLV Buffer */
+ t_u8 tlv_buffer[1];
+ /** MrvlIEtypes_SsidParamSet_t SsidParamSet;
+ * MrvlIEtypes_PMK_t Pmk;
+ * MrvlIEtypes_Passphrase_t Passphrase;
+ * MrvlIEtypes_Bssid_t Bssid;
+ **/
+} MLAN_PACK_END HostCmd_DS_802_11_SUPPLICANT_PMK;
+
+/*
+ * This struct will GET the Supplicant supported bitmaps
+ * The GET_CURRENT action will get the network profile used
+ * for the current assocation.
+ * Define data structure for HostCmd_CMD_802_11_SUPPLICANT_PROFILE
+ */
+typedef MLAN_PACK_START struct _HostCmd_DS_802_11_SUPPLICANT_PROFILE
+{
+ /** GET/SET/GET_CURRENT */
+ t_u16 action;
+ /** Reserved */
+ t_u16 reserved;
+ /** TLVBuffer */
+ t_u8 tlv_buf[1];
+ /* MrvlIEtypes_EncrProto_t */
+} MLAN_PACK_END HostCmd_DS_802_11_SUPPLICANT_PROFILE;
+
+/** HostCmd_CMD_802_11_RF_CHANNEL */
+typedef MLAN_PACK_START struct _HostCmd_DS_802_11_RF_CHANNEL
+{
+ /** Action */
+ t_u16 action;
+ /** Current channel */
+ t_u16 current_channel;
+ /** RF type */
+ t_u16 rf_type;
+ /** Reserved field */
+ t_u16 reserved;
+#ifdef STA_SUPPORT
+ /** Reserved */
+ t_u8 reserved_1[32];
+#else /* STA_SUPPORT */
+ /** List of channels */
+ t_u8 channel_list[32];
+#endif /* !STA_SUPPORT */
+} MLAN_PACK_END HostCmd_DS_802_11_RF_CHANNEL;
+
+/** HostCmd_DS_VERSION_EXT */
+typedef MLAN_PACK_START struct _HostCmd_DS_VERSION_EXT
+{
+ /** Selected version string */
+ t_u8 version_str_sel;
+ /** Version string */
+ char version_str[128];
+} MLAN_PACK_END HostCmd_DS_VERSION_EXT;
+
+/** HostCmd_CMD_802_11_RF_ANTENNA */
+typedef MLAN_PACK_START struct _HostCmd_DS_802_11_RF_ANTENNA
+{
+ /** Action for Tx antenna */
+ t_u16 action_tx;
+ /** Tx antenna mode Bit0:1, Bit1:2, Bit0-1:1+2, 0xffff: diversity */
+ t_u16 tx_antenna_mode;
+ /** Action for Rx antenna */
+ t_u16 action_rx;
+ /** Rx antenna mode Bit0:1, Bit1:2, Bit0-1:1+2, 0xffff: diversity */
+ t_u16 rx_antenna_mode;
+} MLAN_PACK_END HostCmd_DS_802_11_RF_ANTENNA;
+
+/** HostCmd_DS_802_11_IBSS_STATUS */
+typedef MLAN_PACK_START struct _HostCmd_DS_802_11_IBSS_STATUS
+{
+ /** Action */
+ t_u16 action;
+ /** Enable */
+ t_u16 enable;
+ /** BSSID */
+ t_u8 bssid[MLAN_MAC_ADDR_LENGTH];
+ /** Beacon interval */
+ t_u16 beacon_interval;
+ /** ATIM window interval */
+ t_u16 atim_window;
+ /** User G rate protection */
+ t_u16 use_g_rate_protect;
+} MLAN_PACK_END HostCmd_DS_802_11_IBSS_STATUS;
+
+/** HostCmd_DS_MGMT_IE_LIST_CFG */
+typedef MLAN_PACK_START struct _HostCmd_DS_MGMT_IE_LIST
+{
+ /** Action */
+ t_u16 action;
+ /** Get/Set mgmt IE */
+ mlan_ds_misc_custom_ie ds_mgmt_ie;
+} MLAN_PACK_END HostCmd_DS_MGMT_IE_LIST_CFG;
+
+/** HostCmd_CMD_MAC_REG_ACCESS */
+typedef MLAN_PACK_START struct _HostCmd_DS_MAC_REG_ACCESS
+{
+ /** Action */
+ t_u16 action;
+ /** MAC register offset */
+ t_u16 offset;
+ /** MAC register value */
+ t_u32 value;
+} MLAN_PACK_END HostCmd_DS_MAC_REG_ACCESS;
+
+/** HostCmd_CMD_BBP_REG_ACCESS */
+typedef MLAN_PACK_START struct _HostCmd_DS_BBP_REG_ACCESS
+{
+ /** Acion */
+ t_u16 action;
+ /** BBP register offset */
+ t_u16 offset;
+ /** BBP register value */
+ t_u8 value;
+ /** Reserved field */
+ t_u8 reserved[3];
+} MLAN_PACK_END HostCmd_DS_BBP_REG_ACCESS;
+
+/** HostCmd_CMD_RF_REG_ACCESS */
+typedef MLAN_PACK_START struct _HostCmd_DS_RF_REG_ACCESS
+{
+ /** Action */
+ t_u16 action;
+ /** RF register offset */
+ t_u16 offset;
+ /** RF register value */
+ t_u8 value;
+ /** Reserved field */
+ t_u8 reserved[3];
+} MLAN_PACK_END HostCmd_DS_RF_REG_ACCESS;
+
+/** HostCmd_DS_802_11_EEPROM_ACCESS */
+typedef MLAN_PACK_START struct _HostCmd_DS_802_11_EEPROM_ACCESS
+{
+ /** Action */
+ t_u16 action;
+
+ /** multiple 4 */
+ t_u16 offset;
+ /** Number of bytes */
+ t_u16 byte_count;
+ /** Value */
+ t_u8 value;
+} MLAN_PACK_END HostCmd_DS_802_11_EEPROM_ACCESS;
+
+/** HostCmd_DS_MEM_ACCESS */
+typedef MLAN_PACK_START struct _HostCmd_DS_MEM_ACCESS
+{
+ /** Action */
+ t_u16 action;
+ /** Reserved field */
+ t_u16 reserved;
+ /** Address */
+ t_u32 addr;
+ /** Value */
+ t_u32 value;
+} MLAN_PACK_END HostCmd_DS_MEM_ACCESS;
+
+/** HostCmd_DS_SUBSCRIBE_EVENT */
+typedef MLAN_PACK_START struct _HostCmd_DS_SUBSCRIBE_EVENT
+{
+ /** Action */
+ t_u16 action;
+ /** Bitmap of subscribed events */
+ t_u16 event_bitmap;
+} MLAN_PACK_END HostCmd_DS_SUBSCRIBE_EVENT;
+
+/** HostCmd_DS_INACTIVITY_TIMEOUT_EXT */
+typedef MLAN_PACK_START struct _HostCmd_DS_INACTIVITY_TIMEOUT_EXT
+{
+ /** ACT_GET/ACT_SET */
+ t_u16 action;
+ /** uS, 0 means 1000uS(1ms) */
+ t_u16 timeout_unit;
+ /** Inactivity timeout for unicast data */
+ t_u16 unicast_timeout;
+ /** Inactivity timeout for multicast data */
+ t_u16 mcast_timeout;
+ /** Timeout for additional RX traffic after Null PM1 packet exchange */
+ t_u16 ps_entry_timeout;
+ /** Reserved to further expansion */
+ t_u16 reserved;
+} MLAN_PACK_END HostCmd_DS_INACTIVITY_TIMEOUT_EXT;
+
+/** TLV type : STA Mac address */
+#define TLV_TYPE_STA_MAC_ADDRESS (PROPRIETARY_TLV_BASE_ID + 0x20) // 0x0120
+
+/** MrvlIEtypes_MacAddr_t */
+typedef MLAN_PACK_START struct _MrvlIEtypes_MacAddr_t
+{
+ /** Header */
+ MrvlIEtypesHeader_t header;
+ /** mac address */
+ t_u8 mac[MLAN_MAC_ADDR_LENGTH];
+} MLAN_PACK_END MrvlIEtypes_MacAddr_t;
+
+/** Assoc Request */
+#define SUBTYPE_ASSOC_REQUEST 0
+/** ReAssoc Request */
+#define SUBTYPE_REASSOC_REQUEST 2
+/** Probe Resp */
+#define SUBTYPE_PROBE_RESP 5
+/** Disassoc Request */
+#define SUBTYPE_DISASSOC 10
+/** Auth Request */
+#define SUBTYPE_AUTH 11
+/** Deauth Request */
+#define SUBTYPE_DEAUTH 12
+/** Action frame */
+#define SUBTYPE_ACTION 13
+
+#ifdef UAP_SUPPORT
+/** TLV type : AP Channel band Config */
+#define TLV_TYPE_UAP_CHAN_BAND_CONFIG (PROPRIETARY_TLV_BASE_ID + 0x2a) // 0x012a
+/** TLV type : AP Mac address */
+#define TLV_TYPE_UAP_MAC_ADDRESS (PROPRIETARY_TLV_BASE_ID + 0x2b) // 0x012b
+/** TLV type : AP Beacon period */
+#define TLV_TYPE_UAP_BEACON_PERIOD (PROPRIETARY_TLV_BASE_ID + 0x2c) // 0x012c
+/** TLV type : AP DTIM period */
+#define TLV_TYPE_UAP_DTIM_PERIOD (PROPRIETARY_TLV_BASE_ID + 0x2d) // 0x012d
+/** TLV type : AP Tx power */
+#define TLV_TYPE_UAP_TX_POWER (PROPRIETARY_TLV_BASE_ID + 0x2f) // 0x012f
+/** TLV type : AP SSID broadcast control */
+#define TLV_TYPE_UAP_BCAST_SSID_CTL (PROPRIETARY_TLV_BASE_ID + 0x30) // 0x0130
+/** TLV type : AP Preamble control */
+#define TLV_TYPE_UAP_PREAMBLE_CTL (PROPRIETARY_TLV_BASE_ID + 0x31) // 0x0131
+/** TLV type : AP Antenna control */
+#define TLV_TYPE_UAP_ANTENNA_CTL (PROPRIETARY_TLV_BASE_ID + 0x32) // 0x0132
+/** TLV type : AP RTS threshold */
+#define TLV_TYPE_UAP_RTS_THRESHOLD (PROPRIETARY_TLV_BASE_ID + 0x33) // 0x0133
+/** TLV type : AP Tx data rate */
+#define TLV_TYPE_UAP_TX_DATA_RATE (PROPRIETARY_TLV_BASE_ID + 0x35) // 0x0135
+/** TLV type: AP Packet forwarding control */
+#define TLV_TYPE_UAP_PKT_FWD_CTL (PROPRIETARY_TLV_BASE_ID + 0x36) // 0x0136
+/** TLV type: STA information */
+#define TLV_TYPE_UAP_STA_INFO (PROPRIETARY_TLV_BASE_ID + 0x37) // 0x0137
+/** TLV type: AP STA MAC address filter */
+#define TLV_TYPE_UAP_STA_MAC_ADDR_FILTER (PROPRIETARY_TLV_BASE_ID + 0x38) // 0x0138
+/** TLV type: AP STA ageout timer */
+#define TLV_TYPE_UAP_STA_AGEOUT_TIMER (PROPRIETARY_TLV_BASE_ID + 0x39) // 0x0139
+/** TLV type: AP WEP keys */
+#define TLV_TYPE_UAP_WEP_KEY (PROPRIETARY_TLV_BASE_ID + 0x3b) // 0x013b
+/** TLV type: AP WPA passphrase */
+#define TLV_TYPE_UAP_WPA_PASSPHRASE (PROPRIETARY_TLV_BASE_ID + 0x3c) // 0x013c
+/** TLV type: AP protocol */
+#define TLV_TYPE_UAP_ENCRYPT_PROTOCOL (PROPRIETARY_TLV_BASE_ID + 0x40) // 0x0140
+/** TLV type: AP AKMP */
+#define TLV_TYPE_UAP_AKMP (PROPRIETARY_TLV_BASE_ID + 0x41) // 0x0141
+/** TLV type: AP Fragment threshold */
+#define TLV_TYPE_UAP_FRAG_THRESHOLD (PROPRIETARY_TLV_BASE_ID + 0x46) // 0x0146
+/** TLV type: AP Group rekey timer */
+#define TLV_TYPE_UAP_GRP_REKEY_TIME (PROPRIETARY_TLV_BASE_ID + 0x47) // 0x0147
+/**TLV type : AP Max Station number */
+#define TLV_TYPE_UAP_MAX_STA_CNT (PROPRIETARY_TLV_BASE_ID + 0x55) // 0x0155
+/**TLV type : AP Retry limit */
+#define TLV_TYPE_UAP_RETRY_LIMIT (PROPRIETARY_TLV_BASE_ID + 0x5d) // 0x015d
+/** TLV type : AP MCBC data rate */
+#define TLV_TYPE_UAP_MCBC_DATA_RATE (PROPRIETARY_TLV_BASE_ID + 0x62) // 0x0162
+/**TLV type: AP RSN replay protection */
+#define TLV_TYPE_UAP_RSN_REPLAY_PROTECT (PROPRIETARY_TLV_BASE_ID + 0x64) // 0x0164
+/** TLV ID : Management Frame */
+#define TLV_TYPE_UAP_MGMT_FRAME (PROPRIETARY_TLV_BASE_ID + 0x68) // 0x0168
+#ifdef UAP_SUPPORT
+/**TLV type: AP mgmt IE passthru mask */
+#define TLV_TYPE_UAP_MGMT_IE_PASSTHRU_MASK (PROPRIETARY_TLV_BASE_ID + 0x70) // 0x0170
+#endif
+/** TLV : 20/40 coex config */
+#define TLV_TYPE_2040_BSS_COEX_CONTROL (PROPRIETARY_TLV_BASE_ID + 0x98) // 0x0198
+/**TLV type: AP pairwise handshake timeout */
+#define TLV_TYPE_UAP_EAPOL_PWK_HSK_TIMEOUT (PROPRIETARY_TLV_BASE_ID + 0x75) // 0x0175
+/**TLV type: AP pairwise handshake retries */
+#define TLV_TYPE_UAP_EAPOL_PWK_HSK_RETRIES (PROPRIETARY_TLV_BASE_ID + 0x76) // 0x0176
+/**TLV type: AP groupwise handshake timeout */
+#define TLV_TYPE_UAP_EAPOL_GWK_HSK_TIMEOUT (PROPRIETARY_TLV_BASE_ID + 0x77) // 0x0177
+/**TLV type: AP groupwise handshake retries */
+#define TLV_TYPE_UAP_EAPOL_GWK_HSK_RETRIES (PROPRIETARY_TLV_BASE_ID + 0x78) // 0x0178
+/** TLV type: AP PS STA ageout timer */
+#define TLV_TYPE_UAP_PS_STA_AGEOUT_TIMER (PROPRIETARY_TLV_BASE_ID + 0x7b) // 0x017b
+/** TLV type : Pairwise Cipher */
+#define TLV_TYPE_PWK_CIPHER (PROPRIETARY_TLV_BASE_ID + 0x91) // 0x0191
+/** TLV type : Group Cipher */
+#define TLV_TYPE_GWK_CIPHER (PROPRIETARY_TLV_BASE_ID + 0x92) // 0x0192
+/** TLV type : BSS Status */
+#define TLV_TYPE_BSS_STATUS (PROPRIETARY_TLV_BASE_ID + 0x93) // 0x0193
+
+#ifdef WIFI_DIRECT_SUPPORT
+/** TLV type : AP PSK */
+#define TLV_TYPE_UAP_PSK (PROPRIETARY_TLV_BASE_ID + 0xa8) // 0x01a8
+#endif /* WIFI_DIRECT_SUPPORT */
+
+/** MrvlIEtypes_beacon_period_t */
+typedef MLAN_PACK_START struct _MrvlIEtypes_beacon_period_t
+{
+ /** Header */
+ MrvlIEtypesHeader_t header;
+ /** beacon period */
+ t_u16 beacon_period;
+} MLAN_PACK_END MrvlIEtypes_beacon_period_t;
+
+/** MrvlIEtypes_dtim_period_t */
+typedef MLAN_PACK_START struct _MrvlIEtypes_dtim_period_t
+{
+ /** Header */
+ MrvlIEtypesHeader_t header;
+ /** DTIM period */
+ t_u8 dtim_period;
+} MLAN_PACK_END MrvlIEtypes_dtim_period_t;
+
+/** MrvlIEtypes_tx_rate_t */
+typedef MLAN_PACK_START struct _MrvlIEtypes_tx_rate_t
+{
+ /** Header */
+ MrvlIEtypesHeader_t header;
+ /** tx data rate */
+ t_u16 tx_data_rate;
+} MLAN_PACK_END MrvlIEtypes_tx_rate_t;
+
+/** MrvlIEtypes_mcbc_rate_t */
+typedef MLAN_PACK_START struct _MrvlIEtypes_mcbc_rate_t
+{
+ /** Header */
+ MrvlIEtypesHeader_t header;
+ /** mcbc data rate */
+ t_u16 mcbc_data_rate;
+} MLAN_PACK_END MrvlIEtypes_mcbc_rate_t;
+
+/** MrvlIEtypes_tx_power_t */
+typedef MLAN_PACK_START struct _MrvlIEtypes_tx_power_t
+{
+ /** Header */
+ MrvlIEtypesHeader_t header;
+ /** tx power */
+ t_u8 tx_power;
+} MLAN_PACK_END MrvlIEtypes_tx_power_t;
+
+/** MrvlIEtypes_bcast_ssid_t */
+typedef MLAN_PACK_START struct _MrvlIEtypes_bcast_ssid_t
+{
+ /** Header */
+ MrvlIEtypesHeader_t header;
+ /** bcast ssid control*/
+ t_u8 bcast_ssid_ctl;
+} MLAN_PACK_END MrvlIEtypes_bcast_ssid_t;
+
+/** MrvlIEtypes_antenna_mode_t */
+typedef MLAN_PACK_START struct _MrvlIEtypes_antenna_mode_t
+{
+ /** Header */
+ MrvlIEtypesHeader_t header;
+ /** which antenna */
+ t_u8 which_antenna;
+ /** antenna mode*/
+ t_u8 antenna_mode;
+} MLAN_PACK_END MrvlIEtypes_antenna_mode_t;
+
+/** MrvlIEtypes_pkt_forward_t */
+typedef MLAN_PACK_START struct _MrvlIEtypes_pkt_forward_t
+{
+ /** Header */
+ MrvlIEtypesHeader_t header;
+ /** pkt foward control */
+ t_u8 pkt_forward_ctl;
+} MLAN_PACK_END MrvlIEtypes_pkt_forward_t;
+
+/** MrvlIEtypes_max_sta_count_t */
+typedef MLAN_PACK_START struct _MrvlIEtypes_max_sta_count_t
+{
+ /** Header */
+ MrvlIEtypesHeader_t header;
+ /** max station count */
+ t_u16 max_sta_count;
+} MLAN_PACK_END MrvlIEtypes_max_sta_count_t;
+
+/** MrvlIEtypes_sta_ageout_t */
+typedef MLAN_PACK_START struct _MrvlIEtypes_sta_ageout_t
+{
+ /** Header */
+ MrvlIEtypesHeader_t header;
+ /** station age out timer */
+ t_u32 sta_ageout_timer;
+} MLAN_PACK_END MrvlIEtypes_sta_ageout_t;
+
+/** MrvlIEtypes_rts_threshold_t */
+typedef MLAN_PACK_START struct _MrvlIEtypes_rts_threshold_t
+{
+ /** Header */
+ MrvlIEtypesHeader_t header;
+ /** rts threshold */
+ t_u16 rts_threshold;
+} MLAN_PACK_END MrvlIEtypes_rts_threshold_t;
+
+/** MrvlIEtypes_frag_threshold_t */
+typedef MLAN_PACK_START struct _MrvlIEtypes_frag_threshold_t
+{
+ /** Header */
+ MrvlIEtypesHeader_t header;
+ /** frag threshold */
+ t_u16 frag_threshold;
+} MLAN_PACK_END MrvlIEtypes_frag_threshold_t;
+
+/** MrvlIEtypes_retry_limit_t */
+typedef MLAN_PACK_START struct _MrvlIEtypes_retry_limit_t
+{
+ /** Header */
+ MrvlIEtypesHeader_t header;
+ /** retry limit */
+ t_u8 retry_limit;
+} MLAN_PACK_END MrvlIEtypes_retry_limit_t;
+
+/** MrvlIEtypes_eapol_pwk_hsk_timeout_t */
+typedef MLAN_PACK_START struct _MrvlIEtypes_eapol_pwk_hsk_timeout_t
+{
+ /** Header */
+ MrvlIEtypesHeader_t header;
+ /** pairwise update timeout in milliseconds */
+ t_u32 pairwise_update_timeout;
+} MLAN_PACK_END MrvlIEtypes_eapol_pwk_hsk_timeout_t;
+
+/** MrvlIEtypes_eapol_pwk_hsk_retries_t */
+typedef MLAN_PACK_START struct _MrvlIEtypes_eapol_pwk_hsk_retries_t
+{
+ /** Header */
+ MrvlIEtypesHeader_t header;
+ /** pairwise handshake retries */
+ t_u32 pwk_retries;
+} MLAN_PACK_END MrvlIEtypes_eapol_pwk_hsk_retries_t;
+
+/** MrvlIEtypes_eapol_gwk_hsk_timeout_t */
+typedef MLAN_PACK_START struct _MrvlIEtypes_eapol_gwk_hsk_timeout_t
+{
+ /** Header */
+ MrvlIEtypesHeader_t header;
+ /** groupwise update timeout in milliseconds */
+ t_u32 groupwise_update_timeout;
+} MLAN_PACK_END MrvlIEtypes_eapol_gwk_hsk_timeout_t;
+
+/** MrvlIEtypes_eapol_gwk_hsk_retries_t */
+typedef MLAN_PACK_START struct _MrvlIEtypes_eapol_gwk_hsk_retries_t
+{
+ /** Header */
+ MrvlIEtypesHeader_t header;
+ /** groupwise handshake retries */
+ t_u32 gwk_retries;
+} MLAN_PACK_END MrvlIEtypes_eapol_gwk_hsk_retries_t;
+
+#ifdef UAP_SUPPORT
+/** MrvlIEtypes_mgmt_ie_passthru_t */
+typedef MLAN_PACK_START struct _MrvlIEtypes_mgmt_ie_passthru_t
+{
+ /** Header */
+ MrvlIEtypesHeader_t header;
+ /** mgmt IE mask value */
+ t_u32 mgmt_ie_mask;
+} MLAN_PACK_END MrvlIEtypes_mgmt_ie_passthru_t;
+#endif
+
+/** TLV buffer : 2040 coex config */
+typedef MLAN_PACK_START struct _MrvlIEtypes_2040_coex_enable_t
+{
+ /** Header */
+ MrvlIEtypesHeader_t header;
+ /** Enable */
+ t_u8 enable_2040coex;
+} MLAN_PACK_END MrvlIEtypes_2040_coex_enable_t;
+
+/** MrvlIEtypes_mac_filter_t */
+typedef MLAN_PACK_START struct _MrvlIEtypes_mac_filter_t
+{
+ /** Header */
+ MrvlIEtypesHeader_t header;
+ /** Filter mode */
+ t_u8 filter_mode;
+ /** Number of STA MACs */
+ t_u8 count;
+ /** STA MAC addresses buffer */
+ t_u8 mac_address[1];
+} MLAN_PACK_END MrvlIEtypes_mac_filter_t;
+
+/** setting for band_config - band=5GHZ */
+#define BAND_CONFIG_5GHZ 0x01
+
+/** MrvlIEtypes_retry_limit_t */
+typedef MLAN_PACK_START struct _MrvlIEtypes_channel_band_t
+{
+ /** Header */
+ MrvlIEtypesHeader_t header;
+ /** Band Configuration
+ *
+ * [7-6] Channel Selection Mode; 00 manual, 01 ACS
+ * [3-2] Channel Width; 00 20 MHz
+ * [1-0] Band Info; 00 2.4 GHz
+ */
+ t_u8 band_config;
+ /** channel */
+ t_u8 channel;
+} MLAN_PACK_END MrvlIEtypes_channel_band_t;
+
+/** MrvlIEtypes_auth_type_t */
+typedef MLAN_PACK_START struct _MrvlIEtypes_auth_type_t
+{
+ /** Header */
+ MrvlIEtypesHeader_t header;
+ /** Authentication type */
+ t_u8 auth_type;
+} MLAN_PACK_END MrvlIEtypes_auth_type_t;
+
+/** MrvlIEtypes_encrypt_protocol_t */
+typedef MLAN_PACK_START struct _MrvlIEtypes_encrypt_protocol_t
+{
+ /** Header */
+ MrvlIEtypesHeader_t header;
+ /** encryption protocol */
+ t_u16 protocol;
+} MLAN_PACK_END MrvlIEtypes_encrypt_protocol_t;
+
+/** MrvlIEtypes_pwk_cipher_t */
+typedef MLAN_PACK_START struct _MrvlIEtypes_pwk_cipher_t
+{
+ /** Header */
+ MrvlIEtypesHeader_t header;
+ /** protocol */
+ t_u16 protocol;
+ /** pairwise cipher */
+ t_u8 pairwise_cipher;
+ /** reserved */
+ t_u8 reserved;
+} MLAN_PACK_END MrvlIEtypes_pwk_cipher_t;
+
+/** MrvlIEtypes_gwk_cipher_t */
+typedef MLAN_PACK_START struct _MrvlIEtypes_gwk_cipher_t
+{
+ /** Header */
+ MrvlIEtypesHeader_t header;
+ /** group cipher */
+ t_u8 group_cipher;
+ /** reserved */
+ t_u8 reserved;
+} MLAN_PACK_END MrvlIEtypes_gwk_cipher_t;
+
+/** MrvlIEtypes_akmp_t */
+typedef MLAN_PACK_START struct _MrvlIEtypes_akmp_t
+{
+ /** Header */
+ MrvlIEtypesHeader_t header;
+ /** key management */
+ t_u16 key_mgmt;
+ /** key management operation */
+ t_u16 key_mgmt_operation;
+} MLAN_PACK_END MrvlIEtypes_akmp_t;
+
+/** MrvlIEtypes_passphrase_t */
+typedef MLAN_PACK_START struct _MrvlIEtypes_passphrase_t
+{
+ /** Header */
+ MrvlIEtypesHeader_t header;
+ /** passphrase */
+ t_u8 passphrase[1];
+} MLAN_PACK_END MrvlIEtypes_passphrase_t;
+
+/** MrvlIEtypes_rsn_replay_prot_t */
+typedef MLAN_PACK_START struct _MrvlIEtypes_rsn_replay_prot_t
+{
+ /** Header */
+ MrvlIEtypesHeader_t header;
+ /** rsn replay proection */
+ t_u8 rsn_replay_prot;
+} MLAN_PACK_END MrvlIEtypes_rsn_replay_prot_t;
+
+/** MrvlIEtypes_group_rekey_time_t */
+typedef MLAN_PACK_START struct _MrvlIEtypes_group_rekey_time_t
+{
+ /** Header */
+ MrvlIEtypesHeader_t header;
+ /** group key rekey time */
+ t_u32 gk_rekey_time;
+} MLAN_PACK_END MrvlIEtypes_group_rekey_time_t;
+
+/** MrvlIEtypes_wep_key_t */
+typedef MLAN_PACK_START struct _MrvlIEtypes_wep_key_t
+{
+ /** Header */
+ MrvlIEtypesHeader_t header;
+ /** key index */
+ t_u8 key_index;
+ /** is default */
+ t_u8 is_default;
+ /** key data */
+ t_u8 key[1];
+} MLAN_PACK_END MrvlIEtypes_wep_key_t;
+
+/** MrvlIEtypes_bss_status_t */
+typedef MLAN_PACK_START struct _MrvlIEtypes_bss_status_t
+{
+ /** Header */
+ MrvlIEtypesHeader_t header;
+ /** BSS status, READ only */
+ t_u16 bss_status;
+} MLAN_PACK_END MrvlIEtypes_bss_status_t;
+
+/** MrvlIEtypes_preamble_t */
+typedef MLAN_PACK_START struct _MrvlIEtypes_preamble_t
+{
+ /** Header */
+ MrvlIEtypesHeader_t header;
+ /** preamble type, READ only */
+ t_u8 preamble_type;
+} MLAN_PACK_END MrvlIEtypes_preamble_t;
+
+/** MrvlIEtypes_wmm_parameter_t */
+typedef MLAN_PACK_START struct _MrvlIEtypes_wmm_parameter_t
+{
+ /** Header */
+ MrvlIEtypesHeader_t header;
+ /** WMM parameter */
+ WmmParameter_t wmm_para;
+} MLAN_PACK_END MrvlIEtypes_wmm_parameter_t;
+
+/** SNMP_MIB_UAP_INDEX */
+typedef enum _SNMP_MIB_UAP_INDEX
+{
+ tkip_mic_failures = 0x0b,
+ ccmp_decrypt_errors = 0x0c,
+ wep_undecryptable_count = 0x0d,
+ wep_icv_error_count = 0x0e,
+ decrypt_failure_count = 0xf,
+ dot11_failed_count = 0x12,
+ dot11_retry_count = 0x13,
+ dot11_multi_retry_count = 0x14,
+ dot11_frame_dup_count = 0x15,
+ dot11_rts_success_count = 0x16,
+ dot11_rts_failure_count = 0x17,
+ dot11_ack_failure_count = 0x18,
+ dot11_rx_fragment_count = 0x19,
+ dot11_mcast_rx_frame_count = 0x1a,
+ dot11_fcs_error_count = 0x1b,
+ dot11_tx_frame_count = 0x1c,
+ dot11_rsna_tkip_cm_invoked = 0x1d,
+ dot11_rsna_4way_hshk_failures = 0x1e,
+ dot11_mcast_tx_count = 0x1f,
+} SNMP_MIB_UAP_INDEX;
+
+/** MrvlIEtypes_snmp_oid_t */
+typedef MLAN_PACK_START struct _MrvlIEtypes_snmp_oid_t
+{
+ /** Header */
+ MrvlIEtypesHeader_t header;
+ /** data */
+ t_u32 data;
+} MLAN_PACK_END MrvlIEtypes_snmp_oid_t;
+
+/** HostCmd_SYS_CONFIG */
+typedef MLAN_PACK_START struct _HostCmd_DS_SYS_CONFIG
+{
+ /** CMD Action GET/SET*/
+ t_u16 action;
+ /** Tlv buffer */
+ t_u8 tlv_buffer[1];
+} MLAN_PACK_END HostCmd_DS_SYS_CONFIG;
+
+/** HostCmd_SYS_CONFIG */
+typedef MLAN_PACK_START struct _HostCmd_DS_SYS_INFO
+{
+ /** sys info */
+ t_u8 sys_info[64];
+} MLAN_PACK_END HostCmd_DS_SYS_INFO;
+
+/** HostCmd_DS_STA_DEAUTH */
+typedef MLAN_PACK_START struct _HostCmd_DS_STA_DEAUTH
+{
+ /** mac address */
+ t_u8 mac[MLAN_MAC_ADDR_LENGTH];
+ /** reason code */
+ t_u16 reason;
+} MLAN_PACK_END HostCmd_DS_STA_DEAUTH;
+
+/** Host Command id: POWER_MGMT */
+#define HOST_CMD_POWER_MGMT_EXT 0x00ef
+/** TLV type: AP Sleep param */
+#define TLV_TYPE_AP_SLEEP_PARAM (PROPRIETARY_TLV_BASE_ID + 0x6a) // 0x016a
+/** TLV type: AP Inactivity Sleep param */
+#define TLV_TYPE_AP_INACT_SLEEP_PARAM (PROPRIETARY_TLV_BASE_ID + 0x6b) // 0x016b
+
+/** MrvlIEtypes_sleep_param_t */
+typedef MLAN_PACK_START struct _MrvlIEtypes_sleep_param_t
+{
+ /** Header */
+ MrvlIEtypesHeader_t header;
+ /** control bitmap */
+ t_u32 ctrl_bitmap;
+ /** min_sleep */
+ t_u32 min_sleep;
+ /** max_sleep */
+ t_u32 max_sleep;
+} MLAN_PACK_END MrvlIEtypes_sleep_param_t;
+
+/** MrvlIEtypes_inact_sleep_param_t */
+typedef MLAN_PACK_START struct _MrvlIEtypes_inact_sleep_param_t
+{
+ /** Header */
+ MrvlIEtypesHeader_t header;
+ /** inactivity timeout */
+ t_u32 inactivity_to;
+
+ /** min_awake */
+ t_u32 min_awake;
+ /** max_awake */
+ t_u32 max_awake;
+} MLAN_PACK_END MrvlIEtypes_inact_sleep_param_t;
+
+/** HostCmd_DS_POWER_MGMT */
+typedef MLAN_PACK_START struct _HostCmd_DS_POWER_MGMT_EXT
+{
+ /** CMD Action Get/Set*/
+ t_u16 action;
+ /** power mode */
+ t_u16 power_mode;
+} MLAN_PACK_END HostCmd_DS_POWER_MGMT_EXT;
+
+/** MrvlIEtypes_ps_sta_ageout_t */
+typedef MLAN_PACK_START struct _MrvlIEtypes_ps_sta_ageout_t
+{
+ /** Header */
+ MrvlIEtypesHeader_t header;
+ /** station age out timer */
+ t_u32 ps_sta_ageout_timer;
+} MLAN_PACK_END MrvlIEtypes_ps_sta_ageout_t;
+
+/** MrvlIEtypes_sta_info_t */
+typedef MLAN_PACK_START struct _MrvlIEtypes_sta_info_t
+{
+ /** Header */
+ MrvlIEtypesHeader_t header;
+ /** STA MAC address */
+ t_u8 mac_address[MLAN_MAC_ADDR_LENGTH];
+ /** Power mfg status */
+ t_u8 power_mfg_status;
+ /** RSSI */
+ t_s8 rssi;
+} MLAN_PACK_END MrvlIEtypes_sta_info_t;
+
+/** HostCmd_DS_STA_LIST */
+typedef MLAN_PACK_START struct _HostCmd_DS_STA_LIST
+{
+ /** Number of STAs */
+ t_u16 sta_count;
+ /* MrvlIEtypes_sta_info_t sta_info[0]; */
+} MLAN_PACK_END HostCmd_DS_STA_LIST;
+
+/** TLV ID : WAPI Information */
+#define TLV_TYPE_AP_WAPI_INFO (PROPRIETARY_TLV_BASE_ID + 0x67) // 0x0167
+
+/** MrvlIEtypes_sta_info_t */
+typedef MLAN_PACK_START struct _MrvlIEtypes_wapi_info_t
+{
+ /** Header */
+ MrvlIEtypesHeader_t header;
+ /** Multicast PN */
+ t_u8 multicast_PN[16];
+} MLAN_PACK_END MrvlIEtypes_wapi_info_t;
+#endif /* UAP_SUPPORT */
+
+/**
+ * @brief 802.11h Local Power Constraint Marvell extended TLV
+ */
+typedef MLAN_PACK_START struct
+{
+ MrvlIEtypesHeader_t header; /**< Marvell TLV header: ID/Len */
+ t_u8 chan; /**< Channel local constraint applies to */
+
+ /** Power constraint included in beacons and used by fw to offset 11d info */
+ t_u8 constraint;
+
+} MLAN_PACK_END MrvlIEtypes_LocalPowerConstraint_t;
+
+/*
+ *
+ * Data structures for driver/firmware command processing
+ *
+ */
+
+/** TPC Info structure sent in CMD_802_11_TPC_INFO command to firmware */
+typedef MLAN_PACK_START struct
+{
+ MrvlIEtypes_LocalPowerConstraint_t local_constraint; /**< Local constraint */
+ MrvlIEtypes_PowerCapability_t power_cap; /**< Power Capability */
+
+} MLAN_PACK_END HostCmd_DS_802_11_TPC_INFO;
+
+/** TPC Request structure sent in CMD_802_11_TPC_ADAPT_REQ command to firmware */
+typedef MLAN_PACK_START struct
+{
+ t_u8 dest_mac[MLAN_MAC_ADDR_LENGTH]; /**< Destination STA address */
+ t_u16 timeout; /**< Response timeout in ms */
+ t_u8 rate_index; /**< IEEE Rate index to send request */
+
+} MLAN_PACK_END HostCmd_TpcRequest;
+
+/** TPC Response structure received from the CMD_802_11_TPC_ADAPT_REQ command */
+typedef MLAN_PACK_START struct
+{
+ t_u8 tpc_ret_code; /**< Firmware command result status code */
+ t_s8 tx_power; /**< Reported TX Power from the TPC Report element */
+ t_s8 link_margin; /**< Reported link margin from the TPC Report element */
+ t_s8 rssi; /**< RSSI of the received TPC Report frame */
+
+} MLAN_PACK_END HostCmd_TpcResponse;
+
+/** CMD_802_11_TPC_ADAPT_REQ substruct. Union of the TPC request and response */
+typedef MLAN_PACK_START union
+{
+ HostCmd_TpcRequest req; /**< Request struct sent to firmware */
+ HostCmd_TpcResponse resp; /**< Response struct received from firmware */
+
+} MLAN_PACK_END HostCmd_DS_802_11_TPC_ADAPT_REQ;
+
+/** CMD_802_11_CHAN_SW_ANN firmware command substructure */
+typedef MLAN_PACK_START struct
+{
+ t_u8 switch_mode; /**< Set to 1 for a quiet switch request, no STA tx */
+ t_u8 new_chan; /**< Requested new channel */
+ t_u8 switch_count; /**< Number of TBTTs until the switch is to occur */
+} MLAN_PACK_END HostCmd_DS_802_11_CHAN_SW_ANN;
+
+/**
+ * @brief Enumeration of measurement types, including max supported
+ * enum for 11h/11k
+ */
+typedef MLAN_PACK_START enum _MeasType_t
+{
+ WLAN_MEAS_BASIC = 0, /**< 11h: Basic */
+ WLAN_MEAS_NUM_TYPES, /**< Number of enumerated measurements */
+ WLAN_MEAS_11H_MAX_TYPE = WLAN_MEAS_BASIC, /**< Max 11h measurement */
+
+} MLAN_PACK_END MeasType_t;
+
+/**
+ * @brief Mode octet of the measurement request element (7.3.2.21)
+ */
+typedef MLAN_PACK_START struct
+{
+#ifdef BIG_ENDIAN_SUPPORT
+ t_u8 rsvd5_7:3; /**< Reserved */
+ t_u8 duration_mandatory:1; /**< 11k: duration spec. for meas. is mandatory */
+ t_u8 report:1; /**< 11h: en/disable report rcpt. of spec. type */
+ t_u8 request:1; /**< 11h: en/disable requests of specified type */
+ t_u8 enable:1; /**< 11h: enable report/request bits */
+ t_u8 parallel:1; /**< 11k: series or parallel with previous meas */
+#else
+ t_u8 parallel:1; /**< 11k: series or parallel with previous meas */
+ t_u8 enable:1; /**< 11h: enable report/request bits */
+ t_u8 request:1; /**< 11h: en/disable requests of specified type */
+ t_u8 report:1; /**< 11h: en/disable report rcpt. of spec. type */
+ t_u8 duration_mandatory:1; /**< 11k: duration spec. for meas. is mandatory */
+ t_u8 rsvd5_7:3; /**< Reserved */
+#endif /* BIG_ENDIAN_SUPPORT */
+
+} MLAN_PACK_END MeasReqMode_t;
+
+/**
+ * @brief Common measurement request structure (7.3.2.21.1 to 7.3.2.21.3)
+ */
+typedef MLAN_PACK_START struct
+{
+ t_u8 channel; /**< Channel to measure */
+ t_u64 start_time; /**< TSF Start time of measurement (0 for immediate) */
+ t_u16 duration; /**< TU duration of the measurement */
+
+} MLAN_PACK_END MeasReqCommonFormat_t;
+
+/**
+ * @brief Basic measurement request structure (7.3.2.21.1)
+ */
+typedef MeasReqCommonFormat_t MeasReqBasic_t;
+
+/**
+ * @brief CCA measurement request structure (7.3.2.21.2)
+ */
+typedef MeasReqCommonFormat_t MeasReqCCA_t;
+
+/**
+ * @brief RPI measurement request structure (7.3.2.21.3)
+ */
+typedef MeasReqCommonFormat_t MeasReqRPI_t;
+
+/**
+ * @brief Union of the availble measurement request types. Passed in the
+ * driver/firmware interface.
+ */
+typedef union
+{
+ MeasReqBasic_t basic; /**< Basic measurement request */
+ MeasReqCCA_t cca; /**< CCA measurement request */
+ MeasReqRPI_t rpi; /**< RPI measurement request */
+
+} MeasRequest_t;
+
+/**
+ * @brief Mode octet of the measurement report element (7.3.2.22)
+ */
+typedef MLAN_PACK_START struct
+{
+#ifdef BIG_ENDIAN_SUPPORT
+ t_u8 rsvd3_7:5; /**< Reserved */
+ t_u8 refused:1; /**< Measurement refused */
+ t_u8 incapable:1; /**< Incapable of performing measurement */
+ t_u8 late:1; /**< Start TSF time missed for measurement */
+#else
+ t_u8 late:1; /**< Start TSF time missed for measurement */
+ t_u8 incapable:1; /**< Incapable of performing measurement */
+ t_u8 refused:1; /**< Measurement refused */
+ t_u8 rsvd3_7:5; /**< Reserved */
+#endif /* BIG_ENDIAN_SUPPORT */
+
+} MLAN_PACK_END MeasRptMode_t;
+
+/**
+ * @brief Basic measurement report (7.3.2.22.1)
+ */
+typedef MLAN_PACK_START struct
+{
+ t_u8 channel; /**< Channel to measured */
+ t_u64 start_time; /**< Start time (TSF) of measurement */
+ t_u16 duration; /**< Duration of measurement in TUs */
+ MeasRptBasicMap_t map; /**< Basic measurement report */
+
+} MLAN_PACK_END MeasRptBasic_t;
+
+/**
+ * @brief CCA measurement report (7.3.2.22.2)
+ */
+typedef MLAN_PACK_START struct
+{
+ t_u8 channel; /**< Channel to measured */
+ t_u64 start_time; /**< Start time (TSF) of measurement */
+ t_u16 duration; /**< Duration of measurement in TUs */
+ t_u8 busy_fraction; /**< Fractional duration CCA indicated chan busy */
+
+} MLAN_PACK_END MeasRptCCA_t;
+
+/**
+ * @brief RPI measurement report (7.3.2.22.3)
+ */
+typedef MLAN_PACK_START struct
+{
+ t_u8 channel; /**< Channel to measured */
+ t_u64 start_time; /**< Start time (TSF) of measurement */
+ t_u16 duration; /**< Duration of measurement in TUs */
+ t_u8 density[8]; /**< RPI Density histogram report */
+
+} MLAN_PACK_END MeasRptRPI_t;
+
+/**
+ * @brief Union of the availble measurement report types. Passed in the
+ * driver/firmware interface.
+ */
+typedef union
+{
+ MeasRptBasic_t basic; /**< Basic measurement report */
+ MeasRptCCA_t cca; /**< CCA measurement report */
+ MeasRptRPI_t rpi; /**< RPI measurement report */
+
+} MeasReport_t;
+
+/**
+ * @brief Structure passed to firmware to perform a measurement
+ */
+typedef MLAN_PACK_START struct
+{
+ t_u8 mac_addr[MLAN_MAC_ADDR_LENGTH]; /**< Reporting STA address */
+ t_u8 dialog_token; /**< Measurement dialog toke */
+ MeasReqMode_t req_mode; /**< Report mode */
+ MeasType_t meas_type; /**< Measurement type */
+ MeasRequest_t req; /**< Measurement request data */
+
+} MLAN_PACK_END HostCmd_DS_MEASUREMENT_REQUEST;
+
+/**
+ * @brief Structure passed back from firmware with a measurement report,
+ * also can be to send a measurement report to another STA
+ */
+typedef MLAN_PACK_START struct
+{
+ t_u8 mac_addr[MLAN_MAC_ADDR_LENGTH]; /**< Reporting STA address */
+ t_u8 dialog_token; /**< Measurement dialog token */
+ MeasRptMode_t rpt_mode; /**< Report mode */
+ MeasType_t meas_type; /**< Measurement type */
+ MeasReport_t rpt; /**< Measurement report data */
+
+} MLAN_PACK_END HostCmd_DS_MEASUREMENT_REPORT;
+
+typedef MLAN_PACK_START struct
+{
+ t_u16 startFreq;
+ t_u8 chanWidth;
+ t_u8 chanNum;
+
+} MLAN_PACK_END MrvlChannelDesc_t;
+
+typedef MLAN_PACK_START struct
+{
+ MrvlIEtypesHeader_t Header; /**< Header */
+
+ MeasRptBasicMap_t map; /**< IEEE 802.11h basic meas report */
+} MLAN_PACK_END MrvlIEtypes_ChanRpt11hBasic_t;
+
+typedef MLAN_PACK_START struct
+{
+ MrvlChannelDesc_t chan_desc; /**< Channel band, number */
+ t_u32 millisec_dwell_time; /**< Channel dwell time in milliseconds */
+} MLAN_PACK_END HostCmd_DS_CHAN_RPT_REQ;
+
+typedef MLAN_PACK_START struct
+{
+ t_u32 cmd_result; /**< Rpt request command result (0 == SUCCESS) */
+ t_u64 start_tsf; /**< TSF Measurement started */
+ t_u32 duration; /**< Duration of measurement in microsecs */
+ t_u8 tlv_buffer[1]; /**< TLV Buffer */
+} MLAN_PACK_END HostCmd_DS_CHAN_RPT_RSP;
+
+/** statistics threshold */
+typedef MLAN_PACK_START struct
+{
+ /** Header */
+ MrvlIEtypesHeader_t header;
+ /** value */
+ t_u8 value;
+ /** reporting frequency */
+ t_u8 frequency;
+} MLAN_PACK_END MrvlIEtypes_BeaconHighRssiThreshold_t,
+ MrvlIEtypes_BeaconLowRssiThreshold_t,
+ MrvlIEtypes_BeaconHighSnrThreshold_t,
+ MrvlIEtypes_BeaconLowSnrThreshold_t,
+ MrvlIEtypes_FailureCount_t,
+ MrvlIEtypes_DataLowRssiThreshold_t,
+ MrvlIEtypes_DataHighRssiThreshold_t,
+ MrvlIEtypes_DataLowSnrThreshold_t,
+ MrvlIEtypes_DataHighSnrThreshold_t,
+ MrvlIETypes_PreBeaconMissed_t, MrvlIEtypes_BeaconsMissed_t;
+
+/** statistics threshold for LinkQuality */
+typedef MLAN_PACK_START struct
+{
+ /** Header */
+ MrvlIEtypesHeader_t header;
+ /** Link SNR threshold (dB) */
+ t_u16 link_snr;
+ /** Link SNR frequency */
+ t_u16 link_snr_freq;
+ /* Second minimum rate value as per the rate table below */
+ t_u16 link_rate;
+ /* Second minimum rate frequency */
+ t_u16 link_rate_freq;
+ /* Tx latency value (us) */
+ t_u16 link_tx_latency;
+ /* Tx latency frequency */
+ t_u16 link_tx_lantency_freq;
+} MLAN_PACK_END MrvlIEtypes_LinkQualityThreshold_t;
+
+/** HostCmd_DS_COMMAND */
+typedef struct MLAN_PACK_START _HostCmd_DS_COMMAND
+{
+ /** Command Header : Command */
+ t_u16 command;
+ /** Command Header : Size */
+ t_u16 size;
+ /** Command Header : Sequence number */
+ t_u16 seq_num;
+ /** Command Header : Result */
+ t_u16 result;
+ /** Command Body */
+ union
+ {
+ /** Hardware specifications */
+ HostCmd_DS_GET_HW_SPEC hw_spec;
+ /** Cfg data */
+ HostCmd_DS_802_11_CFG_DATA cfg_data;
+ /** MAC control */
+ HostCmd_DS_MAC_CONTROL mac_ctrl;
+ /** MAC address */
+ HostCmd_DS_802_11_MAC_ADDRESS mac_addr;
+ /** MAC muticast address */
+ HostCmd_DS_MAC_MULTICAST_ADR mc_addr;
+ /** Get log */
+ HostCmd_DS_802_11_GET_LOG get_log;
+ /** RSSI information */
+ HostCmd_DS_802_11_RSSI_INFO rssi_info;
+ /** RSSI information response */
+ HostCmd_DS_802_11_RSSI_INFO_RSP rssi_info_rsp;
+ /** SNMP MIB */
+ HostCmd_DS_802_11_SNMP_MIB smib;
+ /** Radio control */
+ HostCmd_DS_802_11_RADIO_CONTROL radio;
+ /** RF channel */
+ HostCmd_DS_802_11_RF_CHANNEL rf_channel;
+ /** Tx rate query */
+ HostCmd_TX_RATE_QUERY tx_rate;
+ /** Tx rate configuration */
+ HostCmd_DS_TX_RATE_CFG tx_rate_cfg;
+ /** Tx power configuration */
+ HostCmd_DS_TXPWR_CFG txp_cfg;
+ /** RF Tx power configuration */
+ HostCmd_DS_802_11_RF_TX_POWER txp;
+
+ /** RF antenna */
+ HostCmd_DS_802_11_RF_ANTENNA antenna;
+ /** Enhanced power save command */
+ HostCmd_DS_802_11_PS_MODE_ENH psmode_enh;
+ HostCmd_DS_802_11_HS_CFG_ENH opt_hs_cfg;
+ /** Scan */
+ HostCmd_DS_802_11_SCAN scan;
+ /** Extended Scan */
+ HostCmd_DS_802_11_SCAN_EXT ext_scan;
+
+ /** Mgmt frame subtype mask */
+ HostCmd_DS_RX_MGMT_IND rx_mgmt_ind;
+ /** Scan response */
+ HostCmd_DS_802_11_SCAN_RSP scan_resp;
+
+ HostCmd_DS_802_11_BG_SCAN_CONFIG bg_scan_config;
+ HostCmd_DS_802_11_BG_SCAN_QUERY bg_scan_query;
+ HostCmd_DS_802_11_BG_SCAN_QUERY_RSP bg_scan_query_resp;
+ HostCmd_DS_SUBSCRIBE_EVENT subscribe_event;
+ /** Associate */
+ HostCmd_DS_802_11_ASSOCIATE associate;
+
+ /** Associate response */
+ HostCmd_DS_802_11_ASSOCIATE_RSP associate_rsp;
+ /** Deauthenticate */
+ HostCmd_DS_802_11_DEAUTHENTICATE deauth;
+ /** Ad-Hoc start */
+ HostCmd_DS_802_11_AD_HOC_START adhoc_start;
+ /** Ad-Hoc start result */
+ HostCmd_DS_802_11_AD_HOC_START_RESULT adhoc_start_result;
+ /** Ad-Hoc join result */
+ HostCmd_DS_802_11_AD_HOC_JOIN_RESULT adhoc_join_result;
+ /** Ad-Hoc join */
+ HostCmd_DS_802_11_AD_HOC_JOIN adhoc_join;
+ /** Domain information */
+ HostCmd_DS_802_11D_DOMAIN_INFO domain_info;
+ /** Domain information response */
+ HostCmd_DS_802_11D_DOMAIN_INFO_RSP domain_info_resp;
+ HostCmd_DS_802_11_TPC_ADAPT_REQ tpc_req;
+ HostCmd_DS_802_11_TPC_INFO tpc_info;
+ HostCmd_DS_802_11_CHAN_SW_ANN chan_sw_ann;
+ HostCmd_DS_CHAN_RPT_REQ chan_rpt_req;
+ HostCmd_DS_MEASUREMENT_REQUEST meas_req;
+ HostCmd_DS_MEASUREMENT_REPORT meas_rpt;
+ /** Add BA request */
+ HostCmd_DS_11N_ADDBA_REQ add_ba_req;
+ /** Add BA response */
+ HostCmd_DS_11N_ADDBA_RSP add_ba_rsp;
+ /** Delete BA entry */
+ HostCmd_DS_11N_DELBA del_ba;
+ /** Tx buffer configuration */
+ HostCmd_DS_TXBUF_CFG tx_buf;
+ /** AMSDU Aggr Ctrl configuration */
+ HostCmd_DS_AMSDU_AGGR_CTRL amsdu_aggr_ctrl;
+ /** 11n configuration */
+ HostCmd_DS_11N_CFG htcfg;
+ /** 11n configuration */
+ HostCmd_DS_TX_BF_CFG tx_bf_cfg;
+ /** WMM status get */
+ HostCmd_DS_WMM_GET_STATUS get_wmm_status;
+ /** WMM ADDTS */
+ HostCmd_DS_WMM_ADDTS_REQ add_ts;
+ /** WMM DELTS */
+ HostCmd_DS_WMM_DELTS_REQ del_ts;
+ /** WMM set/get queue config */
+ HostCmd_DS_WMM_QUEUE_CONFIG queue_config;
+ /** WMM on/of/get queue statistics */
+ HostCmd_DS_WMM_QUEUE_STATS queue_stats;
+ /** WMM get traffic stream status */
+ HostCmd_DS_WMM_TS_STATUS ts_status;
+ /** Key material */
+ HostCmd_DS_802_11_KEY_MATERIAL key_material;
+ /** E-Supplicant PSK */
+ HostCmd_DS_802_11_SUPPLICANT_PMK esupplicant_psk;
+ /** E-Supplicant profile */
+ HostCmd_DS_802_11_SUPPLICANT_PROFILE esupplicant_profile;
+ /** Extended version */
+ HostCmd_DS_VERSION_EXT verext;
+ /** Adhoc Coalescing */
+ HostCmd_DS_802_11_IBSS_STATUS ibss_coalescing;
+ /** Mgmt IE list configuration */
+ HostCmd_DS_MGMT_IE_LIST_CFG mgmt_ie_list;
+ /** System clock configuration */
+ HostCmd_DS_ECL_SYSTEM_CLOCK_CONFIG sys_clock_cfg;
+ /** MAC register access */
+ HostCmd_DS_MAC_REG_ACCESS mac_reg;
+ /** BBP register access */
+ HostCmd_DS_BBP_REG_ACCESS bbp_reg;
+ /** RF register access */
+ HostCmd_DS_RF_REG_ACCESS rf_reg;
+ /** EEPROM register access */
+ HostCmd_DS_802_11_EEPROM_ACCESS eeprom;
+ /** Memory access */
+ HostCmd_DS_MEM_ACCESS mem;
+
+ /** Inactivity timeout extend */
+ HostCmd_DS_INACTIVITY_TIMEOUT_EXT inactivity_to;
+#ifdef UAP_SUPPORT
+ HostCmd_DS_SYS_CONFIG sys_config;
+ HostCmd_DS_SYS_INFO sys_info;
+ HostCmd_DS_STA_DEAUTH sta_deauth;
+ HostCmd_DS_STA_LIST sta_list;
+ HostCmd_DS_POWER_MGMT_EXT pm_cfg;
+#endif /* UAP_SUPPORT */
+
+ /** Sleep period command */
+ HostCmd_DS_802_11_SLEEP_PERIOD sleep_pd;
+ /** Sleep params command */
+ HostCmd_DS_802_11_SLEEP_PARAMS sleep_param;
+
+ /** SDIO GPIO interrupt config command */
+ HostCmd_DS_SDIO_GPIO_INT_CONFIG sdio_gpio_int;
+ HostCmd_DS_SDIO_PULL_CTRL sdio_pull_ctl;
+ HostCmd_DS_SET_BSS_MODE bss_mode;
+ HostCmd_DS_CMD_TX_DATA_PAUSE tx_data_pause;
+#ifdef WIFI_DIRECT_SUPPORT
+ HostCmd_DS_REMAIN_ON_CHANNEL remain_on_chan;
+ HostCmd_DS_WIFI_DIRECT_MODE wifi_direct_mode;
+#endif
+ } params;
+} MLAN_PACK_END HostCmd_DS_COMMAND;
+
+/** PS_CMD_ConfirmSleep */
+typedef MLAN_PACK_START struct _OPT_Confirm_Sleep
+{
+ /** Command */
+ t_u16 command;
+ /** Size */
+ t_u16 size;
+ /** Sequence number */
+ t_u16 seq_num;
+ /** Result */
+ t_u16 result;
+ /** Action */
+ t_u16 action;
+ /** Sleep comfirm param definition */
+ sleep_confirm_param sleep_cfm;
+} MLAN_PACK_END OPT_Confirm_Sleep;
+
+typedef struct MLAN_PACK_START _opt_sleep_confirm_buffer
+{
+ /** Header for interface */
+ t_u8 hdr[4];
+ /** New power save command used to send sleep confirmation to the firmware */
+ OPT_Confirm_Sleep ps_cfm_sleep;
+} MLAN_PACK_END opt_sleep_confirm_buffer;
+
+#ifdef PRAGMA_PACK
+#pragma pack(pop)
+#endif
+
+#endif /* !_MLAN_FW_H_ */
diff --git a/drivers/net/wireless/sd8797/mlan/mlan_ieee.h b/drivers/net/wireless/sd8797/mlan/mlan_ieee.h
new file mode 100644
index 000000000000..923a38056800
--- /dev/null
+++ b/drivers/net/wireless/sd8797/mlan/mlan_ieee.h
@@ -0,0 +1,1318 @@
+/** @file mlan_ieee.h
+ *
+ * @brief This file contains IEEE information element related
+ * definitions used in MLAN and MOAL module.
+ *
+ * Copyright (C) 2008-2011, Marvell International Ltd.
+ *
+ * This software file (the "File") is distributed by Marvell International
+ * Ltd. under the terms of the GNU General Public License Version 2, June 1991
+ * (the "License"). You may use, redistribute and/or modify this File in
+ * accordance with the terms and conditions of the License, a copy of which
+ * is available by writing to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
+ * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
+ *
+ * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
+ * ARE EXPRESSLY DISCLAIMED. The License provides additional details about
+ * this warranty disclaimer.
+ */
+
+/******************************************************
+Change log:
+ 11/03/2008: initial version
+******************************************************/
+
+#ifndef _MLAN_IEEE_H_
+#define _MLAN_IEEE_H_
+
+/** WLAN supported rates */
+#define WLAN_SUPPORTED_RATES 14
+
+/** WLAN supported rates extension*/
+#define WLAN_SUPPORTED_RATES_EXT 32
+
+/** Enumeration definition*/
+/** WLAN_802_11_NETWORK_TYPE */
+typedef enum _WLAN_802_11_NETWORK_TYPE
+{
+ Wlan802_11FH,
+ Wlan802_11DS,
+ /* Defined as upper bound */
+ Wlan802_11NetworkTypeMax
+} WLAN_802_11_NETWORK_TYPE;
+
+/** Maximum size of IEEE Information Elements */
+#define IEEE_MAX_IE_SIZE 256
+
+#ifdef BIG_ENDIAN_SUPPORT
+/** Frame control: Type Mgmt frame */
+#define IEEE80211_FC_MGMT_FRAME_TYPE_MASK 0x3000
+/** Frame control: SubType Mgmt frame */
+#define IEEE80211_GET_FC_MGMT_FRAME_SUBTYPE(fc) (((fc) & 0xF000) >> 12)
+#else
+/** Frame control: Type Mgmt frame */
+#define IEEE80211_FC_MGMT_FRAME_TYPE_MASK 0x000C
+/** Frame control: SubType Mgmt frame */
+#define IEEE80211_GET_FC_MGMT_FRAME_SUBTYPE(fc) (((fc) & 0x00F0) >> 4)
+#endif
+
+#ifdef PRAGMA_PACK
+#pragma pack(push, 1)
+#endif
+
+/** IEEE Type definitions */
+typedef MLAN_PACK_START enum _IEEEtypes_ElementId_e
+{
+ SSID = 0,
+ SUPPORTED_RATES = 1,
+
+ FH_PARAM_SET = 2,
+ DS_PARAM_SET = 3,
+ CF_PARAM_SET = 4,
+
+ IBSS_PARAM_SET = 6,
+
+#ifdef STA_SUPPORT
+ COUNTRY_INFO = 7,
+#endif /* STA_SUPPORT */
+
+ POWER_CONSTRAINT = 32,
+ POWER_CAPABILITY = 33,
+ TPC_REQUEST = 34,
+ TPC_REPORT = 35,
+ SUPPORTED_CHANNELS = 36,
+ CHANNEL_SWITCH_ANN = 37,
+ QUIET = 40,
+ IBSS_DFS = 41,
+ HT_CAPABILITY = 45,
+ HT_OPERATION = 61,
+ BSSCO_2040 = 72,
+ OVERLAPBSSSCANPARAM = 74,
+ EXT_CAPABILITY = 127,
+
+ ERP_INFO = 42,
+
+ EXTENDED_SUPPORTED_RATES = 50,
+
+ VENDOR_SPECIFIC_221 = 221,
+ WMM_IE = VENDOR_SPECIFIC_221,
+
+ WPS_IE = VENDOR_SPECIFIC_221,
+
+ WPA_IE = VENDOR_SPECIFIC_221,
+ RSN_IE = 48,
+ VS_IE = VENDOR_SPECIFIC_221,
+ WAPI_IE = 68,
+} MLAN_PACK_END IEEEtypes_ElementId_e;
+
+/** IEEE IE header */
+typedef MLAN_PACK_START struct _IEEEtypes_Header_t
+{
+ /** Element ID */
+ t_u8 element_id;
+ /** Length */
+ t_u8 len;
+} MLAN_PACK_END IEEEtypes_Header_t, *pIEEEtypes_Header_t;
+
+/** Vendor specific IE header */
+typedef MLAN_PACK_START struct _IEEEtypes_VendorHeader_t
+{
+ /** Element ID */
+ t_u8 element_id;
+ /** Length */
+ t_u8 len;
+ /** OUI */
+ t_u8 oui[3];
+ /** OUI type */
+ t_u8 oui_type;
+ /** OUI subtype */
+ t_u8 oui_subtype;
+ /** Version */
+ t_u8 version;
+} MLAN_PACK_END IEEEtypes_VendorHeader_t, *pIEEEtypes_VendorHeader_t;
+
+/** Vendor specific IE */
+typedef MLAN_PACK_START struct _IEEEtypes_VendorSpecific_t
+{
+ /** Vendor specific IE header */
+ IEEEtypes_VendorHeader_t vend_hdr;
+ /** IE Max - size of previous fields */
+ t_u8 data[IEEE_MAX_IE_SIZE - sizeof(IEEEtypes_VendorHeader_t)];
+}
+MLAN_PACK_END IEEEtypes_VendorSpecific_t, *pIEEEtypes_VendorSpecific_t;
+
+/** IEEE IE */
+typedef MLAN_PACK_START struct _IEEEtypes_Generic_t
+{
+ /** Generic IE header */
+ IEEEtypes_Header_t ieee_hdr;
+ /** IE Max - size of previous fields */
+ t_u8 data[IEEE_MAX_IE_SIZE - sizeof(IEEEtypes_Header_t)];
+}
+MLAN_PACK_END IEEEtypes_Generic_t, *pIEEEtypes_Generic_t;
+
+/** Capability information mask */
+#define CAPINFO_MASK (~(MBIT(15) | MBIT(14) | \
+ MBIT(12) | MBIT(11) | MBIT(9)))
+
+/** Capability Bit Map*/
+#ifdef BIG_ENDIAN_SUPPORT
+typedef MLAN_PACK_START struct _IEEEtypes_CapInfo_t
+{
+ t_u8 rsrvd1:2;
+ t_u8 dsss_ofdm:1;
+ t_u8 rsvrd2:2;
+ t_u8 short_slot_time:1;
+ t_u8 rsrvd3:1;
+ t_u8 spectrum_mgmt:1;
+ t_u8 chan_agility:1;
+ t_u8 pbcc:1;
+ t_u8 short_preamble:1;
+ t_u8 privacy:1;
+ t_u8 cf_poll_rqst:1;
+ t_u8 cf_pollable:1;
+ t_u8 ibss:1;
+ t_u8 ess:1;
+} MLAN_PACK_END IEEEtypes_CapInfo_t, *pIEEEtypes_CapInfo_t;
+#else
+typedef MLAN_PACK_START struct _IEEEtypes_CapInfo_t
+{
+ /** Capability Bit Map : ESS */
+ t_u8 ess:1;
+ /** Capability Bit Map : IBSS */
+ t_u8 ibss:1;
+ /** Capability Bit Map : CF pollable */
+ t_u8 cf_pollable:1;
+ /** Capability Bit Map : CF poll request */
+ t_u8 cf_poll_rqst:1;
+ /** Capability Bit Map : privacy */
+ t_u8 privacy:1;
+ /** Capability Bit Map : Short preamble */
+ t_u8 short_preamble:1;
+ /** Capability Bit Map : PBCC */
+ t_u8 pbcc:1;
+ /** Capability Bit Map : Channel agility */
+ t_u8 chan_agility:1;
+ /** Capability Bit Map : Spectrum management */
+ t_u8 spectrum_mgmt:1;
+ /** Capability Bit Map : Reserved */
+ t_u8 rsrvd3:1;
+ /** Capability Bit Map : Short slot time */
+ t_u8 short_slot_time:1;
+ /** Capability Bit Map : APSD */
+ t_u8 Apsd:1;
+ /** Capability Bit Map : Reserved */
+ t_u8 rsvrd2:1;
+ /** Capability Bit Map : DSS OFDM */
+ t_u8 dsss_ofdm:1;
+ /** Capability Bit Map : Reserved */
+ t_u8 rsrvd1:2;
+} MLAN_PACK_END IEEEtypes_CapInfo_t, *pIEEEtypes_CapInfo_t;
+#endif /* BIG_ENDIAN_SUPPORT */
+
+/** IEEEtypes_CfParamSet_t */
+typedef MLAN_PACK_START struct _IEEEtypes_CfParamSet_t
+{
+ /** CF peremeter : Element ID */
+ t_u8 element_id;
+ /** CF peremeter : Length */
+ t_u8 len;
+ /** CF peremeter : Count */
+ t_u8 cfp_cnt;
+ /** CF peremeter : Period */
+ t_u8 cfp_period;
+ /** CF peremeter : Maximum duration */
+ t_u16 cfp_max_duration;
+ /** CF peremeter : Remaining duration */
+ t_u16 cfp_duration_remaining;
+} MLAN_PACK_END IEEEtypes_CfParamSet_t, *pIEEEtypes_CfParamSet_t;
+
+/** IEEEtypes_IbssParamSet_t */
+typedef MLAN_PACK_START struct _IEEEtypes_IbssParamSet_t
+{
+ /** Element ID */
+ t_u8 element_id;
+ /** Length */
+ t_u8 len;
+ /** ATIM window value in milliseconds */
+ t_u16 atim_window;
+} MLAN_PACK_END IEEEtypes_IbssParamSet_t, *pIEEEtypes_IbssParamSet_t;
+
+/** IEEEtypes_SsParamSet_t */
+typedef MLAN_PACK_START union _IEEEtypes_SsParamSet_t
+{
+ /** SS parameter : CF parameter set */
+ IEEEtypes_CfParamSet_t cf_param_set;
+ /** SS parameter : IBSS parameter set */
+ IEEEtypes_IbssParamSet_t ibss_param_set;
+} MLAN_PACK_END IEEEtypes_SsParamSet_t, *pIEEEtypes_SsParamSet_t;
+
+/** IEEEtypes_FhParamSet_t */
+typedef MLAN_PACK_START struct _IEEEtypes_FhParamSet_t
+{
+ /** FH parameter : Element ID */
+ t_u8 element_id;
+ /** FH parameter : Length */
+ t_u8 len;
+ /** FH parameter : Dwell time in milliseconds */
+ t_u16 dwell_time;
+ /** FH parameter : Hop set */
+ t_u8 hop_set;
+ /** FH parameter : Hop pattern */
+ t_u8 hop_pattern;
+ /** FH parameter : Hop index */
+ t_u8 hop_index;
+} MLAN_PACK_END IEEEtypes_FhParamSet_t, *pIEEEtypes_FhParamSet_t;
+
+/** IEEEtypes_DsParamSet_t */
+typedef MLAN_PACK_START struct _IEEEtypes_DsParamSet_t
+{
+ /** DS parameter : Element ID */
+ t_u8 element_id;
+ /** DS parameter : Length */
+ t_u8 len;
+ /** DS parameter : Current channel */
+ t_u8 current_chan;
+} MLAN_PACK_END IEEEtypes_DsParamSet_t, *pIEEEtypes_DsParamSet_t;
+
+/** IEEEtypes_PhyParamSet_t */
+typedef MLAN_PACK_START union _IEEEtypes_PhyParamSet_t
+{
+ /** FH parameter set */
+ IEEEtypes_FhParamSet_t fh_param_set;
+ /** DS parameter set */
+ IEEEtypes_DsParamSet_t ds_param_set;
+} MLAN_PACK_END IEEEtypes_PhyParamSet_t, *pIEEEtypes_PhyParamSet_t;
+
+/** IEEEtypes_ERPInfo_t */
+typedef MLAN_PACK_START struct _IEEEtypes_ERPInfo_t
+{
+ /** Element ID */
+ t_u8 element_id;
+ /** Length */
+ t_u8 len;
+ /** ERP flags */
+ t_u8 erp_flags;
+} MLAN_PACK_END IEEEtypes_ERPInfo_t, *pIEEEtypes_ERPInfo_t;
+
+/** IEEEtypes_AId_t */
+typedef t_u16 IEEEtypes_AId_t;
+
+/** IEEEtypes_StatusCode_t */
+typedef t_u16 IEEEtypes_StatusCode_t;
+
+/** IEEEtypes_AssocRsp_t */
+typedef MLAN_PACK_START struct _IEEEtypes_AssocRsp_t
+{
+ /** Capability information */
+ IEEEtypes_CapInfo_t capability;
+ /** Association response status code */
+ IEEEtypes_StatusCode_t status_code;
+ /** Association ID */
+ IEEEtypes_AId_t a_id;
+ /** IE data buffer */
+ t_u8 ie_buffer[1];
+} MLAN_PACK_END IEEEtypes_AssocRsp_t, *pIEEEtypes_AssocRsp_t;
+
+/** 802.11 supported rates */
+typedef t_u8 WLAN_802_11_RATES[WLAN_SUPPORTED_RATES];
+
+/** cipher TKIP */
+#define WPA_CIPHER_TKIP 2
+/** cipher AES */
+#define WPA_CIPHER_AES_CCM 4
+/** AKM: 8021x */
+#define RSN_AKM_8021X 1
+/** AKM: PSK */
+#define RSN_AKM_PSK 2
+
+/** wpa_suite_t */
+typedef MLAN_PACK_START struct _wpa_suite_t
+{
+ /** OUI */
+ t_u8 oui[3];
+ /** tyep */
+ t_u8 type;
+} MLAN_PACK_END wpa_suite, wpa_suite_mcast_t;
+
+/** wpa_suite_ucast_t */
+typedef MLAN_PACK_START struct
+{
+ /* count */
+ t_u16 count;
+ /** wpa_suite list */
+ wpa_suite list[1];
+} MLAN_PACK_END wpa_suite_ucast_t, wpa_suite_auth_key_mgmt_t;
+
+/** IEEEtypes_Rsn_t */
+typedef MLAN_PACK_START struct _IEEEtypes_Rsn_t
+{
+ /** Rsn : Element ID */
+ t_u8 element_id;
+ /** Rsn : Length */
+ t_u8 len;
+ /** Rsn : version */
+ t_u16 version;
+ /** Rsn : group cipher */
+ wpa_suite_mcast_t group_cipher;
+ /** Rsn : pairwise cipher */
+ wpa_suite_ucast_t pairwise_cipher;
+} MLAN_PACK_END IEEEtypes_Rsn_t, *pIEEEtypes_Rsn_t;
+
+/** IEEEtypes_Wpa_t */
+typedef MLAN_PACK_START struct _IEEEtypes_Wpa_t
+{
+ /** Wpa : Element ID */
+ t_u8 element_id;
+ /** Wpa : Length */
+ t_u8 len;
+ /** Wpa : oui */
+ t_u8 oui[4];
+ /** version */
+ t_u16 version;
+ /** Wpa : group cipher */
+ wpa_suite_mcast_t group_cipher;
+ /** Wpa : pairwise cipher */
+ wpa_suite_ucast_t pairwise_cipher;
+} MLAN_PACK_END IEEEtypes_Wpa_t, *pIEEEtypes_Wpa_t;
+
+/** Maximum number of AC QOS queues available in the driver/firmware */
+#define MAX_AC_QUEUES 4
+
+/** Data structure of WMM QoS information */
+typedef MLAN_PACK_START struct _IEEEtypes_WmmQosInfo_t
+{
+#ifdef BIG_ENDIAN_SUPPORT
+ /** QoS UAPSD */
+ t_u8 qos_uapsd:1;
+ /** Reserved */
+ t_u8 reserved:3;
+ /** Parameter set count */
+ t_u8 para_set_count:4;
+#else
+ /** Parameter set count */
+ t_u8 para_set_count:4;
+ /** Reserved */
+ t_u8 reserved:3;
+ /** QoS UAPSD */
+ t_u8 qos_uapsd:1;
+#endif /* BIG_ENDIAN_SUPPORT */
+} MLAN_PACK_END IEEEtypes_WmmQosInfo_t, *pIEEEtypes_WmmQosInfo_t;
+
+/** Data structure of WMM Aci/Aifsn */
+typedef MLAN_PACK_START struct _IEEEtypes_WmmAciAifsn_t
+{
+#ifdef BIG_ENDIAN_SUPPORT
+ /** Reserved */
+ t_u8 reserved:1;
+ /** Aci */
+ t_u8 aci:2;
+ /** Acm */
+ t_u8 acm:1;
+ /** Aifsn */
+ t_u8 aifsn:4;
+#else
+ /** Aifsn */
+ t_u8 aifsn:4;
+ /** Acm */
+ t_u8 acm:1;
+ /** Aci */
+ t_u8 aci:2;
+ /** Reserved */
+ t_u8 reserved:1;
+#endif /* BIG_ENDIAN_SUPPORT */
+} MLAN_PACK_END IEEEtypes_WmmAciAifsn_t, *pIEEEtypes_WmmAciAifsn_t;
+
+/** Data structure of WMM ECW */
+typedef MLAN_PACK_START struct _IEEEtypes_WmmEcw_t
+{
+#ifdef BIG_ENDIAN_SUPPORT
+ /** Maximum Ecw */
+ t_u8 ecw_max:4;
+ /** Minimum Ecw */
+ t_u8 ecw_min:4;
+#else
+ /** Minimum Ecw */
+ t_u8 ecw_min:4;
+ /** Maximum Ecw */
+ t_u8 ecw_max:4;
+#endif /* BIG_ENDIAN_SUPPORT */
+} MLAN_PACK_END IEEEtypes_WmmEcw_t, *pIEEEtypes_WmmEcw_t;
+
+/** Data structure of WMM AC parameters */
+typedef MLAN_PACK_START struct _IEEEtypes_WmmAcParameters_t
+{
+ IEEEtypes_WmmAciAifsn_t aci_aifsn; /**< AciAifSn */
+ IEEEtypes_WmmEcw_t ecw; /**< Ecw */
+ t_u16 tx_op_limit; /**< Tx op limit */
+} MLAN_PACK_END IEEEtypes_WmmAcParameters_t, *pIEEEtypes_WmmAcParameters_t;
+
+/** Data structure of WMM Info IE */
+typedef MLAN_PACK_START struct _IEEEtypes_WmmInfo_t
+{
+
+ /**
+ * WMM Info IE - Vendor Specific Header:
+ * element_id [221/0xdd]
+ * Len [7]
+ * Oui [00:50:f2]
+ * OuiType [2]
+ * OuiSubType [0]
+ * Version [1]
+ */
+ IEEEtypes_VendorHeader_t vend_hdr;
+
+ /** QoS information */
+ IEEEtypes_WmmQosInfo_t qos_info;
+
+} MLAN_PACK_END IEEEtypes_WmmInfo_t, *pIEEEtypes_WmmInfo_t;
+
+/** Data structure of WMM parameter IE */
+typedef MLAN_PACK_START struct _IEEEtypes_WmmParameter_t
+{
+ /**
+ * WMM Parameter IE - Vendor Specific Header:
+ * element_id [221/0xdd]
+ * Len [24]
+ * Oui [00:50:f2]
+ * OuiType [2]
+ * OuiSubType [1]
+ * Version [1]
+ */
+ IEEEtypes_VendorHeader_t vend_hdr;
+
+ /** QoS information */
+ IEEEtypes_WmmQosInfo_t qos_info;
+ /** Reserved */
+ t_u8 reserved;
+
+ /** AC Parameters Record WMM_AC_BE, WMM_AC_BK, WMM_AC_VI, WMM_AC_VO */
+ IEEEtypes_WmmAcParameters_t ac_params[MAX_AC_QUEUES];
+} MLAN_PACK_END IEEEtypes_WmmParameter_t, *pIEEEtypes_WmmParameter_t;
+
+/** Enumerator for TSPEC direction */
+typedef MLAN_PACK_START enum _IEEEtypes_WMM_TSPEC_TS_Info_Direction_e
+{
+
+ TSPEC_DIR_UPLINK = 0,
+ TSPEC_DIR_DOWNLINK = 1,
+ /* 2 is a reserved value */
+ TSPEC_DIR_BIDIRECT = 3,
+
+} MLAN_PACK_END IEEEtypes_WMM_TSPEC_TS_Info_Direction_e;
+
+/** Enumerator for TSPEC PSB */
+typedef MLAN_PACK_START enum _IEEEtypes_WMM_TSPEC_TS_Info_PSB_e
+{
+
+ TSPEC_PSB_LEGACY = 0,
+ TSPEC_PSB_TRIG = 1,
+
+} MLAN_PACK_END IEEEtypes_WMM_TSPEC_TS_Info_PSB_e;
+
+/** Enumerator for TSPEC Ack Policy */
+typedef MLAN_PACK_START enum _IEEEtypes_WMM_TSPEC_TS_Info_AckPolicy_e
+{
+
+ TSPEC_ACKPOLICY_NORMAL = 0,
+ TSPEC_ACKPOLICY_NOACK = 1,
+ /* 2 is reserved */
+ TSPEC_ACKPOLICY_BLOCKACK = 3,
+
+} MLAN_PACK_END IEEEtypes_WMM_TSPEC_TS_Info_AckPolicy_e;
+
+/** Enumerator for TSPEC Trafffice type */
+typedef MLAN_PACK_START enum _IEEEtypes_WMM_TSPEC_TS_TRAFFIC_TYPE_e
+{
+
+ TSPEC_TRAFFIC_APERIODIC = 0,
+ TSPEC_TRAFFIC_PERIODIC = 1,
+
+} MLAN_PACK_END IEEEtypes_WMM_TSPEC_TS_TRAFFIC_TYPE_e;
+
+/** Data structure of WMM TSPEC information */
+typedef MLAN_PACK_START struct
+{
+#ifdef BIG_ENDIAN_SUPPORT
+ t_u8 Reserved17_23:7; // ! Reserved
+ t_u8 Schedule:1;
+ IEEEtypes_WMM_TSPEC_TS_Info_AckPolicy_e AckPolicy:2;
+ t_u8 UserPri:3; // ! 802.1d User Priority
+ IEEEtypes_WMM_TSPEC_TS_Info_PSB_e PowerSaveBehavior:1; // !
+ // Legacy/Trigg
+ t_u8 Aggregation:1; // ! Reserved
+ t_u8 AccessPolicy2:1; // !
+ t_u8 AccessPolicy1:1; // !
+ IEEEtypes_WMM_TSPEC_TS_Info_Direction_e Direction:2;
+ t_u8 TID:4; // ! Unique identifier
+ IEEEtypes_WMM_TSPEC_TS_TRAFFIC_TYPE_e TrafficType:1;
+#else
+ IEEEtypes_WMM_TSPEC_TS_TRAFFIC_TYPE_e TrafficType:1;
+ t_u8 TID:4; // ! Unique identifier
+ IEEEtypes_WMM_TSPEC_TS_Info_Direction_e Direction:2;
+ t_u8 AccessPolicy1:1; // !
+ t_u8 AccessPolicy2:1; // !
+ t_u8 Aggregation:1; // ! Reserved
+ IEEEtypes_WMM_TSPEC_TS_Info_PSB_e PowerSaveBehavior:1; // !
+ // Legacy/Trigg
+ t_u8 UserPri:3; // ! 802.1d User Priority
+ IEEEtypes_WMM_TSPEC_TS_Info_AckPolicy_e AckPolicy:2;
+ t_u8 Schedule:1;
+ t_u8 Reserved17_23:7; // ! Reserved
+#endif
+} MLAN_PACK_END IEEEtypes_WMM_TSPEC_TS_Info_t;
+
+/** Data structure of WMM TSPEC Nominal Size */
+typedef MLAN_PACK_START struct
+{
+#ifdef BIG_ENDIAN_SUPPORT
+ t_u16 Fixed:1; // ! 1: Fixed size given in Size, 0: Var, size
+ // is nominal
+ t_u16 Size:15; // ! Nominal size in octets
+#else
+ t_u16 Size:15; // ! Nominal size in octets
+ t_u16 Fixed:1; // ! 1: Fixed size given in Size, 0: Var, size
+ // is nominal
+#endif
+} MLAN_PACK_END IEEEtypes_WMM_TSPEC_NomMSDUSize_t;
+
+/** Data structure of WMM TSPEC SBWA */
+typedef MLAN_PACK_START struct
+{
+#ifdef BIG_ENDIAN_SUPPORT
+ t_u16 Whole:3; // ! Whole portion
+ t_u16 Fractional:13; // ! Fractional portion
+#else
+ t_u16 Fractional:13; // ! Fractional portion
+ t_u16 Whole:3; // ! Whole portion
+#endif
+} MLAN_PACK_END IEEEtypes_WMM_TSPEC_SBWA;
+
+/** Data structure of WMM TSPEC Body */
+typedef MLAN_PACK_START struct
+{
+
+ IEEEtypes_WMM_TSPEC_TS_Info_t TSInfo;
+ IEEEtypes_WMM_TSPEC_NomMSDUSize_t NomMSDUSize;
+ t_u16 MaximumMSDUSize;
+ t_u32 MinServiceInterval;
+ t_u32 MaxServiceInterval;
+ t_u32 InactivityInterval;
+ t_u32 SuspensionInterval;
+ t_u32 ServiceStartTime;
+ t_u32 MinimumDataRate;
+ t_u32 MeanDataRate;
+ t_u32 PeakDataRate;
+ t_u32 MaxBurstSize;
+ t_u32 DelayBound;
+ t_u32 MinPHYRate;
+ IEEEtypes_WMM_TSPEC_SBWA SurplusBWAllowance;
+ t_u16 MediumTime;
+} MLAN_PACK_END IEEEtypes_WMM_TSPEC_Body_t;
+
+/** Data structure of WMM TSPEC all elements */
+typedef MLAN_PACK_START struct
+{
+ t_u8 ElementId;
+ t_u8 Len;
+ t_u8 OuiType[4]; /* 00:50:f2:02 */
+ t_u8 OuiSubType; /* 01 */
+ t_u8 Version;
+
+ IEEEtypes_WMM_TSPEC_Body_t TspecBody;
+
+} MLAN_PACK_END IEEEtypes_WMM_TSPEC_t;
+
+/** WMM Action Category values */
+typedef MLAN_PACK_START enum _IEEEtypes_ActionCategory_e
+{
+
+ IEEE_MGMT_ACTION_CATEGORY_SPECTRUM_MGMT = 0,
+ IEEE_MGMT_ACTION_CATEGORY_QOS = 1,
+ IEEE_MGMT_ACTION_CATEGORY_DLS = 2,
+ IEEE_MGMT_ACTION_CATEGORY_BLOCK_ACK = 3,
+ IEEE_MGMT_ACTION_CATEGORY_PUBLIC = 4,
+ IEEE_MGMT_ACTION_CATEGORY_RADIO_RSRC = 5,
+ IEEE_MGMT_ACTION_CATEGORY_FAST_BSS_TRANS = 6,
+ IEEE_MGMT_ACTION_CATEGORY_HT = 7,
+
+ IEEE_MGMT_ACTION_CATEGORY_WNM = 10,
+ IEEE_MGMT_ACTION_CATEGORY_UNPROTECT_WNM = 11,
+
+ IEEE_MGMT_ACTION_CATEGORY_WMM_TSPEC = 17
+} MLAN_PACK_END IEEEtypes_ActionCategory_e;
+
+/** WMM TSPEC operations */
+typedef MLAN_PACK_START enum _IEEEtypes_WMM_Tspec_Action_e
+{
+
+ TSPEC_ACTION_CODE_ADDTS_REQ = 0,
+ TSPEC_ACTION_CODE_ADDTS_RSP = 1,
+ TSPEC_ACTION_CODE_DELTS = 2,
+
+} MLAN_PACK_END IEEEtypes_WMM_Tspec_Action_e;
+
+/** WMM TSPEC Category Action Base */
+typedef MLAN_PACK_START struct
+{
+
+ IEEEtypes_ActionCategory_e category;
+ IEEEtypes_WMM_Tspec_Action_e action;
+ t_u8 dialogToken;
+
+} MLAN_PACK_END IEEEtypes_WMM_Tspec_Action_Base_Tspec_t;
+
+/** WMM TSPEC AddTS request structure */
+typedef MLAN_PACK_START struct
+{
+
+ IEEEtypes_WMM_Tspec_Action_Base_Tspec_t tspecAct;
+ t_u8 statusCode;
+ IEEEtypes_WMM_TSPEC_t tspecIE;
+
+ /* Place holder for additional elements after the TSPEC */
+ t_u8 subElem[256];
+
+} MLAN_PACK_END IEEEtypes_Action_WMM_AddTsReq_t;
+
+/** WMM TSPEC AddTS response structure */
+typedef MLAN_PACK_START struct
+{
+ IEEEtypes_WMM_Tspec_Action_Base_Tspec_t tspecAct;
+ t_u8 statusCode;
+ IEEEtypes_WMM_TSPEC_t tspecIE;
+
+ /* Place holder for additional elements after the TSPEC */
+ t_u8 subElem[256];
+
+} MLAN_PACK_END IEEEtypes_Action_WMM_AddTsRsp_t;
+
+/** WMM TSPEC DelTS structure */
+typedef MLAN_PACK_START struct
+{
+ IEEEtypes_WMM_Tspec_Action_Base_Tspec_t tspecAct;
+ t_u8 reasonCode;
+ IEEEtypes_WMM_TSPEC_t tspecIE;
+
+} MLAN_PACK_END IEEEtypes_Action_WMM_DelTs_t;
+
+/** union of WMM TSPEC structures */
+typedef MLAN_PACK_START union
+{
+ IEEEtypes_WMM_Tspec_Action_Base_Tspec_t tspecAct;
+
+ IEEEtypes_Action_WMM_AddTsReq_t addTsReq;
+ IEEEtypes_Action_WMM_AddTsRsp_t addTsRsp;
+ IEEEtypes_Action_WMM_DelTs_t delTs;
+
+} MLAN_PACK_END IEEEtypes_Action_WMMAC_t;
+
+/** union of WMM TSPEC & Action category */
+typedef MLAN_PACK_START union
+{
+ IEEEtypes_ActionCategory_e category;
+
+ IEEEtypes_Action_WMMAC_t wmmAc;
+
+} MLAN_PACK_END IEEEtypes_ActionFrame_t;
+
+/** Data structure for subband set */
+typedef MLAN_PACK_START struct _IEEEtypes_SubbandSet_t
+{
+ /** First channel */
+ t_u8 first_chan;
+ /** Number of channels */
+ t_u8 no_of_chan;
+ /** Maximum Tx power in dBm */
+ t_u8 max_tx_pwr;
+} MLAN_PACK_END IEEEtypes_SubbandSet_t, *pIEEEtypes_SubbandSet_t;
+
+#ifdef STA_SUPPORT
+/** Data structure for Country IE */
+typedef MLAN_PACK_START struct _IEEEtypes_CountryInfoSet_t
+{
+ /** Element ID */
+ t_u8 element_id;
+ /** Length */
+ t_u8 len;
+ /** Country code */
+ t_u8 country_code[COUNTRY_CODE_LEN];
+ /** Set of subbands */
+ IEEEtypes_SubbandSet_t sub_band[1];
+} MLAN_PACK_END IEEEtypes_CountryInfoSet_t, *pIEEEtypes_CountryInfoSet_t;
+
+/** Data structure for Country IE full set */
+typedef MLAN_PACK_START struct _IEEEtypes_CountryInfoFullSet_t
+{
+ /** Element ID */
+ t_u8 element_id;
+ /** Length */
+ t_u8 len;
+ /** Country code */
+ t_u8 country_code[COUNTRY_CODE_LEN];
+ /** Set of subbands */
+ IEEEtypes_SubbandSet_t sub_band[MRVDRV_MAX_SUBBAND_802_11D];
+} MLAN_PACK_END IEEEtypes_CountryInfoFullSet_t,
+ *pIEEEtypes_CountryInfoFullSet_t;
+
+#endif /* STA_SUPPORT */
+
+/** HT Capabilities Data */
+typedef struct MLAN_PACK_START _HTCap_t
+{
+ /** HT Capabilities Info field */
+ t_u16 ht_cap_info;
+ /** A-MPDU Parameters field */
+ t_u8 ampdu_param;
+ /** Supported MCS Set field */
+ t_u8 supported_mcs_set[16];
+ /** HT Extended Capabilities field */
+ t_u16 ht_ext_cap;
+ /** Transmit Beamforming Capabilities field */
+ t_u32 tx_bf_cap;
+ /** Antenna Selection Capability field */
+ t_u8 asel;
+} MLAN_PACK_END HTCap_t, *pHTCap_t;
+
+/** HT Information Data */
+typedef struct MLAN_PACK_START _HTInfo_t
+{
+ /** Primary channel */
+ t_u8 pri_chan;
+ /** Field 2 */
+ t_u8 field2;
+ /** Field 3 */
+ t_u16 field3;
+ /** Field 4 */
+ t_u16 field4;
+ /** Bitmap indicating MCSs supported by all HT STAs in the BSS */
+ t_u8 basic_mcs_set[16];
+} MLAN_PACK_END HTInfo_t, *pHTInfo_t;
+
+/** 20/40 BSS Coexistence Data */
+typedef struct MLAN_PACK_START _BSSCo2040_t
+{
+ /** 20/40 BSS Coexistence value */
+ t_u8 bss_co_2040_value;
+} MLAN_PACK_END BSSCo2040_t, *pBSSCo2040_t;
+
+/** Extended Capabilities Data */
+typedef struct MLAN_PACK_START _ExtCap_t
+{
+ /** Extended Capabilities value */
+ t_u8 ext_cap_value;
+} MLAN_PACK_END ExtCap_t, *pExtCap_t;
+
+/** Overlapping BSS Scan Parameters Data */
+typedef struct MLAN_PACK_START _OverlapBSSScanParam_t
+{
+ /** OBSS Scan Passive Dwell in milliseconds */
+ t_u16 obss_scan_passive_dwell;
+ /** OBSS Scan Active Dwell in milliseconds */
+ t_u16 obss_scan_active_dwell;
+ /** BSS Channel Width Trigger Scan Interval in seconds */
+ t_u16 bss_chan_width_trigger_scan_int;
+ /** OBSS Scan Passive Total Per Channel */
+ t_u16 obss_scan_passive_total;
+ /** OBSS Scan Active Total Per Channel */
+ t_u16 obss_scan_active_total;
+ /** BSS Width Channel Transition Delay Factor */
+ t_u16 bss_width_chan_trans_delay;
+ /** OBSS Scan Activity Threshold */
+ t_u16 obss_scan_active_threshold;
+} MLAN_PACK_END OBSSScanParam_t, *pOBSSScanParam_t;
+
+/** HT Capabilities IE */
+typedef MLAN_PACK_START struct _IEEEtypes_HTCap_t
+{
+ /** Generic IE header */
+ IEEEtypes_Header_t ieee_hdr;
+ /** HTCap struct */
+ HTCap_t ht_cap;
+} MLAN_PACK_END IEEEtypes_HTCap_t, *pIEEEtypes_HTCap_t;
+
+/** HT Information IE */
+typedef MLAN_PACK_START struct _IEEEtypes_HTInfo_t
+{
+ /** Generic IE header */
+ IEEEtypes_Header_t ieee_hdr;
+ /** HTInfo struct */
+ HTInfo_t ht_info;
+} MLAN_PACK_END IEEEtypes_HTInfo_t, *pIEEEtypes_HTInfo_t;
+
+/** 20/40 BSS Coexistence IE */
+typedef MLAN_PACK_START struct _IEEEtypes_2040BSSCo_t
+{
+ /** Generic IE header */
+ IEEEtypes_Header_t ieee_hdr;
+ /** BSSCo2040_t struct */
+ BSSCo2040_t bss_co_2040;
+} MLAN_PACK_END IEEEtypes_2040BSSCo_t, *pIEEEtypes_2040BSSCo_t;
+
+/** Extended Capabilities IE */
+typedef MLAN_PACK_START struct _IEEEtypes_ExtCap_t
+{
+ /** Generic IE header */
+ IEEEtypes_Header_t ieee_hdr;
+ /** ExtCap_t struct */
+ ExtCap_t ext_cap;
+} MLAN_PACK_END IEEEtypes_ExtCap_t, *pIEEEtypes_ExtCap_t;
+
+/** Overlapping BSS Scan Parameters IE */
+typedef MLAN_PACK_START struct _IEEEtypes_OverlapBSSScanParam_t
+{
+ /** Generic IE header */
+ IEEEtypes_Header_t ieee_hdr;
+ /** OBSSScanParam_t struct */
+ OBSSScanParam_t obss_scan_param;
+} MLAN_PACK_END IEEEtypes_OverlapBSSScanParam_t,
+ *pIEEEtypes_OverlapBSSScanParam_t;
+
+/** Maximum number of subbands in the IEEEtypes_SupportedChannels_t structure */
+#define WLAN_11H_MAX_SUBBANDS 5
+
+/** Maximum number of DFS channels configured in IEEEtypes_IBSS_DFS_t */
+#define WLAN_11H_MAX_IBSS_DFS_CHANNELS 25
+
+/** IEEE Power Constraint element (7.3.2.15) */
+typedef MLAN_PACK_START struct
+{
+ t_u8 element_id; /**< IEEE Element ID = 32 */
+ t_u8 len; /**< Element length after id and len */
+ t_u8 local_constraint; /**< Local power constraint applied to 11d chan info */
+} MLAN_PACK_END IEEEtypes_PowerConstraint_t;
+
+/** IEEE Power Capability element (7.3.2.16) */
+typedef MLAN_PACK_START struct
+{
+ t_u8 element_id; /**< IEEE Element ID = 33 */
+ t_u8 len; /**< Element length after id and len */
+ t_s8 min_tx_power_capability; /**< Minimum Transmit power (dBm) */
+ t_s8 max_tx_power_capability; /**< Maximum Transmit power (dBm) */
+} MLAN_PACK_END IEEEtypes_PowerCapability_t;
+
+/** IEEE TPC Report element (7.3.2.18) */
+typedef MLAN_PACK_START struct
+{
+ t_u8 element_id; /**< IEEE Element ID = 35 */
+ t_u8 len; /**< Element length after id and len */
+ t_s8 tx_power; /**< Max power used to transmit the TPC Report frame (dBm) */
+ t_s8 link_margin; /**< Link margin when TPC Request received (dB) */
+} MLAN_PACK_END IEEEtypes_TPCReport_t;
+
+/* IEEE Supported Channel sub-band description (7.3.2.19) */
+/**
+ * Sub-band description used in the supported channels element.
+ */
+typedef MLAN_PACK_START struct
+{
+ t_u8 start_chan; /**< Starting channel in the subband */
+ t_u8 num_chans; /**< Number of channels in the subband */
+
+} MLAN_PACK_END IEEEtypes_SupportChan_Subband_t;
+
+/* IEEE Supported Channel element (7.3.2.19) */
+/**
+ * Sent in association requests. Details the sub-bands and number
+ * of channels supported in each subband
+ */
+typedef MLAN_PACK_START struct
+{
+ t_u8 element_id; /**< IEEE Element ID = 36 */
+ t_u8 len; /**< Element length after id and len */
+
+ /** Configured sub-bands information in the element */
+ IEEEtypes_SupportChan_Subband_t subband[WLAN_11H_MAX_SUBBANDS];
+
+} MLAN_PACK_END IEEEtypes_SupportedChannels_t;
+
+/* IEEE Channel Switch Announcement Element (7.3.2.20) */
+/**
+ * Provided in beacons and probe responses. Used to advertise when
+ * and to which channel it is changing to. Only starting STAs in
+ * an IBSS and APs are allowed to originate a chan switch element.
+ */
+typedef MLAN_PACK_START struct
+{
+ t_u8 element_id; /**< IEEE Element ID = 37 */
+ t_u8 len; /**< Element length after id and len */
+ t_u8 chan_switch_mode; /**< STA should not transmit any frames if 1 */
+ t_u8 new_channel_num; /**< Channel # that AP/IBSS is moving to */
+ t_u8 chan_switch_count; /**< # of TBTTs before channel switch */
+
+} MLAN_PACK_END IEEEtypes_ChanSwitchAnn_t;
+
+/* IEEE Quiet Period Element (7.3.2.23) */
+/**
+ * Provided in beacons and probe responses. Indicates times during
+ * which the STA should not be transmitting data. Only starting STAs in
+ * an IBSS and APs are allowed to originate a quiet element.
+ */
+typedef MLAN_PACK_START struct
+{
+ t_u8 element_id; /**< IEEE Element ID = 40 */
+ t_u8 len; /**< Element length after id and len */
+ t_u8 quiet_count; /**< Number of TBTTs until beacon with the quiet period */
+ t_u8 quiet_period; /**< Regular quiet period, # of TBTTS between periods */
+ t_u16 quiet_duration; /**< Duration of the quiet period in TUs */
+ t_u16 quiet_offset; /**< Offset in TUs from the TBTT for the quiet period */
+
+} MLAN_PACK_END IEEEtypes_Quiet_t;
+
+/**
+*** @brief Map octet of the basic measurement report (7.3.2.22.1)
+**/
+typedef MLAN_PACK_START struct
+{
+#ifdef BIG_ENDIAN_SUPPORT
+ t_u8 rsvd5_7:3; /**< Reserved */
+ t_u8 unmeasured:1; /**< Channel is unmeasured */
+ t_u8 radar:1; /**< Radar detected on channel */
+ t_u8 unidentified_sig:1; /**< Unidentified signal found on channel */
+ t_u8 ofdm_preamble:1; /**< OFDM preamble detected on channel */
+ t_u8 bss:1; /**< At least one valid MPDU received on channel */
+#else
+ t_u8 bss:1; /**< At least one valid MPDU received on channel */
+ t_u8 ofdm_preamble:1; /**< OFDM preamble detected on channel */
+ t_u8 unidentified_sig:1; /**< Unidentified signal found on channel */
+ t_u8 radar:1; /**< Radar detected on channel */
+ t_u8 unmeasured:1; /**< Channel is unmeasured */
+ t_u8 rsvd5_7:3; /**< Reserved */
+#endif /* BIG_ENDIAN_SUPPORT */
+
+} MLAN_PACK_END MeasRptBasicMap_t;
+
+/* IEEE DFS Channel Map field (7.3.2.24) */
+/**
+ * Used to list supported channels and provide a octet "map" field which
+ * contains a basic measurement report for that channel in the
+ * IEEEtypes_IBSS_DFS_t element
+ */
+typedef MLAN_PACK_START struct
+{
+ t_u8 channel_number; /**< Channel number */
+ MeasRptBasicMap_t rpt_map; /**< Basic measurement report for the channel */
+
+} MLAN_PACK_END IEEEtypes_ChannelMap_t;
+
+/* IEEE IBSS DFS Element (7.3.2.24) */
+/**
+ * IBSS DFS element included in ad hoc beacons and probe responses.
+ * Provides information regarding the IBSS DFS Owner as well as the
+ * originating STAs supported channels and basic measurement results.
+ */
+typedef MLAN_PACK_START struct
+{
+ t_u8 element_id; /**< IEEE Element ID = 41 */
+ t_u8 len; /**< Element length after id and len */
+ t_u8 dfs_owner[MLAN_MAC_ADDR_LENGTH]; /**< DFS Owner STA Address */
+ t_u8 dfs_recovery_interval; /**< DFS Recovery time in TBTTs */
+
+ /** Variable length map field, one Map entry for each supported channel */
+ IEEEtypes_ChannelMap_t channel_map[WLAN_11H_MAX_IBSS_DFS_CHANNELS];
+
+} MLAN_PACK_END IEEEtypes_IBSS_DFS_t;
+
+/* 802.11h BSS information kept for each BSSID received in scan results */
+/**
+ * IEEE BSS information needed from scan results for later processing in
+ * join commands
+ */
+typedef struct
+{
+ t_u8 sensed_11h; /**< Capability bit set or 11h IE found in this BSS */
+
+ IEEEtypes_PowerConstraint_t power_constraint; /**< Power Constraint IE */
+ IEEEtypes_PowerCapability_t power_capability; /**< Power Capability IE */
+ IEEEtypes_TPCReport_t tpc_report; /**< TPC Report IE */
+ IEEEtypes_ChanSwitchAnn_t chan_switch_ann; /**< Channel Switch Announcement IE */
+ IEEEtypes_Quiet_t quiet; /**< Quiet IE */
+ IEEEtypes_IBSS_DFS_t ibss_dfs; /**< IBSS DFS Element IE */
+
+} wlan_11h_bss_info_t;
+
+#ifdef STA_SUPPORT
+/** Macro for maximum size of scan response buffer */
+#define MAX_SCAN_RSP_BUF (16 * 1024)
+
+/** Maximum number of channels that can be sent in user scan config */
+#define WLAN_USER_SCAN_CHAN_MAX 50
+
+/** Maximum length of SSID list */
+#define MRVDRV_MAX_SSID_LIST_LENGTH 10
+
+/** Scan all the channels in specified band */
+#define BAND_SPECIFIED 0x80
+
+/**
+ * IOCTL SSID List sub-structure sent in wlan_ioctl_user_scan_cfg
+ *
+ * Used to specify SSID specific filters as well as SSID pattern matching
+ * filters for scan result processing in firmware.
+ */
+typedef MLAN_PACK_START struct _wlan_user_scan_ssid
+{
+ /** SSID */
+ t_u8 ssid[MLAN_MAX_SSID_LENGTH + 1];
+ /** Maximum length of SSID */
+ t_u8 max_len;
+} MLAN_PACK_END wlan_user_scan_ssid;
+
+/**
+ * @brief IOCTL channel sub-structure sent in wlan_ioctl_user_scan_cfg
+ *
+ * Multiple instances of this structure are included in the IOCTL command
+ * to configure a instance of a scan on the specific channel.
+ */
+typedef MLAN_PACK_START struct _wlan_user_scan_chan
+{
+ /** Channel Number to scan */
+ t_u8 chan_number;
+ /** Radio type: 'B/G' Band = 0, 'A' Band = 1 */
+ t_u8 radio_type;
+ /** Scan type: Active = 1, Passive = 2 */
+ t_u8 scan_type;
+ /** Reserved */
+ t_u8 reserved;
+ /** Scan duration in milliseconds; if 0 default used */
+ t_u32 scan_time;
+} MLAN_PACK_END wlan_user_scan_chan;
+
+/**
+ * Input structure to configure an immediate scan cmd to firmware
+ *
+ * Specifies a number of parameters to be used in general for the scan
+ * as well as a channel list (wlan_user_scan_chan) for each scan period
+ * desired.
+ */
+typedef MLAN_PACK_START struct
+{
+ /**
+ * Flag set to keep the previous scan table intact
+ *
+ * If set, the scan results will accumulate, replacing any previous
+ * matched entries for a BSS with the new scan data
+ */
+ t_u8 keep_previous_scan;
+ /**
+ * BSS mode to be sent in the firmware command
+ *
+ * Field can be used to restrict the types of networks returned in the
+ * scan. Valid settings are:
+ *
+ * - MLAN_SCAN_MODE_BSS (infrastructure)
+ * - MLAN_SCAN_MODE_IBSS (adhoc)
+ * - MLAN_SCAN_MODE_ANY (unrestricted, adhoc and infrastructure)
+ */
+ t_u8 bss_mode;
+ /**
+ * Configure the number of probe requests for active chan scans
+ */
+ t_u8 num_probes;
+ /**
+ * @brief Reserved
+ */
+ t_u8 reserved;
+ /**
+ * @brief BSSID filter sent in the firmware command to limit the results
+ */
+ t_u8 specific_bssid[MLAN_MAC_ADDR_LENGTH];
+ /**
+ * SSID filter list used in the to limit the scan results
+ */
+ wlan_user_scan_ssid ssid_list[MRVDRV_MAX_SSID_LIST_LENGTH];
+ /**
+ * Variable number (fixed maximum) of channels to scan up
+ */
+ wlan_user_scan_chan chan_list[WLAN_USER_SCAN_CHAN_MAX];
+} MLAN_PACK_END wlan_user_scan_cfg;
+
+/** Default scan interval in millisecond*/
+#define DEFAULT_BGSCAN_INTERVAL 30000
+
+/** action get all, except pps/uapsd config */
+#define BG_SCAN_ACT_GET 0x0000
+/** action set all, except pps/uapsd config */
+#define BG_SCAN_ACT_SET 0x0001
+/** action get pps/uapsd config */
+#define BG_SCAN_ACT_GET_PPS_UAPSD 0x0100
+/** action set pps/uapsd config */
+#define BG_SCAN_ACT_SET_PPS_UAPSD 0x0101
+/** action set all */
+#define BG_SCAN_ACT_SET_ALL 0xff01
+/** ssid match */
+#define BG_SCAN_SSID_MATCH 0x0001
+/** ssid match and RSSI exceeded */
+#define BG_SCAN_SSID_RSSI_MATCH 0x0004
+/** Maximum number of channels that can be sent in bg scan config */
+#define WLAN_BG_SCAN_CHAN_MAX 32
+
+/**
+ * Input structure to configure bs scan cmd to firmware
+ */
+typedef MLAN_PACK_START struct
+{
+ /** action */
+ t_u16 action;
+ /** enable/disable */
+ t_u8 enable;
+ /** BSS type:
+ * MLAN_SCAN_MODE_BSS (infrastructure)
+ * MLAN_SCAN_MODE_IBSS (adhoc)
+ * MLAN_SCAN_MODE_ANY (unrestricted, adhoc and infrastructure)
+ */
+ t_u8 bss_type;
+ /** number of channel scanned during each scan */
+ t_u8 chan_per_scan;
+ /** interval between consecutive scan */
+ t_u32 scan_interval;
+ /** bit 0: ssid match bit 1: ssid match and SNR exceeded
+ * bit 2: ssid match and RSSI exceeded
+ * bit 31: wait for all channel scan to complete to report scan result
+ */
+ t_u32 report_condition;
+ /* Configure the number of probe requests for active chan scans */
+ t_u8 num_probes;
+ /** RSSI threshold */
+ t_u8 rssi_threshold;
+ /** SNR threshold */
+ t_u8 snr_threshold;
+ /** SSID filter list used in the to limit the scan results */
+ wlan_user_scan_ssid ssid_list[MRVDRV_MAX_SSID_LIST_LENGTH];
+ /** Variable number (fixed maximum) of channels to scan up */
+ wlan_user_scan_chan chan_list[WLAN_BG_SCAN_CHAN_MAX];
+} MLAN_PACK_END wlan_bgscan_cfg;
+#endif /* STA_SUPPORT */
+
+#ifdef PRAGMA_PACK
+#pragma pack(pop)
+#endif
+
+/** BSSDescriptor_t
+ * Structure used to store information for beacon/probe response
+ */
+typedef struct _BSSDescriptor_t
+{
+ /** MAC address */
+ mlan_802_11_mac_addr mac_address;
+
+ /** SSID */
+ mlan_802_11_ssid ssid;
+
+ /** WEP encryption requirement */
+ t_u32 privacy;
+
+ /** Receive signal strength in dBm */
+ t_s32 rssi;
+
+ /** Channel */
+ t_u32 channel;
+
+ /** Freq */
+ t_u32 freq;
+
+ /** Beacon period */
+ t_u16 beacon_period;
+
+ /** ATIM window */
+ t_u32 atim_window;
+
+ /** ERP flags */
+ t_u8 erp_flags;
+
+ /** Type of network in use */
+ WLAN_802_11_NETWORK_TYPE network_type_use;
+
+ /** Network infrastructure mode */
+ t_u32 bss_mode;
+
+ /** Network supported rates */
+ WLAN_802_11_RATES supported_rates;
+
+ /** Supported data rates */
+ t_u8 data_rates[WLAN_SUPPORTED_RATES];
+
+ /** Network band.
+ * BAND_B(0x01): 'b' band
+ * BAND_G(0x02): 'g' band
+ * BAND_A(0X04): 'a' band
+ */
+ t_u16 bss_band;
+
+ /** TSF timestamp from the current firmware TSF */
+ t_u64 network_tsf;
+
+ /** TSF value included in the beacon/probe response */
+ t_u8 time_stamp[8];
+
+ /** PHY parameter set */
+ IEEEtypes_PhyParamSet_t phy_param_set;
+
+ /** SS parameter set */
+ IEEEtypes_SsParamSet_t ss_param_set;
+
+ /** Capability information */
+ IEEEtypes_CapInfo_t cap_info;
+
+ /** WMM IE */
+ IEEEtypes_WmmParameter_t wmm_ie;
+
+ /** 802.11h BSS information */
+ wlan_11h_bss_info_t wlan_11h_bss_info;
+
+ /** Indicate disabling 11n when associate with AP */
+ t_u8 disable_11n;
+ /** 802.11n BSS information */
+ /** HT Capabilities IE */
+ IEEEtypes_HTCap_t *pht_cap;
+ /** HT Capabilities Offset */
+ t_u16 ht_cap_offset;
+ /** HT Information IE */
+ IEEEtypes_HTInfo_t *pht_info;
+ /** HT Information Offset */
+ t_u16 ht_info_offset;
+ /** 20/40 BSS Coexistence IE */
+ IEEEtypes_2040BSSCo_t *pbss_co_2040;
+ /** 20/40 BSS Coexistence Offset */
+ t_u16 bss_co_2040_offset;
+ /** Extended Capabilities IE */
+ IEEEtypes_ExtCap_t *pext_cap;
+ /** Extended Capabilities Offset */
+ t_u16 ext_cap_offset;
+ /** Overlapping BSS Scan Parameters IE */
+ IEEEtypes_OverlapBSSScanParam_t *poverlap_bss_scan_param;
+ /** Overlapping BSS Scan Parameters Offset */
+ t_u16 overlap_bss_offset;
+
+#ifdef STA_SUPPORT
+ /** Country information set */
+ IEEEtypes_CountryInfoFullSet_t country_info;
+#endif /* STA_SUPPORT */
+
+ /** WPA IE */
+ IEEEtypes_VendorSpecific_t *pwpa_ie;
+ /** WPA IE offset in the beacon buffer */
+ t_u16 wpa_offset;
+ /** RSN IE */
+ IEEEtypes_Generic_t *prsn_ie;
+ /** RSN IE offset in the beacon buffer */
+ t_u16 rsn_offset;
+#ifdef STA_SUPPORT
+ /** WAPI IE */
+ IEEEtypes_Generic_t *pwapi_ie;
+ /** WAPI IE offset in the beacon buffer */
+ t_u16 wapi_offset;
+#endif
+
+ /** Pointer to the returned scan response */
+ t_u8 *pbeacon_buf;
+ /** Length of the stored scan response */
+ t_u32 beacon_buf_size;
+ /** Max allocated size for updated scan response */
+ t_u32 beacon_buf_size_max;
+
+} BSSDescriptor_t, *pBSSDescriptor_t;
+
+#endif /* !_MLAN_IEEE_H_ */
diff --git a/drivers/net/wireless/sd8797/mlan/mlan_init.c b/drivers/net/wireless/sd8797/mlan/mlan_init.c
new file mode 100644
index 000000000000..e949502e7d69
--- /dev/null
+++ b/drivers/net/wireless/sd8797/mlan/mlan_init.c
@@ -0,0 +1,1038 @@
+/** @file mlan_init.c
+ *
+ * @brief This file contains the initialization for FW
+ * and HW.
+ *
+ * Copyright (C) 2008-2011, Marvell International Ltd.
+ *
+ * This software file (the "File") is distributed by Marvell International
+ * Ltd. under the terms of the GNU General Public License Version 2, June 1991
+ * (the "License"). You may use, redistribute and/or modify this File in
+ * accordance with the terms and conditions of the License, a copy of which
+ * is available by writing to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
+ * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
+ *
+ * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
+ * ARE EXPRESSLY DISCLAIMED. The License provides additional details about
+ * this warranty disclaimer.
+ */
+
+/********************************************************
+Change log:
+ 10/13/2008: initial version
+********************************************************/
+
+#include "mlan.h"
+#ifdef STA_SUPPORT
+#include "mlan_join.h"
+#endif
+#include "mlan_util.h"
+#include "mlan_fw.h"
+#include "mlan_main.h"
+#include "mlan_init.h"
+#include "mlan_wmm.h"
+#include "mlan_11n.h"
+#include "mlan_11h.h"
+#include "mlan_meas.h"
+#include "mlan_sdio.h"
+
+/********************************************************
+ Global Variables
+********************************************************/
+
+/********************************************************
+ Local Functions
+********************************************************/
+
+/**
+ * @brief This function adds a BSS priority table
+ *
+ * @param priv A pointer to mlan_private structure
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+static mlan_status
+wlan_add_bsspriotbl(pmlan_private priv)
+{
+ pmlan_adapter pmadapter = priv->adapter;
+ mlan_bssprio_node *pbssprio = MNULL;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ if ((status =
+ pmadapter->callbacks.moal_malloc(pmadapter->pmoal_handle,
+ sizeof(mlan_bssprio_node),
+ MLAN_MEM_DEF,
+ (t_u8 **) & pbssprio))) {
+ PRINTM(MERROR, "Failed to allocate bsspriotbl\n");
+ LEAVE();
+ return status;
+ }
+
+ pbssprio->priv = priv;
+
+ util_init_list((pmlan_linked_list) pbssprio);
+
+ if (!pmadapter->bssprio_tbl[priv->bss_priority].bssprio_cur)
+ pmadapter->bssprio_tbl[priv->bss_priority].bssprio_cur = pbssprio;
+
+ util_enqueue_list_tail(pmadapter->pmoal_handle,
+ &pmadapter->bssprio_tbl[priv->
+ bss_priority].bssprio_head,
+ (pmlan_linked_list) pbssprio,
+ pmadapter->callbacks.moal_spin_lock,
+ pmadapter->callbacks.moal_spin_unlock);
+
+ LEAVE();
+ return status;
+}
+
+/**
+ * @brief This function deletes the BSS priority table
+ *
+ * @param priv A pointer to mlan_private structure
+ *
+ * @return N/A
+ */
+static t_void
+wlan_delete_bsspriotbl(pmlan_private priv)
+{
+ int i;
+ pmlan_adapter pmadapter = priv->adapter;
+ mlan_bssprio_node *pbssprio_node = MNULL, *ptmp_node = MNULL, **ppcur =
+ MNULL;
+ pmlan_list_head phead;
+
+ ENTER();
+
+ for (i = 0; i < pmadapter->priv_num; ++i) {
+ phead = &pmadapter->bssprio_tbl[i].bssprio_head;
+ ppcur = &pmadapter->bssprio_tbl[i].bssprio_cur;
+ PRINTM(MINFO,
+ "Delete BSS priority table, index = %d, i = %d, phead = %p, pcur = %p\n",
+ priv->bss_index, i, phead, *ppcur);
+ if (*ppcur) {
+ pbssprio_node =
+ (mlan_bssprio_node *) util_peek_list(pmadapter->pmoal_handle,
+ phead,
+ pmadapter->callbacks.
+ moal_spin_lock,
+ pmadapter->callbacks.
+ moal_spin_unlock);
+ while (pbssprio_node && ((pmlan_list_head) pbssprio_node != phead)) {
+ ptmp_node = pbssprio_node->pnext;
+ if (pbssprio_node->priv == priv) {
+ PRINTM(MINFO, "Delete node, pnode = %p, pnext = %p\n",
+ pbssprio_node, ptmp_node);
+ util_unlink_list(pmadapter->pmoal_handle, phead,
+ (pmlan_linked_list) pbssprio_node,
+ pmadapter->callbacks.moal_spin_lock,
+ pmadapter->callbacks.moal_spin_unlock);
+ pmadapter->callbacks.moal_mfree(pmadapter->pmoal_handle,
+ (t_u8 *) pbssprio_node);
+ }
+ pbssprio_node = ptmp_node;
+ }
+ *ppcur = (mlan_bssprio_node *) phead;
+ }
+ }
+
+ LEAVE();
+}
+
+/********************************************************
+ Global Functions
+********************************************************/
+
+/**
+ * @brief This function allocates buffer for the members of adapter
+ * structure like command buffer and BSSID list.
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status
+wlan_allocate_adapter(pmlan_adapter pmadapter)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+#ifdef STA_SUPPORT
+ t_u32 buf_size;
+ BSSDescriptor_t *ptemp_scan_table = MNULL;
+#endif
+
+ ENTER();
+
+#ifdef STA_SUPPORT
+ /* Allocate buffer to store the BSSID list */
+ buf_size = sizeof(BSSDescriptor_t) * MRVDRV_MAX_BSSID_LIST;
+ ret =
+ pmadapter->callbacks.moal_malloc(pmadapter->pmoal_handle, buf_size,
+ MLAN_MEM_DEF,
+ (t_u8 **) & ptemp_scan_table);
+ if (ret != MLAN_STATUS_SUCCESS || !ptemp_scan_table) {
+ PRINTM(MERROR, "Failed to allocate scan table\n");
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+ pmadapter->pscan_table = ptemp_scan_table;
+ ret =
+ pmadapter->callbacks.moal_malloc(pmadapter->pmoal_handle,
+ DEFAULT_SCAN_BEACON_BUFFER,
+ MLAN_MEM_DEF,
+ (t_u8 **) & pmadapter->bcn_buf);
+ if (ret != MLAN_STATUS_SUCCESS || !pmadapter->bcn_buf) {
+ PRINTM(MERROR, "Failed to allocate bcn buf\n");
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+ pmadapter->bcn_buf_size = DEFAULT_SCAN_BEACON_BUFFER;
+#endif
+
+ /* Allocate command buffer */
+ ret = wlan_alloc_cmd_buffer(pmadapter);
+ if (ret != MLAN_STATUS_SUCCESS) {
+ PRINTM(MERROR, "Failed to allocate command buffer\n");
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+
+ ret =
+ pmadapter->callbacks.moal_malloc(pmadapter->pmoal_handle,
+ MAX_MP_REGS + DMA_ALIGNMENT,
+ MLAN_MEM_DEF | MLAN_MEM_DMA,
+ (t_u8 **) & pmadapter->mp_regs_buf);
+ if (ret != MLAN_STATUS_SUCCESS || !pmadapter->mp_regs_buf) {
+ PRINTM(MERROR, "Failed to allocate mp_regs_buf\n");
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+ pmadapter->mp_regs =
+ (t_u8 *) ALIGN_ADDR(pmadapter->mp_regs_buf, DMA_ALIGNMENT);
+
+#if defined(SDIO_MULTI_PORT_TX_AGGR) || defined(SDIO_MULTI_PORT_RX_AGGR)
+ ret = wlan_alloc_sdio_mpa_buffers(pmadapter, SDIO_MP_TX_AGGR_DEF_BUF_SIZE,
+ SDIO_MP_RX_AGGR_DEF_BUF_SIZE);
+ if (ret != MLAN_STATUS_SUCCESS) {
+ PRINTM(MERROR, "Failed to allocate sdio mp-a buffers\n");
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+#endif
+
+ pmadapter->psleep_cfm =
+ wlan_alloc_mlan_buffer(pmadapter, sizeof(opt_sleep_confirm_buffer), 0,
+ MTRUE);
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function initializes the private structure
+ * and sets default values to the members of mlan_private.
+ *
+ * @param priv A pointer to mlan_private structure
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status
+wlan_init_priv(pmlan_private priv)
+{
+ t_u32 i;
+ pmlan_adapter pmadapter = priv->adapter;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ priv->media_connected = MFALSE;
+ memset(pmadapter, priv->curr_addr, 0xff, MLAN_MAC_ADDR_LENGTH);
+
+#ifdef STA_SUPPORT
+ priv->pkt_tx_ctrl = 0;
+ priv->bss_mode = MLAN_BSS_MODE_INFRA;
+ priv->data_rate = 0; /* Initially indicate the rate as auto */
+ priv->is_data_rate_auto = MTRUE;
+ priv->bcn_avg_factor = DEFAULT_BCN_AVG_FACTOR;
+ priv->data_avg_factor = DEFAULT_DATA_AVG_FACTOR;
+
+ priv->sec_info.wep_status = Wlan802_11WEPDisabled;
+ priv->sec_info.authentication_mode = MLAN_AUTH_MODE_AUTO;
+ priv->sec_info.encryption_mode = MLAN_ENCRYPTION_MODE_NONE;
+ for (i = 0; i < sizeof(priv->wep_key) / sizeof(priv->wep_key[0]); i++)
+ memset(pmadapter, &priv->wep_key[i], 0, sizeof(mrvl_wep_key_t));
+ priv->wep_key_curr_index = 0;
+ priv->ewpa_query = MFALSE;
+ priv->adhoc_aes_enabled = MFALSE;
+ priv->curr_pkt_filter =
+ HostCmd_ACT_MAC_RX_ON | HostCmd_ACT_MAC_TX_ON |
+ HostCmd_ACT_MAC_ETHERNETII_ENABLE;
+
+ priv->beacon_period = MLAN_BEACON_INTERVAL;
+ priv->pattempted_bss_desc = MNULL;
+ memset(pmadapter, &priv->curr_bss_params, 0, sizeof(priv->curr_bss_params));
+ priv->listen_interval = MLAN_DEFAULT_LISTEN_INTERVAL;
+
+ memset(pmadapter, &priv->assoc_rsp_buf, 0, sizeof(priv->assoc_rsp_buf));
+ priv->assoc_rsp_size = 0;
+
+ wlan_11d_priv_init(priv);
+ wlan_11h_priv_init(priv);
+#if defined(UAP_SUPPORT)
+ priv->uap_bss_started = MFALSE;
+ memset(pmadapter, &priv->uap_state_chan_cb, 0,
+ sizeof(priv->uap_state_chan_cb));
+#endif
+#if defined(UAP_SUPPORT)
+ priv->num_drop_pkts = 0;
+#endif
+#if defined(STA_SUPPORT)
+ priv->adhoc_state_prev = ADHOC_IDLE;
+ memset(pmadapter, &priv->adhoc_last_start_ssid, 0,
+ sizeof(priv->adhoc_last_start_ssid));
+#endif
+ priv->adhoc_channel = DEFAULT_AD_HOC_CHANNEL;
+ priv->atim_window = 0;
+ priv->adhoc_state = ADHOC_IDLE;
+ priv->tx_power_level = 0;
+ priv->max_tx_power_level = 0;
+ priv->min_tx_power_level = 0;
+ priv->tx_rate = 0;
+ priv->rxpd_htinfo = 0;
+ priv->rxpd_rate = 0;
+ priv->rate_bitmap = 0;
+ priv->data_rssi_last = 0;
+ priv->data_rssi_avg = 0;
+ priv->data_nf_avg = 0;
+ priv->data_nf_last = 0;
+ priv->bcn_rssi_last = 0;
+ priv->bcn_rssi_avg = 0;
+ priv->bcn_nf_avg = 0;
+ priv->bcn_nf_last = 0;
+ memset(pmadapter, &priv->wpa_ie, 0, sizeof(priv->wpa_ie));
+ memset(pmadapter, &priv->aes_key, 0, sizeof(priv->aes_key));
+ priv->wpa_ie_len = 0;
+ priv->wpa_is_gtk_set = MFALSE;
+
+ memset(pmadapter, &priv->wps, 0, sizeof(priv->wps));
+ memset(pmadapter, &priv->gen_ie_buf, 0, sizeof(priv->gen_ie_buf));
+ priv->gen_ie_buf_len = 0;
+#endif /* STA_SUPPORT */
+
+ priv->tx_bf_cap = 0;
+ priv->wmm_required = MTRUE;
+ priv->wmm_enabled = MFALSE;
+ priv->wmm_qosinfo = 0;
+#ifdef STA_SUPPORT
+ priv->pcurr_bcn_buf = MNULL;
+ priv->curr_bcn_size = 0;
+#endif /* STA_SUPPORT */
+
+ for (i = 0; i < MAX_NUM_TID; i++)
+ priv->addba_reject[i] = ADDBA_RSP_STATUS_ACCEPT;
+ priv->max_amsdu = 0;
+
+ priv->scan_block = MFALSE;
+
+ if (GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_STA) {
+ priv->port_ctrl_mode = MTRUE;
+ } else {
+ priv->port_ctrl_mode = MFALSE;
+ }
+ priv->port_open = MFALSE;
+
+ if (!ret)
+ ret = wlan_add_bsspriotbl(priv);
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function initializes the adapter structure
+ * and sets default values to the members of adapter.
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ *
+ * @return N/A
+ */
+t_void
+wlan_init_adapter(pmlan_adapter pmadapter)
+{
+ int i;
+ opt_sleep_confirm_buffer *sleep_cfm_buf = MNULL;
+
+ ENTER();
+
+ sleep_cfm_buf = (opt_sleep_confirm_buffer *) (pmadapter->psleep_cfm->pbuf +
+ pmadapter->psleep_cfm->
+ data_offset);
+
+#ifdef MFG_CMD_SUPPORT
+ if (pmadapter->init_para.mfg_mode == MLAN_INIT_PARA_DISABLED) {
+ pmadapter->mfg_mode = MFALSE;
+ } else {
+ pmadapter->mfg_mode = pmadapter->init_para.mfg_mode;
+ }
+#endif
+
+ pmadapter->int_mode = pmadapter->init_para.int_mode;
+ pmadapter->gpio_pin = pmadapter->init_para.gpio_pin;
+
+#if defined(STA_SUPPORT)
+ pmadapter->pwarm_reset_ioctl_req = MNULL;
+#endif
+ pmadapter->cmd_sent = MFALSE;
+ pmadapter->data_sent = MTRUE;
+ pmadapter->mp_rd_bitmap = 0;
+ pmadapter->mp_wr_bitmap = 0;
+ pmadapter->curr_rd_port = 1;
+ pmadapter->curr_wr_port = 1;
+ for (i = 0; i < MAX_NUM_TID; i++) {
+ pmadapter->tx_eligibility[i] = 1;
+ }
+ pmadapter->mp_data_port_mask = DATA_PORT_MASK;
+
+#ifdef SDIO_MULTI_PORT_TX_AGGR
+ pmadapter->mpa_tx.buf_len = 0;
+ pmadapter->mpa_tx.pkt_cnt = 0;
+ pmadapter->mpa_tx.start_port = 0;
+
+ if (!pmadapter->init_para.mpa_tx_cfg) {
+ pmadapter->mpa_tx.enabled = MFALSE;
+ } else if (pmadapter->init_para.mpa_tx_cfg == MLAN_INIT_PARA_DISABLED) {
+ pmadapter->mpa_tx.enabled = MFALSE;
+ } else {
+ pmadapter->mpa_tx.enabled = MTRUE;
+ }
+ pmadapter->mpa_tx.pkt_aggr_limit = SDIO_MP_AGGR_DEF_PKT_LIMIT;
+#endif /* SDIO_MULTI_PORT_TX_AGGR */
+
+#ifdef SDIO_MULTI_PORT_RX_AGGR
+ pmadapter->mpa_rx.buf_len = 0;
+ pmadapter->mpa_rx.pkt_cnt = 0;
+ pmadapter->mpa_rx.start_port = 0;
+
+ if (!pmadapter->init_para.mpa_rx_cfg) {
+ pmadapter->mpa_rx.enabled = MFALSE;
+ } else if (pmadapter->init_para.mpa_rx_cfg == MLAN_INIT_PARA_DISABLED) {
+ pmadapter->mpa_rx.enabled = MFALSE;
+ } else {
+ pmadapter->mpa_rx.enabled = MTRUE;
+ }
+ pmadapter->mpa_rx.pkt_aggr_limit = SDIO_MP_AGGR_DEF_PKT_LIMIT;
+#endif /* SDIO_MULTI_PORT_RX_AGGR */
+
+ pmadapter->cmd_resp_received = MFALSE;
+ pmadapter->event_received = MFALSE;
+ pmadapter->data_received = MFALSE;
+
+ pmadapter->cmd_timer_is_set = MFALSE;
+
+ /* PnP and power profile */
+ pmadapter->surprise_removed = MFALSE;
+
+ /* Status variables */
+ pmadapter->hw_status = WlanHardwareStatusInitializing;
+
+ if (!pmadapter->init_para.ps_mode) {
+ pmadapter->ps_mode = DEFAULT_PS_MODE;
+ } else if (pmadapter->init_para.ps_mode == MLAN_INIT_PARA_DISABLED) {
+ pmadapter->ps_mode = Wlan802_11PowerModeCAM;
+ } else {
+ pmadapter->ps_mode = Wlan802_11PowerModePSP;
+ }
+ pmadapter->ps_state = PS_STATE_AWAKE;
+ pmadapter->need_to_wakeup = MFALSE;
+
+#ifdef STA_SUPPORT
+ /* Scan type */
+ pmadapter->scan_type = MLAN_SCAN_TYPE_ACTIVE;
+ /* Scan mode */
+ pmadapter->scan_mode = HostCmd_BSS_MODE_ANY;
+ /* Scan time */
+ pmadapter->specific_scan_time = MRVDRV_SPECIFIC_SCAN_CHAN_TIME;
+ pmadapter->active_scan_time = MRVDRV_ACTIVE_SCAN_CHAN_TIME;
+ pmadapter->passive_scan_time = MRVDRV_PASSIVE_SCAN_CHAN_TIME;
+
+ pmadapter->num_in_scan_table = 0;
+ memset(pmadapter, pmadapter->pscan_table, 0,
+ (sizeof(BSSDescriptor_t) * MRVDRV_MAX_BSSID_LIST));
+ pmadapter->ext_scan = 0;
+ pmadapter->scan_probes = DEFAULT_PROBES;
+
+ memset(pmadapter, pmadapter->bcn_buf, 0, pmadapter->bcn_buf_size);
+ pmadapter->pbcn_buf_end = pmadapter->bcn_buf;
+
+ pmadapter->radio_on = RADIO_ON;
+ pmadapter->multiple_dtim = MRVDRV_DEFAULT_MULTIPLE_DTIM;
+
+ pmadapter->local_listen_interval = 0; /* default value in firmware
+ will be used */
+#endif /* STA_SUPPORT */
+
+ pmadapter->is_deep_sleep = MFALSE;
+ pmadapter->idle_time = DEEP_SLEEP_IDLE_TIME;
+ if (!pmadapter->init_para.auto_ds) {
+ pmadapter->init_auto_ds = DEFAULT_AUTO_DS_MODE;
+ } else if (pmadapter->init_para.auto_ds == MLAN_INIT_PARA_DISABLED) {
+ pmadapter->init_auto_ds = MFALSE;
+ } else {
+ pmadapter->init_auto_ds = MTRUE;
+ }
+
+ pmadapter->delay_null_pkt = MFALSE;
+ pmadapter->delay_to_ps = DELAY_TO_PS_DEFAULT;
+ pmadapter->enhanced_ps_mode = PS_MODE_AUTO;
+
+ pmadapter->gen_null_pkt = MFALSE; /* Disable NULL Pkt generation-default */
+ pmadapter->pps_uapsd_mode = MFALSE; /* Disable pps/uapsd mode -default */
+
+ pmadapter->pm_wakeup_card_req = MFALSE;
+
+ pmadapter->pm_wakeup_fw_try = MFALSE;
+
+ if (!pmadapter->init_para.max_tx_buf)
+ pmadapter->max_tx_buf_size = MLAN_TX_DATA_BUF_SIZE_2K;
+ else
+ pmadapter->max_tx_buf_size = (t_u16) pmadapter->init_para.max_tx_buf;
+ pmadapter->tx_buf_size = MLAN_TX_DATA_BUF_SIZE_2K;
+ pmadapter->curr_tx_buf_size = MLAN_TX_DATA_BUF_SIZE_2K;
+
+ pmadapter->is_hs_configured = MFALSE;
+ pmadapter->hs_cfg.conditions = HOST_SLEEP_DEF_COND;
+ pmadapter->hs_cfg.gpio = HOST_SLEEP_DEF_GPIO;
+ pmadapter->hs_cfg.gap = HOST_SLEEP_DEF_GAP;
+ pmadapter->hs_activated = MFALSE;
+
+ memset(pmadapter, pmadapter->event_body, 0, sizeof(pmadapter->event_body));
+ pmadapter->hw_dot_11n_dev_cap = 0;
+ pmadapter->hw_dev_mcs_support = 0;
+ pmadapter->usr_dot_11n_dev_cap_bg = 0;
+ pmadapter->usr_dot_11n_dev_cap_a = 0;
+ pmadapter->usr_dev_mcs_support = 0;
+#ifdef STA_SUPPORT
+ pmadapter->chan_bandwidth = 0;
+ pmadapter->adhoc_11n_enabled = MFALSE;
+#endif /* STA_SUPPORT */
+
+ /* Initialize 802.11d */
+ wlan_11d_init(pmadapter);
+
+ wlan_11h_init(pmadapter);
+
+ wlan_wmm_init(pmadapter);
+
+ if (pmadapter->psleep_cfm) {
+ pmadapter->psleep_cfm->buf_type = MLAN_BUF_TYPE_CMD;
+ pmadapter->psleep_cfm->data_len = sizeof(OPT_Confirm_Sleep);
+ memset(pmadapter, &sleep_cfm_buf->ps_cfm_sleep, 0,
+ sizeof(OPT_Confirm_Sleep));
+ sleep_cfm_buf->ps_cfm_sleep.command =
+ wlan_cpu_to_le16(HostCmd_CMD_802_11_PS_MODE_ENH);
+ sleep_cfm_buf->ps_cfm_sleep.size =
+ wlan_cpu_to_le16(sizeof(OPT_Confirm_Sleep));
+ sleep_cfm_buf->ps_cfm_sleep.result = 0;
+ sleep_cfm_buf->ps_cfm_sleep.action = wlan_cpu_to_le16(SLEEP_CONFIRM);
+ sleep_cfm_buf->ps_cfm_sleep.sleep_cfm.resp_ctrl =
+ wlan_cpu_to_le16(RESP_NEEDED);
+ }
+ memset(pmadapter, &pmadapter->sleep_params, 0,
+ sizeof(pmadapter->sleep_params));
+ memset(pmadapter, &pmadapter->sleep_period, 0,
+ sizeof(pmadapter->sleep_period));
+ pmadapter->tx_lock_flag = MFALSE;
+ pmadapter->null_pkt_interval = 0;
+ pmadapter->fw_bands = 0;
+ pmadapter->config_bands = 0;
+ pmadapter->adhoc_start_band = 0;
+ pmadapter->pscan_channels = MNULL;
+ pmadapter->fw_release_number = 0;
+ pmadapter->fw_cap_info = 0;
+ memset(pmadapter, &pmadapter->upld_buf, 0, sizeof(pmadapter->upld_buf));
+ pmadapter->upld_len = 0;
+ pmadapter->event_cause = 0;
+ pmadapter->pmlan_buffer_event = MNULL;
+ memset(pmadapter, &pmadapter->region_channel, 0,
+ sizeof(pmadapter->region_channel));
+ pmadapter->region_code = 0;
+ pmadapter->bcn_miss_time_out = DEFAULT_BCN_MISS_TIMEOUT;
+ pmadapter->adhoc_awake_period = 0;
+#ifdef STA_SUPPORT
+ memset(pmadapter, &pmadapter->arp_filter, 0, sizeof(pmadapter->arp_filter));
+ pmadapter->arp_filter_size = 0;
+#endif /* STA_SUPPORT */
+
+ LEAVE();
+ return;
+}
+
+/**
+ * @brief This function intializes the lock variables and
+ * the list heads.
+ *
+ * @param pmadapter A pointer to a mlan_adapter structure
+ *
+ * @return MLAN_STATUS_SUCCESS -- on success,
+ * otherwise MLAN_STATUS_FAILURE
+ *
+ */
+mlan_status
+wlan_init_lock_list(IN pmlan_adapter pmadapter)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ pmlan_private priv = MNULL;
+ pmlan_callbacks pcb = &pmadapter->callbacks;
+ t_s32 i = 0;
+ t_u32 j = 0;
+
+ ENTER();
+
+ if (pcb->moal_init_lock(pmadapter->pmoal_handle, &pmadapter->pmlan_lock)
+ != MLAN_STATUS_SUCCESS) {
+ ret = MLAN_STATUS_FAILURE;
+ goto error;
+ }
+ if (pcb->moal_init_lock(pmadapter->pmoal_handle, &pmadapter->pint_lock)
+ != MLAN_STATUS_SUCCESS) {
+ ret = MLAN_STATUS_FAILURE;
+ goto error;
+ }
+ if (pcb->
+ moal_init_lock(pmadapter->pmoal_handle, &pmadapter->pmain_proc_lock)
+ != MLAN_STATUS_SUCCESS) {
+ ret = MLAN_STATUS_FAILURE;
+ goto error;
+ }
+ if (pcb->moal_init_lock(pmadapter->pmoal_handle, &pmadapter->pmlan_cmd_lock)
+ != MLAN_STATUS_SUCCESS) {
+ ret = MLAN_STATUS_FAILURE;
+ goto error;
+ }
+ for (i = 0; i < pmadapter->priv_num; i++) {
+ if (pmadapter->priv[i]) {
+ priv = pmadapter->priv[i];
+ if (pcb->moal_init_lock(pmadapter->pmoal_handle, &priv->rx_pkt_lock)
+ != MLAN_STATUS_SUCCESS) {
+ ret = MLAN_STATUS_FAILURE;
+ goto error;
+ }
+ if (pcb->
+ moal_init_lock(pmadapter->pmoal_handle,
+ &priv->wmm.ra_list_spinlock)
+ != MLAN_STATUS_SUCCESS) {
+ ret = MLAN_STATUS_FAILURE;
+ goto error;
+ }
+#ifdef STA_SUPPORT
+ if (pcb->
+ moal_init_lock(pmadapter->pmoal_handle,
+ &priv->curr_bcn_buf_lock)
+ != MLAN_STATUS_SUCCESS) {
+ ret = MLAN_STATUS_FAILURE;
+ goto error;
+ }
+#endif
+ }
+ }
+
+ /* Initialize bypass_txq */
+ util_init_list_head((t_void *) pmadapter->pmoal_handle,
+ &pmadapter->bypass_txq, MTRUE,
+ pmadapter->callbacks.moal_init_lock);
+ /* Initialize cmd_free_q */
+ util_init_list_head((t_void *) pmadapter->pmoal_handle,
+ &pmadapter->cmd_free_q, MTRUE,
+ pmadapter->callbacks.moal_init_lock);
+ /* Initialize cmd_pending_q */
+ util_init_list_head((t_void *) pmadapter->pmoal_handle,
+ &pmadapter->cmd_pending_q, MTRUE,
+ pmadapter->callbacks.moal_init_lock);
+ /* Initialize scan_pending_q */
+ util_init_list_head((t_void *) pmadapter->pmoal_handle,
+ &pmadapter->scan_pending_q, MTRUE,
+ pmadapter->callbacks.moal_init_lock);
+
+ for (i = 0; i < pmadapter->priv_num; ++i) {
+ util_init_list_head((t_void *) pmadapter->pmoal_handle,
+ &pmadapter->bssprio_tbl[i].bssprio_head,
+ MTRUE, pmadapter->callbacks.moal_init_lock);
+ pmadapter->bssprio_tbl[i].bssprio_cur = MNULL;
+ }
+
+ for (i = 0; i < pmadapter->priv_num; i++) {
+ if (pmadapter->priv[i]) {
+ priv = pmadapter->priv[i];
+ for (j = 0; j < MAX_NUM_TID; ++j) {
+ util_init_list_head((t_void *) pmadapter->pmoal_handle,
+ &priv->wmm.tid_tbl_ptr[j].ra_list, MTRUE,
+ priv->adapter->callbacks.moal_init_lock);
+ }
+ util_init_list_head((t_void *) pmadapter->pmoal_handle,
+ &priv->tx_ba_stream_tbl_ptr, MTRUE,
+ pmadapter->callbacks.moal_init_lock);
+ util_init_list_head((t_void *) pmadapter->pmoal_handle,
+ &priv->rx_reorder_tbl_ptr, MTRUE,
+ pmadapter->callbacks.moal_init_lock);
+ util_scalar_init((t_void *) pmadapter->pmoal_handle,
+ &priv->wmm.tx_pkts_queued, 0,
+ priv->wmm.ra_list_spinlock,
+ pmadapter->callbacks.moal_init_lock);
+ util_scalar_init((t_void *) pmadapter->pmoal_handle,
+ &priv->wmm.highest_queued_prio, HIGH_PRIO_TID,
+ priv->wmm.ra_list_spinlock,
+ pmadapter->callbacks.moal_init_lock);
+ util_init_list_head((t_void *) pmadapter->pmoal_handle,
+ &priv->sta_list, MTRUE,
+ pmadapter->callbacks.moal_init_lock);
+ }
+ }
+
+ error:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function releases the lock variables
+ *
+ * @param pmadapter A pointer to a mlan_adapter structure
+ *
+ * @return None
+ *
+ */
+t_void
+wlan_free_lock_list(IN pmlan_adapter pmadapter)
+{
+ pmlan_private priv = MNULL;
+ pmlan_callbacks pcb = &pmadapter->callbacks;
+ t_s32 i = 0;
+ t_s32 j = 0;
+
+ ENTER();
+
+ if (pmadapter->pmlan_lock)
+ pcb->moal_free_lock(pmadapter->pmoal_handle, pmadapter->pmlan_lock);
+ if (pmadapter->pint_lock)
+ pcb->moal_free_lock(pmadapter->pmoal_handle, pmadapter->pint_lock);
+ if (pmadapter->pmain_proc_lock)
+ pcb->moal_free_lock(pmadapter->pmoal_handle,
+ pmadapter->pmain_proc_lock);
+ if (pmadapter->pmlan_cmd_lock)
+ pcb->moal_free_lock(pmadapter->pmoal_handle, pmadapter->pmlan_cmd_lock);
+
+ for (i = 0; i < pmadapter->priv_num; i++) {
+ if (pmadapter->priv[i]) {
+ priv = pmadapter->priv[i];
+ if (priv->rx_pkt_lock)
+ pcb->moal_free_lock(pmadapter->pmoal_handle, priv->rx_pkt_lock);
+ if (priv->wmm.ra_list_spinlock)
+ pcb->moal_free_lock(pmadapter->pmoal_handle,
+ priv->wmm.ra_list_spinlock);
+#ifdef STA_SUPPORT
+ if (priv->curr_bcn_buf_lock)
+ pcb->moal_free_lock(pmadapter->pmoal_handle,
+ priv->curr_bcn_buf_lock);
+#endif
+ }
+ }
+
+ /* Free lists */
+ util_free_list_head((t_void *) pmadapter->pmoal_handle,
+ &pmadapter->bypass_txq,
+ pmadapter->callbacks.moal_free_lock);
+ util_free_list_head((t_void *) pmadapter->pmoal_handle,
+ &pmadapter->cmd_free_q,
+ pmadapter->callbacks.moal_free_lock);
+
+ util_free_list_head((t_void *) pmadapter->pmoal_handle,
+ &pmadapter->cmd_pending_q,
+ pmadapter->callbacks.moal_free_lock);
+
+ util_free_list_head((t_void *) pmadapter->pmoal_handle,
+ &pmadapter->scan_pending_q,
+ pmadapter->callbacks.moal_free_lock);
+
+ for (i = 0; i < pmadapter->priv_num; i++)
+ util_free_list_head((t_void *) pmadapter->pmoal_handle,
+ &pmadapter->bssprio_tbl[i].bssprio_head,
+ pcb->moal_free_lock);
+
+ for (i = 0; i < pmadapter->priv_num; i++) {
+ if (pmadapter->priv[i]) {
+ priv = pmadapter->priv[i];
+ util_free_list_head((t_void *) pmadapter->pmoal_handle,
+ &priv->sta_list,
+ priv->adapter->callbacks.moal_free_lock);
+
+ for (j = 0; j < MAX_NUM_TID; ++j)
+ util_free_list_head((t_void *) priv->adapter->pmoal_handle,
+ &priv->wmm.tid_tbl_ptr[j].ra_list,
+ priv->adapter->callbacks.moal_free_lock);
+ util_free_list_head((t_void *) priv->adapter->pmoal_handle,
+ &priv->tx_ba_stream_tbl_ptr,
+ priv->adapter->callbacks.moal_free_lock);
+ util_free_list_head((t_void *) priv->adapter->pmoal_handle,
+ &priv->rx_reorder_tbl_ptr,
+ priv->adapter->callbacks.moal_free_lock);
+ util_scalar_free((t_void *) priv->adapter->pmoal_handle,
+ &priv->wmm.tx_pkts_queued,
+ priv->adapter->callbacks.moal_free_lock);
+ util_scalar_free((t_void *) priv->adapter->pmoal_handle,
+ &priv->wmm.highest_queued_prio,
+ priv->adapter->callbacks.moal_free_lock);
+ }
+ }
+
+ LEAVE();
+ return;
+}
+
+/**
+ * @brief This function intializes the timers
+ *
+ * @param pmadapter A pointer to a mlan_adapter structure
+ *
+ * @return MLAN_STATUS_SUCCESS -- on success,
+ * otherwise MLAN_STATUS_FAILURE
+ *
+ */
+mlan_status
+wlan_init_timer(IN pmlan_adapter pmadapter)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ pmlan_callbacks pcb = &pmadapter->callbacks;
+
+ ENTER();
+
+ if (pcb->
+ moal_init_timer(pmadapter->pmoal_handle, &pmadapter->pmlan_cmd_timer,
+ wlan_cmd_timeout_func, pmadapter)
+ != MLAN_STATUS_SUCCESS) {
+ ret = MLAN_STATUS_FAILURE;
+ goto error;
+ }
+ error:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function releases the timers
+ *
+ * @param pmadapter A pointer to a mlan_adapter structure
+ *
+ * @return None
+ *
+ */
+t_void
+wlan_free_timer(IN pmlan_adapter pmadapter)
+{
+ pmlan_callbacks pcb = &pmadapter->callbacks;
+
+ ENTER();
+
+ if (pmadapter->pmlan_cmd_timer)
+ pcb->moal_free_timer(pmadapter->pmoal_handle,
+ pmadapter->pmlan_cmd_timer);
+
+ LEAVE();
+ return;
+}
+
+/**
+ * @brief This function initializes firmware
+ *
+ * @param pmadapter A pointer to mlan_adapter
+ *
+ * @return MLAN_STATUS_SUCCESS, MLAN_STATUS_PENDING or MLAN_STATUS_FAILURE
+ */
+mlan_status
+wlan_init_fw(IN pmlan_adapter pmadapter)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ pmlan_private priv = MNULL;
+ t_u8 i = 0;
+
+ ENTER();
+
+ /* Initialize adapter structure */
+ wlan_init_adapter(pmadapter);
+
+ for (i = 0; i < pmadapter->priv_num; i++) {
+ if (pmadapter->priv[i]) {
+ priv = pmadapter->priv[i];
+
+ /* Initialize private structure */
+ if ((ret = wlan_init_priv(priv))) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ }
+ }
+#ifdef MFG_CMD_SUPPORT
+ if (pmadapter->mfg_mode != MTRUE) {
+#endif
+ /* Issue firmware initialize commands for first BSS, for other
+ interfaces it will be called after getting the last init command
+ response of previous interface */
+ priv = wlan_get_priv(pmadapter, MLAN_BSS_ROLE_ANY);
+ ret = priv->ops.init_cmd(priv, MTRUE);
+ if (ret == MLAN_STATUS_FAILURE)
+ goto done;
+#ifdef MFG_CMD_SUPPORT
+ }
+#endif
+
+ if (util_peek_list(pmadapter->pmoal_handle, &pmadapter->cmd_pending_q,
+ pmadapter->callbacks.moal_spin_lock,
+ pmadapter->callbacks.moal_spin_unlock)) {
+ /* Send the first command in queue and return */
+ if (mlan_main_process(pmadapter) == MLAN_STATUS_FAILURE)
+ ret = MLAN_STATUS_FAILURE;
+ else
+ ret = MLAN_STATUS_PENDING;
+ } else {
+ pmadapter->hw_status = WlanHardwareStatusReady;
+ }
+ done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function frees the structure of adapter
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ *
+ * @return N/A
+ */
+t_void
+wlan_free_adapter(pmlan_adapter pmadapter)
+{
+ mlan_callbacks *pcb = (mlan_callbacks *) & pmadapter->callbacks;
+
+ ENTER();
+
+ if (!pmadapter) {
+ PRINTM(MERROR, "The adapter is NULL\n");
+ LEAVE();
+ return;
+ }
+
+ wlan_cancel_all_pending_cmd(pmadapter);
+ /* Free command buffer */
+ PRINTM(MINFO, "Free Command buffer\n");
+ wlan_free_cmd_buffer(pmadapter);
+
+ if (pmadapter->cmd_timer_is_set) {
+ /* Cancel command timeout timer */
+ pcb->moal_stop_timer(pmadapter->pmoal_handle,
+ pmadapter->pmlan_cmd_timer);
+ pmadapter->cmd_timer_is_set = MFALSE;
+ }
+#ifdef STA_SUPPORT
+ PRINTM(MINFO, "Free ScanTable\n");
+ if (pmadapter->pscan_table) {
+ pcb->moal_mfree(pmadapter->pmoal_handle,
+ (t_u8 *) pmadapter->pscan_table);
+ pmadapter->pscan_table = MNULL;
+ }
+ if (pmadapter->bcn_buf) {
+ pcb->moal_mfree(pmadapter->pmoal_handle, (t_u8 *) pmadapter->bcn_buf);
+ pmadapter->bcn_buf = MNULL;
+ }
+#endif
+
+ wlan_11h_cleanup(pmadapter);
+
+ if (pmadapter->mp_regs_buf) {
+ pcb->moal_mfree(pmadapter->pmoal_handle,
+ (t_u8 *) pmadapter->mp_regs_buf);
+ pmadapter->mp_regs_buf = MNULL;
+ pmadapter->mp_regs = MNULL;
+ }
+#if defined(SDIO_MULTI_PORT_TX_AGGR) || defined(SDIO_MULTI_PORT_RX_AGGR)
+ wlan_free_sdio_mpa_buffers(pmadapter);
+#endif
+ wlan_free_mlan_buffer(pmadapter, pmadapter->psleep_cfm);
+ pmadapter->psleep_cfm = MNULL;
+
+ LEAVE();
+ return;
+}
+
+/**
+ * @brief This function frees the structure of priv
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ *
+ * @return N/A
+ */
+t_void
+wlan_free_priv(mlan_private * pmpriv)
+{
+ ENTER();
+ wlan_clean_txrx(pmpriv);
+ wlan_delete_bsspriotbl(pmpriv);
+
+#ifdef STA_SUPPORT
+ wlan_free_curr_bcn(pmpriv);
+#endif /* STA_SUPPORT */
+
+ wlan_delete_station_list(pmpriv);
+ LEAVE();
+}
+
+/**
+ * @brief The cmdresp handler calls this function for init_fw_complete callback
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ *
+ * @return MLAN_STATUS_SUCCESS
+ * The firmware initialization callback succeeded.
+ */
+mlan_status
+wlan_init_fw_complete(IN pmlan_adapter pmadapter)
+{
+ mlan_status status = MLAN_STATUS_SUCCESS;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ pmlan_callbacks pcb = &pmadapter->callbacks;
+
+ ENTER();
+
+ /* Check if hardware is ready */
+ if (pmadapter->hw_status != WlanHardwareStatusReady)
+ status = MLAN_STATUS_FAILURE;
+
+ /* Invoke callback */
+ ret = pcb->moal_init_fw_complete(pmadapter->pmoal_handle, status);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief The cmdresp handler calls this function for shutdown_fw_complete callback
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ *
+ * @return MLAN_STATUS_SUCCESS
+ * The firmware shutdown callback succeeded.
+ */
+mlan_status
+wlan_shutdown_fw_complete(IN pmlan_adapter pmadapter)
+{
+ pmlan_callbacks pcb = &pmadapter->callbacks;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+ pmadapter->hw_status = WlanHardwareStatusNotReady;
+ /* Invoke callback */
+ ret = pcb->moal_shutdown_fw_complete(pmadapter->pmoal_handle, status);
+ LEAVE();
+ return ret;
+}
diff --git a/drivers/net/wireless/sd8797/mlan/mlan_init.h b/drivers/net/wireless/sd8797/mlan/mlan_init.h
new file mode 100644
index 000000000000..4496741a3cfb
--- /dev/null
+++ b/drivers/net/wireless/sd8797/mlan/mlan_init.h
@@ -0,0 +1,88 @@
+/** @file mlan_init.h
+ *
+ * @brief This file defines the FW initialization data
+ * structures.
+ *
+ * Copyright (C) 2008-2011, Marvell International Ltd.
+ *
+ * This software file (the "File") is distributed by Marvell International
+ * Ltd. under the terms of the GNU General Public License Version 2, June 1991
+ * (the "License"). You may use, redistribute and/or modify this File in
+ * accordance with the terms and conditions of the License, a copy of which
+ * is available by writing to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
+ * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
+ *
+ * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
+ * ARE EXPRESSLY DISCLAIMED. The License provides additional details about
+ * this warranty disclaimer.
+ */
+
+/******************************************************
+Change log:
+ 10/13/2008: initial version
+******************************************************/
+
+#ifndef _MLAN_INIT_H_
+#define _MLAN_INIT_H_
+
+/** Tx buffer size for firmware download*/
+#define FW_DNLD_TX_BUF_SIZE 620
+/** Rx buffer size for firmware download*/
+#define FW_DNLD_RX_BUF_SIZE 2048
+/** Max firmware retry */
+#define MAX_FW_RETRY 3
+
+/** Firmware has last block */
+#define FW_HAS_LAST_BLOCK 0x00000004
+
+/** Firmware data transmit size */
+#define FW_DATA_XMIT_SIZE \
+ sizeof(FWHeader) + DataLength + sizeof(t_u32)
+
+/** FWHeader */
+typedef struct _FWHeader
+{
+ /** FW download command */
+ t_u32 dnld_cmd;
+ /** FW base address */
+ t_u32 base_addr;
+ /** FW data length */
+ t_u32 data_length;
+ /** FW CRC */
+ t_u32 crc;
+} FWHeader;
+
+/** FWData */
+typedef struct _FWData
+{
+ /** FW data header */
+ FWHeader fw_header;
+ /** FW data sequence number */
+ t_u32 seq_num;
+ /** FW data buffer */
+ t_u8 data[1];
+} FWData;
+
+/** FWSyncHeader */
+typedef struct _FWSyncHeader
+{
+ /** FW sync header command */
+ t_u32 cmd;
+ /** FW sync header sequence number */
+ t_u32 seq_num;
+} FWSyncHeader;
+
+#ifdef BIG_ENDIAN_SUPPORT
+/** Convert sequence number and command fields of fwheader to correct endian format */
+#define endian_convert_syncfwheader(x) { \
+ (x)->cmd = wlan_le32_to_cpu((x)->cmd); \
+ (x)->seq_num = wlan_le32_to_cpu((x)->seq_num); \
+ }
+#else
+/** Convert sequence number and command fields of fwheader to correct endian format */
+#define endian_convert_syncfwheader(x)
+#endif /* BIG_ENDIAN_SUPPORT */
+
+#endif /* _MLAN_INIT_H_ */
diff --git a/drivers/net/wireless/sd8797/mlan/mlan_ioctl.h b/drivers/net/wireless/sd8797/mlan/mlan_ioctl.h
new file mode 100644
index 000000000000..b947ce09675b
--- /dev/null
+++ b/drivers/net/wireless/sd8797/mlan/mlan_ioctl.h
@@ -0,0 +1,2918 @@
+/** @file mlan_ioctl.h
+ *
+ * @brief This file declares the IOCTL data structures and APIs.
+ *
+ * Copyright (C) 2008-2011, Marvell International Ltd.
+ *
+ * This software file (the "File") is distributed by Marvell International
+ * Ltd. under the terms of the GNU General Public License Version 2, June 1991
+ * (the "License"). You may use, redistribute and/or modify this File in
+ * accordance with the terms and conditions of the License, a copy of which
+ * is available by writing to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
+ * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
+ *
+ * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
+ * ARE EXPRESSLY DISCLAIMED. The License provides additional details about
+ * this warranty disclaimer.
+ */
+
+/******************************************************
+Change log:
+ 11/07/2008: initial version
+******************************************************/
+
+#ifndef _MLAN_IOCTL_H_
+#define _MLAN_IOCTL_H_
+
+/** Enumeration for IOCTL request ID */
+enum _mlan_ioctl_req_id
+{
+ /* Scan Group */
+ MLAN_IOCTL_SCAN = 0x00010000,
+ MLAN_OID_SCAN_NORMAL,
+ MLAN_OID_SCAN_SPECIFIC_SSID,
+ MLAN_OID_SCAN_USER_CONFIG,
+ MLAN_OID_SCAN_CONFIG,
+ MLAN_OID_SCAN_GET_CURRENT_BSS,
+ MLAN_OID_SCAN_CANCEL,
+ MLAN_OID_SCAN_TABLE_FLUSH,
+ MLAN_OID_SCAN_BGSCAN_CONFIG,
+ /* BSS Configuration Group */
+ MLAN_IOCTL_BSS = 0x00020000,
+ MLAN_OID_BSS_START,
+ MLAN_OID_BSS_STOP,
+ MLAN_OID_BSS_MODE,
+ MLAN_OID_BSS_CHANNEL,
+ MLAN_OID_BSS_CHANNEL_LIST,
+ MLAN_OID_BSS_MAC_ADDR,
+ MLAN_OID_BSS_MULTICAST_LIST,
+ MLAN_OID_BSS_FIND_BSS,
+ MLAN_OID_IBSS_BCN_INTERVAL,
+ MLAN_OID_IBSS_ATIM_WINDOW,
+ MLAN_OID_IBSS_CHANNEL,
+#ifdef UAP_SUPPORT
+ MLAN_OID_UAP_BSS_CONFIG,
+ MLAN_OID_UAP_DEAUTH_STA,
+ MLAN_OID_UAP_BSS_RESET,
+#endif
+#if defined(STA_SUPPORT) && defined(UAP_SUPPORT)
+ MLAN_OID_BSS_ROLE,
+#endif
+#ifdef WIFI_DIRECT_SUPPORT
+ MLAN_OID_WIFI_DIRECT_MODE,
+#endif
+
+ /* Radio Configuration Group */
+ MLAN_IOCTL_RADIO_CFG = 0x00030000,
+ MLAN_OID_RADIO_CTRL,
+ MLAN_OID_BAND_CFG,
+ MLAN_OID_ANT_CFG,
+#ifdef WIFI_DIRECT_SUPPORT
+ MLAN_OID_REMAIN_CHAN_CFG,
+#endif
+
+ /* SNMP MIB Group */
+ MLAN_IOCTL_SNMP_MIB = 0x00040000,
+ MLAN_OID_SNMP_MIB_RTS_THRESHOLD,
+ MLAN_OID_SNMP_MIB_FRAG_THRESHOLD,
+ MLAN_OID_SNMP_MIB_RETRY_COUNT,
+#if defined(UAP_SUPPORT)
+ MLAN_OID_SNMP_MIB_DOT11D,
+ MLAN_OID_SNMP_MIB_DOT11H,
+#endif
+
+ /* Status Information Group */
+ MLAN_IOCTL_GET_INFO = 0x00050000,
+ MLAN_OID_GET_STATS,
+ MLAN_OID_GET_SIGNAL,
+ MLAN_OID_GET_FW_INFO,
+ MLAN_OID_GET_VER_EXT,
+ MLAN_OID_GET_BSS_INFO,
+ MLAN_OID_GET_DEBUG_INFO,
+#ifdef UAP_SUPPORT
+ MLAN_OID_UAP_STA_LIST,
+#endif
+
+ /* Security Configuration Group */
+ MLAN_IOCTL_SEC_CFG = 0x00060000,
+ MLAN_OID_SEC_CFG_AUTH_MODE,
+ MLAN_OID_SEC_CFG_ENCRYPT_MODE,
+ MLAN_OID_SEC_CFG_WPA_ENABLED,
+ MLAN_OID_SEC_CFG_ENCRYPT_KEY,
+ MLAN_OID_SEC_CFG_PASSPHRASE,
+ MLAN_OID_SEC_CFG_EWPA_ENABLED,
+ MLAN_OID_SEC_CFG_ESUPP_MODE,
+ MLAN_OID_SEC_CFG_WAPI_ENABLED,
+ MLAN_OID_SEC_CFG_PORT_CTRL_ENABLED,
+
+ /* Rate Group */
+ MLAN_IOCTL_RATE = 0x00070000,
+ MLAN_OID_RATE_CFG,
+ MLAN_OID_GET_DATA_RATE,
+ MLAN_OID_SUPPORTED_RATES,
+
+ /* Power Configuration Group */
+ MLAN_IOCTL_POWER_CFG = 0x00080000,
+ MLAN_OID_POWER_CFG,
+ MLAN_OID_POWER_CFG_EXT,
+
+ /* Power Management Configuration Group */
+ MLAN_IOCTL_PM_CFG = 0x00090000,
+ MLAN_OID_PM_CFG_IEEE_PS,
+ MLAN_OID_PM_CFG_HS_CFG,
+ MLAN_OID_PM_CFG_INACTIVITY_TO,
+ MLAN_OID_PM_CFG_DEEP_SLEEP,
+ MLAN_OID_PM_CFG_SLEEP_PD,
+ MLAN_OID_PM_CFG_PS_CFG,
+ MLAN_OID_PM_CFG_SLEEP_PARAMS,
+#ifdef UAP_SUPPORT
+ MLAN_OID_PM_CFG_PS_MODE,
+#endif /* UAP_SUPPORT */
+ MLAN_OID_PM_INFO,
+
+ /* WMM Configuration Group */
+ MLAN_IOCTL_WMM_CFG = 0x000A0000,
+ MLAN_OID_WMM_CFG_ENABLE,
+ MLAN_OID_WMM_CFG_QOS,
+ MLAN_OID_WMM_CFG_ADDTS,
+ MLAN_OID_WMM_CFG_DELTS,
+ MLAN_OID_WMM_CFG_QUEUE_CONFIG,
+ MLAN_OID_WMM_CFG_QUEUE_STATS,
+ MLAN_OID_WMM_CFG_QUEUE_STATUS,
+ MLAN_OID_WMM_CFG_TS_STATUS,
+
+ /* WPS Configuration Group */
+ MLAN_IOCTL_WPS_CFG = 0x000B0000,
+ MLAN_OID_WPS_CFG_SESSION,
+
+ /* 802.11n Configuration Group */
+ MLAN_IOCTL_11N_CFG = 0x000C0000,
+ MLAN_OID_11N_CFG_TX,
+ MLAN_OID_11N_HTCAP_CFG,
+ MLAN_OID_11N_CFG_ADDBA_REJECT,
+ MLAN_OID_11N_CFG_AGGR_PRIO_TBL,
+ MLAN_OID_11N_CFG_ADDBA_PARAM,
+ MLAN_OID_11N_CFG_MAX_TX_BUF_SIZE,
+ MLAN_OID_11N_CFG_AMSDU_AGGR_CTRL,
+ MLAN_OID_11N_CFG_SUPPORTED_MCS_SET,
+ MLAN_OID_11N_CFG_TX_BF_CAP,
+ MLAN_OID_11N_CFG_TX_BF_CFG,
+ MLAN_OID_11N_CFG_STREAM_CFG,
+
+ /* 802.11d Configuration Group */
+ MLAN_IOCTL_11D_CFG = 0x000D0000,
+#ifdef STA_SUPPORT
+ MLAN_OID_11D_CFG_ENABLE,
+ MLAN_OID_11D_CLR_CHAN_TABLE,
+#endif /* STA_SUPPORT */
+ MLAN_OID_11D_DOMAIN_INFO,
+
+ /* Register Memory Access Group */
+ MLAN_IOCTL_REG_MEM = 0x000E0000,
+ MLAN_OID_REG_RW,
+ MLAN_OID_EEPROM_RD,
+ MLAN_OID_MEM_RW,
+
+ /* Multi-Radio Configuration Group */
+ MLAN_IOCTL_MFR_CFG = 0x00100000,
+
+ /* 802.11h Configuration Group */
+ MLAN_IOCTL_11H_CFG = 0x00110000,
+ MLAN_OID_11H_CHANNEL_CHECK,
+ MLAN_OID_11H_LOCAL_POWER_CONSTRAINT,
+#if defined(DFS_TESTING_SUPPORT)
+ MLAN_OID_11H_DFS_TESTING,
+#endif
+
+ /* Miscellaneous Configuration Group */
+ MLAN_IOCTL_MISC_CFG = 0x00200000,
+ MLAN_OID_MISC_GEN_IE,
+ MLAN_OID_MISC_REGION,
+ MLAN_OID_MISC_WARM_RESET,
+#if defined(SDIO_MULTI_PORT_TX_AGGR) || defined(SDIO_MULTI_PORT_RX_AGGR)
+ MLAN_OID_MISC_SDIO_MPA_CTRL,
+#endif
+ MLAN_OID_MISC_HOST_CMD,
+ MLAN_OID_MISC_SYS_CLOCK,
+ MLAN_OID_MISC_SOFT_RESET,
+ MLAN_OID_MISC_WWS,
+ MLAN_OID_MISC_INIT_SHUTDOWN,
+ MLAN_OID_MISC_CUSTOM_IE,
+ MLAN_OID_MISC_TX_DATAPAUSE,
+ MLAN_OID_MISC_IP_ADDR,
+ MLAN_OID_MISC_MAC_CONTROL,
+ MLAN_OID_MISC_MEF_CFG,
+ MLAN_OID_MISC_THERMAL,
+ MLAN_OID_MISC_RX_MGMT_IND,
+ MLAN_OID_MISC_SUBSCRIBE_EVENT,
+#ifdef DEBUG_LEVEL1
+ MLAN_OID_MISC_DRVDBG,
+#endif
+};
+
+/** Sub command size */
+#define MLAN_SUB_COMMAND_SIZE 4
+
+/** Enumeration for the action of IOCTL request */
+enum _mlan_act_ioctl
+{
+ MLAN_ACT_SET = 1,
+ MLAN_ACT_GET,
+ MLAN_ACT_CANCEL
+};
+
+/** Enumeration for generic enable/disable */
+enum _mlan_act_generic
+{
+ MLAN_ACT_DISABLE = 0,
+ MLAN_ACT_ENABLE = 1
+};
+
+/** Enumeration for scan mode */
+enum _mlan_scan_mode
+{
+ MLAN_SCAN_MODE_UNCHANGED = 0,
+ MLAN_SCAN_MODE_BSS,
+ MLAN_SCAN_MODE_IBSS,
+ MLAN_SCAN_MODE_ANY
+};
+
+/** Enumeration for scan type */
+enum _mlan_scan_type
+{
+ MLAN_SCAN_TYPE_UNCHANGED = 0,
+ MLAN_SCAN_TYPE_ACTIVE,
+ MLAN_SCAN_TYPE_PASSIVE
+};
+
+/** Max number of supported rates */
+#define MLAN_SUPPORTED_RATES 32
+
+/** RSSI scan */
+#define SCAN_RSSI(RSSI) (0x100 - ((t_u8)(RSSI)))
+
+/** Max passive scan time for each channel in milliseconds */
+#define MRVDRV_MAX_PASSIVE_SCAN_CHAN_TIME 2000
+
+/** Max active scan time for each channel in milliseconds */
+#define MRVDRV_MAX_ACTIVE_SCAN_CHAN_TIME 500
+
+/** Maximum number of probes to send on each channel */
+#define MAX_PROBES 4
+
+/** Default number of probes to send on each channel */
+#define DEFAULT_PROBES 4
+
+/**
+ * @brief Sub-structure passed in wlan_ioctl_get_scan_table_entry for each BSS
+ *
+ * Fixed field information returned for the scan response in the IOCTL
+ * response.
+ */
+typedef struct _wlan_get_scan_table_fixed
+{
+ /** BSSID of this network */
+ t_u8 bssid[MLAN_MAC_ADDR_LENGTH];
+ /** Channel this beacon/probe response was detected */
+ t_u8 channel;
+ /** RSSI for the received packet */
+ t_u8 rssi;
+ /** TSF value in microseconds from the firmware at packet reception */
+ t_u64 network_tsf;
+} wlan_get_scan_table_fixed;
+
+/** mlan_802_11_ssid data structure */
+typedef struct _mlan_802_11_ssid
+{
+ /** SSID Length */
+ t_u32 ssid_len;
+ /** SSID information field */
+ t_u8 ssid[MLAN_MAX_SSID_LENGTH];
+} mlan_802_11_ssid, *pmlan_802_11_ssid;
+
+/**
+ * Sructure to retrieve the scan table
+ */
+typedef struct
+{
+ /**
+ * - Zero based scan entry to start retrieval in command request
+ * - Number of scans entries returned in command response
+ */
+ t_u32 scan_number;
+ /**
+ * Buffer marker for multiple wlan_ioctl_get_scan_table_entry structures.
+ * Each struct is padded to the nearest 32 bit boundary.
+ */
+ t_u8 scan_table_entry_buf[1];
+} wlan_ioctl_get_scan_table_info;
+
+/**
+ * Structure passed in the wlan_ioctl_get_scan_table_info for each
+ * BSS returned in the WLAN_GET_SCAN_RESP IOCTL
+ */
+typedef struct _wlan_ioctl_get_scan_table_entry
+{
+ /**
+ * Fixed field length included in the response.
+ *
+ * Length value is included so future fixed fields can be added to the
+ * response without breaking backwards compatibility. Use the length
+ * to find the offset for the bssInfoLength field, not a sizeof() calc.
+ */
+ t_u32 fixed_field_length;
+
+ /**
+ * Length of the BSS Information (probe resp or beacon) that
+ * follows after the fixed_field_length
+ */
+ t_u32 bss_info_length;
+
+ /**
+ * Always present, fixed length data fields for the BSS
+ */
+ wlan_get_scan_table_fixed fixed_fields;
+
+ /*
+ * Probe response or beacon scanned for the BSS.
+ *
+ * Field layout:
+ * - TSF 8 octets
+ * - Beacon Interval 2 octets
+ * - Capability Info 2 octets
+ *
+ * - IEEE Infomation Elements; variable number & length per 802.11 spec
+ */
+ /* t_u8 bss_info_buffer[0]; */
+} wlan_ioctl_get_scan_table_entry;
+
+/** Type definition of mlan_scan_time_params */
+typedef struct _mlan_scan_time_params
+{
+ /** Scan channel time for specific scan in milliseconds */
+ t_u32 specific_scan_time;
+ /** Scan channel time for active scan in milliseconds */
+ t_u32 active_scan_time;
+ /** Scan channel time for passive scan in milliseconds */
+ t_u32 passive_scan_time;
+} mlan_scan_time_params, *pmlan_scan_time_params;
+
+/** Type definition of mlan_user_scan */
+typedef struct _mlan_user_scan
+{
+ /** Length of scan_cfg_buf */
+ t_u32 scan_cfg_len;
+ /** Buffer of scan config */
+ t_u8 scan_cfg_buf[1];
+} mlan_user_scan, *pmlan_user_scan;
+
+/** Type definition of mlan_scan_req */
+typedef struct _mlan_scan_req
+{
+ /** BSS mode for scanning */
+ t_u32 scan_mode;
+ /** Scan type */
+ t_u32 scan_type;
+ /** SSID */
+ mlan_802_11_ssid scan_ssid;
+ /** Scan time parameters */
+ mlan_scan_time_params scan_time;
+ /** Scan config parameters in user scan */
+ mlan_user_scan user_scan;
+} mlan_scan_req, *pmlan_scan_req;
+
+/** Type defnition of mlan_scan_resp */
+typedef struct _mlan_scan_resp
+{
+ /** Number of scan result */
+ t_u32 num_in_scan_table;
+ /** Scan table */
+ t_u8 *pscan_table;
+ /* Age in seconds */
+ t_u32 age_in_secs;
+} mlan_scan_resp, *pmlan_scan_resp;
+
+/** Type definition of mlan_scan_cfg */
+typedef struct _mlan_scan_cfg
+{
+ /** Scan type */
+ t_u32 scan_type;
+ /** BSS mode for scanning */
+ t_u32 scan_mode;
+ /** Scan probe */
+ t_u32 scan_probe;
+ /** Scan time parameters */
+ mlan_scan_time_params scan_time;
+ /** Extended Scan */
+ t_u32 ext_scan;
+} mlan_scan_cfg, *pmlan_scan_cfg;
+
+/** Type defnition of mlan_ds_scan for MLAN_IOCTL_SCAN */
+typedef struct _mlan_ds_scan
+{
+ /** Sub-command */
+ t_u32 sub_command;
+ /** Scan request/response */
+ union
+ {
+ /** Scan request */
+ mlan_scan_req scan_req;
+ /** Scan response */
+ mlan_scan_resp scan_resp;
+ /** Scan config parameters in user scan */
+ mlan_user_scan user_scan;
+ /** Scan config parameters */
+ mlan_scan_cfg scan_cfg;
+ } param;
+} mlan_ds_scan, *pmlan_ds_scan;
+
+/*-----------------------------------------------------------------*/
+/** BSS Configuration Group */
+/*-----------------------------------------------------------------*/
+/** Enumeration for BSS mode */
+enum _mlan_bss_mode
+{
+ MLAN_BSS_MODE_INFRA = 1,
+ MLAN_BSS_MODE_IBSS,
+ MLAN_BSS_MODE_AUTO
+};
+
+/** Maximum key length */
+#define MLAN_MAX_KEY_LENGTH 32
+
+/** max Wmm AC queues */
+#define MAX_AC_QUEUES 4
+
+/** Maximum atim window in milliseconds */
+#define MLAN_MAX_ATIM_WINDOW 50
+
+/** Minimum beacon interval */
+#define MLAN_MIN_BEACON_INTERVAL 20
+/** Maximum beacon interval */
+#define MLAN_MAX_BEACON_INTERVAL 1000
+/** Default beacon interval */
+#define MLAN_BEACON_INTERVAL 100
+
+/** Receive all packets */
+#define MLAN_PROMISC_MODE 1
+/** Receive multicast packets in multicast list */
+#define MLAN_MULTICAST_MODE 2
+/** Receive all multicast packets */
+#define MLAN_ALL_MULTI_MODE 4
+
+/** Maximum size of multicast list */
+#define MLAN_MAX_MULTICAST_LIST_SIZE 32
+
+/** mlan_multicast_list data structure for MLAN_OID_BSS_MULTICAST_LIST */
+typedef struct _mlan_multicast_list
+{
+ /** Multicast mode */
+ t_u32 mode;
+ /** Number of multicast addresses in the list */
+ t_u32 num_multicast_addr;
+ /** Multicast address list */
+ mlan_802_11_mac_addr mac_list[MLAN_MAX_MULTICAST_LIST_SIZE];
+} mlan_multicast_list, *pmlan_multicast_list;
+
+/** Max channel */
+#define MLAN_MAX_CHANNEL 165
+
+/** Maximum number of channels in table */
+#define MLAN_MAX_CHANNEL_NUM 128
+
+/** Channel/frequence for MLAN_OID_BSS_CHANNEL */
+typedef struct _chan_freq
+{
+ /** Channel Number */
+ t_u32 channel;
+ /** Frequency of this Channel */
+ t_u32 freq;
+} chan_freq;
+
+/** mlan_chan_list data structure for MLAN_OID_BSS_CHANNEL_LIST */
+typedef struct _mlan_chan_list
+{
+ /** Number of channel */
+ t_u32 num_of_chan;
+ /** Channel-Frequency table */
+ chan_freq cf[MLAN_MAX_CHANNEL_NUM];
+} mlan_chan_list;
+
+/** mlan_ssid_bssid data structure for MLAN_OID_BSS_START and MLAN_OID_BSS_FIND_BSS */
+typedef struct _mlan_ssid_bssid
+{
+ /** SSID */
+ mlan_802_11_ssid ssid;
+ /** BSSID */
+ mlan_802_11_mac_addr bssid;
+ /** index in BSSID list, start from 1 */
+ t_u32 idx;
+} mlan_ssid_bssid;
+
+#ifdef UAP_SUPPORT
+/** Maximum packet forward control value */
+#define MAX_PKT_FWD_CTRL 15
+/** Maximum BEACON period */
+#define MAX_BEACON_PERIOD 4000
+/** Minimum BEACON period */
+#define MIN_BEACON_PERIOD 50
+/** Maximum DTIM period */
+#define MAX_DTIM_PERIOD 100
+/** Minimum DTIM period */
+#define MIN_DTIM_PERIOD 1
+/** Maximum TX Power Limit */
+#define MAX_TX_POWER 20
+/** Minimum TX Power Limit */
+#define MIN_TX_POWER 0
+/** MAX station count */
+#define MAX_STA_COUNT 10
+/** Maximum RTS threshold */
+#define MAX_RTS_THRESHOLD 2347
+/** Maximum fragmentation threshold */
+#define MAX_FRAG_THRESHOLD 2346
+/** Minimum fragmentation threshold */
+#define MIN_FRAG_THRESHOLD 256
+/** data rate 54 M */
+#define DATA_RATE_54M 108
+/** antenna A */
+#define ANTENNA_MODE_A 0
+/** antenna B */
+#define ANTENNA_MODE_B 1
+/** transmit antenna */
+#define TX_ANTENNA 1
+/** receive antenna */
+#define RX_ANTENNA 0
+/** Maximum stage out time */
+#define MAX_STAGE_OUT_TIME 864000
+/** Minimum stage out time */
+#define MIN_STAGE_OUT_TIME 300
+/** Maximum Retry Limit */
+#define MAX_RETRY_LIMIT 14
+
+/** Maximum group key timer in seconds */
+#define MAX_GRP_TIMER 86400
+
+/** Maximum value of 4 byte configuration */
+#define MAX_VALID_DWORD 0x7FFFFFFF /* (1 << 31) - 1 */
+
+/** Band config ACS mode */
+#define BAND_CONFIG_ACS_MODE 0x40
+/** Band config manual */
+#define BAND_CONFIG_MANUAL 0x00
+
+/** Maximum data rates */
+#define MAX_DATA_RATES 14
+
+/** auto data rate */
+#define DATA_RATE_AUTO 0
+
+/**filter mode: disable */
+#define MAC_FILTER_MODE_DISABLE 0
+/**filter mode: block mac address */
+#define MAC_FILTER_MODE_ALLOW_MAC 1
+/**filter mode: block mac address */
+#define MAC_FILTER_MODE_BLOCK_MAC 2
+/** Maximum mac filter num */
+#define MAX_MAC_FILTER_NUM 16
+
+/* Bitmap for protocol to use */
+/** No security */
+#define PROTOCOL_NO_SECURITY 0x01
+/** Static WEP */
+#define PROTOCOL_STATIC_WEP 0x02
+/** WPA */
+#define PROTOCOL_WPA 0x08
+/** WPA2 */
+#define PROTOCOL_WPA2 0x20
+/** WP2 Mixed */
+#define PROTOCOL_WPA2_MIXED 0x28
+/** EAP */
+#define PROTOCOL_EAP 0x40
+/** WAPI */
+#define PROTOCOL_WAPI 0x80
+
+/** Key_mgmt_psk */
+#define KEY_MGMT_NONE 0x04
+/** Key_mgmt_none */
+#define KEY_MGMT_PSK 0x02
+/** Key_mgmt_eap */
+#define KEY_MGMT_EAP 0x01
+
+/** TKIP */
+#define CIPHER_TKIP 0x04
+/** AES CCMP */
+#define CIPHER_AES_CCMP 0x08
+
+/** Valid cipher bitmap */
+#define VALID_CIPHER_BITMAP 0x0c
+
+/** Channel List Entry */
+typedef struct _channel_list
+{
+ /** Channel Number */
+ t_u8 chan_number;
+ /** Band Config */
+ t_u8 band_config_type;
+} scan_chan_list;
+
+/** mac_filter data structure */
+typedef struct _mac_filter
+{
+ /** mac filter mode */
+ t_u16 filter_mode;
+ /** mac adress count */
+ t_u16 mac_count;
+ /** mac address list */
+ mlan_802_11_mac_addr mac_list[MAX_MAC_FILTER_NUM];
+} mac_filter;
+
+/** wpa parameter */
+typedef struct _wpa_param
+{
+ /** Pairwise cipher WPA */
+ t_u8 pairwise_cipher_wpa;
+ /** Pairwise cipher WPA2 */
+ t_u8 pairwise_cipher_wpa2;
+ /** group cipher */
+ t_u8 group_cipher;
+ /** RSN replay protection */
+ t_u8 rsn_protection;
+ /** passphrase length */
+ t_u32 length;
+ /** passphrase */
+ t_u8 passphrase[64];
+ /**group key rekey time in seconds */
+ t_u32 gk_rekey_time;
+} wpa_param;
+
+/** wep key */
+typedef struct _wep_key
+{
+ /** key index 0-3 */
+ t_u8 key_index;
+ /** is default */
+ t_u8 is_default;
+ /** length */
+ t_u16 length;
+ /** key data */
+ t_u8 key[26];
+} wep_key;
+
+/** wep param */
+typedef struct _wep_param
+{
+ /** key 0 */
+ wep_key key0;
+ /** key 1 */
+ wep_key key1;
+ /** key 2 */
+ wep_key key2;
+ /** key 3 */
+ wep_key key3;
+} wep_param;
+
+/** Data structure of WMM QoS information */
+typedef struct _wmm_qos_info_t
+{
+#ifdef BIG_ENDIAN_SUPPORT
+ /** QoS UAPSD */
+ t_u8 qos_uapsd:1;
+ /** Reserved */
+ t_u8 reserved:3;
+ /** Parameter set count */
+ t_u8 para_set_count:4;
+#else
+ /** Parameter set count */
+ t_u8 para_set_count:4;
+ /** Reserved */
+ t_u8 reserved:3;
+ /** QoS UAPSD */
+ t_u8 qos_uapsd:1;
+#endif /* BIG_ENDIAN_SUPPORT */
+} wmm_qos_info_t, *pwmm_qos_info_t;
+
+/** Data structure of WMM ECW */
+typedef struct _wmm_ecw_t
+{
+#ifdef BIG_ENDIAN_SUPPORT
+ /** Maximum Ecw */
+ t_u8 ecw_max:4;
+ /** Minimum Ecw */
+ t_u8 ecw_min:4;
+#else
+ /** Minimum Ecw */
+ t_u8 ecw_min:4;
+ /** Maximum Ecw */
+ t_u8 ecw_max:4;
+#endif /* BIG_ENDIAN_SUPPORT */
+} wmm_ecw_t, *pwmm_ecw_t;
+
+/** Data structure of WMM Aci/Aifsn */
+typedef struct _wmm_aci_aifsn_t
+{
+#ifdef BIG_ENDIAN_SUPPORT
+ /** Reserved */
+ t_u8 reserved:1;
+ /** Aci */
+ t_u8 aci:2;
+ /** Acm */
+ t_u8 acm:1;
+ /** Aifsn */
+ t_u8 aifsn:4;
+#else
+ /** Aifsn */
+ t_u8 aifsn:4;
+ /** Acm */
+ t_u8 acm:1;
+ /** Aci */
+ t_u8 aci:2;
+ /** Reserved */
+ t_u8 reserved:1;
+#endif /* BIG_ENDIAN_SUPPORT */
+} wmm_aci_aifsn_t, *pwmm_aci_aifsn_t;
+
+/** Data structure of WMM AC parameters */
+typedef struct _wmm_ac_parameters_t
+{
+ wmm_aci_aifsn_t aci_aifsn; /**< AciAifSn */
+ wmm_ecw_t ecw; /**< Ecw */
+ t_u16 tx_op_limit; /**< Tx op limit */
+} wmm_ac_parameters_t, *pwmm_ac_parameters_t;
+
+/** Data structure of WMM parameter IE */
+typedef struct _wmm_parameter_t
+{
+ /** OuiType: 00:50:f2:02 */
+ t_u8 ouitype[4];
+ /** Oui subtype: 01 */
+ t_u8 ouisubtype;
+ /** version: 01 */
+ t_u8 version;
+ /** QoS information */
+ t_u8 qos_info;
+ /** Reserved */
+ t_u8 reserved;
+ /** AC Parameters Record WMM_AC_BE, WMM_AC_BK, WMM_AC_VI, WMM_AC_VO */
+ wmm_ac_parameters_t ac_params[MAX_AC_QUEUES];
+} wmm_parameter_t, *pwmm_parameter_t;
+
+/** mlan_bss_param
+ * Note: For each entry you must enter an invalid value
+ * in the MOAL function woal_set_sys_config_invalid_data().
+ * Otherwise for a valid data an unwanted TLV will be
+ * added to that command.
+ */
+typedef struct _mlan_uap_bss_param
+{
+ /** AP mac addr */
+ mlan_802_11_mac_addr mac_addr;
+ /** SSID */
+ mlan_802_11_ssid ssid;
+ /** Broadcast ssid control */
+ t_u8 bcast_ssid_ctl;
+ /** Radio control: on/off */
+ t_u8 radio_ctl;
+ /** dtim period */
+ t_u8 dtim_period;
+ /** beacon period */
+ t_u16 beacon_period;
+ /** rates */
+ t_u8 rates[MAX_DATA_RATES];
+ /** Tx data rate */
+ t_u16 tx_data_rate;
+ /** multicast/broadcast data rate */
+ t_u16 mcbc_data_rate;
+ /** Tx power level in dBm */
+ t_u8 tx_power_level;
+ /** Tx antenna */
+ t_u8 tx_antenna;
+ /** Rx antenna */
+ t_u8 rx_antenna;
+ /** packet forward control */
+ t_u8 pkt_forward_ctl;
+ /** max station count */
+ t_u16 max_sta_count;
+ /** mac filter */
+ mac_filter filter;
+ /** station ageout timer in unit of 100ms */
+ t_u32 sta_ageout_timer;
+ /** PS station ageout timer in unit of 100ms */
+ t_u32 ps_sta_ageout_timer;
+ /** RTS threshold */
+ t_u16 rts_threshold;
+ /** fragmentation threshold */
+ t_u16 frag_threshold;
+ /** retry_limit */
+ t_u16 retry_limit;
+ /** pairwise update timeout in milliseconds */
+ t_u32 pairwise_update_timeout;
+ /** pairwise handshake retries */
+ t_u32 pwk_retries;
+ /** groupwise update timeout in milliseconds */
+ t_u32 groupwise_update_timeout;
+ /** groupwise handshake retries */
+ t_u32 gwk_retries;
+ /** preamble type */
+ t_u8 preamble_type;
+ /** band cfg */
+ t_u8 band_cfg;
+ /** channel */
+ t_u8 channel;
+ /** auth mode */
+ t_u16 auth_mode;
+ /** encryption protocol */
+ t_u16 protocol;
+ /** key managment type */
+ t_u16 key_mgmt;
+ /** wep param */
+ wep_param wep_cfg;
+ /** wpa param */
+ wpa_param wpa_cfg;
+ /** Mgmt IE passthru mask */
+ t_u32 mgmt_ie_passthru_mask;
+ /*
+ * 11n HT Cap HTCap_t ht_cap
+ */
+ /** HT Capabilities Info field */
+ t_u16 ht_cap_info;
+ /** A-MPDU Parameters field */
+ t_u8 ampdu_param;
+ /** Supported MCS Set field */
+ t_u8 supported_mcs_set[16];
+ /** HT Extended Capabilities field */
+ t_u16 ht_ext_cap;
+ /** Transmit Beamforming Capabilities field */
+ t_u32 tx_bf_cap;
+ /** Antenna Selection Capability field */
+ t_u8 asel;
+ /** Enable 2040 Coex */
+ t_u8 enable_2040coex;
+ /** key management operation */
+ t_u16 key_mgmt_operation;
+ /** BSS status */
+ t_u16 bss_status;
+#ifdef WIFI_DIRECT_SUPPORT
+ /* pre shared key */
+ t_u8 psk[MLAN_MAX_KEY_LENGTH];
+#endif /* WIFI_DIRECT_SUPPORT */
+ /** Number of channels in scan_channel_list */
+ t_u32 num_of_chan;
+ /** scan channel list in ACS mode */
+ scan_chan_list chan_list[MLAN_MAX_CHANNEL];
+ /** Wmm parameters */
+ wmm_parameter_t wmm_para;
+} mlan_uap_bss_param;
+
+/** mlan_deauth_param */
+typedef struct _mlan_deauth_param
+{
+ /** STA mac addr */
+ t_u8 mac_addr[MLAN_MAC_ADDR_LENGTH];
+ /** deauth reason */
+ t_u16 reason_code;
+} mlan_deauth_param;
+#endif
+
+#ifdef WIFI_DIRECT_SUPPORT
+/** mode: disable wifi direct */
+#define WIFI_DIRECT_MODE_DISABLE 0
+/** mode: listen */
+#define WIFI_DIRECT_MODE_LISTEN 1
+/** mode: GO */
+#define WIFI_DIRECT_MODE_GO 2
+/** mode: client */
+#define WIFI_DIRECT_MODE_CLIENT 3
+/** mode: find */
+#define WIFI_DIRECT_MODE_FIND 4
+/** mode: stop find */
+#define WIFI_DIRECT_MODE_STOP_FIND 5
+#endif
+
+/** Type definition of mlan_ds_bss for MLAN_IOCTL_BSS */
+typedef struct _mlan_ds_bss
+{
+ /** Sub-command */
+ t_u32 sub_command;
+ /** BSS parameter */
+ union
+ {
+ /** SSID-BSSID for MLAN_OID_BSS_START */
+ mlan_ssid_bssid ssid_bssid;
+ /** BSSID for MLAN_OID_BSS_STOP */
+ mlan_802_11_mac_addr bssid;
+ /** BSS mode for MLAN_OID_BSS_MODE */
+ t_u32 bss_mode;
+ /** BSS channel/frequency for MLAN_OID_BSS_CHANNEL */
+ chan_freq bss_chan;
+ /** BSS channel list for MLAN_OID_BSS_CHANNEL_LIST */
+ mlan_chan_list chanlist;
+ /** MAC address for MLAN_OID_BSS_MAC_ADDR */
+ mlan_802_11_mac_addr mac_addr;
+ /** Multicast list for MLAN_OID_BSS_MULTICAST_LIST */
+ mlan_multicast_list multicast_list;
+ /** Beacon interval for MLAN_OID_IBSS_BCN_INTERVAL */
+ t_u32 bcn_interval;
+ /** ATIM window for MLAN_OID_IBSS_ATIM_WINDOW */
+ t_u32 atim_window;
+#ifdef UAP_SUPPORT
+ /** BSS param for AP mode */
+ mlan_uap_bss_param bss_config;
+ /** deauth param for MLAN_OID_UAP_DEAUTH_STA */
+ mlan_deauth_param deauth_param;
+#endif
+#if defined(STA_SUPPORT) && defined(UAP_SUPPORT)
+ /** BSS role */
+ t_u8 bss_role;
+#endif
+#ifdef WIFI_DIRECT_SUPPORT
+ t_u16 wfd_mode;
+#endif
+ } param;
+} mlan_ds_bss, *pmlan_ds_bss;
+
+/*-----------------------------------------------------------------*/
+/** Radio Control Group */
+/*-----------------------------------------------------------------*/
+/** Enumeration for band */
+enum _mlan_band_def
+{
+ BAND_B = 1,
+ BAND_G = 2,
+ BAND_A = 4,
+ BAND_GN = 8,
+ BAND_AN = 16,
+};
+
+/** NO secondary channel */
+#define NO_SEC_CHANNEL 0
+/** secondary channel is above primary channel */
+#define SEC_CHANNEL_ABOVE 1
+/** secondary channel is below primary channel */
+#define SEC_CHANNEL_BELOW 3
+/** Channel bandwidth */
+#define CHANNEL_BW_20MHZ 0
+#define CHANNEL_BW_40MHZ_ABOVE 1
+#define CHANNEL_BW_40MHZ_BELOW 3
+
+/** Type definition of mlan_ds_band_cfg for MLAN_OID_BAND_CFG */
+typedef struct _mlan_ds_band_cfg
+{
+ /** Infra band */
+ t_u32 config_bands;
+ /** Ad-hoc start band */
+ t_u32 adhoc_start_band;
+ /** Ad-hoc start channel */
+ t_u32 adhoc_channel;
+ /** Ad-hoc channel bandwidth */
+ t_u32 sec_chan_offset;
+ /** fw supported band */
+ t_u32 fw_bands;
+} mlan_ds_band_cfg;
+
+/** Type definition of mlan_ds_ant_cfg for MLAN_OID_ANT_CFG */
+typedef struct _mlan_ds_ant_cfg
+{
+ /** Tx antenna mode */
+ t_u32 tx_antenna;
+ /** Rx antenna mode */
+ t_u32 rx_antenna;
+} mlan_ds_ant_cfg, *pmlan_ds_ant_cfg;
+
+#ifdef WIFI_DIRECT_SUPPORT
+/** Type definition of mlan_ds_remain_chan for MLAN_OID_REMAIN_CHAN_CFG */
+typedef struct _mlan_ds_remain_chan
+{
+ /** remove flag */
+ t_u16 remove;
+ /** status */
+ t_u8 status;
+ /** Band cfg */
+ t_u8 bandcfg;
+ /** channel */
+ t_u8 channel;
+ /** remain time: Unit ms*/
+ t_u32 remain_period;
+} mlan_ds_remain_chan, *pmlan_ds_remain_chan;
+#endif
+
+/** Type definition of mlan_ds_radio_cfg for MLAN_IOCTL_RADIO_CFG */
+typedef struct _mlan_ds_radio_cfg
+{
+ /** Sub-command */
+ t_u32 sub_command;
+ /** Radio control parameter */
+ union
+ {
+ /** Radio on/off for MLAN_OID_RADIO_CTRL */
+ t_u32 radio_on_off;
+ /** Band info for MLAN_OID_BAND_CFG */
+ mlan_ds_band_cfg band_cfg;
+ /** Antenna info for MLAN_OID_ANT_CFG */
+ mlan_ds_ant_cfg ant_cfg;
+ /** Antenna info for MLAN_OID_ANT_CFG */
+ t_u32 antenna;
+#ifdef WIFI_DIRECT_SUPPORT
+ /** remain on channel for MLAN_OID_REMAIN_CHAN_CFG */
+ mlan_ds_remain_chan remain_chan;
+#endif
+ } param;
+} mlan_ds_radio_cfg, *pmlan_ds_radio_cfg;
+
+/*-----------------------------------------------------------------*/
+/** SNMP MIB Group */
+/*-----------------------------------------------------------------*/
+/** Type definition of mlan_ds_snmp_mib for MLAN_IOCTL_SNMP_MIB */
+typedef struct _mlan_ds_snmp_mib
+{
+ /** Sub-command */
+ t_u32 sub_command;
+ /** SNMP MIB parameter */
+ union
+ {
+ /** RTS threshold for MLAN_OID_SNMP_MIB_RTS_THRESHOLD */
+ t_u32 rts_threshold;
+ /** Fragment threshold for MLAN_OID_SNMP_MIB_FRAG_THRESHOLD */
+ t_u32 frag_threshold;
+ /** Retry count for MLAN_OID_SNMP_MIB_RETRY_COUNT */
+ t_u32 retry_count;
+#if defined(UAP_SUPPORT)
+ /** OID value for MLAN_OID_SNMP_MIB_DOT11D/H */
+ t_u32 oid_value;
+#endif
+ } param;
+} mlan_ds_snmp_mib, *pmlan_ds_snmp_mib;
+
+/*-----------------------------------------------------------------*/
+/** Status Information Group */
+/*-----------------------------------------------------------------*/
+/** Enumeration for ad-hoc status */
+enum _mlan_adhoc_status
+{
+ ADHOC_IDLE,
+ ADHOC_STARTED,
+ ADHOC_JOINED,
+ ADHOC_COALESCED, ADHOC_STARTING
+};
+
+/** Type definition of mlan_ds_get_stats for MLAN_OID_GET_STATS */
+typedef struct _mlan_ds_get_stats
+{
+ /** Statistics counter */
+ /** Multicast transmitted frame count */
+ t_u32 mcast_tx_frame;
+ /** Failure count */
+ t_u32 failed;
+ /** Retry count */
+ t_u32 retry;
+ /** Multi entry count */
+ t_u32 multi_retry;
+ /** Duplicate frame count */
+ t_u32 frame_dup;
+ /** RTS success count */
+ t_u32 rts_success;
+ /** RTS failure count */
+ t_u32 rts_failure;
+ /** Ack failure count */
+ t_u32 ack_failure;
+ /** Rx fragmentation count */
+ t_u32 rx_frag;
+ /** Multicast Tx frame count */
+ t_u32 mcast_rx_frame;
+ /** FCS error count */
+ t_u32 fcs_error;
+ /** Tx frame count */
+ t_u32 tx_frame;
+ /** WEP ICV error count */
+ t_u32 wep_icv_error[4];
+} mlan_ds_get_stats, *pmlan_ds_get_stats;
+
+/** Type definition of mlan_ds_uap_stats for MLAN_OID_GET_STATS */
+typedef struct _mlan_ds_uap_stats
+{
+ /** tkip mic failures */
+ t_u32 tkip_mic_failures;
+ /** ccmp decrypt errors */
+ t_u32 ccmp_decrypt_errors;
+ /** wep undecryptable count */
+ t_u32 wep_undecryptable_count;
+ /** wep icv error count */
+ t_u32 wep_icv_error_count;
+ /** decrypt failure count */
+ t_u32 decrypt_failure_count;
+ /** dot11 multicast tx count */
+ t_u32 mcast_tx_count;
+ /** dot11 failed count */
+ t_u32 failed_count;
+ /** dot11 retry count */
+ t_u32 retry_count;
+ /** dot11 multi retry count */
+ t_u32 multi_retry_count;
+ /** dot11 frame duplicate count */
+ t_u32 frame_dup_count;
+ /** dot11 rts success count */
+ t_u32 rts_success_count;
+ /** dot11 rts failure count */
+ t_u32 rts_failure_count;
+ /** dot11 ack failure count */
+ t_u32 ack_failure_count;
+ /** dot11 rx ragment count */
+ t_u32 rx_fragment_count;
+ /** dot11 mcast rx frame count */
+ t_u32 mcast_rx_frame_count;
+ /** dot11 fcs error count */
+ t_u32 fcs_error_count;
+ /** dot11 tx frame count */
+ t_u32 tx_frame_count;
+ /** dot11 rsna tkip cm invoked */
+ t_u32 rsna_tkip_cm_invoked;
+ /** dot11 rsna 4way handshake failures */
+ t_u32 rsna_4way_hshk_failures;
+} mlan_ds_uap_stats, *pmlan_ds_uap_stats;
+
+/** Mask of last beacon RSSI */
+#define BCN_RSSI_LAST_MASK 0x00000001
+/** Mask of average beacon RSSI */
+#define BCN_RSSI_AVG_MASK 0x00000002
+/** Mask of last data RSSI */
+#define DATA_RSSI_LAST_MASK 0x00000004
+/** Mask of average data RSSI */
+#define DATA_RSSI_AVG_MASK 0x00000008
+/** Mask of last beacon SNR */
+#define BCN_SNR_LAST_MASK 0x00000010
+/** Mask of average beacon SNR */
+#define BCN_SNR_AVG_MASK 0x00000020
+/** Mask of last data SNR */
+#define DATA_SNR_LAST_MASK 0x00000040
+/** Mask of average data SNR */
+#define DATA_SNR_AVG_MASK 0x00000080
+/** Mask of last beacon NF */
+#define BCN_NF_LAST_MASK 0x00000100
+/** Mask of average beacon NF */
+#define BCN_NF_AVG_MASK 0x00000200
+/** Mask of last data NF */
+#define DATA_NF_LAST_MASK 0x00000400
+/** Mask of average data NF */
+#define DATA_NF_AVG_MASK 0x00000800
+/** Mask of all RSSI_INFO */
+#define ALL_RSSI_INFO_MASK 0x00000fff
+
+/** Type definition of mlan_ds_get_signal for MLAN_OID_GET_SIGNAL */
+typedef struct _mlan_ds_get_signal
+{
+ /** Selector of get operation */
+ /*
+ * Bit0: Last Beacon RSSI, Bit1: Average Beacon RSSI,
+ * Bit2: Last Data RSSI, Bit3: Average Data RSSI,
+ * Bit4: Last Beacon SNR, Bit5: Average Beacon SNR,
+ * Bit6: Last Data SNR, Bit7: Average Data SNR,
+ * Bit8: Last Beacon NF, Bit9: Average Beacon NF,
+ * Bit10: Last Data NF, Bit11: Average Data NF
+ */
+ t_u16 selector;
+
+ /** RSSI */
+ /** RSSI of last beacon */
+ t_s16 bcn_rssi_last;
+ /** RSSI of beacon average */
+ t_s16 bcn_rssi_avg;
+ /** RSSI of last data packet */
+ t_s16 data_rssi_last;
+ /** RSSI of data packet average */
+ t_s16 data_rssi_avg;
+
+ /** SNR */
+ /** SNR of last beacon */
+ t_s16 bcn_snr_last;
+ /** SNR of beacon average */
+ t_s16 bcn_snr_avg;
+ /** SNR of last data packet */
+ t_s16 data_snr_last;
+ /** SNR of data packet average */
+ t_s16 data_snr_avg;
+
+ /** NF */
+ /** NF of last beacon */
+ t_s16 bcn_nf_last;
+ /** NF of beacon average */
+ t_s16 bcn_nf_avg;
+ /** NF of last data packet */
+ t_s16 data_nf_last;
+ /** NF of data packet average */
+ t_s16 data_nf_avg;
+} mlan_ds_get_signal, *pmlan_ds_get_signal;
+
+/** mlan_fw_info data structure for MLAN_OID_GET_FW_INFO */
+typedef struct _mlan_fw_info
+{
+ /** Firmware version */
+ t_u32 fw_ver;
+ /** MAC address */
+ mlan_802_11_mac_addr mac_addr;
+ /** Device support for MIMO abstraction of MCSs */
+ t_u8 hw_dev_mcs_support;
+ /** fw supported band */
+ t_u8 fw_bands;
+} mlan_fw_info, *pmlan_fw_info;
+
+/** Version string buffer length */
+#define MLAN_MAX_VER_STR_LEN 128
+
+/** mlan_ver_ext data structure for MLAN_OID_GET_VER_EXT */
+typedef struct _mlan_ver_ext
+{
+ /** Selected version string */
+ t_u32 version_str_sel;
+ /** Version string */
+ char version_str[MLAN_MAX_VER_STR_LEN];
+} mlan_ver_ext, *pmlan_ver_ext;
+
+/** mlan_bss_info data structure for MLAN_OID_GET_BSS_INFO */
+typedef struct _mlan_bss_info
+{
+ /** BSS mode */
+ t_u32 bss_mode;
+ /** SSID */
+ mlan_802_11_ssid ssid;
+ /** Table index */
+ t_u32 scan_table_idx;
+ /** Channel */
+ t_u32 bss_chan;
+ /** Band */
+ t_u8 bss_band;
+ /** Region code */
+ t_u32 region_code;
+ /** Connection status */
+ t_u32 media_connected;
+ /** Radio on */
+ t_u32 radio_on;
+ /** Max power level in dBm */
+ t_u32 max_power_level;
+ /** Min power level in dBm */
+ t_u32 min_power_level;
+ /** Adhoc state */
+ t_u32 adhoc_state;
+ /** NF of last beacon */
+ t_s32 bcn_nf_last;
+ /** wep status */
+ t_u32 wep_status;
+ /** Host Sleep configured flag */
+ t_u32 is_hs_configured;
+ /** Deep Sleep flag */
+ t_u32 is_deep_sleep;
+ /** BSSID */
+ mlan_802_11_mac_addr bssid;
+#ifdef STA_SUPPORT
+ /** Capability Info */
+ t_u16 capability_info;
+ /** Listen Interval */
+ t_u16 listen_interval;
+ /** Association Id */
+ t_u16 assoc_id;
+ /** AP/Peer supported rates */
+ t_u8 peer_supp_rates[MLAN_SUPPORTED_RATES];
+#endif /* STA_SUPPORT */
+} mlan_bss_info, *pmlan_bss_info;
+
+/** MAXIMUM number of TID */
+#define MAX_NUM_TID 8
+
+/** Max RX Win size */
+#define MAX_RX_WINSIZE 64
+
+/** rx_reorder_tbl */
+typedef struct
+{
+ /** TID */
+ t_u16 tid;
+ /** TA */
+ t_u8 ta[MLAN_MAC_ADDR_LENGTH];
+ /** Start window */
+ t_u32 start_win;
+ /** Window size */
+ t_u32 win_size;
+ /** amsdu flag */
+ t_u8 amsdu;
+ /** buffer status */
+ t_u32 buffer[MAX_RX_WINSIZE];
+} rx_reorder_tbl;
+
+/** tx_ba_stream_tbl */
+typedef struct
+{
+ /** TID */
+ t_u16 tid;
+ /** RA */
+ t_u8 ra[MLAN_MAC_ADDR_LENGTH];
+ /** amsdu flag */
+ t_u8 amsdu;
+} tx_ba_stream_tbl;
+
+/** Debug command number */
+#define DBG_CMD_NUM 5
+
+/** mlan_debug_info data structure for MLAN_OID_GET_DEBUG_INFO */
+typedef struct _mlan_debug_info
+{
+ /* WMM AC_BK count */
+ t_u32 wmm_ac_bk;
+ /* WMM AC_BE count */
+ t_u32 wmm_ac_be;
+ /* WMM AC_VI count */
+ t_u32 wmm_ac_vi;
+ /* WMM AC_VO count */
+ t_u32 wmm_ac_vo;
+ /** Corresponds to max_tx_buf_size member of mlan_adapter*/
+ t_u32 max_tx_buf_size;
+ /** Corresponds to tx_buf_size member of mlan_adapter*/
+ t_u32 tx_buf_size;
+ /** Corresponds to curr_tx_buf_size member of mlan_adapter*/
+ t_u32 curr_tx_buf_size;
+ /** Tx table num */
+ t_u32 tx_tbl_num;
+ /** Tx ba stream table */
+ tx_ba_stream_tbl tx_tbl[MLAN_MAX_TX_BASTREAM_SUPPORTED];
+ /** Rx table num */
+ t_u32 rx_tbl_num;
+ /** Rx reorder table*/
+ rx_reorder_tbl rx_tbl[MLAN_MAX_RX_BASTREAM_SUPPORTED];
+ /** Corresponds to ps_mode member of mlan_adapter */
+ t_u16 ps_mode;
+ /** Corresponds to ps_state member of mlan_adapter */
+ t_u32 ps_state;
+#ifdef STA_SUPPORT
+ /** Corresponds to is_deep_sleep member of mlan_adapter */
+ t_u8 is_deep_sleep;
+#endif /** STA_SUPPORT */
+ /** Corresponds to pm_wakeup_card_req member of mlan_adapter */
+ t_u8 pm_wakeup_card_req;
+ /** Corresponds to pm_wakeup_fw_try member of mlan_adapter */
+ t_u32 pm_wakeup_fw_try;
+ /** Corresponds to is_hs_configured member of mlan_adapter */
+ t_u8 is_hs_configured;
+ /** Corresponds to hs_activated member of mlan_adapter */
+ t_u8 hs_activated;
+ /** Corresponds to pps_uapsd_mode member of mlan_adapter */
+ t_u16 pps_uapsd_mode;
+ /** Corresponds to sleep_period.period member of mlan_adapter */
+ t_u16 sleep_pd;
+ /** Corresponds to wmm_qosinfo member of mlan_private */
+ t_u8 qos_cfg;
+ /** Corresponds to tx_lock_flag member of mlan_adapter */
+ t_u8 tx_lock_flag;
+ /** Corresponds to port_open member of mlan_private */
+ t_u8 port_open;
+ /** Corresponds to scan_processing member of mlan_adapter */
+ t_u32 scan_processing;
+ /** Number of host to card command failures */
+ t_u32 num_cmd_host_to_card_failure;
+ /** Number of host to card sleep confirm failures */
+ t_u32 num_cmd_sleep_cfm_host_to_card_failure;
+ /** Number of host to card Tx failures */
+ t_u32 num_tx_host_to_card_failure;
+ /** Number of card to host command/event failures */
+ t_u32 num_cmdevt_card_to_host_failure;
+ /** Number of card to host Rx failures */
+ t_u32 num_rx_card_to_host_failure;
+ /** Number of interrupt read failures */
+ t_u32 num_int_read_failure;
+ /** Last interrupt status */
+ t_u32 last_int_status;
+ /** Number of deauthentication events */
+ t_u32 num_event_deauth;
+ /** Number of disassosiation events */
+ t_u32 num_event_disassoc;
+ /** Number of link lost events */
+ t_u32 num_event_link_lost;
+ /** Number of deauthentication commands */
+ t_u32 num_cmd_deauth;
+ /** Number of association comamnd successes */
+ t_u32 num_cmd_assoc_success;
+ /** Number of association command failures */
+ t_u32 num_cmd_assoc_failure;
+ /** Number of Tx timeouts */
+ t_u32 num_tx_timeout;
+ /** Number of command timeouts */
+ t_u32 num_cmd_timeout;
+ /** Timeout command ID */
+ t_u16 timeout_cmd_id;
+ /** Timeout command action */
+ t_u16 timeout_cmd_act;
+ /** List of last command IDs */
+ t_u16 last_cmd_id[DBG_CMD_NUM];
+ /** List of last command actions */
+ t_u16 last_cmd_act[DBG_CMD_NUM];
+ /** Last command index */
+ t_u16 last_cmd_index;
+ /** List of last command response IDs */
+ t_u16 last_cmd_resp_id[DBG_CMD_NUM];
+ /** Last command response index */
+ t_u16 last_cmd_resp_index;
+ /** List of last events */
+ t_u16 last_event[DBG_CMD_NUM];
+ /** Last event index */
+ t_u16 last_event_index;
+
+ /** Corresponds to data_sent member of mlan_adapter */
+ t_u8 data_sent;
+ /** Corresponds to cmd_sent member of mlan_adapter */
+ t_u8 cmd_sent;
+ /** SDIO multiple port read bitmap */
+ t_u32 mp_rd_bitmap;
+ /** SDIO multiple port write bitmap */
+ t_u32 mp_wr_bitmap;
+ /** Current available port for read */
+ t_u8 curr_rd_port;
+ /** Current available port for write */
+ t_u8 curr_wr_port;
+ /** Corresponds to cmdresp_received member of mlan_adapter */
+ t_u8 cmd_resp_received;
+ /** Corresponds to event_received member of mlan_adapter */
+ t_u8 event_received;
+ /** pendig tx pkts */
+ t_u32 tx_pkts_queued;
+#ifdef UAP_SUPPORT
+ /** pending bridge pkts */
+ t_u16 num_bridge_pkts;
+ /** dropped pkts */
+ t_u32 num_drop_pkts;
+#endif
+} mlan_debug_info, *pmlan_debug_info;
+
+#ifdef UAP_SUPPORT
+/** Maximum number of clients supported by AP */
+#define MAX_NUM_CLIENTS 16
+
+/** station info */
+typedef struct _sta_info
+{
+ /** STA MAC address */
+ t_u8 mac_address[MLAN_MAC_ADDR_LENGTH];
+ /** Power mfg status */
+ t_u8 power_mfg_status;
+ /** RSSI */
+ t_s8 rssi;
+} sta_info;
+
+/** mlan_ds_sta_list structure for MLAN_OID_UAP_STA_LIST */
+typedef struct _mlan_ds_sta_list
+{
+ /** station count */
+ t_u16 sta_count;
+ /** station list */
+ sta_info info[MAX_NUM_CLIENTS];
+} mlan_ds_sta_list, *pmlan_ds_sta_list;
+#endif
+
+/** Type definition of mlan_ds_get_info for MLAN_IOCTL_GET_INFO */
+typedef struct _mlan_ds_get_info
+{
+ /** Sub-command */
+ t_u32 sub_command;
+
+ /** Status information parameter */
+ union
+ {
+ /** Signal information for MLAN_OID_GET_SIGNAL */
+ mlan_ds_get_signal signal;
+ /** Statistics information for MLAN_OID_GET_STATS */
+ mlan_ds_get_stats stats;
+ /** Firmware information for MLAN_OID_GET_FW_INFO */
+ mlan_fw_info fw_info;
+ /** Extended version information for MLAN_OID_GET_VER_EXT */
+ mlan_ver_ext ver_ext;
+ /** BSS information for MLAN_OID_GET_BSS_INFO */
+ mlan_bss_info bss_info;
+ /** Debug information for MLAN_OID_GET_DEBUG_INFO */
+ mlan_debug_info debug_info;
+#ifdef UAP_SUPPORT
+ /** UAP Statistics information for MLAN_OID_GET_STATS */
+ mlan_ds_uap_stats ustats;
+ /** UAP station list for MLAN_OID_UAP_STA_LIST */
+ mlan_ds_sta_list sta_list;
+#endif
+ } param;
+} mlan_ds_get_info, *pmlan_ds_get_info;
+
+/*-----------------------------------------------------------------*/
+/** Security Configuration Group */
+/*-----------------------------------------------------------------*/
+/** Enumeration for authentication mode */
+enum _mlan_auth_mode
+{
+ MLAN_AUTH_MODE_OPEN = 0x00,
+ MLAN_AUTH_MODE_SHARED = 0x01,
+ MLAN_AUTH_MODE_NETWORKEAP = 0x80,
+ MLAN_AUTH_MODE_AUTO = 0xFF,
+};
+
+/** Enumeration for encryption mode */
+enum _mlan_encryption_mode
+{
+ MLAN_ENCRYPTION_MODE_NONE = 0,
+ MLAN_ENCRYPTION_MODE_WEP40 = 1,
+ MLAN_ENCRYPTION_MODE_TKIP = 2,
+ MLAN_ENCRYPTION_MODE_CCMP = 3,
+ MLAN_ENCRYPTION_MODE_WEP104 = 4,
+};
+
+/** Enumeration for PSK */
+enum _mlan_psk_type
+{
+ MLAN_PSK_PASSPHRASE = 1,
+ MLAN_PSK_PMK,
+ MLAN_PSK_CLEAR,
+ MLAN_PSK_QUERY,
+};
+
+/** The bit to indicate the key is for unicast */
+#define MLAN_KEY_INDEX_UNICAST 0x40000000
+/** The key index to indicate default key */
+#define MLAN_KEY_INDEX_DEFAULT 0x000000ff
+/** Maximum key length */
+// #define MLAN_MAX_KEY_LENGTH 32
+/** Minimum passphrase length */
+#define MLAN_MIN_PASSPHRASE_LENGTH 8
+/** Maximum passphrase length */
+#define MLAN_MAX_PASSPHRASE_LENGTH 63
+/** PMK length */
+#define MLAN_PMK_HEXSTR_LENGTH 64
+/* A few details needed for WEP (Wireless Equivalent Privacy) */
+/** 104 bits */
+#define MAX_WEP_KEY_SIZE 13
+/** 40 bits RC4 - WEP */
+#define MIN_WEP_KEY_SIZE 5
+/** packet number size */
+#define PN_SIZE 16
+/** max seq size of wpa/wpa2 key */
+#define SEQ_MAX_SIZE 8
+
+/** key flag for tx_seq */
+#define KEY_FLAG_TX_SEQ_VALID 0x00000001
+/** key flag for rx_seq */
+#define KEY_FLAG_RX_SEQ_VALID 0x00000002
+/** key flag for group key */
+#define KEY_FLAG_GROUP_KEY 0x00000004
+/** key flag for tx and rx */
+#define KEY_FLAG_SET_TX_KEY 0x00000008
+/** key flag for remove key */
+#define KEY_FLAG_REMOVE_KEY 0x80000000
+
+/** Type definition of mlan_ds_encrypt_key for MLAN_OID_SEC_CFG_ENCRYPT_KEY */
+typedef struct _mlan_ds_encrypt_key
+{
+ /** Key disabled, all other fields will be ignore when this flag set to MTRUE */
+ t_u32 key_disable;
+ /** key removed flag, when this flag is set to MTRUE, only key_index will be check */
+ t_u32 key_remove;
+ /** Key index, used as current tx key index when is_current_wep_key is set to MTRUE */
+ t_u32 key_index;
+ /** Current Tx key flag */
+ t_u32 is_current_wep_key;
+ /** Key length */
+ t_u32 key_len;
+ /** Key */
+ t_u8 key_material[MLAN_MAX_KEY_LENGTH];
+ /** mac address */
+ t_u8 mac_addr[MLAN_MAC_ADDR_LENGTH];
+ /** wapi key flag */
+ t_u32 is_wapi_key;
+ /** Initial packet number */
+ t_u8 pn[PN_SIZE];
+ /** key flags */
+ t_u32 key_flags;
+} mlan_ds_encrypt_key, *pmlan_ds_encrypt_key;
+
+/** Type definition of mlan_passphrase_t */
+typedef struct _mlan_passphrase_t
+{
+ /** Length of passphrase */
+ t_u32 passphrase_len;
+ /** Passphrase */
+ t_u8 passphrase[MLAN_MAX_PASSPHRASE_LENGTH];
+} mlan_passphrase_t;
+
+/** Type defnition of mlan_pmk_t */
+typedef struct _mlan_pmk_t
+{
+ /** PMK */
+ t_u8 pmk[MLAN_MAX_KEY_LENGTH];
+} mlan_pmk_t;
+
+/** Type definition of mlan_ds_passphrase for MLAN_OID_SEC_CFG_PASSPHRASE */
+typedef struct _mlan_ds_passphrase
+{
+ /** SSID may be used */
+ mlan_802_11_ssid ssid;
+ /** BSSID may be used */
+ mlan_802_11_mac_addr bssid;
+ /** Flag for passphrase or pmk used */
+ t_u16 psk_type;
+ /** Passphrase or PMK */
+ union
+ {
+ /** Passphrase */
+ mlan_passphrase_t passphrase;
+ /** PMK */
+ mlan_pmk_t pmk;
+ } psk;
+} mlan_ds_passphrase, *pmlan_ds_passphrase;
+
+/** Type definition of mlan_ds_esupp_mode for MLAN_OID_SEC_CFG_ESUPP_MODE */
+typedef struct _mlan_ds_ewpa_mode
+{
+ /** RSN mode */
+ t_u32 rsn_mode;
+ /** Active pairwise cipher */
+ t_u32 act_paircipher;
+ /** Active pairwise cipher */
+ t_u32 act_groupcipher;
+} mlan_ds_esupp_mode, *pmlan_ds_esupp_mode;
+
+/** Type definition of mlan_ds_sec_cfg for MLAN_IOCTL_SEC_CFG */
+typedef struct _mlan_ds_sec_cfg
+{
+ /** Sub-command */
+ t_u32 sub_command;
+ /** Security configuration parameter */
+ union
+ {
+ /** Authentication mode for MLAN_OID_SEC_CFG_AUTH_MODE */
+ t_u32 auth_mode;
+ /** Encryption mode for MLAN_OID_SEC_CFG_ENCRYPT_MODE */
+ t_u32 encrypt_mode;
+ /** WPA enabled flag for MLAN_OID_SEC_CFG_WPA_ENABLED */
+ t_u32 wpa_enabled;
+ /** WAPI enabled flag for MLAN_OID_SEC_CFG_WAPI_ENABLED */
+ t_u32 wapi_enabled;
+ /** Port Control enabled flag for MLAN_OID_SEC_CFG_PORT_CTRL */
+ t_u32 port_ctrl_enabled;
+ /** Encryption key for MLAN_OID_SEC_CFG_ENCRYPT_KEY */
+ mlan_ds_encrypt_key encrypt_key;
+ /** Passphrase for MLAN_OID_SEC_CFG_PASSPHRASE */
+ mlan_ds_passphrase passphrase;
+ /** Embedded supplicant WPA enabled flag for MLAN_OID_SEC_CFG_EWPA_ENABLED */
+ t_u32 ewpa_enabled;
+ /** Embedded supplicant mode for MLAN_OID_SEC_CFG_ESUPP_MODE */
+ mlan_ds_esupp_mode esupp_mode;
+ } param;
+} mlan_ds_sec_cfg, *pmlan_ds_sec_cfg;
+
+/*-----------------------------------------------------------------*/
+/** Rate Configuration Group */
+/*-----------------------------------------------------------------*/
+/** Enumeration for rate type */
+enum _mlan_rate_type
+{
+ MLAN_RATE_INDEX,
+ MLAN_RATE_VALUE
+};
+
+/** Enumeration for rate format */
+enum _mlan_rate_format
+{
+ MLAN_RATE_FORMAT_LG = 0,
+ MLAN_RATE_FORMAT_HT,
+ MLAN_RATE_FORMAT_AUTO = 0xFF,
+};
+/** Max bitmap rates size */
+#define MAX_BITMAP_RATES_SIZE 10
+
+/** Type definition of mlan_rate_cfg_t for MLAN_OID_RATE_CFG */
+typedef struct _mlan_rate_cfg_t
+{
+ /** Fixed rate: 0, auto rate: 1 */
+ t_u32 is_rate_auto;
+ /** Rate type. 0: index; 1: valude */
+ t_u32 rate_type;
+ /** Rate/MCS index or rate value if fixed rate */
+ t_u32 rate;
+ /** Rate Bitmap */
+ t_u16 bitmap_rates[MAX_BITMAP_RATES_SIZE];
+} mlan_rate_cfg_t;
+
+/** HT channel bandwidth */
+typedef enum _mlan_ht_bw
+{
+ MLAN_HT_BW20,
+ MLAN_HT_BW40,
+} mlan_ht_bw;
+
+/** HT guard interval */
+typedef enum _mlan_ht_gi
+{
+ MLAN_HT_LGI,
+ MLAN_HT_SGI,
+} mlan_ht_gi;
+
+/** Band and BSS mode */
+typedef struct _mlan_band_data_rate
+{
+ /** Band configuration */
+ t_u8 config_bands;
+ /** BSS mode (Infra or IBSS) */
+ t_u8 bss_mode;
+} mlan_band_data_rate;
+
+/** Type definition of mlan_data_rate for MLAN_OID_GET_DATA_RATE */
+typedef struct _mlan_data_rate
+{
+ /** Tx data rate */
+ t_u32 tx_data_rate;
+ /** Rx data rate */
+ t_u32 rx_data_rate;
+
+ /** Tx channel bandwidth */
+ t_u32 tx_ht_bw;
+ /** Tx guard interval */
+ t_u32 tx_ht_gi;
+ /** Rx channel bandwidth */
+ t_u32 rx_ht_bw;
+ /** Rx guard interval */
+ t_u32 rx_ht_gi;
+} mlan_data_rate;
+
+/** Type definition of mlan_ds_rate for MLAN_IOCTL_RATE */
+typedef struct _mlan_ds_rate
+{
+ /** Sub-command */
+ t_u32 sub_command;
+ /** Rate configuration parameter */
+ union
+ {
+ /** Rate configuration for MLAN_OID_RATE_CFG */
+ mlan_rate_cfg_t rate_cfg;
+ /** Data rate for MLAN_OID_GET_DATA_RATE */
+ mlan_data_rate data_rate;
+ /** Supported rates for MLAN_OID_SUPPORTED_RATES */
+ t_u8 rates[MLAN_SUPPORTED_RATES];
+ /** Band/BSS mode for getting supported rates */
+ mlan_band_data_rate rate_band_cfg;
+ } param;
+} mlan_ds_rate, *pmlan_ds_rate;
+
+/*-----------------------------------------------------------------*/
+/** Power Configuration Group */
+/*-----------------------------------------------------------------*/
+
+/** Type definition of mlan_power_cfg_t for MLAN_OID_POWER_CFG */
+typedef struct _mlan_power_cfg_t
+{
+ /** Is power auto */
+ t_u32 is_power_auto;
+ /** Power level in dBm */
+ t_u32 power_level;
+} mlan_power_cfg_t;
+
+/** max power table size */
+#define MAX_POWER_TABLE_SIZE 128
+
+/** The HT BW40 bit in Tx rate index */
+#define TX_RATE_HT_BW40_BIT MBIT(7)
+
+/** Type definition of mlan_power_cfg_ext for MLAN_OID_POWER_CFG_EXT */
+typedef struct _mlan_power_cfg_ext
+{
+ /** Length of power_data */
+ t_u32 len;
+ /** Buffer of power configuration data */
+ t_u32 power_data[MAX_POWER_TABLE_SIZE];
+} mlan_power_cfg_ext;
+
+/** Type definition of mlan_ds_power_cfg for MLAN_IOCTL_POWER_CFG */
+typedef struct _mlan_ds_power_cfg
+{
+ /** Sub-command */
+ t_u32 sub_command;
+ /** Power configuration parameter */
+ union
+ {
+ /** Power configuration for MLAN_OID_POWER_CFG */
+ mlan_power_cfg_t power_cfg;
+ /** Extended power configuration for MLAN_OID_POWER_CFG_EXT */
+ mlan_power_cfg_ext power_ext;
+ } param;
+} mlan_ds_power_cfg, *pmlan_ds_power_cfg;
+
+/*-----------------------------------------------------------------*/
+/** Power Management Configuration Group */
+/*-----------------------------------------------------------------*/
+/** Host sleep config conditions : Cancel */
+#define HOST_SLEEP_CFG_CANCEL 0xffffffff
+
+/** Host sleep config condition: broadcast data */
+#define HOST_SLEEP_COND_BROADCAST_DATA MBIT(0)
+/** Host sleep config condition: unicast data */
+#define HOST_SLEEP_COND_UNICAST_DATA MBIT(1)
+/** Host sleep config condition: mac event */
+#define HOST_SLEEP_COND_MAC_EVENT MBIT(2)
+/** Host sleep config condition: multicast data */
+#define HOST_SLEEP_COND_MULTICAST_DATA MBIT(3)
+
+/** Host sleep config conditions: Default */
+#define HOST_SLEEP_DEF_COND (HOST_SLEEP_COND_BROADCAST_DATA | HOST_SLEEP_COND_UNICAST_DATA | HOST_SLEEP_COND_MAC_EVENT)
+/** Host sleep config GPIO : Default */
+#define HOST_SLEEP_DEF_GPIO 0xff
+/** Host sleep config gap : Default */
+#define HOST_SLEEP_DEF_GAP 200
+
+/** Type definition of mlan_ds_hs_cfg for MLAN_OID_PM_CFG_HS_CFG */
+typedef struct _mlan_ds_hs_cfg
+{
+ /** MTRUE to invoke the HostCmd, MFALSE otherwise */
+ t_u32 is_invoke_hostcmd;
+ /** Host sleep config condition */
+ /** Bit0: broadcast data
+ * Bit1: unicast data
+ * Bit2: mac event
+ * Bit3: multicast data
+ */
+ t_u32 conditions;
+ /** GPIO pin or 0xff for interface */
+ t_u32 gpio;
+ /** Gap in milliseconds or or 0xff for special setting when GPIO is used to wakeup host */
+ t_u32 gap;
+} mlan_ds_hs_cfg, *pmlan_ds_hs_cfg;
+
+/** Enable deep sleep mode */
+#define DEEP_SLEEP_ON 1
+/** Disable deep sleep mode */
+#define DEEP_SLEEP_OFF 0
+
+/** Default idle time in milliseconds for auto deep sleep */
+#define DEEP_SLEEP_IDLE_TIME 100
+
+typedef struct _mlan_ds_auto_ds
+{
+ /** auto ds mode, 0 - disable, 1 - enable */
+ t_u16 auto_ds;
+ /** auto ds idle time in milliseconds */
+ t_u16 idletime;
+} mlan_ds_auto_ds;
+
+/** Type definition of mlan_ds_inactivity_to for MLAN_OID_PM_CFG_INACTIVITY_TO */
+typedef struct _mlan_ds_inactivity_to
+{
+ /** Timeout unit in microsecond, 0 means 1000us (1ms) */
+ t_u32 timeout_unit;
+ /** Inactivity timeout for unicast data */
+ t_u32 unicast_timeout;
+ /** Inactivity timeout for multicast data */
+ t_u32 mcast_timeout;
+ /** Timeout for additional Rx traffic after Null PM1 packet exchange */
+ t_u32 ps_entry_timeout;
+} mlan_ds_inactivity_to, *pmlan_ds_inactivity_to;
+
+/** Minimum sleep period in milliseconds */
+#define MIN_SLEEP_PERIOD 10
+/** Maximum sleep period in milliseconds */
+#define MAX_SLEEP_PERIOD 60
+/** Special setting for UPSD certification tests */
+#define SLEEP_PERIOD_RESERVED_FF 0xFF
+
+/** PS null interval disable */
+#define PS_NULL_DISABLE (-1)
+
+/** Local listen interval disable */
+#define MRVDRV_LISTEN_INTERVAL_DISABLE (-1)
+/** Minimum listen interval */
+#define MRVDRV_MIN_LISTEN_INTERVAL 0
+
+/** Minimum multiple DTIM */
+#define MRVDRV_MIN_MULTIPLE_DTIM 0
+/** Maximum multiple DTIM */
+#define MRVDRV_MAX_MULTIPLE_DTIM 5
+/** Ignore multiple DTIM */
+#define MRVDRV_IGNORE_MULTIPLE_DTIM 0xfffe
+/** Match listen interval to closest DTIM */
+#define MRVDRV_MATCH_CLOSEST_DTIM 0xfffd
+
+/** Minimum adhoc awake period */
+#define MIN_ADHOC_AWAKE_PD 0
+/** Maximum adhoc awake period */
+#define MAX_ADHOC_AWAKE_PD 31
+/** Special adhoc awake period */
+#define SPECIAL_ADHOC_AWAKE_PD 255
+
+/** Minimum beacon miss timeout in milliseconds */
+#define MIN_BCN_MISS_TO 0
+/** Maximum beacon miss timeout in milliseconds */
+#define MAX_BCN_MISS_TO 50
+/** Disable beacon miss timeout */
+#define DISABLE_BCN_MISS_TO 65535
+
+/** Minimum delay to PS in milliseconds */
+#define MIN_DELAY_TO_PS 0
+/** Maximum delay to PS in milliseconds */
+#define MAX_DELAY_TO_PS 65535
+/** Delay to PS unchanged */
+#define DELAY_TO_PS_UNCHANGED (-1)
+/** Default delay to PS in milliseconds */
+#define DELAY_TO_PS_DEFAULT 1000
+
+/** PS mode: Unchanged */
+#define PS_MODE_UNCHANGED 0
+/** PS mode: Auto */
+#define PS_MODE_AUTO 1
+/** PS mode: Poll */
+#define PS_MODE_POLL 2
+/** PS mode: Null */
+#define PS_MODE_NULL 3
+
+/** Type definition of mlan_ds_ps_cfg for MLAN_OID_PM_CFG_PS_CFG */
+typedef struct _mlan_ds_ps_cfg
+{
+ /** PS null interval in seconds */
+ t_u32 ps_null_interval;
+ /** Multiple DTIM interval */
+ t_u32 multiple_dtim_interval;
+ /** Listen interval */
+ t_u32 listen_interval;
+ /** Adhoc awake period */
+ t_u32 adhoc_awake_period;
+ /** Beacon miss timeout in milliseconds */
+ t_u32 bcn_miss_timeout;
+ /** Delay to PS in milliseconds */
+ t_s32 delay_to_ps;
+ /** PS mode */
+ t_u32 ps_mode;
+} mlan_ds_ps_cfg, *pmlan_ds_ps_cfg;
+
+/** Type definition of mlan_ds_sleep_params for MLAN_OID_PM_CFG_SLEEP_PARAMS */
+typedef struct _mlan_ds_sleep_params
+{
+ /** Error */
+ t_u32 error;
+ /** Offset in microseconds */
+ t_u32 offset;
+ /** Stable time in microseconds */
+ t_u32 stable_time;
+ /** Calibration control */
+ t_u32 cal_control;
+ /** External sleep clock */
+ t_u32 ext_sleep_clk;
+ /** Reserved */
+ t_u32 reserved;
+} mlan_ds_sleep_params, *pmlan_ds_sleep_params;
+
+/** sleep_param */
+typedef struct _ps_sleep_param
+{
+ /** control bitmap */
+ t_u32 ctrl_bitmap;
+ /** minimum sleep period (micro second) */
+ t_u32 min_sleep;
+ /** maximum sleep period (micro second) */
+ t_u32 max_sleep;
+} ps_sleep_param;
+
+/** inactivity sleep_param */
+typedef struct _inact_sleep_param
+{
+ /** inactivity timeout (micro second) */
+ t_u32 inactivity_to;
+ /** miniumu awake period (micro second) */
+ t_u32 min_awake;
+ /** maximum awake period (micro second) */
+ t_u32 max_awake;
+} inact_sleep_param;
+
+/** flag for ps mode */
+#define PS_FLAG_PS_MODE 1
+/** flag for sleep param */
+#define PS_FLAG_SLEEP_PARAM 2
+/** flag for inactivity sleep param */
+#define PS_FLAG_INACT_SLEEP_PARAM 4
+
+/** Disable power mode */
+#define PS_MODE_DISABLE 0
+/** Enable periodic dtim ps */
+#define PS_MODE_PERIODIC_DTIM 1
+/** Enable inactivity ps */
+#define PS_MODE_INACTIVITY 2
+
+/** mlan_ds_ps_mgmt */
+typedef struct _mlan_ds_ps_mgmt
+{
+ /** flags for valid field */
+ t_u16 flags;
+ /** power mode */
+ t_u16 ps_mode;
+ /** sleep param */
+ ps_sleep_param sleep_param;
+ /** inactivity sleep param */
+ inact_sleep_param inact_param;
+} mlan_ds_ps_mgmt;
+
+/** mlan_ds_ps_info */
+typedef struct _mlan_ds_ps_info
+{
+ /** suspend allowed flag */
+ t_u32 is_suspend_allowed;
+} mlan_ds_ps_info;
+
+/** Type definition of mlan_ds_pm_cfg for MLAN_IOCTL_PM_CFG */
+typedef struct _mlan_ds_pm_cfg
+{
+ /** Sub-command */
+ t_u32 sub_command;
+ /** Power management parameter */
+ union
+ {
+ /** Power saving mode for MLAN_OID_PM_CFG_IEEE_PS */
+ t_u32 ps_mode;
+ /** Host Sleep configuration for MLAN_OID_PM_CFG_HS_CFG */
+ mlan_ds_hs_cfg hs_cfg;
+ /** Deep sleep mode for MLAN_OID_PM_CFG_DEEP_SLEEP */
+ mlan_ds_auto_ds auto_deep_sleep;
+ /** Inactivity timeout for MLAN_OID_PM_CFG_INACTIVITY_TO */
+ mlan_ds_inactivity_to inactivity_to;
+ /** Sleep period for MLAN_OID_PM_CFG_SLEEP_PD */
+ t_u32 sleep_period;
+ /** PS configuration parameters for MLAN_OID_PM_CFG_PS_CFG */
+ mlan_ds_ps_cfg ps_cfg;
+ /** PS configuration parameters for MLAN_OID_PM_CFG_SLEEP_PARAMS */
+ mlan_ds_sleep_params sleep_params;
+ /** PS configuration parameters for MLAN_OID_PM_CFG_PS_MODE */
+ mlan_ds_ps_mgmt ps_mgmt;
+ /** power info for MLAN_OID_PM_INFO */
+ mlan_ds_ps_info ps_info;
+ } param;
+} mlan_ds_pm_cfg, *pmlan_ds_pm_cfg;
+
+/*-----------------------------------------------------------------*/
+/** WMM Configuration Group */
+/*-----------------------------------------------------------------*/
+
+/** WMM TSpec size */
+#define MLAN_WMM_TSPEC_SIZE 63
+/** WMM Add TS extra IE bytes */
+#define MLAN_WMM_ADDTS_EXTRA_IE_BYTES 256
+/** WMM statistics for packets hist bins */
+#define MLAN_WMM_STATS_PKTS_HIST_BINS 7
+/** Maximum number of AC QOS queues available */
+#define MLAN_WMM_MAX_AC_QUEUES 4
+
+/**
+ * @brief IOCTL structure to send an ADDTS request and retrieve the response.
+ *
+ * IOCTL structure from the application layer relayed to firmware to
+ * instigate an ADDTS management frame with an appropriate TSPEC IE as well
+ * as any additional IEs appended in the ADDTS Action frame.
+ *
+ * @sa woal_wmm_addts_req_ioctl
+ */
+typedef struct
+{
+ mlan_cmd_result_e cmd_result; /**< Firmware execution result */
+
+ t_u32 timeout_ms; /**< Timeout value in milliseconds */
+ t_u8 ieee_status_code; /**< IEEE status code */
+
+ t_u32 ie_data_len; /**< Length of ie block in ie_data */
+ t_u8 ie_data[MLAN_WMM_TSPEC_SIZE /**< TSPEC to send in the ADDTS */
+ + MLAN_WMM_ADDTS_EXTRA_IE_BYTES]; /**< Extra IE buf*/
+} wlan_ioctl_wmm_addts_req_t;
+
+/**
+ * @brief IOCTL structure to send a DELTS request.
+ *
+ * IOCTL structure from the application layer relayed to firmware to
+ * instigate an DELTS management frame with an appropriate TSPEC IE.
+ *
+ * @sa woal_wmm_delts_req_ioctl
+ */
+typedef struct
+{
+ mlan_cmd_result_e cmd_result; /**< Firmware execution result */
+ t_u8 ieee_reason_code; /**< IEEE reason code sent, unused for WMM */
+ t_u32 ie_data_len; /**< Length of ie block in ie_data */
+ t_u8 ie_data[MLAN_WMM_TSPEC_SIZE]; /**< TSPEC to send in the DELTS */
+} wlan_ioctl_wmm_delts_req_t;
+
+/**
+ * @brief IOCTL structure to configure a specific AC Queue's parameters
+ *
+ * IOCTL structure from the application layer relayed to firmware to
+ * get, set, or default the WMM AC queue parameters.
+ *
+ * - msdu_lifetime_expiry is ignored if set to 0 on a set command
+ *
+ * @sa woal_wmm_queue_config_ioctl
+ */
+typedef struct
+{
+ mlan_wmm_queue_config_action_e action; /**< Set, Get, or Default */
+ mlan_wmm_ac_e access_category; /**< WMM_AC_BK(0) to WMM_AC_VO(3) */
+ t_u16 msdu_lifetime_expiry; /**< lifetime expiry in TUs */
+ t_u8 supported_rates[10]; /**< Not supported yet */
+} wlan_ioctl_wmm_queue_config_t;
+
+/**
+ * @brief IOCTL structure to start, stop, and get statistics for a WMM AC
+ *
+ * IOCTL structure from the application layer relayed to firmware to
+ * start or stop statistical collection for a given AC. Also used to
+ * retrieve and clear the collected stats on a given AC.
+ *
+ * @sa woal_wmm_queue_stats_ioctl
+ */
+typedef struct
+{
+ /** Action of Queue Config : Start, Stop, or Get */
+ mlan_wmm_queue_stats_action_e action;
+ /** User Priority */
+ t_u8 user_priority;
+ /** Number of successful packets transmitted */
+ t_u16 pkt_count;
+ /** Packets lost; not included in pkt_count */
+ t_u16 pkt_loss;
+ /** Average Queue delay in microseconds */
+ t_u32 avg_queue_delay;
+ /** Average Transmission delay in microseconds */
+ t_u32 avg_tx_delay;
+ /** Calculated used time in units of 32 microseconds */
+ t_u16 used_time;
+ /** Calculated policed time in units of 32 microseconds */
+ t_u16 policed_time;
+ /** Queue Delay Histogram; number of packets per queue delay range
+ *
+ * [0] - 0ms <= delay < 5ms
+ * [1] - 5ms <= delay < 10ms
+ * [2] - 10ms <= delay < 20ms
+ * [3] - 20ms <= delay < 30ms
+ * [4] - 30ms <= delay < 40ms
+ * [5] - 40ms <= delay < 50ms
+ * [6] - 50ms <= delay < msduLifetime (TUs)
+ */
+ t_u16 delay_histogram[MLAN_WMM_STATS_PKTS_HIST_BINS];
+} wlan_ioctl_wmm_queue_stats_t,
+/** Type definition of mlan_ds_wmm_queue_stats for MLAN_OID_WMM_CFG_QUEUE_STATS */
+ mlan_ds_wmm_queue_stats, *pmlan_ds_wmm_queue_stats;
+
+/**
+ * @brief IOCTL sub structure for a specific WMM AC Status
+ */
+typedef struct
+{
+ /** WMM Acm */
+ t_u8 wmm_acm;
+ /** Flow required flag */
+ t_u8 flow_required;
+ /** Flow created flag */
+ t_u8 flow_created;
+ /** Disabled flag */
+ t_u8 disabled;
+} wlan_ioctl_wmm_queue_status_ac_t;
+
+/**
+ * @brief IOCTL structure to retrieve the WMM AC Queue status
+ *
+ * IOCTL structure from the application layer to retrieve:
+ * - ACM bit setting for the AC
+ * - Firmware status (flow required, flow created, flow disabled)
+ *
+ * @sa woal_wmm_queue_status_ioctl
+ */
+typedef struct
+{
+ /** WMM AC queue status */
+ wlan_ioctl_wmm_queue_status_ac_t ac_status[MLAN_WMM_MAX_AC_QUEUES];
+} wlan_ioctl_wmm_queue_status_t,
+/** Type definition of mlan_ds_wmm_queue_status for MLAN_OID_WMM_CFG_QUEUE_STATUS */
+ mlan_ds_wmm_queue_status, *pmlan_ds_wmm_queue_status;
+
+/** Type definition of mlan_ds_wmm_addts for MLAN_OID_WMM_CFG_ADDTS */
+typedef struct _mlan_ds_wmm_addts
+{
+ /** Result of ADDTS request */
+ mlan_cmd_result_e result;
+ /** Timeout value in milliseconds */
+ t_u32 timeout;
+ /** IEEE status code */
+ t_u32 status_code;
+ /** Dialog token */
+ t_u8 dialog_tok;
+ /** TSPEC data length */
+ t_u8 ie_data_len;
+ /** TSPEC to send in the ADDTS + buffering for any extra IEs */
+ t_u8 ie_data[MLAN_WMM_TSPEC_SIZE + MLAN_WMM_ADDTS_EXTRA_IE_BYTES];
+} mlan_ds_wmm_addts, *pmlan_ds_wmm_addts;
+
+/** Type definition of mlan_ds_wmm_delts for MLAN_OID_WMM_CFG_DELTS */
+typedef struct _mlan_ds_wmm_delts
+{
+ /** Result of DELTS request */
+ mlan_cmd_result_e result;
+ /** IEEE status code */
+ t_u32 status_code;
+ /** TSPEC data length */
+ t_u8 ie_data_len;
+ /** TSPEC to send in the DELTS */
+ t_u8 ie_data[MLAN_WMM_TSPEC_SIZE];
+} mlan_ds_wmm_delts, *pmlan_ds_wmm_delts;
+
+/** Type definition of mlan_ds_wmm_queue_config for MLAN_OID_WMM_CFG_QUEUE_CONFIG */
+typedef struct _mlan_ds_wmm_queue_config
+{
+ /** Action of Queue Config : Set, Get, or Default */
+ mlan_wmm_queue_config_action_e action;
+ /** WMM Access Category: WMM_AC_BK(0) to WMM_AC_VO(3) */
+ mlan_wmm_ac_e access_category;
+ /** Lifetime expiry in TUs */
+ t_u16 msdu_lifetime_expiry;
+ /** Reserve for future use */
+ t_u8 reserved[10];
+} mlan_ds_wmm_queue_config, *pmlan_ds_wmm_queue_config;
+
+/** Type definition of mlan_ds_wmm_cfg for MLAN_IOCTL_WMM_CFG */
+typedef struct _mlan_ds_wmm_cfg
+{
+ /** Sub-command */
+ t_u32 sub_command;
+ /** WMM configuration parameter */
+ union
+ {
+ /** WMM enable for MLAN_OID_WMM_CFG_ENABLE */
+ t_u32 wmm_enable;
+ /** QoS configuration for MLAN_OID_WMM_CFG_QOS */
+ t_u8 qos_cfg;
+ /** WMM add TS for MLAN_OID_WMM_CFG_ADDTS */
+ mlan_ds_wmm_addts addts;
+ /** WMM delete TS for MLAN_OID_WMM_CFG_DELTS */
+ mlan_ds_wmm_delts delts;
+ /** WMM queue configuration for MLAN_OID_WMM_CFG_QUEUE_CONFIG */
+ mlan_ds_wmm_queue_config q_cfg;
+ /** WMM queue status for MLAN_OID_WMM_CFG_QUEUE_STATS */
+ mlan_ds_wmm_queue_stats q_stats;
+ /** WMM queue status for MLAN_OID_WMM_CFG_QUEUE_STATUS */
+ mlan_ds_wmm_queue_status q_status;
+ /** WMM TS status for MLAN_OID_WMM_CFG_TS_STATUS */
+ mlan_ds_wmm_ts_status ts_status;
+ } param;
+} mlan_ds_wmm_cfg, *pmlan_ds_wmm_cfg;
+
+/*-----------------------------------------------------------------*/
+/** WPS Configuration Group */
+/*-----------------------------------------------------------------*/
+/** Enumeration for WPS session */
+enum _mlan_wps_status
+{
+ MLAN_WPS_CFG_SESSION_START = 1,
+ MLAN_WPS_CFG_SESSION_END = 0
+};
+
+/** Type definition of mlan_ds_wps_cfg for MLAN_IOCTL_WPS_CFG */
+typedef struct _mlan_ds_wps_cfg
+{
+ /** Sub-command */
+ t_u32 sub_command;
+ /** WPS configuration parameter */
+ union
+ {
+ /** WPS session for MLAN_OID_WPS_CFG_SESSION */
+ t_u32 wps_session;
+ } param;
+} mlan_ds_wps_cfg, *pmlan_ds_wps_cfg;
+
+/*-----------------------------------------------------------------*/
+/** 802.11n Configuration Group */
+/*-----------------------------------------------------------------*/
+/** Maximum MCS */
+#define NUM_MCS_FIELD 16
+
+/** Supported stream modes */
+#define HT_STREAM_MODE_1X1 0x11
+#define HT_STREAM_MODE_2X2 0x22
+
+/* Both 2.4G and 5G band selected */
+#define BAND_SELECT_BOTH 0
+/* Band 2.4G selected */
+#define BAND_SELECT_BG 1
+/* Band 5G selected */
+#define BAND_SELECT_A 2
+
+/** Type definition of mlan_ds_11n_htcap_cfg for MLAN_OID_11N_HTCAP_CFG */
+typedef struct _mlan_ds_11n_htcap_cfg
+{
+ /** HT Capability information */
+ t_u32 htcap;
+ /** Band selection */
+ t_u32 misc_cfg;
+ /** Hardware HT cap information required */
+ t_u32 hw_cap_req;
+} mlan_ds_11n_htcap_cfg, *pmlan_ds_11n_htcap_cfg;
+
+/** Type definition of mlan_ds_11n_addba_param for MLAN_OID_11N_CFG_ADDBA_PARAM */
+typedef struct _mlan_ds_11n_addba_param
+{
+ /** Timeout */
+ t_u32 timeout;
+ /** Buffer size for ADDBA request */
+ t_u32 txwinsize;
+ /** Buffer size for ADDBA response */
+ t_u32 rxwinsize;
+ /** amsdu for ADDBA request */
+ t_u8 txamsdu;
+ /** amsdu for ADDBA response */
+ t_u8 rxamsdu;
+} mlan_ds_11n_addba_param, *pmlan_ds_11n_addba_param;
+
+/** Type definition of mlan_ds_11n_tx_cfg for MLAN_OID_11N_CFG_TX */
+typedef struct _mlan_ds_11n_tx_cfg
+{
+ /** HTTxCap */
+ t_u16 httxcap;
+ /** HTTxInfo */
+ t_u16 httxinfo;
+ /** Band selection */
+ t_u32 misc_cfg;
+} mlan_ds_11n_tx_cfg, *pmlan_ds_11n_tx_cfg;
+
+/** BF Global Configuration */
+#define BF_GLOBAL_CONFIGURATION 0x00
+/** Performs NDP sounding for PEER specified */
+#define TRIGGER_SOUNDING_FOR_PEER 0x01
+/** TX BF interval for channel sounding */
+#define SET_GET_BF_PERIODICITY 0x02
+/** Tell FW not to perform any sounding for peer */
+#define TX_BF_FOR_PEER_ENBL 0x03
+/** TX BF SNR threshold for peer */
+#define SET_SNR_THR_PEER 0x04
+
+/* Maximum number of peer MAC and status/SNR tuples */
+#define MAX_PEER_MAC_TUPLES 10
+
+/** Any new subcommand structure should be declare here */
+
+/** bf global cfg args */
+typedef struct _mlan_bf_global_cfg_args
+{
+ /** Global enable/disable bf */
+ t_u8 bf_enbl;
+ /** Global enable/disable sounding */
+ t_u8 sounding_enbl;
+ /** FB Type */
+ t_u8 fb_type;
+ /** SNR Threshold */
+ t_u8 snr_threshold;
+ /** Sounding interval in milliseconds */
+ t_u16 sounding_interval;
+ /** BF mode */
+ t_u8 bf_mode;
+ /** Reserved */
+ t_u8 reserved;
+} mlan_bf_global_cfg_args;
+
+/** trigger sounding args */
+typedef struct _mlan_trigger_sound_args
+{
+ /** Peer MAC address */
+ t_u8 peer_mac[MLAN_MAC_ADDR_LENGTH];
+ /** Status */
+ t_u8 status;
+} mlan_trigger_sound_args;
+
+/** bf periodicity args */
+typedef struct _mlan_bf_periodicity_args
+{
+ /** Peer MAC address */
+ t_u8 peer_mac[MLAN_MAC_ADDR_LENGTH];
+ /** Current Tx BF Interval in milliseconds */
+ t_u16 interval;
+ /** Status */
+ t_u8 status;
+} mlan_bf_periodicity_args;
+
+/** tx bf peer args */
+typedef struct _mlan_tx_bf_peer_args
+{
+ /** Peer MAC address */
+ t_u8 peer_mac[MLAN_MAC_ADDR_LENGTH];
+ /** Reserved */
+ t_u16 reserved;
+ /** Enable/Disable Beamforming */
+ t_u8 bf_enbl;
+ /** Enable/Disable sounding */
+ t_u8 sounding_enbl;
+ /** FB Type */
+ t_u8 fb_type;
+} mlan_tx_bf_peer_args;
+
+/** SNR threshold args */
+typedef struct _mlan_snr_thr_args
+{
+ /** Peer MAC address */
+ t_u8 peer_mac[MLAN_MAC_ADDR_LENGTH];
+ /** SNR for peer */
+ t_u8 snr;
+} mlan_snr_thr_args;
+
+/** Type definition of mlan_ds_11n_tx_bf_cfg for MLAN_OID_11N_CFG_TX_BF_CFG */
+typedef struct _mlan_ds_11n_tx_bf_cfg
+{
+ /** BF Action */
+ t_u16 bf_action;
+ /** Action */
+ t_u16 action;
+ /** Number of peers */
+ t_u32 no_of_peers;
+ union
+ {
+ mlan_bf_global_cfg_args bf_global_cfg;
+ mlan_trigger_sound_args bf_sound[MAX_PEER_MAC_TUPLES];
+ mlan_bf_periodicity_args bf_periodicity[MAX_PEER_MAC_TUPLES];
+ mlan_tx_bf_peer_args tx_bf_peer[MAX_PEER_MAC_TUPLES];
+ mlan_snr_thr_args bf_snr[MAX_PEER_MAC_TUPLES];
+ } body;
+} mlan_ds_11n_tx_bf_cfg, *pmlan_ds_11n_tx_bf_cfg;
+
+/** Type definition of mlan_ds_11n_amsdu_aggr_ctrl for
+ * MLAN_OID_11N_AMSDU_AGGR_CTRL*/
+typedef struct _mlan_ds_11n_amsdu_aggr_ctrl
+{
+ /** Enable/Disable */
+ t_u16 enable;
+ /** Current AMSDU size valid */
+ t_u16 curr_buf_size;
+} mlan_ds_11n_amsdu_aggr_ctrl, *pmlan_ds_11n_amsdu_aggr_ctrl;
+
+/** Type definition of mlan_ds_11n_aggr_prio_tbl for MLAN_OID_11N_CFG_AGGR_PRIO_TBL */
+typedef struct _mlan_ds_11n_aggr_prio_tbl
+{
+ /** ampdu priority table */
+ t_u8 ampdu[MAX_NUM_TID];
+ /** amsdu priority table */
+ t_u8 amsdu[MAX_NUM_TID];
+} mlan_ds_11n_aggr_prio_tbl, *pmlan_ds_11n_aggr_prio_tbl;
+
+/** Type definition of mlan_ds_11n_cfg for MLAN_IOCTL_11N_CFG */
+typedef struct _mlan_ds_11n_cfg
+{
+ /** Sub-command */
+ t_u32 sub_command;
+ /** 802.11n configuration parameter */
+ union
+ {
+ /** Tx param for 11n for MLAN_OID_11N_CFG_TX */
+ mlan_ds_11n_tx_cfg tx_cfg;
+ /** Aggr priority table for MLAN_OID_11N_CFG_AGGR_PRIO_TBL */
+ mlan_ds_11n_aggr_prio_tbl aggr_prio_tbl;
+ /** Add BA param for MLAN_OID_11N_CFG_ADDBA_PARAM */
+ mlan_ds_11n_addba_param addba_param;
+ /** Add BA Reject paramters for MLAN_OID_11N_CFG_ADDBA_REJECT */
+ t_u8 addba_reject[MAX_NUM_TID];
+ /** Tx buf size for MLAN_OID_11N_CFG_MAX_TX_BUF_SIZE */
+ t_u32 tx_buf_size;
+ /** HT cap info configuration for MLAN_OID_11N_HTCAP_CFG */
+ mlan_ds_11n_htcap_cfg htcap_cfg;
+ /** Tx param for 11n for MLAN_OID_11N_AMSDU_AGGR_CTRL */
+ mlan_ds_11n_amsdu_aggr_ctrl amsdu_aggr_ctrl;
+ /** Supported MCS Set field */
+ t_u8 supported_mcs_set[NUM_MCS_FIELD];
+ /** Transmit Beamforming Capabilities field */
+ t_u32 tx_bf_cap;
+ /** Transmit Beamforming configuration */
+ mlan_ds_11n_tx_bf_cfg tx_bf;
+ /** HT stream configuration */
+ t_u32 stream_cfg;
+ } param;
+} mlan_ds_11n_cfg, *pmlan_ds_11n_cfg;
+
+/** Country code length */
+#define COUNTRY_CODE_LEN 3
+
+/*-----------------------------------------------------------------*/
+/** 802.11d Configuration Group */
+/*-----------------------------------------------------------------*/
+/** Maximum subbands for 11d */
+#define MRVDRV_MAX_SUBBAND_802_11D 83
+
+#ifdef STA_SUPPORT
+/** Data structure for subband set */
+typedef struct _mlan_ds_subband_set_t
+{
+ /** First channel */
+ t_u8 first_chan;
+ /** Number of channels */
+ t_u8 no_of_chan;
+ /** Maximum Tx power in dBm */
+ t_u8 max_tx_pwr;
+} mlan_ds_subband_set_t;
+
+/** Domain regulatory information */
+typedef struct _mlan_ds_11d_domain_info
+{
+ /** Country Code */
+ t_u8 country_code[COUNTRY_CODE_LEN];
+ /** Band that channels in sub_band belong to */
+ t_u8 band;
+ /** No. of subband in below */
+ t_u8 no_of_sub_band;
+ /** Subband data to send/last sent */
+ mlan_ds_subband_set_t sub_band[MRVDRV_MAX_SUBBAND_802_11D];
+} mlan_ds_11d_domain_info;
+#endif
+
+/** Type definition of mlan_ds_11d_cfg for MLAN_IOCTL_11D_CFG */
+typedef struct _mlan_ds_11d_cfg
+{
+ /** Sub-command */
+ t_u32 sub_command;
+ /** 802.11d configuration parameter */
+ union
+ {
+#ifdef STA_SUPPORT
+ /** Enable for MLAN_OID_11D_CFG_ENABLE */
+ t_u32 enable_11d;
+ /** Domain info for MLAN_OID_11D_DOMAIN_INFO */
+ mlan_ds_11d_domain_info domain_info;
+#endif /* STA_SUPPORT */
+#ifdef UAP_SUPPORT
+ /** tlv data for MLAN_OID_11D_DOMAIN_INFO */
+ t_u8 domain_tlv[MAX_IE_SIZE];
+#endif /* UAP_SUPPORT */
+ } param;
+} mlan_ds_11d_cfg, *pmlan_ds_11d_cfg;
+
+/*-----------------------------------------------------------------*/
+/** Register Memory Access Group */
+/*-----------------------------------------------------------------*/
+/** Enumeration for register type */
+enum _mlan_reg_type
+{
+ MLAN_REG_MAC = 1,
+ MLAN_REG_BBP,
+ MLAN_REG_RF,
+ MLAN_REG_CAU,
+};
+
+/** Type definition of mlan_ds_reg_rw for MLAN_OID_REG_RW */
+typedef struct _mlan_ds_reg_rw
+{
+ /** Register type */
+ t_u32 type;
+ /** Offset */
+ t_u32 offset;
+ /** Value */
+ t_u32 value;
+} mlan_ds_reg_rw;
+
+/** Maximum EEPROM data */
+#define MAX_EEPROM_DATA 256
+
+/** Type definition of mlan_ds_read_eeprom for MLAN_OID_EEPROM_RD */
+typedef struct _mlan_ds_read_eeprom
+{
+ /** Multiples of 4 */
+ t_u16 offset;
+ /** Number of bytes */
+ t_u16 byte_count;
+ /** Value */
+ t_u8 value[MAX_EEPROM_DATA];
+} mlan_ds_read_eeprom;
+
+/** Type definition of mlan_ds_mem_rw for MLAN_OID_MEM_RW */
+typedef struct _mlan_ds_mem_rw
+{
+ /** Address */
+ t_u32 addr;
+ /** Value */
+ t_u32 value;
+} mlan_ds_mem_rw;
+
+/** Type definition of mlan_ds_reg_mem for MLAN_IOCTL_REG_MEM */
+typedef struct _mlan_ds_reg_mem
+{
+ /** Sub-command */
+ t_u32 sub_command;
+ /** Register memory access parameter */
+ union
+ {
+ /** Register access for MLAN_OID_REG_RW */
+ mlan_ds_reg_rw reg_rw;
+ /** EEPROM access for MLAN_OID_EEPROM_RD */
+ mlan_ds_read_eeprom rd_eeprom;
+ /** Memory access for MLAN_OID_MEM_RW */
+ mlan_ds_mem_rw mem_rw;
+ } param;
+} mlan_ds_reg_mem, *pmlan_ds_reg_mem;
+
+/*-----------------------------------------------------------------*/
+/** Multi-Radio Configuration Group */
+/*-----------------------------------------------------------------*/
+
+/*-----------------------------------------------------------------*/
+/** 802.11h Configuration Group */
+/*-----------------------------------------------------------------*/
+#if defined(DFS_TESTING_SUPPORT)
+/** Type definition of mlan_ds_11h_dfs_testing for MLAN_OID_11H_DFS_TESTING */
+typedef struct _mlan_ds_11h_dfs_testing
+{
+ /** User-configured CAC period in milliseconds, 0 to use default */
+ t_u16 usr_cac_period_msec;
+ /** User-configured NOP period in seconds, 0 to use default */
+ t_u16 usr_nop_period_sec;
+ /** User-configured skip channel change, 0 to disable */
+ t_u8 usr_no_chan_change;
+ /** User-configured fixed channel to change to, 0 to use random channel */
+ t_u8 usr_fixed_new_chan;
+} mlan_ds_11h_dfs_testing, *pmlan_ds_11h_dfs_testing;
+#endif
+
+/** Type definition of mlan_ds_11h_cfg for MLAN_IOCTL_11H_CFG */
+typedef struct _mlan_ds_11h_cfg
+{
+ /** Sub-command */
+ t_u32 sub_command;
+ union
+ {
+ /** Local power constraint for MLAN_OID_11H_LOCAL_POWER_CONSTRAINT */
+ t_s8 usr_local_power_constraint;
+#if defined(DFS_TESTING_SUPPORT)
+ /** User-configuation for MLAN_OID_11H_DFS_TESTING */
+ mlan_ds_11h_dfs_testing dfs_testing;
+#endif
+ } param;
+} mlan_ds_11h_cfg, *pmlan_ds_11h_cfg;
+
+/*-----------------------------------------------------------------*/
+/** Miscellaneous Configuration Group */
+/*-----------------------------------------------------------------*/
+
+/** CMD buffer size */
+#define MLAN_SIZE_OF_CMD_BUFFER 2048
+
+/** LDO Internal */
+#define LDO_INTERNAL 0
+/** LDO External */
+#define LDO_EXTERNAL 1
+
+/** Enumeration for IE type */
+enum _mlan_ie_type
+{
+ MLAN_IE_TYPE_GEN_IE = 0,
+#ifdef STA_SUPPORT
+ MLAN_IE_TYPE_ARP_FILTER,
+#endif /* STA_SUPPORT */
+};
+
+/** Type definition of mlan_ds_misc_gen_ie for MLAN_OID_MISC_GEN_IE */
+typedef struct _mlan_ds_misc_gen_ie
+{
+ /** IE type */
+ t_u32 type;
+ /** IE length */
+ t_u32 len;
+ /** IE buffer */
+ t_u8 ie_data[MAX_IE_SIZE];
+} mlan_ds_misc_gen_ie;
+
+#if defined(SDIO_MULTI_PORT_TX_AGGR) || defined(SDIO_MULTI_PORT_RX_AGGR)
+/** Type definition of mlan_ds_misc_sdio_mpa_ctrl for MLAN_OID_MISC_SDIO_MPA_CTRL */
+typedef struct _mlan_ds_misc_sdio_mpa_ctrl
+{
+ /** SDIO MP-A TX enable/disable */
+ t_u16 tx_enable;
+ /** SDIO MP-A RX enable/disable */
+ t_u16 rx_enable;
+ /** SDIO MP-A TX buf size */
+ t_u16 tx_buf_size;
+ /** SDIO MP-A RX buf size */
+ t_u16 rx_buf_size;
+ /** SDIO MP-A TX Max Ports */
+ t_u16 tx_max_ports;
+ /** SDIO MP-A RX Max Ports */
+ t_u16 rx_max_ports;
+} mlan_ds_misc_sdio_mpa_ctrl;
+#endif
+
+/** Type definition of mlan_ds_misc_cmd for MLAN_OID_MISC_HOST_CMD */
+typedef struct _mlan_ds_misc_cmd
+{
+ /** Command length */
+ t_u32 len;
+ /** Command buffer */
+ t_u8 cmd[MLAN_SIZE_OF_CMD_BUFFER];
+} mlan_ds_misc_cmd;
+
+/** Maximum number of system clocks */
+#define MLAN_MAX_CLK_NUM 16
+
+/** Clock type : Configurable */
+#define MLAN_CLK_CONFIGURABLE 0
+/** Clock type : Supported */
+#define MLAN_CLK_SUPPORTED 1
+
+/** Type definition of mlan_ds_misc_sys_clock for MLAN_OID_MISC_SYS_CLOCK */
+typedef struct _mlan_ds_misc_sys_clock
+{
+ /** Current system clock */
+ t_u16 cur_sys_clk;
+ /** Clock type */
+ t_u16 sys_clk_type;
+ /** Number of clocks */
+ t_u16 sys_clk_num;
+ /** System clocks */
+ t_u16 sys_clk[MLAN_MAX_CLK_NUM];
+} mlan_ds_misc_sys_clock;
+
+/** Enumeration for function init/shutdown */
+enum _mlan_func_cmd
+{
+ MLAN_FUNC_INIT = 1,
+ MLAN_FUNC_SHUTDOWN,
+};
+
+/** Type definition of mlan_ds_misc_tx_datapause for MLAN_OID_MISC_TX_DATAPAUSE */
+typedef struct _mlan_ds_misc_tx_datapause
+{
+ /** Tx data pause flag */
+ t_u16 tx_pause;
+ /** Max number of Tx buffers for all PS clients */
+ t_u16 tx_buf_cnt;
+} mlan_ds_misc_tx_datapause;
+
+/** IP address length */
+#define IPADDR_LEN (16)
+/** Max number of ip */
+#define MAX_IPADDR (4)
+/** IP address type - IPv4*/
+#define IPADDR_TYPE_IPV4 (1)
+/** IP operation remove */
+#define MLAN_IPADDR_OP_IP_REMOVE (0)
+/** IP operation ARP filter */
+#define MLAN_IPADDR_OP_ARP_FILTER MBIT(0)
+/** IP operation ARP response */
+#define MLAN_IPADDR_OP_AUTO_ARP_RESP MBIT(1)
+
+/** Type definition of mlan_ds_misc_ipaddr_cfg for MLAN_OID_MISC_IP_ADDR */
+typedef struct _mlan_ds_misc_ipaddr_cfg
+{
+ /** Operation code */
+ t_u32 op_code;
+ /** IP address type */
+ t_u32 ip_addr_type;
+ /** Number of IP */
+ t_u32 ip_addr_num;
+ /** IP address */
+ t_u8 ip_addr[MAX_IPADDR][IPADDR_LEN];
+} mlan_ds_misc_ipaddr_cfg;
+
+/* MEF configuration disable */
+#define MEF_CFG_DISABLE 0
+/* MEF configuration Rx filter enable */
+#define MEF_CFG_RX_FILTER_ENABLE 1
+/* MEF configuration auto ARP response */
+#define MEF_CFG_AUTO_ARP_RESP 2
+/* MEF configuration host command */
+#define MEF_CFG_HOSTCMD 0xFFFF
+
+/** Type definition of mlan_ds_misc_mef_cfg for MLAN_OID_MISC_MEF_CFG */
+typedef struct _mlan_ds_misc_mef_cfg
+{
+ /** Sub-ID for operation */
+ t_u32 sub_id;
+ /** Parameter according to sub-ID */
+ union
+ {
+ /** MEF command buffer for MEF_CFG_HOSTCMD */
+ mlan_ds_misc_cmd cmd_buf;
+ } param;
+} mlan_ds_misc_mef_cfg;
+
+/** BITMAP for subscribe event rssi low */
+#define SUBSCRIBE_EVT_RSSI_LOW MBIT(0)
+/** BITMAP for subscribe event snr low */
+#define SUBSCRIBE_EVT_SNR_LOW MBIT(1)
+/** BITMAP for subscribe event max fail */
+#define SUBSCRIBE_EVT_MAX_FAIL MBIT(2)
+/** BITMAP for subscribe event beacon missed */
+#define SUBSCRIBE_EVT_BEACON_MISSED MBIT(3)
+/** BITMAP for subscribe event rssi high */
+#define SUBSCRIBE_EVT_RSSI_HIGH MBIT(4)
+/** BITMAP for subscribe event snr high */
+#define SUBSCRIBE_EVT_SNR_HIGH MBIT(5)
+/** BITMAP for subscribe event data rssi low */
+#define SUBSCRIBE_EVT_DATA_RSSI_LOW MBIT(6)
+/** BITMAP for subscribe event data snr low */
+#define SUBSCRIBE_EVT_DATA_SNR_LOW MBIT(7)
+/** BITMAP for subscribe event data rssi high */
+#define SUBSCRIBE_EVT_DATA_RSSI_HIGH MBIT(8)
+/** BITMAP for subscribe event data snr high */
+#define SUBSCRIBE_EVT_DATA_SNR_HIGH MBIT(9)
+/** BITMAP for subscribe event link quality */
+#define SUBSCRIBE_EVT_LINK_QUALITY MBIT(10)
+/** BITMAP for subscribe event pre_beacon_lost */
+#define SUBSCRIBE_EVT_PRE_BEACON_LOST MBIT(11)
+
+/** Type definition of mlan_ds_subscribe_evt for MLAN_OID_MISC_CFP_CODE */
+typedef struct _mlan_ds_subscribe_evt
+{
+ /** bitmap for subscribe event */
+ t_u16 evt_bitmap;
+ /** Absolute value of RSSI threshold value (dBm) */
+ t_u8 low_rssi;
+ /** 0--report once, 1--report everytime happen, N -- report only happend > N consecutive times */
+ t_u8 low_rssi_freq;
+ /** SNR threshold value (dB) */
+ t_u8 low_snr;
+ /** 0--report once, 1--report everytime happen, N -- report only happend > N consecutive times */
+ t_u8 low_snr_freq;
+ /** Failure count threshold */
+ t_u8 failure_count;
+ /** 0--report once, 1--report everytime happen, N -- report only happend > N consecutive times */
+ t_u8 failure_count_freq;
+ /** num of missed beacons */
+ t_u8 beacon_miss;
+ /** 0--report once, 1--report everytime happen, N -- report only happend > N consecutive times */
+ t_u8 beacon_miss_freq;
+ /** Absolute value of RSSI threshold value (dBm) */
+ t_u8 high_rssi;
+ /** 0--report once, 1--report everytime happen, N -- report only happend > N consecutive times */
+ t_u8 high_rssi_freq;
+ /** SNR threshold value (dB) */
+ t_u8 high_snr;
+ /** 0--report once, 1--report everytime happen, N -- report only happend > N consecutive times */
+ t_u8 high_snr_freq;
+ /** Absolute value of data RSSI threshold value (dBm) */
+ t_u8 data_low_rssi;
+ /** 0--report once, 1--report everytime happen, N -- report only happend > N consecutive times */
+ t_u8 data_low_rssi_freq;
+ /** Absolute value of data SNR threshold value (dBm) */
+ t_u8 data_low_snr;
+ /** 0--report once, 1--report everytime happen, N -- report only happend > N consecutive times */
+ t_u8 data_low_snr_freq;
+ /** Absolute value of data RSSI threshold value (dBm) */
+ t_u8 data_high_rssi;
+ /** 0--report once, 1--report everytime happen, N -- report only happend > N consecutive times */
+ t_u8 data_high_rssi_freq;
+ /** Absolute value of data SNR threshold value (dBm) */
+ t_u8 data_high_snr;
+ /** 0--report once, 1--report everytime happen, N -- report only happend > N consecutive times */
+ t_u8 data_high_snr_freq;
+ /* Link SNR threshold (dB) */
+ t_u16 link_snr;
+ /* Link SNR frequency */
+ t_u16 link_snr_freq;
+ /* Second minimum rate value as per the rate table below */
+ t_u16 link_rate;
+ /* Second minimum rate frequency */
+ t_u16 link_rate_freq;
+ /* Tx latency value (us) */
+ t_u16 link_tx_latency;
+ /* Tx latency frequency */
+ t_u16 link_tx_lantency_freq;
+ /* Number of pre missed beacons */
+ t_u8 pre_beacon_miss;
+} mlan_ds_subscribe_evt;
+
+/** Type definition of mlan_ds_misc_cfg for MLAN_IOCTL_MISC_CFG */
+typedef struct _mlan_ds_misc_cfg
+{
+ /** Sub-command */
+ t_u32 sub_command;
+ /** Miscellaneous configuration parameter */
+ union
+ {
+ /** Generic IE for MLAN_OID_MISC_GEN_IE */
+ mlan_ds_misc_gen_ie gen_ie;
+ /** Region code for MLAN_OID_MISC_REGION */
+ t_u32 region_code;
+#if defined(SDIO_MULTI_PORT_TX_AGGR) || defined(SDIO_MULTI_PORT_RX_AGGR)
+ /** SDIO MP-A Ctrl command for MLAN_OID_MISC_SDIO_MPA_CTRL */
+ mlan_ds_misc_sdio_mpa_ctrl mpa_ctrl;
+#endif
+ /** Hostcmd for MLAN_OID_MISC_HOST_CMD */
+ mlan_ds_misc_cmd hostcmd;
+ /** System clock for MLAN_OID_MISC_SYS_CLOCK */
+ mlan_ds_misc_sys_clock sys_clock;
+ /** WWS set/get for MLAN_OID_MISC_WWS */
+ t_u32 wws_cfg;
+ /** Function init/shutdown for MLAN_OID_MISC_INIT_SHUTDOWN */
+ t_u32 func_init_shutdown;
+ /** Custom IE for MLAN_OID_MISC_CUSTOM_IE */
+ mlan_ds_misc_custom_ie cust_ie;
+ /** Tx data pause for MLAN_OID_MISC_TX_DATAPAUSE */
+ mlan_ds_misc_tx_datapause tx_datapause;
+ /** IP address configuration */
+ mlan_ds_misc_ipaddr_cfg ipaddr_cfg;
+ /** MAC control for MLAN_OID_MISC_MAC_CONTROL */
+ t_u32 mac_ctrl;
+ /** MEF configuration for MLAN_OID_MISC_MEF_CFG */
+ mlan_ds_misc_mef_cfg mef_cfg;
+ /** Thermal reading for MLAN_OID_MISC_THERMAL */
+ t_u32 thermal;
+ /** Mgmt subtype mask for MLAN_OID_MISC_RX_MGMT_IND */
+ t_u32 mgmt_subtype_mask;
+ /** subscribe event for MLAN_OID_MISC_SUBSCRIBE_EVENT */
+ mlan_ds_subscribe_evt subscribe_event;
+#ifdef DEBUG_LEVEL1
+ /** Driver debug bit masks */
+ t_u32 drvdbg;
+#endif
+ } param;
+} mlan_ds_misc_cfg, *pmlan_ds_misc_cfg;
+
+#endif /* !_MLAN_IOCTL_H_ */
diff --git a/drivers/net/wireless/sd8797/mlan/mlan_join.c b/drivers/net/wireless/sd8797/mlan/mlan_join.c
new file mode 100644
index 000000000000..c997a6f804ee
--- /dev/null
+++ b/drivers/net/wireless/sd8797/mlan/mlan_join.c
@@ -0,0 +1,1853 @@
+/** @file mlan_join.c
+ *
+ * @brief Functions implementing wlan infrastructure and adhoc join routines
+ *
+ * IOCTL handlers as well as command preparation and response routines
+ * for sending adhoc start, adhoc join, and association commands
+ * to the firmware.
+ *
+ * Copyright (C) 2008-2011, Marvell International Ltd.
+ *
+ * This software file (the "File") is distributed by Marvell International
+ * Ltd. under the terms of the GNU General Public License Version 2, June 1991
+ * (the "License"). You may use, redistribute and/or modify this File in
+ * accordance with the terms and conditions of the License, a copy of which
+ * is available by writing to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
+ * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
+ *
+ * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
+ * ARE EXPRESSLY DISCLAIMED. The License provides additional details about
+ * this warranty disclaimer.
+ */
+
+/******************************************************
+Change log:
+ 10/30/2008: initial version
+******************************************************/
+
+#include "mlan.h"
+#include "mlan_join.h"
+#include "mlan_util.h"
+#include "mlan_fw.h"
+#include "mlan_main.h"
+#include "mlan_wmm.h"
+#include "mlan_11n.h"
+#include "mlan_11h.h"
+
+/********************************************************
+ Local Constants
+********************************************************/
+
+/********************************************************
+ Local Variables
+********************************************************/
+
+/********************************************************
+ Global Variables
+********************************************************/
+
+/********************************************************
+ Local Functions
+********************************************************/
+/**
+ * @brief Append a generic IE as a pass through TLV to a TLV buffer.
+ *
+ * This function is called from the network join command prep. routine.
+ * If the IE buffer has been setup by the application, this routine appends
+ * the buffer as a pass through TLV type to the request.
+ *
+ * @param priv A pointer to mlan_private structure
+ * @param ppbuffer pointer to command buffer pointer
+ *
+ * @return bytes added to the buffer
+ */
+static int
+wlan_cmd_append_generic_ie(mlan_private * priv, t_u8 ** ppbuffer)
+{
+ int ret_len = 0;
+ MrvlIEtypesHeader_t ie_header;
+
+ ENTER();
+
+ /* Null Checks */
+ if (ppbuffer == MNULL) {
+ LEAVE();
+ return 0;
+ }
+ if (*ppbuffer == MNULL) {
+ LEAVE();
+ return 0;
+ }
+
+ /*
+ * If there is a generic ie buffer setup, append it to the return
+ * parameter buffer pointer.
+ */
+ if (priv->gen_ie_buf_len) {
+ PRINTM(MINFO, "append generic IE %d to %p\n", priv->gen_ie_buf_len,
+ *ppbuffer);
+
+ /* Wrap the generic IE buffer with a pass through TLV type */
+ ie_header.type = wlan_cpu_to_le16(TLV_TYPE_PASSTHROUGH);
+ ie_header.len = wlan_cpu_to_le16(priv->gen_ie_buf_len);
+ memcpy(priv->adapter, *ppbuffer, &ie_header, sizeof(ie_header));
+
+ /* Increment the return size and the return buffer pointer param */
+ *ppbuffer += sizeof(ie_header);
+ ret_len += sizeof(ie_header);
+
+ /* Copy the generic IE buffer to the output buffer, advance pointer */
+ memcpy(priv->adapter, *ppbuffer, priv->gen_ie_buf,
+ priv->gen_ie_buf_len);
+
+ /* Increment the return size and the return buffer pointer param */
+ *ppbuffer += priv->gen_ie_buf_len;
+ ret_len += priv->gen_ie_buf_len;
+
+ /* Reset the generic IE buffer */
+ priv->gen_ie_buf_len = 0;
+ }
+
+ /* return the length appended to the buffer */
+ LEAVE();
+ return ret_len;
+}
+
+/**
+ * @brief Append TSF tracking info from the scan table for the target AP
+ *
+ * This function is called from the network join command prep. routine.
+ * The TSF table TSF sent to the firmware contains two TSF values:
+ * - the TSF of the target AP from its previous beacon/probe response
+ * - the TSF timestamp of our local MAC at the time we observed the
+ * beacon/probe response.
+ *
+ * The firmware uses the timestamp values to set an initial TSF value
+ * in the MAC for the new association after a reassociation attempt.
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param ppbuffer A pointer to command buffer pointer
+ * @param pbss_desc A pointer to the BSS Descriptor from the scan table of
+ * the AP we are trying to join
+ *
+ * @return bytes added to the buffer
+ */
+static int
+wlan_cmd_append_tsf_tlv(mlan_private * pmriv, t_u8 ** ppbuffer,
+ BSSDescriptor_t * pbss_desc)
+{
+ MrvlIEtypes_TsfTimestamp_t tsf_tlv;
+ t_u64 tsf_val;
+
+ ENTER();
+
+ /* Null Checks */
+ if (ppbuffer == MNULL) {
+ LEAVE();
+ return 0;
+ }
+ if (*ppbuffer == MNULL) {
+ LEAVE();
+ return 0;
+ }
+
+ memset(pmriv->adapter, &tsf_tlv, 0x00, sizeof(MrvlIEtypes_TsfTimestamp_t));
+
+ tsf_tlv.header.type = wlan_cpu_to_le16(TLV_TYPE_TSFTIMESTAMP);
+ tsf_tlv.header.len = wlan_cpu_to_le16(2 * sizeof(tsf_val));
+
+ memcpy(pmriv->adapter, *ppbuffer, &tsf_tlv, sizeof(tsf_tlv.header));
+ *ppbuffer += sizeof(tsf_tlv.header);
+
+ /* TSF timestamp from the firmware TSF when the bcn/prb rsp was received */
+ tsf_val = wlan_cpu_to_le64(pbss_desc->network_tsf);
+ memcpy(pmriv->adapter, *ppbuffer, &tsf_val, sizeof(tsf_val));
+ *ppbuffer += sizeof(tsf_val);
+
+ memcpy(pmriv->adapter, &tsf_val, pbss_desc->time_stamp, sizeof(tsf_val));
+
+ PRINTM(MINFO, "ASSOC: TSF offset calc: %016llx - %016llx\n",
+ tsf_val, pbss_desc->network_tsf);
+
+ memcpy(pmriv->adapter, *ppbuffer, &tsf_val, sizeof(tsf_val));
+ *ppbuffer += sizeof(tsf_val);
+
+ LEAVE();
+ return (sizeof(tsf_tlv.header) + (2 * sizeof(tsf_val)));
+}
+
+/**
+ * @brief This function finds out the common rates between rate1 and rate2.
+ *
+ * It will fill common rates in rate1 as output if found.
+ *
+ * NOTE: Setting the MSB of the basic rates needs to be taken
+ * care of, either before or after calling this function
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param rate1 the buffer which keeps input and output
+ * @param rate1_size the size of rate1 buffer
+ * @param rate2 the buffer which keeps rate2
+ * @param rate2_size the size of rate2 buffer.
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+static mlan_status
+wlan_get_common_rates(IN mlan_private * pmpriv,
+ IN t_u8 * rate1,
+ IN t_u32 rate1_size, IN t_u8 * rate2, IN t_u32 rate2_size)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_callbacks *pcb = (mlan_callbacks *) & pmpriv->adapter->callbacks;
+ t_u8 *ptr = rate1;
+ t_u8 *tmp = MNULL;
+ t_u32 i, j;
+
+ ENTER();
+
+ ret =
+ pcb->moal_malloc(pmpriv->adapter->pmoal_handle, rate1_size,
+ MLAN_MEM_DEF, &tmp);
+ if (ret != MLAN_STATUS_SUCCESS || !tmp) {
+ PRINTM(MERROR, "Failed to allocate buffer\n");
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ memcpy(pmpriv->adapter, tmp, rate1, rate1_size);
+ memset(pmpriv->adapter, rate1, 0, rate1_size);
+
+ for (i = 0; rate2[i] && i < rate2_size; i++) {
+ for (j = 0; tmp[j] && j < rate1_size; j++) {
+ /* Check common rate, excluding the bit for basic rate */
+ if ((rate2[i] & 0x7F) == (tmp[j] & 0x7F)) {
+ *rate1++ = tmp[j];
+ break;
+ }
+ }
+ }
+
+ HEXDUMP("rate1 (AP) Rates", tmp, rate1_size);
+ HEXDUMP("rate2 (Card) Rates", rate2, rate2_size);
+ HEXDUMP("Common Rates", ptr, rate1 - ptr);
+ PRINTM(MINFO, "Tx DataRate is set to 0x%X\n", pmpriv->data_rate);
+
+ if (!pmpriv->is_data_rate_auto) {
+ while (*ptr) {
+ if ((*ptr & 0x7f) == pmpriv->data_rate) {
+ ret = MLAN_STATUS_SUCCESS;
+ goto done;
+ }
+ ptr++;
+ }
+ PRINTM(MMSG, "Previously set fixed data rate %#x is not "
+ "compatible with the network\n", pmpriv->data_rate);
+
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ ret = MLAN_STATUS_SUCCESS;
+ done:
+ if (tmp)
+ pcb->moal_mfree(pmpriv->adapter->pmoal_handle, tmp);
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Create the intersection of the rates supported by a target BSS and
+ * our pmadapter settings for use in an assoc/join command.
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param pbss_desc BSS Descriptor whose rates are used in the setup
+ * @param pout_rates Output: Octet array of rates common between the BSS
+ * and the pmadapter supported rates settings
+ * @param pout_rates_size Output: Number of rates/octets set in pout_rates
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+static mlan_status
+wlan_setup_rates_from_bssdesc(IN mlan_private * pmpriv,
+ IN BSSDescriptor_t * pbss_desc,
+ OUT t_u8 * pout_rates,
+ OUT t_u32 * pout_rates_size)
+{
+ t_u8 card_rates[WLAN_SUPPORTED_RATES];
+ t_u32 card_rates_size = 0;
+ ENTER();
+ /* Copy AP supported rates */
+ memcpy(pmpriv->adapter, pout_rates, pbss_desc->supported_rates,
+ WLAN_SUPPORTED_RATES);
+ /* Get the STA supported rates */
+ card_rates_size = wlan_get_active_data_rates(pmpriv, pmpriv->bss_mode,
+ pmpriv->config_bands,
+ card_rates);
+ /* Get the common rates between AP and STA supported rates */
+ if (wlan_get_common_rates(pmpriv, pout_rates, WLAN_SUPPORTED_RATES,
+ card_rates, card_rates_size)) {
+ *pout_rates_size = 0;
+ PRINTM(MERROR, "wlan_get_common_rates failed\n");
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+
+ *pout_rates_size =
+ MIN(wlan_strlen((char *) pout_rates), WLAN_SUPPORTED_RATES);
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief Update the scan entry TSF timestamps to reflect a new association
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param pnew_bss_desc A pointer to the newly associated AP's scan table entry
+ *
+ * @return N/A
+ */
+static t_void
+wlan_update_tsf_timestamps(IN mlan_private * pmpriv,
+ IN BSSDescriptor_t * pnew_bss_desc)
+{
+ mlan_adapter *pmadapter = pmpriv->adapter;
+ t_u32 table_idx;
+ t_u64 new_tsf_base;
+ t_s64 tsf_delta;
+
+ ENTER();
+
+ memcpy(pmpriv->adapter, &new_tsf_base, pnew_bss_desc->time_stamp,
+ sizeof(new_tsf_base));
+
+ tsf_delta = new_tsf_base - pnew_bss_desc->network_tsf;
+
+ PRINTM(MINFO, "TSF: Update TSF timestamps, 0x%016llx -> 0x%016llx\n",
+ pnew_bss_desc->network_tsf, new_tsf_base);
+
+ for (table_idx = 0; table_idx < pmadapter->num_in_scan_table; table_idx++) {
+ pmadapter->pscan_table[table_idx].network_tsf += tsf_delta;
+ }
+
+ LEAVE();
+}
+
+/**
+ * @brief Append a wapi IE
+ *
+ * This function is called from the network join command prep. routine.
+ * If the IE buffer has been setup by the application, this routine appends
+ * the buffer as a wapi TLV type to the request.
+ *
+ * @param priv A pointer to mlan_private structure
+ * @param ppBuffer pointer to command buffer pointer
+ *
+ * @return bytes added to the buffer
+ */
+static int
+wlan_cmd_append_wapi_ie(mlan_private * priv, t_u8 ** ppBuffer)
+{
+ int retLen = 0;
+ MrvlIEtypesHeader_t ie_header;
+
+ ENTER();
+
+ /* Null Checks */
+ if (ppBuffer == MNULL) {
+ LEAVE();
+ return 0;
+ }
+ if (*ppBuffer == MNULL) {
+ LEAVE();
+ return 0;
+ }
+
+ /*
+ * If there is a wapi ie buffer setup, append it to the return
+ * parameter buffer pointer.
+ */
+ if (priv->wapi_ie_len) {
+ PRINTM(MCMND, "append wapi ie %d to %p\n", priv->wapi_ie_len,
+ *ppBuffer);
+
+ /* Wrap the generic IE buffer with a pass through TLV type */
+ ie_header.type = wlan_cpu_to_le16(TLV_TYPE_WAPI_IE);
+ ie_header.len = wlan_cpu_to_le16(priv->wapi_ie_len);
+ memcpy(priv->adapter, *ppBuffer, &ie_header, sizeof(ie_header));
+
+ /* Increment the return size and the return buffer pointer param */
+ *ppBuffer += sizeof(ie_header);
+ retLen += sizeof(ie_header);
+
+ /* Copy the wapi IE buffer to the output buffer, advance pointer */
+ memcpy(priv->adapter, *ppBuffer, priv->wapi_ie, priv->wapi_ie_len);
+
+ /* Increment the return size and the return buffer pointer param */
+ *ppBuffer += priv->wapi_ie_len;
+ retLen += priv->wapi_ie_len;
+
+ }
+ /* return the length appended to the buffer */
+ LEAVE();
+ return retLen;
+}
+
+/********************************************************
+ Global Functions
+********************************************************/
+/**
+ * @brief This function prepares command of association.
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param cmd A pointer to HostCmd_DS_COMMAND structure
+ * @param pdata_buf A pointer cast of BSSDescriptor_t from the
+ * scan table to assoc
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status
+wlan_cmd_802_11_associate(IN mlan_private * pmpriv,
+ IN HostCmd_DS_COMMAND * cmd, IN t_void * pdata_buf)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_adapter *pmadapter = pmpriv->adapter;
+ HostCmd_DS_802_11_ASSOCIATE *passo = &cmd->params.associate;
+ BSSDescriptor_t *pbss_desc;
+ MrvlIEtypes_SsIdParamSet_t *pssid_tlv;
+ MrvlIEtypes_PhyParamSet_t *pphy_tlv;
+ MrvlIEtypes_SsParamSet_t *pss_tlv;
+ MrvlIEtypes_RatesParamSet_t *prates_tlv;
+ MrvlIEtypes_AuthType_t *pauth_tlv;
+ MrvlIEtypes_RsnParamSet_t *prsn_ie_tlv;
+ MrvlIEtypes_ChanListParamSet_t *pchan_tlv;
+ WLAN_802_11_RATES rates;
+ t_u32 rates_size;
+ t_u16 tmp_cap;
+ t_u8 *pos;
+
+ ENTER();
+
+ pbss_desc = (BSSDescriptor_t *) pdata_buf;
+ pos = (t_u8 *) passo;
+
+ cmd->command = wlan_cpu_to_le16(HostCmd_CMD_802_11_ASSOCIATE);
+
+ /* Save so we know which BSS Desc to use in the response handler */
+ pmpriv->pattempted_bss_desc = pbss_desc;
+
+ memcpy(pmadapter, passo->peer_sta_addr,
+ pbss_desc->mac_address, sizeof(passo->peer_sta_addr));
+ pos += sizeof(passo->peer_sta_addr);
+
+ /* Set the listen interval */
+ passo->listen_interval = wlan_cpu_to_le16(pmpriv->listen_interval);
+ /* Set the beacon period */
+ passo->beacon_period = wlan_cpu_to_le16(pbss_desc->beacon_period);
+
+ pos += sizeof(passo->cap_info);
+ pos += sizeof(passo->listen_interval);
+ pos += sizeof(passo->beacon_period);
+ pos += sizeof(passo->dtim_period);
+
+ pssid_tlv = (MrvlIEtypes_SsIdParamSet_t *) pos;
+ pssid_tlv->header.type = wlan_cpu_to_le16(TLV_TYPE_SSID);
+ pssid_tlv->header.len = (t_u16) pbss_desc->ssid.ssid_len;
+ memcpy(pmadapter, pssid_tlv->ssid, pbss_desc->ssid.ssid,
+ pssid_tlv->header.len);
+ pos += sizeof(pssid_tlv->header) + pssid_tlv->header.len;
+ pssid_tlv->header.len = wlan_cpu_to_le16(pssid_tlv->header.len);
+
+ pphy_tlv = (MrvlIEtypes_PhyParamSet_t *) pos;
+ pphy_tlv->header.type = wlan_cpu_to_le16(TLV_TYPE_PHY_DS);
+ pphy_tlv->header.len = sizeof(pphy_tlv->fh_ds.ds_param_set);
+ memcpy(pmadapter, &pphy_tlv->fh_ds.ds_param_set,
+ &pbss_desc->phy_param_set.ds_param_set.current_chan,
+ sizeof(pphy_tlv->fh_ds.ds_param_set));
+ pos += sizeof(pphy_tlv->header) + pphy_tlv->header.len;
+ pphy_tlv->header.len = wlan_cpu_to_le16(pphy_tlv->header.len);
+
+ pss_tlv = (MrvlIEtypes_SsParamSet_t *) pos;
+ pss_tlv->header.type = wlan_cpu_to_le16(TLV_TYPE_CF);
+ pss_tlv->header.len = sizeof(pss_tlv->cf_ibss.cf_param_set);
+ pos += sizeof(pss_tlv->header) + pss_tlv->header.len;
+ pss_tlv->header.len = wlan_cpu_to_le16(pss_tlv->header.len);
+
+ /* Get the common rates supported between the driver and the BSS Desc */
+ if (wlan_setup_rates_from_bssdesc(pmpriv, pbss_desc, rates, &rates_size)) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ /* Save the data rates into Current BSS state structure */
+ pmpriv->curr_bss_params.num_of_rates = rates_size;
+ memcpy(pmadapter, &pmpriv->curr_bss_params.data_rates, rates, rates_size);
+
+ /* Setup the Rates TLV in the association command */
+ prates_tlv = (MrvlIEtypes_RatesParamSet_t *) pos;
+ prates_tlv->header.type = wlan_cpu_to_le16(TLV_TYPE_RATES);
+ prates_tlv->header.len = wlan_cpu_to_le16((t_u16) rates_size);
+ memcpy(pmadapter, prates_tlv->rates, rates, rates_size);
+ pos += sizeof(prates_tlv->header) + rates_size;
+ PRINTM(MINFO, "ASSOC_CMD: Rates size = %d\n", rates_size);
+
+ /* Add the Authentication type to be used for Auth frames if needed */
+ if (pmpriv->sec_info.authentication_mode != MLAN_AUTH_MODE_AUTO) {
+ pauth_tlv = (MrvlIEtypes_AuthType_t *) pos;
+ pauth_tlv->header.type = wlan_cpu_to_le16(TLV_TYPE_AUTH_TYPE);
+ pauth_tlv->header.len = sizeof(pauth_tlv->auth_type);
+ if (pmpriv->sec_info.wep_status == Wlan802_11WEPEnabled)
+ pauth_tlv->auth_type =
+ wlan_cpu_to_le16((t_u16) pmpriv->sec_info.authentication_mode);
+ else
+ pauth_tlv->auth_type = wlan_cpu_to_le16(MLAN_AUTH_MODE_OPEN);
+ pos += sizeof(pauth_tlv->header) + pauth_tlv->header.len;
+ pauth_tlv->header.len = wlan_cpu_to_le16(pauth_tlv->header.len);
+ }
+
+ if (IS_SUPPORT_MULTI_BANDS(pmadapter)
+ && (pbss_desc->bss_band & pmpriv->config_bands)
+ && !(ISSUPP_11NENABLED(pmadapter->fw_cap_info)
+ && (!pbss_desc->disable_11n)
+ && (pmpriv->config_bands & BAND_GN
+ || pmpriv->config_bands & BAND_AN)
+ && (pbss_desc->pht_cap)
+ )
+ ) {
+ /* Append a channel TLV for the channel the attempted AP was found on */
+ pchan_tlv = (MrvlIEtypes_ChanListParamSet_t *) pos;
+ pchan_tlv->header.type = wlan_cpu_to_le16(TLV_TYPE_CHANLIST);
+ pchan_tlv->header.len = wlan_cpu_to_le16(sizeof(ChanScanParamSet_t));
+
+ memset(pmadapter, pchan_tlv->chan_scan_param, 0x00,
+ sizeof(ChanScanParamSet_t));
+ pchan_tlv->chan_scan_param[0].chan_number =
+ (pbss_desc->phy_param_set.ds_param_set.current_chan);
+ PRINTM(MINFO, "Assoc: TLV Chan = %d\n",
+ pchan_tlv->chan_scan_param[0].chan_number);
+
+ pchan_tlv->chan_scan_param[0].radio_type =
+ wlan_band_to_radio_type((t_u8) pbss_desc->bss_band);
+
+ PRINTM(MINFO, "Assoc: TLV Band = %d\n",
+ pchan_tlv->chan_scan_param[0].radio_type);
+ pos += sizeof(pchan_tlv->header) + sizeof(ChanScanParamSet_t);
+ }
+ if (!pmpriv->wps.session_enable) {
+ if ((pmpriv->sec_info.wpa_enabled || pmpriv->sec_info.wpa2_enabled)) {
+ prsn_ie_tlv = (MrvlIEtypes_RsnParamSet_t *) pos;
+ prsn_ie_tlv->header.type = (t_u16) pmpriv->wpa_ie[0]; /* WPA_IE
+ or
+ RSN_IE
+ */
+ prsn_ie_tlv->header.type = prsn_ie_tlv->header.type & 0x00FF;
+ prsn_ie_tlv->header.type =
+ wlan_cpu_to_le16(prsn_ie_tlv->header.type);
+ prsn_ie_tlv->header.len = (t_u16) pmpriv->wpa_ie[1];
+ prsn_ie_tlv->header.len = prsn_ie_tlv->header.len & 0x00FF;
+ if (prsn_ie_tlv->header.len <= (sizeof(pmpriv->wpa_ie) - 2))
+ memcpy(pmadapter, prsn_ie_tlv->rsn_ie, &pmpriv->wpa_ie[2],
+ prsn_ie_tlv->header.len);
+ else {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ HEXDUMP("ASSOC_CMD: RSN IE", (t_u8 *) prsn_ie_tlv,
+ sizeof(prsn_ie_tlv->header) + prsn_ie_tlv->header.len);
+ pos += sizeof(prsn_ie_tlv->header) + prsn_ie_tlv->header.len;
+ prsn_ie_tlv->header.len = wlan_cpu_to_le16(prsn_ie_tlv->header.len);
+ } else if (pmpriv->sec_info.ewpa_enabled) {
+ prsn_ie_tlv = (MrvlIEtypes_RsnParamSet_t *) pos;
+ if (pbss_desc->pwpa_ie) {
+ prsn_ie_tlv->header.type =
+ (t_u16) (*(pbss_desc->pwpa_ie)).vend_hdr.element_id;
+ prsn_ie_tlv->header.type = prsn_ie_tlv->header.type & 0x00FF;
+ prsn_ie_tlv->header.type =
+ wlan_cpu_to_le16(prsn_ie_tlv->header.type);
+ prsn_ie_tlv->header.len =
+ (t_u16) (*(pbss_desc->pwpa_ie)).vend_hdr.len;
+ prsn_ie_tlv->header.len = prsn_ie_tlv->header.len & 0x00FF;
+ if (prsn_ie_tlv->header.len <= (sizeof(pmpriv->wpa_ie))) {
+ memcpy(pmadapter, prsn_ie_tlv->rsn_ie,
+ &((*(pbss_desc->pwpa_ie)).vend_hdr.oui[0]),
+ prsn_ie_tlv->header.len);
+ } else {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ HEXDUMP("ASSOC_CMD: RSN IE", (t_u8 *) prsn_ie_tlv,
+ sizeof(prsn_ie_tlv->header) + prsn_ie_tlv->header.len);
+ pos += sizeof(prsn_ie_tlv->header) + prsn_ie_tlv->header.len;
+ prsn_ie_tlv->header.len =
+ wlan_cpu_to_le16(prsn_ie_tlv->header.len);
+ }
+ if (pbss_desc->prsn_ie) {
+ prsn_ie_tlv = (MrvlIEtypes_RsnParamSet_t *) pos;
+ prsn_ie_tlv->header.type =
+ (t_u16) (*(pbss_desc->prsn_ie)).ieee_hdr.element_id;
+ prsn_ie_tlv->header.type = prsn_ie_tlv->header.type & 0x00FF;
+ prsn_ie_tlv->header.type =
+ wlan_cpu_to_le16(prsn_ie_tlv->header.type);
+ prsn_ie_tlv->header.len =
+ (t_u16) (*(pbss_desc->prsn_ie)).ieee_hdr.len;
+ prsn_ie_tlv->header.len = prsn_ie_tlv->header.len & 0x00FF;
+ if (prsn_ie_tlv->header.len <= (sizeof(pmpriv->wpa_ie))) {
+ memcpy(pmadapter, prsn_ie_tlv->rsn_ie,
+ &((*(pbss_desc->prsn_ie)).data[0])
+ , prsn_ie_tlv->header.len);
+ } else {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ HEXDUMP("ASSOC_CMD: RSN IE", (t_u8 *) prsn_ie_tlv,
+ sizeof(prsn_ie_tlv->header) + prsn_ie_tlv->header.len);
+ pos += sizeof(prsn_ie_tlv->header) + prsn_ie_tlv->header.len;
+ prsn_ie_tlv->header.len =
+ wlan_cpu_to_le16(prsn_ie_tlv->header.len);
+ }
+ }
+ }
+
+ if (ISSUPP_11NENABLED(pmadapter->fw_cap_info)
+ && (!pbss_desc->disable_11n)
+ && (pmpriv->config_bands & BAND_GN || pmpriv->config_bands & BAND_AN))
+ wlan_cmd_append_11n_tlv(pmpriv, pbss_desc, &pos);
+
+ wlan_wmm_process_association_req(pmpriv, &pos, &pbss_desc->wmm_ie,
+ pbss_desc->pht_cap);
+ if (pmpriv->sec_info.wapi_enabled && pmpriv->wapi_ie_len) {
+ wlan_cmd_append_wapi_ie(pmpriv, &pos);
+ }
+
+ wlan_cmd_append_generic_ie(pmpriv, &pos);
+
+ wlan_cmd_append_tsf_tlv(pmpriv, &pos, pbss_desc);
+
+ if (wlan_11d_create_dnld_countryinfo(pmpriv, (t_u8) pbss_desc->bss_band)) {
+ PRINTM(MERROR, "Dnld_countryinfo_11d failed\n");
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ if (wlan_11d_parse_dnld_countryinfo(pmpriv, pmpriv->pattempted_bss_desc)) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ /*
+ * Call 11h join API after capability bits are set so adhoc/infra 11h
+ * behavior can be properly triggered. pos modified if data is appended
+ */
+ wlan_11h_process_join(pmpriv, &pos, &passo->cap_info,
+ (t_u8) pbss_desc->bss_band,
+ pbss_desc->phy_param_set.ds_param_set.current_chan,
+ &pbss_desc->wlan_11h_bss_info);
+
+ cmd->size = wlan_cpu_to_le16((t_u16) (pos - (t_u8 *) passo) + S_DS_GEN);
+
+ /* Set the Capability info at last */
+ memcpy(pmadapter, &tmp_cap, &pbss_desc->cap_info, sizeof(passo->cap_info));
+
+ if (pmpriv->config_bands == BAND_B) {
+ SHORT_SLOT_TIME_DISABLED(tmp_cap);
+ }
+
+ tmp_cap &= CAPINFO_MASK;
+ PRINTM(MINFO, "ASSOC_CMD: tmp_cap=%4X CAPINFO_MASK=%4lX\n",
+ tmp_cap, CAPINFO_MASK);
+ tmp_cap = wlan_cpu_to_le16(tmp_cap);
+ memcpy(pmadapter, &passo->cap_info, &tmp_cap, sizeof(passo->cap_info));
+
+ done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Association firmware command response handler
+ *
+ * The response buffer for the association command has the following
+ * memory layout.
+ *
+ * For cases where an association response was not received (indicated
+ * by the CapInfo and AId field):
+ *
+ * .------------------------------------------------------------.
+ * | Header(4 * sizeof(t_u16)): Standard command response hdr |
+ * .------------------------------------------------------------.
+ * | cap_info/Error Return(t_u16): |
+ * | 0xFFFF(-1): Internal error for association |
+ * | 0xFFFE(-2): Authentication unhandled message |
+ * | 0xFFFD(-3): Authentication refused |
+ * | 0xFFFC(-4): Timeout waiting for AP response |
+ * | 0xFFFB(-5): Internal error for authentication |
+ * .------------------------------------------------------------.
+ * | status_code(t_u16): |
+ * | If cap_info is -1: |
+ * | An internal firmware failure prevented the |
+ * | command from being processed. The status code |
+ * | is 6 if associate response parameter invlaid, |
+ * | 1 otherwise. |
+ * | |
+ * | If cap_info is -2: |
+ * | An authentication frame was received but was |
+ * | not handled by the firmware. IEEE Status code |
+ * | for the failure is returned. |
+ * | |
+ * | If cap_info is -3: |
+ * | An authentication frame was received and the |
+ * | status_code is the IEEE Status reported in the |
+ * | response. |
+ * | |
+ * | If cap_info is -4: |
+ * | (1) Association response timeout |
+ * | (2) Authentication response timeout |
+ * | |
+ * | If cap_info is -5: |
+ * | An internal firmware failure prevented the |
+ * | command from being processed. The status code |
+ * | is 6 if authentication parameter invlaid, |
+ * | 1 otherwise. |
+ * .------------------------------------------------------------.
+ * | a_id(t_u16): 0xFFFF |
+ * .------------------------------------------------------------.
+ *
+ *
+ * For cases where an association response was received, the IEEE
+ * standard association response frame is returned:
+ *
+ * .------------------------------------------------------------.
+ * | Header(4 * sizeof(t_u16)): Standard command response hdr |
+ * .------------------------------------------------------------.
+ * | cap_info(t_u16): IEEE Capability |
+ * .------------------------------------------------------------.
+ * | status_code(t_u16): IEEE Status Code |
+ * .------------------------------------------------------------.
+ * | a_id(t_u16): IEEE Association ID |
+ * .------------------------------------------------------------.
+ * | IEEE IEs(variable): Any received IEs comprising the |
+ * | remaining portion of a received |
+ * | association response frame. |
+ * .------------------------------------------------------------.
+ *
+ * For simplistic handling, the status_code field can be used to determine
+ * an association success (0) or failure (non-zero).
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param resp A pointer to HostCmd_DS_COMMAND
+ * @param pioctl_buf A pointer to mlan_ioctl_req structure
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status
+wlan_ret_802_11_associate(IN mlan_private * pmpriv,
+ IN HostCmd_DS_COMMAND * resp, IN t_void * pioctl_buf)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_ioctl_req *pioctl_req = (mlan_ioctl_req *) pioctl_buf;
+ IEEEtypes_AssocRsp_t *passoc_rsp;
+ BSSDescriptor_t *pbss_desc;
+ t_u8 enable_data = MTRUE;
+ t_u8 event_buf[100];
+ mlan_event *pevent = (mlan_event *) event_buf;
+
+ ENTER();
+
+ passoc_rsp = (IEEEtypes_AssocRsp_t *) & resp->params;
+ passoc_rsp->status_code = wlan_le16_to_cpu(passoc_rsp->status_code);
+
+ HEXDUMP("ASSOC_RESP:", (t_u8 *) & resp->params, (resp->size - S_DS_GEN));
+
+ pmpriv->assoc_rsp_size = MIN(resp->size - S_DS_GEN,
+ sizeof(pmpriv->assoc_rsp_buf));
+
+ memcpy(pmpriv->adapter, pmpriv->assoc_rsp_buf, &resp->params,
+ pmpriv->assoc_rsp_size);
+
+ if (passoc_rsp->status_code) {
+ pmpriv->adapter->dbg.num_cmd_assoc_failure++;
+ PRINTM(MERROR, "ASSOC_RESP: Association Failed, "
+ "status code = %d, error = 0x%x, a_id = 0x%x\n",
+ wlan_le16_to_cpu(passoc_rsp->status_code),
+ wlan_le16_to_cpu(*(t_u16 *) & passoc_rsp->capability),
+ wlan_le16_to_cpu(passoc_rsp->a_id));
+
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ /* Send a Media Connected event, according to the Spec */
+ pmpriv->media_connected = MTRUE;
+
+ pmpriv->adapter->pps_uapsd_mode = MFALSE;
+ pmpriv->adapter->tx_lock_flag = MFALSE;
+ pmpriv->adapter->delay_null_pkt = MFALSE;
+
+ /* Set the attempted BSSID Index to current */
+ pbss_desc = pmpriv->pattempted_bss_desc;
+
+ PRINTM(MINFO, "ASSOC_RESP: %s\n", pbss_desc->ssid.ssid);
+
+ /* Make a copy of current BSSID descriptor */
+ memcpy(pmpriv->adapter, &pmpriv->curr_bss_params.bss_descriptor,
+ pbss_desc, sizeof(BSSDescriptor_t));
+
+ /* Update curr_bss_params */
+ pmpriv->curr_bss_params.bss_descriptor.channel
+ = pbss_desc->phy_param_set.ds_param_set.current_chan;
+
+ pmpriv->curr_bss_params.band = (t_u8) pbss_desc->bss_band;
+
+ /*
+ * Adjust the timestamps in the scan table to be relative to the newly
+ * associated AP's TSF
+ */
+ wlan_update_tsf_timestamps(pmpriv, pbss_desc);
+
+ if (pbss_desc->wmm_ie.vend_hdr.element_id == WMM_IE)
+ pmpriv->curr_bss_params.wmm_enabled = MTRUE;
+ else
+ pmpriv->curr_bss_params.wmm_enabled = MFALSE;
+
+ if ((pmpriv->wmm_required
+ || (pbss_desc->pht_cap &&
+ (pbss_desc->pht_cap->ieee_hdr.element_id == HT_CAPABILITY))
+ ) && pmpriv->curr_bss_params.wmm_enabled)
+ pmpriv->wmm_enabled = MTRUE;
+ else
+ pmpriv->wmm_enabled = MFALSE;
+
+ pmpriv->curr_bss_params.wmm_uapsd_enabled = MFALSE;
+
+ if (pmpriv->wmm_enabled == MTRUE)
+ pmpriv->curr_bss_params.wmm_uapsd_enabled
+ = pbss_desc->wmm_ie.qos_info.qos_uapsd;
+
+ PRINTM(MINFO, "ASSOC_RESP: curr_pkt_filter is 0x%x\n",
+ pmpriv->curr_pkt_filter);
+ if (pmpriv->sec_info.wpa_enabled || pmpriv->sec_info.wpa2_enabled)
+ pmpriv->wpa_is_gtk_set = MFALSE;
+
+ if (pmpriv->wmm_enabled)
+ /* Don't re-enable carrier until we get the WMM_GET_STATUS event */
+ enable_data = MFALSE;
+ else
+ /* Since WMM is not enabled, setup the queues with the defaults */
+ wlan_wmm_setup_queues(pmpriv);
+
+ if (enable_data) {
+ PRINTM(MINFO, "Post association, re-enabling data flow\n");
+ }
+
+ /* Reset SNR/NF/RSSI values */
+ pmpriv->data_rssi_last = 0;
+ pmpriv->data_nf_last = 0;
+ pmpriv->data_rssi_avg = 0;
+ pmpriv->data_nf_avg = 0;
+ pmpriv->bcn_rssi_last = 0;
+ pmpriv->bcn_nf_last = 0;
+ pmpriv->bcn_rssi_avg = 0;
+ pmpriv->bcn_nf_avg = 0;
+ pmpriv->rxpd_rate = 0;
+ pmpriv->rxpd_htinfo = 0;
+ if (pbss_desc->pht_cap) {
+ if (GETHT_MAXAMSDU(pbss_desc->pht_cap->ht_cap.ht_cap_info))
+ pmpriv->max_amsdu = MLAN_TX_DATA_BUF_SIZE_8K;
+ else
+ pmpriv->max_amsdu = MLAN_TX_DATA_BUF_SIZE_4K;
+ }
+
+ wlan_save_curr_bcn(pmpriv);
+
+ pmpriv->adapter->dbg.num_cmd_assoc_success++;
+
+ PRINTM(MINFO, "ASSOC_RESP: Associated\n");
+ pevent->bss_index = pmpriv->bss_index;
+ pevent->event_id = MLAN_EVENT_ID_DRV_CONNECTED;
+ pevent->event_len = MLAN_MAC_ADDR_LENGTH;
+ memcpy(pmpriv->adapter, (t_u8 *) pevent->event_buf,
+ (t_u8 *) pmpriv->curr_bss_params.bss_descriptor.mac_address,
+ MLAN_MAC_ADDR_LENGTH);
+
+ /* Add the ra_list here for infra mode as there will be only 1 ra always */
+ wlan_ralist_add(pmpriv, pmpriv->curr_bss_params.bss_descriptor.mac_address);
+
+ wlan_recv_event(pmpriv, MLAN_EVENT_ID_DRV_CONNECTED, pevent);
+
+ /* Send OBSS scan param to the application if available */
+ wlan_2040_coex_event(pmpriv);
+
+ if (!pmpriv->sec_info.wpa_enabled
+ && !pmpriv->sec_info.wpa2_enabled
+ && !pmpriv->sec_info.ewpa_enabled && !pmpriv->sec_info.wapi_enabled) {
+ /* We are in Open/WEP mode, open port immediately */
+ if (pmpriv->port_ctrl_mode == MTRUE) {
+ pmpriv->port_open = MTRUE;
+ PRINTM(MINFO, "ASSOC_RESP: port_status = OPEN\n");
+ }
+ }
+
+ if (pmpriv->sec_info.wpa_enabled
+ || pmpriv->sec_info.wpa2_enabled
+ || pmpriv->sec_info.ewpa_enabled || pmpriv->sec_info.wapi_enabled)
+ pmpriv->scan_block = MTRUE;
+
+ done:
+ /* Need to indicate IOCTL complete */
+ if (pioctl_req != MNULL) {
+ if (ret != MLAN_STATUS_SUCCESS) {
+ if (passoc_rsp->status_code)
+ pioctl_req->status_code =
+ wlan_le16_to_cpu(passoc_rsp->status_code);
+ else
+ pioctl_req->status_code = MLAN_ERROR_CMD_ASSOC_FAIL;
+ } else {
+ pioctl_req->status_code = MLAN_ERROR_NO_ERROR;
+ }
+ }
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function prepares command of ad_hoc_start.
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param cmd A pointer to HostCmd_DS_COMMAND structure
+ * @param pdata_buf A pointer cast of mlan_802_11_ssid structure
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status
+wlan_cmd_802_11_ad_hoc_start(IN mlan_private * pmpriv,
+ IN HostCmd_DS_COMMAND * cmd, IN t_void * pdata_buf)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_adapter *pmadapter = pmpriv->adapter;
+ HostCmd_DS_802_11_AD_HOC_START *padhoc_start = &cmd->params.adhoc_start;
+ BSSDescriptor_t *pbss_desc;
+ t_u32 cmd_append_size = 0;
+ t_u32 i;
+ t_u16 tmp_cap;
+ MrvlIEtypes_ChanListParamSet_t *pchan_tlv;
+
+ MrvlIEtypes_RsnParamSet_t *prsn_ie_tlv;
+ MrvlIETypes_HTCap_t *pht_cap;
+ MrvlIETypes_HTInfo_t *pht_info;
+ /* wpa ie for WPA_NONE AES */
+ const t_u8 wpa_ie[24] = { 0xdd, 0x16, 0x00, 0x50, 0xf2, 0x01, 0x01, 0x00,
+ 0x00, 0x50, 0xf2, 0x04, 0x01, 0x00, 0x00, 0x50,
+ 0xf2, 0x00, 0x01, 0x00, 0x00, 0x50, 0xf2, 0x00
+ };
+ t_s32 append_size_11h = 0;
+ t_u8 *pos = (t_u8 *) padhoc_start + sizeof(HostCmd_DS_802_11_AD_HOC_START);
+
+ ENTER();
+
+ if (!pmadapter) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ cmd->command = wlan_cpu_to_le16(HostCmd_CMD_802_11_AD_HOC_START);
+
+ pbss_desc = &pmpriv->curr_bss_params.bss_descriptor;
+ pmpriv->pattempted_bss_desc = pbss_desc;
+
+ /*
+ * Fill in the parameters for 2 data structures:
+ * 1. HostCmd_DS_802_11_AD_HOC_START command
+ * 2. pbss_desc
+ * Driver will fill up SSID, bss_mode,IBSS param, Physical Param,
+ * probe delay, and Cap info.
+ * Firmware will fill up beacon period, Basic rates
+ * and operational rates.
+ */
+
+ memset(pmadapter, padhoc_start->ssid, 0, MLAN_MAX_SSID_LENGTH);
+
+ memcpy(pmadapter, padhoc_start->ssid,
+ ((mlan_802_11_ssid *) pdata_buf)->ssid,
+ MIN(MLAN_MAX_SSID_LENGTH,
+ ((mlan_802_11_ssid *) pdata_buf)->ssid_len));
+
+ PRINTM(MINFO, "ADHOC_S_CMD: SSID = %s\n", padhoc_start->ssid);
+
+ memset(pmadapter, pbss_desc->ssid.ssid, 0, MLAN_MAX_SSID_LENGTH);
+ memcpy(pmadapter, pbss_desc->ssid.ssid,
+ ((mlan_802_11_ssid *) pdata_buf)->ssid,
+ MIN(MLAN_MAX_SSID_LENGTH,
+ ((mlan_802_11_ssid *) pdata_buf)->ssid_len));
+
+ pbss_desc->ssid.ssid_len =
+ MIN(MLAN_MAX_SSID_LENGTH, ((mlan_802_11_ssid *) pdata_buf)->ssid_len);
+
+ /* Set the BSS mode */
+ padhoc_start->bss_mode = HostCmd_BSS_MODE_IBSS;
+ pbss_desc->bss_mode = MLAN_BSS_MODE_IBSS;
+ padhoc_start->beacon_period = wlan_cpu_to_le16(pmpriv->beacon_period);
+ pbss_desc->beacon_period = pmpriv->beacon_period;
+
+ /* Set Physical param set */
+/** Parameter IE Id */
+#define DS_PARA_IE_ID 3
+/** Parameter IE length */
+#define DS_PARA_IE_LEN 1
+
+ padhoc_start->phy_param_set.ds_param_set.element_id = DS_PARA_IE_ID;
+ padhoc_start->phy_param_set.ds_param_set.len = DS_PARA_IE_LEN;
+
+ if (!wlan_get_cfp_by_band_and_channel
+ (pmadapter, pmadapter->adhoc_start_band, (t_u16) pmpriv->adhoc_channel,
+ pmadapter->region_channel)) {
+
+ chan_freq_power_t *cfp;
+ cfp =
+ wlan_get_cfp_by_band_and_channel(pmadapter,
+ pmadapter->adhoc_start_band,
+ FIRST_VALID_CHANNEL,
+ pmadapter->region_channel);
+ if (cfp)
+ pmpriv->adhoc_channel = (t_u8) cfp->channel;
+ }
+
+ MASSERT(pmpriv->adhoc_channel);
+
+ PRINTM(MINFO, "ADHOC_S_CMD: Creating ADHOC on Channel %d\n",
+ pmpriv->adhoc_channel);
+
+ pmpriv->curr_bss_params.bss_descriptor.channel = pmpriv->adhoc_channel;
+ pmpriv->curr_bss_params.band = pmadapter->adhoc_start_band;
+
+ pbss_desc->channel = pmpriv->adhoc_channel;
+ padhoc_start->phy_param_set.ds_param_set.current_chan =
+ pmpriv->adhoc_channel;
+
+ memcpy(pmadapter, &pbss_desc->phy_param_set,
+ &padhoc_start->phy_param_set, sizeof(IEEEtypes_PhyParamSet_t));
+
+ pbss_desc->network_type_use = Wlan802_11DS;
+
+ /* Set IBSS param set */
+/** IBSS parameter IE Id */
+#define IBSS_PARA_IE_ID 6
+/** IBSS parameter IE length */
+#define IBSS_PARA_IE_LEN 2
+
+ padhoc_start->ss_param_set.ibss_param_set.element_id = IBSS_PARA_IE_ID;
+ padhoc_start->ss_param_set.ibss_param_set.len = IBSS_PARA_IE_LEN;
+ padhoc_start->ss_param_set.ibss_param_set.atim_window
+ = wlan_cpu_to_le16(pmpriv->atim_window);
+ pbss_desc->atim_window = pmpriv->atim_window;
+ memcpy(pmadapter, &pbss_desc->ss_param_set,
+ &padhoc_start->ss_param_set, sizeof(IEEEtypes_SsParamSet_t));
+
+ /* Set Capability info */
+ padhoc_start->cap.ess = 0;
+ padhoc_start->cap.ibss = 1;
+ pbss_desc->cap_info.ibss = 1;
+
+ /* Set up privacy in pbss_desc */
+ if (pmpriv->sec_info.wep_status == Wlan802_11WEPEnabled
+ || pmpriv->adhoc_aes_enabled
+ || pmpriv->sec_info.wpa_enabled || pmpriv->sec_info.ewpa_enabled) {
+/** Ad-Hoc capability privacy on */
+#define AD_HOC_CAP_PRIVACY_ON 1
+ PRINTM(MINFO, "ADHOC_S_CMD: wep_status set, Privacy to WEP\n");
+ pbss_desc->privacy = Wlan802_11PrivFilter8021xWEP;
+ padhoc_start->cap.privacy = AD_HOC_CAP_PRIVACY_ON;
+ } else {
+ PRINTM(MWARN, "ADHOC_S_CMD: wep_status NOT set, Setting "
+ "Privacy to ACCEPT ALL\n");
+ pbss_desc->privacy = Wlan802_11PrivFilterAcceptAll;
+ }
+
+ memset(pmadapter, padhoc_start->DataRate, 0,
+ sizeof(padhoc_start->DataRate));
+ wlan_get_active_data_rates(pmpriv, pmpriv->bss_mode,
+ pmadapter->adhoc_start_band,
+ padhoc_start->DataRate);
+ if ((pmadapter->adhoc_start_band & BAND_G) &&
+ (pmpriv->curr_pkt_filter & HostCmd_ACT_MAC_ADHOC_G_PROTECTION_ON)) {
+ ret =
+ wlan_prepare_cmd(pmpriv, HostCmd_CMD_MAC_CONTROL,
+ HostCmd_ACT_GEN_SET, 0, MNULL,
+ &pmpriv->curr_pkt_filter);
+
+ if (ret) {
+ PRINTM(MERROR, "ADHOC_S_CMD: G Protection config failed\n");
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ }
+ /* Find the last non zero */
+ for (i = 0; i < sizeof(padhoc_start->DataRate) && padhoc_start->DataRate[i];
+ i++);
+
+ pmpriv->curr_bss_params.num_of_rates = i;
+
+ /* Copy the ad-hoc creating rates into Current BSS rate structure */
+ memcpy(pmadapter, &pmpriv->curr_bss_params.data_rates,
+ &padhoc_start->DataRate, pmpriv->curr_bss_params.num_of_rates);
+
+ PRINTM(MINFO, "ADHOC_S_CMD: Rates=%02x %02x %02x %02x \n",
+ padhoc_start->DataRate[0], padhoc_start->DataRate[1],
+ padhoc_start->DataRate[2], padhoc_start->DataRate[3]);
+
+ PRINTM(MINFO, "ADHOC_S_CMD: AD HOC Start command is ready\n");
+
+ if (IS_SUPPORT_MULTI_BANDS(pmadapter)) {
+ /* Append a channel TLV */
+ pchan_tlv = (MrvlIEtypes_ChanListParamSet_t *) pos;
+ pchan_tlv->header.type = wlan_cpu_to_le16(TLV_TYPE_CHANLIST);
+ pchan_tlv->header.len = wlan_cpu_to_le16(sizeof(ChanScanParamSet_t));
+
+ memset(pmadapter, pchan_tlv->chan_scan_param, 0x00,
+ sizeof(ChanScanParamSet_t));
+ pchan_tlv->chan_scan_param[0].chan_number =
+ (t_u8) pmpriv->curr_bss_params.bss_descriptor.channel;
+
+ PRINTM(MINFO, "ADHOC_S_CMD: TLV Chan = %d\n",
+ pchan_tlv->chan_scan_param[0].chan_number);
+
+ pchan_tlv->chan_scan_param[0].radio_type
+ = wlan_band_to_radio_type(pmpriv->curr_bss_params.band);
+ if (pmadapter->adhoc_start_band & BAND_GN
+ || pmadapter->adhoc_start_band & BAND_AN) {
+ if (pmadapter->chan_bandwidth == CHANNEL_BW_40MHZ_ABOVE) {
+ pchan_tlv->chan_scan_param[0].radio_type |=
+ SECOND_CHANNEL_ABOVE;
+ pchan_tlv->chan_scan_param[0].radio_type |= CHAN_BW_40MHZ << 2;
+ } else if (pmadapter->chan_bandwidth == CHANNEL_BW_40MHZ_BELOW) {
+ pchan_tlv->chan_scan_param[0].radio_type |=
+ SECOND_CHANNEL_BELOW;
+ pchan_tlv->chan_scan_param[0].radio_type |= CHAN_BW_40MHZ << 2;
+ }
+ }
+ PRINTM(MINFO, "ADHOC_S_CMD: TLV Band = %d\n",
+ pchan_tlv->chan_scan_param[0].radio_type);
+ pos += sizeof(pchan_tlv->header) + sizeof(ChanScanParamSet_t);
+ cmd_append_size +=
+ sizeof(pchan_tlv->header) + sizeof(ChanScanParamSet_t);
+ }
+
+ if (wlan_11d_create_dnld_countryinfo(pmpriv, pmpriv->curr_bss_params.band)) {
+ PRINTM(MERROR, "ADHOC_S_CMD: dnld_countryinfo_11d failed\n");
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ /*
+ * Call 11h start API to add any 11h flags/elements as TLV parameters
+ */
+ append_size_11h = wlan_11h_process_start(pmpriv, &pos, &padhoc_start->cap,
+ pmpriv->adhoc_channel,
+ &pbss_desc->wlan_11h_bss_info);
+ if (append_size_11h >= 0)
+ cmd_append_size += append_size_11h;
+ else {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ if (pmpriv->sec_info.ewpa_enabled) {
+ memcpy(pmadapter, pmpriv->wpa_ie, wpa_ie, sizeof(wpa_ie));
+ pmpriv->wpa_ie_len = sizeof(wpa_ie);
+ }
+
+ if (pmpriv->sec_info.wpa_enabled || pmpriv->sec_info.ewpa_enabled) {
+ prsn_ie_tlv = (MrvlIEtypes_RsnParamSet_t *) pos;
+ prsn_ie_tlv->header.type = (t_u16) pmpriv->wpa_ie[0]; /* WPA_IE or
+ RSN_IE */
+ prsn_ie_tlv->header.type = prsn_ie_tlv->header.type & 0x00FF;
+ prsn_ie_tlv->header.type = wlan_cpu_to_le16(prsn_ie_tlv->header.type);
+ prsn_ie_tlv->header.len = (t_u16) pmpriv->wpa_ie[1];
+ prsn_ie_tlv->header.len = prsn_ie_tlv->header.len & 0x00FF;
+ if (prsn_ie_tlv->header.len <= (sizeof(pmpriv->wpa_ie) - 2))
+ memcpy(pmadapter, prsn_ie_tlv->rsn_ie, &pmpriv->wpa_ie[2],
+ prsn_ie_tlv->header.len);
+ else {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ DBG_HEXDUMP(MCMD_D, "ADHOC_S_CMD: RSN IE", (t_u8 *) prsn_ie_tlv,
+ sizeof(prsn_ie_tlv->header) + prsn_ie_tlv->header.len);
+ pos += sizeof(prsn_ie_tlv->header) + prsn_ie_tlv->header.len;
+ cmd_append_size +=
+ sizeof(prsn_ie_tlv->header) + prsn_ie_tlv->header.len;
+ prsn_ie_tlv->header.len = wlan_cpu_to_le16(prsn_ie_tlv->header.len);
+ }
+
+ if (pmadapter->adhoc_11n_enabled == MTRUE) {
+ {
+ pht_cap = (MrvlIETypes_HTCap_t *) pos;
+ memset(pmadapter, pht_cap, 0, sizeof(MrvlIETypes_HTCap_t));
+ pht_cap->header.type = wlan_cpu_to_le16(HT_CAPABILITY);
+ pht_cap->header.len = sizeof(HTCap_t);
+ wlan_fill_ht_cap_tlv(pmpriv, pht_cap, pmpriv->curr_bss_params.band);
+ HEXDUMP("ADHOC_START: HT_CAPABILITIES IE", (t_u8 *) pht_cap,
+ sizeof(MrvlIETypes_HTCap_t));
+ pos += sizeof(MrvlIETypes_HTCap_t);
+ cmd_append_size += sizeof(MrvlIETypes_HTCap_t);
+ pht_cap->header.len = wlan_cpu_to_le16(pht_cap->header.len);
+ }
+ {
+ pht_info = (MrvlIETypes_HTInfo_t *) pos;
+ memset(pmadapter, pht_info, 0, sizeof(MrvlIETypes_HTInfo_t));
+ pht_info->header.type = wlan_cpu_to_le16(HT_OPERATION);
+ pht_info->header.len = sizeof(HTInfo_t);
+ pht_info->ht_info.pri_chan =
+ (t_u8) pmpriv->curr_bss_params.bss_descriptor.channel;
+ if (pmadapter->chan_bandwidth) {
+ pht_info->ht_info.field2 = pmadapter->chan_bandwidth;
+ SET_CHANWIDTH40(pht_info->ht_info.field2);
+ }
+ pht_info->ht_info.field3 = NON_GREENFIELD_STAS;
+ pht_info->ht_info.basic_mcs_set[0] = 0xff;
+ HEXDUMP("ADHOC_START: HT_INFORMATION IE", (t_u8 *) pht_info,
+ sizeof(MrvlIETypes_HTInfo_t));
+ pos += sizeof(MrvlIETypes_HTInfo_t);
+ cmd_append_size += sizeof(MrvlIETypes_HTInfo_t);
+ pht_info->header.len = wlan_cpu_to_le16(pht_info->header.len);
+ }
+ }
+
+ cmd->size =
+ (t_u16) wlan_cpu_to_le16((t_u16) (sizeof(HostCmd_DS_802_11_AD_HOC_START)
+ + S_DS_GEN + cmd_append_size));
+
+ memcpy(pmadapter, &tmp_cap, &padhoc_start->cap, sizeof(t_u16));
+
+ if (pmadapter->adhoc_start_band == BAND_B) {
+ SHORT_SLOT_TIME_DISABLED(tmp_cap);
+ } else {
+ SHORT_SLOT_TIME_ENABLED(tmp_cap);
+ }
+
+ tmp_cap = wlan_cpu_to_le16(tmp_cap);
+ memcpy(pmadapter, &padhoc_start->cap, &tmp_cap, sizeof(t_u16));
+
+ ret = MLAN_STATUS_SUCCESS;
+ done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function prepares command of ad_hoc_join.
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param cmd A pointer to HostCmd_DS_COMMAND structure
+ * @param pdata_buf Void cast of BSSDescriptor_t from the
+ * scan table to join
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status
+wlan_cmd_802_11_ad_hoc_join(IN mlan_private * pmpriv,
+ IN HostCmd_DS_COMMAND * cmd, IN t_void * pdata_buf)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_adapter *pmadapter = pmpriv->adapter;
+ HostCmd_DS_802_11_AD_HOC_JOIN *padhoc_join = &cmd->params.adhoc_join;
+ BSSDescriptor_t *pbss_desc = (BSSDescriptor_t *) pdata_buf;
+ MrvlIEtypes_ChanListParamSet_t *pchan_tlv;
+ MrvlIEtypes_RsnParamSet_t *prsn_ie_tlv;
+ t_u32 cmd_append_size = 0;
+ t_u16 tmp_cap;
+ t_u32 i, rates_size = 0;
+ t_u16 curr_pkt_filter;
+ t_u8 *pos = (t_u8 *) padhoc_join + sizeof(HostCmd_DS_802_11_AD_HOC_JOIN);
+
+ ENTER();
+
+/** Use G protection */
+#define USE_G_PROTECTION 0x02
+ if (pbss_desc->erp_flags & USE_G_PROTECTION) {
+ curr_pkt_filter =
+ pmpriv->curr_pkt_filter | HostCmd_ACT_MAC_ADHOC_G_PROTECTION_ON;
+
+ ret = wlan_prepare_cmd(pmpriv,
+ HostCmd_CMD_MAC_CONTROL,
+ HostCmd_ACT_GEN_SET, 0, MNULL, &curr_pkt_filter);
+ if (ret) {
+ PRINTM(MERROR, "ADHOC_J_CMD: G Protection config failed\n");
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ }
+
+ pmpriv->pattempted_bss_desc = pbss_desc;
+
+ cmd->command = wlan_cpu_to_le16(HostCmd_CMD_802_11_AD_HOC_JOIN);
+
+ padhoc_join->bss_descriptor.bss_mode = HostCmd_BSS_MODE_IBSS;
+
+ padhoc_join->bss_descriptor.beacon_period
+ = wlan_cpu_to_le16(pbss_desc->beacon_period);
+
+ memcpy(pmadapter, &padhoc_join->bss_descriptor.bssid,
+ &pbss_desc->mac_address, MLAN_MAC_ADDR_LENGTH);
+
+ memcpy(pmadapter, &padhoc_join->bss_descriptor.ssid,
+ &pbss_desc->ssid.ssid,
+ MIN(MLAN_MAX_SSID_LENGTH, pbss_desc->ssid.ssid_len));
+
+ memcpy(pmadapter, &padhoc_join->bss_descriptor.phy_param_set,
+ &pbss_desc->phy_param_set, sizeof(IEEEtypes_PhyParamSet_t));
+
+ memcpy(pmadapter, &padhoc_join->bss_descriptor.ss_param_set,
+ &pbss_desc->ss_param_set, sizeof(IEEEtypes_SsParamSet_t));
+
+ memcpy(pmadapter, &tmp_cap, &pbss_desc->cap_info,
+ sizeof(IEEEtypes_CapInfo_t));
+
+ tmp_cap &= CAPINFO_MASK;
+
+ PRINTM(MINFO, "ADHOC_J_CMD: tmp_cap=%4X CAPINFO_MASK=%4lX\n",
+ tmp_cap, CAPINFO_MASK);
+ memcpy(pmadapter, &padhoc_join->bss_descriptor.cap, &tmp_cap,
+ sizeof(IEEEtypes_CapInfo_t));
+
+ /* Information on BSSID descriptor passed to FW */
+ PRINTM(MINFO,
+ "ADHOC_J_CMD: BSSID = %02x-%02x-%02x-%02x-%02x-%02x, SSID = %s\n",
+ padhoc_join->bss_descriptor.bssid[0],
+ padhoc_join->bss_descriptor.bssid[1],
+ padhoc_join->bss_descriptor.bssid[2],
+ padhoc_join->bss_descriptor.bssid[3],
+ padhoc_join->bss_descriptor.bssid[4],
+ padhoc_join->bss_descriptor.bssid[5],
+ padhoc_join->bss_descriptor.ssid);
+
+ for (i = 0; i < WLAN_SUPPORTED_RATES && pbss_desc->supported_rates[i]; i++);
+ rates_size = i;
+
+ /* Copy Data Rates from the Rates recorded in scan response */
+ memset(pmadapter, padhoc_join->bss_descriptor.data_rates, 0,
+ sizeof(padhoc_join->bss_descriptor.data_rates));
+ memcpy(pmadapter, padhoc_join->bss_descriptor.data_rates,
+ pbss_desc->supported_rates, rates_size);
+
+ HEXDUMP("Adapted Rates:", padhoc_join->bss_descriptor.data_rates,
+ rates_size);
+
+ /* Copy the adhoc join rates into Current BSS state structure */
+ pmpriv->curr_bss_params.num_of_rates = rates_size;
+ memcpy(pmadapter, &pmpriv->curr_bss_params.data_rates,
+ pbss_desc->supported_rates, rates_size);
+
+ /* Copy the channel information */
+ pmpriv->curr_bss_params.bss_descriptor.channel = pbss_desc->channel;
+ pmpriv->curr_bss_params.band = (t_u8) pbss_desc->bss_band;
+
+ if (pmpriv->sec_info.wep_status == Wlan802_11WEPEnabled
+ || pmpriv->adhoc_aes_enabled
+ || pmpriv->sec_info.wpa_enabled || pmpriv->sec_info.ewpa_enabled)
+ padhoc_join->bss_descriptor.cap.privacy = AD_HOC_CAP_PRIVACY_ON;
+
+ if (IS_SUPPORT_MULTI_BANDS(pmadapter)) {
+ /* Append a channel TLV */
+ pchan_tlv = (MrvlIEtypes_ChanListParamSet_t *) pos;
+ pchan_tlv->header.type = wlan_cpu_to_le16(TLV_TYPE_CHANLIST);
+ pchan_tlv->header.len = wlan_cpu_to_le16(sizeof(ChanScanParamSet_t));
+
+ memset(pmadapter, pchan_tlv->chan_scan_param, 0x00,
+ sizeof(ChanScanParamSet_t));
+ pchan_tlv->chan_scan_param[0].chan_number =
+ (pbss_desc->phy_param_set.ds_param_set.current_chan);
+ PRINTM(MINFO, "ADHOC_J_CMD: TLV Chan = %d\n",
+ pchan_tlv->chan_scan_param[0].chan_number);
+
+ pchan_tlv->chan_scan_param[0].radio_type
+ = wlan_band_to_radio_type((t_u8) pbss_desc->bss_band);
+
+ PRINTM(MINFO, "ADHOC_J_CMD: TLV Band = %d\n",
+ pchan_tlv->chan_scan_param[0].radio_type);
+ pos += sizeof(pchan_tlv->header) + sizeof(ChanScanParamSet_t);
+ cmd_append_size +=
+ sizeof(pchan_tlv->header) + sizeof(ChanScanParamSet_t);
+ }
+
+ if (wlan_11d_create_dnld_countryinfo(pmpriv, (t_u8) pbss_desc->bss_band)) {
+ PRINTM(MERROR, "Dnld_countryinfo_11d failed\n");
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ if (wlan_11d_parse_dnld_countryinfo(pmpriv, pmpriv->pattempted_bss_desc)) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ /*
+ * Call 11h join API after capability bits are set so
+ * adhoc/infra 11h behavior can be properly triggered.
+ * pos modified if data is appended
+ */
+ cmd_append_size += wlan_11h_process_join(pmpriv, &pos,
+ &padhoc_join->bss_descriptor.cap,
+ (t_u8) pbss_desc->bss_band,
+ pbss_desc->channel,
+ &pbss_desc->wlan_11h_bss_info);
+
+ if (pmpriv->sec_info.wpa_enabled) {
+ prsn_ie_tlv = (MrvlIEtypes_RsnParamSet_t *) pos;
+ prsn_ie_tlv->header.type = (t_u16) pmpriv->wpa_ie[0]; /* WPA_IE or
+ RSN_IE */
+ prsn_ie_tlv->header.type = prsn_ie_tlv->header.type & 0x00FF;
+ prsn_ie_tlv->header.type = wlan_cpu_to_le16(prsn_ie_tlv->header.type);
+ prsn_ie_tlv->header.len = (t_u16) pmpriv->wpa_ie[1];
+ prsn_ie_tlv->header.len = prsn_ie_tlv->header.len & 0x00FF;
+ if (prsn_ie_tlv->header.len <= (sizeof(pmpriv->wpa_ie) - 2))
+ memcpy(pmadapter, prsn_ie_tlv->rsn_ie, &pmpriv->wpa_ie[2],
+ prsn_ie_tlv->header.len);
+ else {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ HEXDUMP("ADHOC_JOIN: RSN IE", (t_u8 *) prsn_ie_tlv,
+ sizeof(prsn_ie_tlv->header) + prsn_ie_tlv->header.len);
+ pos += sizeof(prsn_ie_tlv->header) + prsn_ie_tlv->header.len;
+ cmd_append_size +=
+ sizeof(prsn_ie_tlv->header) + prsn_ie_tlv->header.len;
+ prsn_ie_tlv->header.len = wlan_cpu_to_le16(prsn_ie_tlv->header.len);
+ } else if (pmpriv->sec_info.ewpa_enabled) {
+ prsn_ie_tlv = (MrvlIEtypes_RsnParamSet_t *) pos;
+ if (pbss_desc->pwpa_ie) {
+ prsn_ie_tlv->header.type =
+ (t_u16) (*(pbss_desc->pwpa_ie)).vend_hdr.element_id;
+ prsn_ie_tlv->header.type = prsn_ie_tlv->header.type & 0x00FF;
+ prsn_ie_tlv->header.type =
+ wlan_cpu_to_le16(prsn_ie_tlv->header.type);
+ prsn_ie_tlv->header.len =
+ (t_u16) (*(pbss_desc->pwpa_ie)).vend_hdr.len;
+ prsn_ie_tlv->header.len = prsn_ie_tlv->header.len & 0x00FF;
+ if (prsn_ie_tlv->header.len <= (sizeof(pmpriv->wpa_ie))) {
+ memcpy(pmadapter, prsn_ie_tlv->rsn_ie,
+ &((*(pbss_desc->pwpa_ie)).vend_hdr.oui[0]),
+ prsn_ie_tlv->header.len);
+ } else {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ HEXDUMP("ADHOC_JOIN: RSN IE", (t_u8 *) prsn_ie_tlv,
+ sizeof(prsn_ie_tlv->header) + prsn_ie_tlv->header.len);
+ pos += sizeof(prsn_ie_tlv->header) + prsn_ie_tlv->header.len;
+ cmd_append_size +=
+ sizeof(prsn_ie_tlv->header) + prsn_ie_tlv->header.len;
+ prsn_ie_tlv->header.len = wlan_cpu_to_le16(prsn_ie_tlv->header.len);
+ }
+ if (pbss_desc->prsn_ie) {
+ prsn_ie_tlv = (MrvlIEtypes_RsnParamSet_t *) pos;
+ prsn_ie_tlv->header.type =
+ (t_u16) (*(pbss_desc->prsn_ie)).ieee_hdr.element_id;
+ prsn_ie_tlv->header.type = prsn_ie_tlv->header.type & 0x00FF;
+ prsn_ie_tlv->header.type =
+ wlan_cpu_to_le16(prsn_ie_tlv->header.type);
+ prsn_ie_tlv->header.len =
+ (t_u16) (*(pbss_desc->prsn_ie)).ieee_hdr.len;
+ prsn_ie_tlv->header.len = prsn_ie_tlv->header.len & 0x00FF;
+ if (prsn_ie_tlv->header.len <= (sizeof(pmpriv->wpa_ie))) {
+ memcpy(pmadapter, prsn_ie_tlv->rsn_ie,
+ &((*(pbss_desc->prsn_ie)).data[0])
+ , prsn_ie_tlv->header.len);
+ } else {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ HEXDUMP("ADHOC_JOIN: RSN IE", (t_u8 *) prsn_ie_tlv,
+ sizeof(prsn_ie_tlv->header) + prsn_ie_tlv->header.len);
+ pos += sizeof(prsn_ie_tlv->header) + prsn_ie_tlv->header.len;
+ cmd_append_size +=
+ sizeof(prsn_ie_tlv->header) + prsn_ie_tlv->header.len;
+ prsn_ie_tlv->header.len = wlan_cpu_to_le16(prsn_ie_tlv->header.len);
+ }
+ }
+
+ if (ISSUPP_11NENABLED(pmadapter->fw_cap_info)
+ )
+ cmd_append_size += wlan_cmd_append_11n_tlv(pmpriv, pbss_desc, &pos);
+
+ cmd->size =
+ (t_u16) wlan_cpu_to_le16((t_u16) (sizeof(HostCmd_DS_802_11_AD_HOC_JOIN)
+ + S_DS_GEN + cmd_append_size));
+
+ memcpy(pmadapter, &tmp_cap, &padhoc_join->bss_descriptor.cap,
+ sizeof(IEEEtypes_CapInfo_t));
+ tmp_cap = wlan_cpu_to_le16(tmp_cap);
+
+ memcpy(pmadapter, &padhoc_join->bss_descriptor.cap,
+ &tmp_cap, sizeof(IEEEtypes_CapInfo_t));
+
+ done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function handles the command response of ad_hoc_start and
+ * ad_hoc_join
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param resp A pointer to HostCmd_DS_COMMAND
+ * @param pioctl_buf A pointer to mlan_ioctl_req structure
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status
+wlan_ret_802_11_ad_hoc(IN mlan_private * pmpriv,
+ IN HostCmd_DS_COMMAND * resp, IN t_void * pioctl_buf)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_ioctl_req *pioctl_req = (mlan_ioctl_req *) pioctl_buf;
+ HostCmd_DS_802_11_AD_HOC_START_RESULT *padhoc_start_result =
+ &resp->params.adhoc_start_result;
+ HostCmd_DS_802_11_AD_HOC_JOIN_RESULT *padhoc_join_result =
+ &resp->params.adhoc_join_result;
+ BSSDescriptor_t *pbss_desc;
+ t_u16 command = resp->command;
+ t_u8 result = 0;
+ t_u8 event_buf[100];
+ mlan_event *pevent = (mlan_event *) event_buf;
+
+ ENTER();
+
+ if (command == HostCmd_CMD_802_11_AD_HOC_START)
+ result = padhoc_start_result->result;
+ else
+ result = padhoc_join_result->result;
+
+ pbss_desc = pmpriv->pattempted_bss_desc;
+
+ /*
+ * Join result code 0 --> SUCCESS
+ */
+ if (result) {
+ PRINTM(MERROR, "ADHOC_RESP Failed 0x%x\n", result);
+ if (pmpriv->media_connected == MTRUE)
+ wlan_reset_connect_state(pmpriv, MTRUE);
+ if (pmpriv->adhoc_state == ADHOC_STARTING)
+ pmpriv->adhoc_state = ADHOC_IDLE;
+
+ memset(pmpriv->adapter, &pmpriv->curr_bss_params.bss_descriptor,
+ 0x00, sizeof(BSSDescriptor_t));
+
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ /* Send a Media Connected event, according to the Spec */
+ pmpriv->media_connected = MTRUE;
+
+ if (command == HostCmd_CMD_802_11_AD_HOC_START) {
+ PRINTM(MINFO, "ADHOC_S_RESP %s\n", pbss_desc->ssid.ssid);
+
+ /* Update the created network descriptor with the new BSSID */
+ memcpy(pmpriv->adapter, pbss_desc->mac_address,
+ padhoc_start_result->bssid, MLAN_MAC_ADDR_LENGTH);
+
+ pmpriv->adhoc_state = ADHOC_STARTED;
+ if (pmpriv->adapter->state_rdh.stage == RDH_RESTART_INTFS)
+ wlan_11h_radar_detected_callback((t_void *) pmpriv);
+ } else {
+ /*
+ * Now the join cmd should be successful.
+ * If BSSID has changed use SSID to compare instead of BSSID
+ */
+ PRINTM(MINFO, "ADHOC_J_RESP %s\n", pbss_desc->ssid.ssid);
+
+ /*
+ * Make a copy of current BSSID descriptor, only needed for join since
+ * the current descriptor is already being used for adhoc start
+ */
+ memcpy(pmpriv->adapter, &pmpriv->curr_bss_params.bss_descriptor,
+ pbss_desc, sizeof(BSSDescriptor_t));
+
+ pmpriv->adhoc_state = ADHOC_JOINED;
+ }
+
+ PRINTM(MINFO, "ADHOC_RESP: Channel = %d\n", pmpriv->adhoc_channel);
+ PRINTM(MINFO, "ADHOC_RESP: BSSID = %02x:%02x:%02x:%02x:%02x:%02x\n",
+ pmpriv->curr_bss_params.bss_descriptor.mac_address[0],
+ pmpriv->curr_bss_params.bss_descriptor.mac_address[1],
+ pmpriv->curr_bss_params.bss_descriptor.mac_address[2],
+ pmpriv->curr_bss_params.bss_descriptor.mac_address[3],
+ pmpriv->curr_bss_params.bss_descriptor.mac_address[4],
+ pmpriv->curr_bss_params.bss_descriptor.mac_address[5]);
+
+ pevent->bss_index = pmpriv->bss_index;
+ pevent->event_id = MLAN_EVENT_ID_DRV_CONNECTED;
+ pevent->event_len = MLAN_MAC_ADDR_LENGTH;
+ memcpy(pmpriv->adapter, (t_u8 *) pevent->event_buf,
+ (t_u8 *) pmpriv->curr_bss_params.bss_descriptor.mac_address,
+ MLAN_MAC_ADDR_LENGTH);
+ wlan_recv_event(pmpriv, MLAN_EVENT_ID_DRV_CONNECTED, pevent);
+ wlan_save_curr_bcn(pmpriv);
+
+ done:
+ /* Need to indicate IOCTL complete */
+ if (pioctl_req != MNULL) {
+ if (ret != MLAN_STATUS_SUCCESS) {
+ pioctl_req->status_code = MLAN_ERROR_CMD_ASSOC_FAIL;
+ } else {
+ pioctl_req->status_code = MLAN_ERROR_NO_ERROR;
+ }
+ }
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Associated to a specific BSS discovered in a scan
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param pioctl_buf A pointer to MLAN IOCTL Request buffer
+ * @param pbss_desc A pointer to the BSS descriptor to associate with.
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status
+wlan_associate(IN mlan_private * pmpriv,
+ IN t_void * pioctl_buf, IN BSSDescriptor_t * pbss_desc)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ t_u8 current_bssid[MLAN_MAC_ADDR_LENGTH];
+ pmlan_ioctl_req pioctl_req = (mlan_ioctl_req *) pioctl_buf;
+
+ ENTER();
+
+ /* Return error if the pmadapter or table entry is not marked as infra */
+ if ((pmpriv->bss_mode != MLAN_BSS_MODE_INFRA) ||
+ (pbss_desc->bss_mode != MLAN_BSS_MODE_INFRA)) {
+ if (pioctl_req)
+ pioctl_req->status_code = MLAN_ERROR_IOCTL_INVALID;
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+
+ memcpy(pmpriv->adapter, &current_bssid,
+ &pmpriv->curr_bss_params.bss_descriptor.mac_address,
+ sizeof(current_bssid));
+
+ /* Clear any past association response stored for application retrieval */
+ pmpriv->assoc_rsp_size = 0;
+
+ ret = wlan_prepare_cmd(pmpriv,
+ HostCmd_CMD_802_11_ASSOCIATE,
+ HostCmd_ACT_GEN_SET, 0, pioctl_buf, pbss_desc);
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Start an Adhoc Network
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param pioctl_buf A pointer to MLAN IOCTL Request buffer
+ * @param padhoc_ssid The ssid of the Adhoc Network
+ *
+ * @return MLAN_STATUS_SUCCESS--success, MLAN_STATUS_FAILURE--fail
+ */
+mlan_status
+wlan_adhoc_start(IN mlan_private * pmpriv,
+ IN t_void * pioctl_buf, IN mlan_802_11_ssid * padhoc_ssid)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ wlan_meas_state_t *pmeas_state = &pmpriv->adapter->state_meas;
+ t_u8 radar = MFALSE;
+ pmlan_ioctl_req pioctl_req = (mlan_ioctl_req *) pioctl_buf;
+
+ ENTER();
+
+ /*
+ * If the report indicates no measurement was done, leave the default
+ * return value alone.
+ */
+ if (!pmeas_state->meas_rpt_returned.rpt.basic.map.unmeasured) {
+ radar =
+ pmeas_state->meas_rpt_returned.rpt.basic.map.radar ? MTRUE : MFALSE;
+ }
+
+ if (radar) {
+ if (pioctl_req)
+ pioctl_req->status_code = MLAN_ERROR_IOCTL_INVALID;
+ ret = MLAN_STATUS_FAILURE;
+ LEAVE();
+ return ret;
+ }
+
+ PRINTM(MINFO, "Adhoc Channel = %d\n", pmpriv->adhoc_channel);
+ PRINTM(MINFO, "curr_bss_params.channel = %d\n",
+ pmpriv->curr_bss_params.bss_descriptor.channel);
+ PRINTM(MINFO, "curr_bss_params.band = %d\n", pmpriv->curr_bss_params.band);
+
+ ret = wlan_prepare_cmd(pmpriv,
+ HostCmd_CMD_802_11_AD_HOC_START,
+ HostCmd_ACT_GEN_SET, 0, pioctl_buf, padhoc_ssid);
+#if defined(STA_SUPPORT)
+ if (ret == MLAN_STATUS_SUCCESS)
+ memcpy(pmpriv->adapter, &pmpriv->adhoc_last_start_ssid,
+ padhoc_ssid, sizeof(mlan_802_11_ssid));
+#endif
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Join an adhoc network found in a previous scan
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param pioctl_buf A pointer to MLAN IOCTL Request buffer
+ * @param pbss_desc A pointer to the BSS descriptor found in a previous scan
+ * to attempt to join
+ *
+ * @return MLAN_STATUS_SUCCESS--success, MLAN_STATUS_FAILURE--fail
+ */
+mlan_status
+wlan_adhoc_join(IN mlan_private * pmpriv,
+ IN t_void * pioctl_buf, IN BSSDescriptor_t * pbss_desc)
+{
+ pmlan_adapter pmadapter = pmpriv->adapter;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ pmlan_ioctl_req pioctl_req = (mlan_ioctl_req *) pioctl_buf;
+
+ ENTER();
+
+ PRINTM(MINFO, "wlan_adhoc_join: CurBss.ssid =%s\n",
+ pmpriv->curr_bss_params.bss_descriptor.ssid.ssid);
+ PRINTM(MINFO, "wlan_adhoc_join: CurBss.ssid_len =%u\n",
+ pmpriv->curr_bss_params.bss_descriptor.ssid.ssid_len);
+ PRINTM(MINFO, "wlan_adhoc_join: ssid =%s\n", pbss_desc->ssid.ssid);
+ PRINTM(MINFO, "wlan_adhoc_join: ssid len =%u\n", pbss_desc->ssid.ssid_len);
+
+ /* Check if the requested SSID is already joined */
+ if (pmpriv->curr_bss_params.bss_descriptor.ssid.ssid_len &&
+ !wlan_ssid_cmp(pmadapter, &pbss_desc->ssid,
+ &pmpriv->curr_bss_params.bss_descriptor.ssid) &&
+ (pmpriv->curr_bss_params.bss_descriptor.bss_mode ==
+ MLAN_BSS_MODE_IBSS)) {
+
+ PRINTM(MINFO,
+ "ADHOC_J_CMD: New ad-hoc SSID is the same as current, "
+ "not attempting to re-join\n");
+
+ if (pioctl_req)
+ pioctl_req->status_code = MLAN_ERROR_IOCTL_INVALID;
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+
+ PRINTM(MINFO, "curr_bss_params.channel = %d\n",
+ pmpriv->curr_bss_params.bss_descriptor.channel);
+ PRINTM(MINFO, "curr_bss_params.band = %d\n", pmpriv->curr_bss_params.band);
+
+ ret = wlan_prepare_cmd(pmpriv,
+ HostCmd_CMD_802_11_AD_HOC_JOIN,
+ HostCmd_ACT_GEN_SET, 0, pioctl_buf, pbss_desc);
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Send Deauthentication Request or Stop the AdHoc network depending on mode
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param pioctl_req A pointer to mlan_ioctl_req structure
+ * @param mac A pointer to mlan_802_11_mac_addr structure
+ *
+ * @return MLAN_STATUS_SUCCESS--success, MLAN_STATUS_FAILURE--fail, MLAN_STATUS_PENDING--pending
+ */
+mlan_status
+wlan_disconnect(IN mlan_private * pmpriv,
+ IN mlan_ioctl_req * pioctl_req, IN mlan_802_11_mac_addr * mac)
+{
+ mlan_802_11_mac_addr mac_address;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ t_u8 zero_mac[] = { 0, 0, 0, 0, 0, 0 };
+
+ ENTER();
+
+ if (pmpriv->media_connected == MTRUE) {
+ if (pmpriv->bss_mode == MLAN_BSS_MODE_INFRA) {
+ if (mac) {
+ if (!memcmp(pmpriv->adapter, mac, zero_mac, sizeof(zero_mac)))
+ memcpy(pmpriv->adapter, (t_u8 *) & mac_address,
+ (t_u8 *) & pmpriv->curr_bss_params.bss_descriptor.
+ mac_address, MLAN_MAC_ADDR_LENGTH);
+ else {
+ memcpy(pmpriv->adapter, (t_u8 *) & mac_address,
+ (t_u8 *) mac, MLAN_MAC_ADDR_LENGTH);
+ }
+ } else {
+ memcpy(pmpriv->adapter, (t_u8 *) & mac_address,
+ (t_u8 *) & pmpriv->curr_bss_params.bss_descriptor.
+ mac_address, MLAN_MAC_ADDR_LENGTH);
+ }
+
+ ret = wlan_prepare_cmd(pmpriv,
+ HostCmd_CMD_802_11_DEAUTHENTICATE,
+ HostCmd_ACT_GEN_SET,
+ 0, (t_void *) pioctl_req, &mac_address);
+
+ if (ret == MLAN_STATUS_SUCCESS && pioctl_req)
+ ret = MLAN_STATUS_PENDING;
+
+ } else if (pmpriv->bss_mode == MLAN_BSS_MODE_IBSS) {
+ ret = wlan_prepare_cmd(pmpriv,
+ HostCmd_CMD_802_11_AD_HOC_STOP,
+ HostCmd_ACT_GEN_SET,
+ 0, (t_void *) pioctl_req, MNULL);
+
+ if (ret == MLAN_STATUS_SUCCESS && pioctl_req)
+ ret = MLAN_STATUS_PENDING;
+ }
+ }
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Convert band to radio type used in channel TLV
+ *
+ * @param band Band enumeration to convert to a channel TLV radio type
+ *
+ * @return Radio type designator for use in a channel TLV
+ */
+t_u8
+wlan_band_to_radio_type(IN t_u8 band)
+{
+ t_u8 ret_radio_type;
+
+ ENTER();
+
+ switch (band) {
+ case BAND_A:
+ case BAND_AN:
+ case BAND_A | BAND_AN:
+ ret_radio_type = HostCmd_SCAN_RADIO_TYPE_A;
+ break;
+ case BAND_B:
+ case BAND_G:
+ case BAND_B | BAND_G:
+ default:
+ ret_radio_type = HostCmd_SCAN_RADIO_TYPE_BG;
+ break;
+ }
+
+ LEAVE();
+ return ret_radio_type;
+}
diff --git a/drivers/net/wireless/sd8797/mlan/mlan_join.h b/drivers/net/wireless/sd8797/mlan/mlan_join.h
new file mode 100644
index 000000000000..d7091f3a4b28
--- /dev/null
+++ b/drivers/net/wireless/sd8797/mlan/mlan_join.h
@@ -0,0 +1,40 @@
+/** @file mlan_join.h
+ *
+ * @brief This file defines the interface for the WLAN infrastructure
+ * and adhoc join routines.
+ *
+ * Driver interface functions and type declarations for the join module
+ * implemented in mlan_join.c. Process all start/join requests for
+ * both adhoc and infrastructure networks
+ *
+ * Copyright (C) 2008-2011, Marvell International Ltd.
+ *
+ * This software file (the "File") is distributed by Marvell International
+ * Ltd. under the terms of the GNU General Public License Version 2, June 1991
+ * (the "License"). You may use, redistribute and/or modify this File in
+ * accordance with the terms and conditions of the License, a copy of which
+ * is available by writing to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
+ * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
+ *
+ * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
+ * ARE EXPRESSLY DISCLAIMED. The License provides additional details about
+ * this warranty disclaimer.
+ */
+
+/******************************************************
+Change log:
+ 10/13/2008: initial version
+******************************************************/
+
+#ifndef _MLAN_JOIN_H_
+#define _MLAN_JOIN_H_
+
+/** Size of buffer allocated to store the association response from firmware */
+#define MRVDRV_ASSOC_RSP_BUF_SIZE 500
+
+/** Size of buffer allocated to store IEs passed to firmware in the assoc req */
+#define MRVDRV_GENIE_BUF_SIZE 256
+
+#endif /* _MLAN_JOIN_H_ */
diff --git a/drivers/net/wireless/sd8797/mlan/mlan_main.h b/drivers/net/wireless/sd8797/mlan/mlan_main.h
new file mode 100644
index 000000000000..1a0a4e1d1871
--- /dev/null
+++ b/drivers/net/wireless/sd8797/mlan/mlan_main.h
@@ -0,0 +1,2693 @@
+/** @file mlan_main.h
+ *
+ * @brief This file defines the private and adapter data
+ * structures and declares global function prototypes used
+ * in MLAN module.
+ *
+ * Copyright (C) 2008-2011, Marvell International Ltd.
+ *
+ * This software file (the "File") is distributed by Marvell International
+ * Ltd. under the terms of the GNU General Public License Version 2, June 1991
+ * (the "License"). You may use, redistribute and/or modify this File in
+ * accordance with the terms and conditions of the License, a copy of which
+ * is available by writing to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
+ * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
+ *
+ * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
+ * ARE EXPRESSLY DISCLAIMED. The License provides additional details about
+ * this warranty disclaimer.
+ */
+
+/******************************************************
+Change log:
+ 10/13/2008: initial version
+******************************************************/
+
+#ifndef _MLAN_MAIN_H_
+#define _MLAN_MAIN_H_
+
+#ifdef DEBUG_LEVEL1
+extern t_void(*print_callback) (IN t_void * pmoal_handle,
+ IN t_u32 level, IN t_s8 * pformat, IN ...);
+extern t_u32 drvdbg;
+
+#ifdef DEBUG_LEVEL2
+#define PRINTM_MINFO(msg...) do {if ((drvdbg & MINFO) && (print_callback)) \
+ print_callback(MNULL, MINFO, msg);} while(0)
+#define PRINTM_MWARN(msg...) do {if ((drvdbg & MWARN) && (print_callback)) \
+ print_callback(MNULL, MWARN, msg);} while(0)
+#define PRINTM_MENTRY(msg...) do {if ((drvdbg & MENTRY) && (print_callback)) \
+ print_callback(MNULL, MENTRY, msg);} while(0)
+#else
+#define PRINTM_MINFO(msg...) do {} while (0)
+#define PRINTM_MWARN(msg...) do {} while (0)
+#define PRINTM_MENTRY(msg...) do {} while (0)
+#endif /* DEBUG_LEVEL2 */
+
+#define PRINTM_MFW_D(msg...) do {if ((drvdbg & MFW_D) && (print_callback)) \
+ print_callback(MNULL, MFW_D, msg);} while(0)
+#define PRINTM_MCMD_D(msg...) do {if ((drvdbg & MCMD_D) && (print_callback)) \
+ print_callback(MNULL, MCMD_D, msg);} while(0)
+#define PRINTM_MDAT_D(msg...) do {if ((drvdbg & MDAT_D) && (print_callback)) \
+ print_callback(MNULL, MDAT_D, msg);} while(0)
+#define PRINTM_MIF_D(msg...) do {if ((drvdbg & MIF_D) && (print_callback)) \
+ print_callback(MNULL, MIF_D, msg);} while(0)
+
+#define PRINTM_MIOCTL(msg...) do {if ((drvdbg & MIOCTL) && (print_callback)) \
+ print_callback(MNULL, MIOCTL, msg);} while(0)
+#define PRINTM_MINTR(msg...) do {if ((drvdbg & MINTR) && (print_callback)) \
+ print_callback(MNULL, MINTR, msg);} while(0)
+#define PRINTM_MEVENT(msg...) do {if ((drvdbg & MEVENT) && (print_callback)) \
+ print_callback(MNULL, MEVENT, msg);} while(0)
+#define PRINTM_MCMND(msg...) do {if ((drvdbg & MCMND) && (print_callback)) \
+ print_callback(MNULL, MCMND, msg);} while(0)
+#define PRINTM_MDATA(msg...) do {if ((drvdbg & MDATA) && (print_callback)) \
+ print_callback(MNULL, MDATA, msg);} while(0)
+#define PRINTM_MERROR(msg...) do {if ((drvdbg & MERROR) && (print_callback)) \
+ print_callback(MNULL, MERROR, msg);} while(0)
+#define PRINTM_MFATAL(msg...) do {if ((drvdbg & MFATAL) && (print_callback)) \
+ print_callback(MNULL, MFATAL, msg);} while(0)
+#define PRINTM_MMSG(msg...) do {if ((drvdbg & MMSG) && (print_callback)) \
+ print_callback(MNULL, MMSG, msg);} while(0)
+
+#define PRINTM(level,msg...) PRINTM_##level(msg)
+
+#ifdef DEBUG_LEVEL2
+
+/** Hexdump for level-2 debugging */
+#define HEXDUMP(x,y,z) \
+do { \
+ if ((drvdbg & (MHEX_DUMP | MINFO)) && (print_callback)) \
+ print_callback(MNULL, MHEX_DUMP | MINFO, x, y, z); \
+} while (0)
+#else
+
+/** Hexdump for debugging */
+#define HEXDUMP(x,y,z) do {} while (0)
+#endif /* DEBUG_LEVEL2 */
+
+/** Log debug message */
+#ifdef __GNUC__
+#define PRINTM_NETINTF(level, pmpriv) \
+do { \
+ if ((drvdbg & level) && pmpriv \
+ && pmpriv->adapter->callbacks.moal_print_netintf) \
+ pmpriv->adapter->callbacks.moal_print_netintf( \
+ pmpriv->adapter->pmoal_handle, \
+ pmpriv->bss_index, level); \
+} while (0)
+#endif /* __GNUC__ */
+
+/** Max hex dump data length */
+#define MAX_DATA_DUMP_LEN 64
+
+/** Debug hexdump for level-1 debugging */
+#define DBG_HEXDUMP(level,x,y,z) \
+do { \
+ if ((drvdbg & level) && print_callback) \
+ print_callback(MNULL, MHEX_DUMP | level, x, y, z); \
+} while (0)
+
+#else /* DEBUG_LEVEL1 */
+
+#define PRINTM(level,msg...) do {} while (0)
+
+#define PRINTM_NETINTF(level, pmpriv) do {} while (0)
+
+/** Debug hexdump for level-1 debugging */
+#define DBG_HEXDUMP(level,x,y,z) do {} while (0)
+
+/** Hexdump for debugging */
+#define HEXDUMP(x,y,z) do {} while (0)
+
+#endif /* DEBUG_LEVEL1 */
+
+/** Log entry point for debugging */
+#define ENTER() \
+do { \
+ PRINTM(MENTRY, "Enter: %s\n", __FUNCTION__); \
+} while (0)
+
+/** Log exit point for debugging */
+#define LEAVE() \
+do { \
+ PRINTM(MENTRY, "Leave: %s\n", __FUNCTION__); \
+} while (0)
+
+/** Find minimum */
+#ifndef MIN
+#define MIN(a,b) ((a) < (b) ? (a) : (b))
+#endif
+
+/** Find maximum */
+#ifndef MAX
+#define MAX(a,b) ((a) > (b) ? (a) : (b))
+#endif
+
+#ifdef memset
+#undef memset
+#endif
+/** Memset routine */
+#define memset(adapter, s, c, len) \
+ adapter->callbacks.moal_memset(adapter->pmoal_handle, s, c, len)
+
+#ifdef memmove
+#undef memmove
+#endif
+/** Memmove routine */
+#define memmove(adapter, dest, src, len) \
+ adapter->callbacks.moal_memmove(adapter->pmoal_handle, dest, src, len)
+
+#ifdef memcpy
+#undef memcpy
+#endif
+/** Memcpy routine */
+#define memcpy(adapter, to, from, len) \
+ adapter->callbacks.moal_memcpy(adapter->pmoal_handle, to, from, len)
+
+#ifdef memcmp
+#undef memcmp
+#endif
+/** Memcmp routine */
+#define memcmp(adapter, s1, s2, len) \
+ adapter->callbacks.moal_memcmp(adapter->pmoal_handle, s1, s2, len)
+
+/** Find number of elements */
+#ifndef NELEMENTS
+#define NELEMENTS(x) (sizeof(x)/sizeof(x[0]))
+#endif
+
+/** SWAP: swap t_u8 */
+#define SWAP_U8(a,b) {t_u8 t; t=a; a=b; b=t;}
+
+/** SWAP: swap t_u8 */
+#define SWAP_U16(a,b) {t_u16 t; t=a; a=b; b=t;}
+
+/** MLAN MNULL pointer */
+#define MNULL (0)
+
+/** 16 bits byte swap */
+#define swap_byte_16(x) \
+((t_u16)((((t_u16)(x) & 0x00ffU) << 8) | \
+ (((t_u16)(x) & 0xff00U) >> 8)))
+
+/** 32 bits byte swap */
+#define swap_byte_32(x) \
+((t_u32)((((t_u32)(x) & 0x000000ffUL) << 24) | \
+ (((t_u32)(x) & 0x0000ff00UL) << 8) | \
+ (((t_u32)(x) & 0x00ff0000UL) >> 8) | \
+ (((t_u32)(x) & 0xff000000UL) >> 24)))
+
+/** 64 bits byte swap */
+#define swap_byte_64(x) \
+((t_u64)((t_u64)(((t_u64)(x) & 0x00000000000000ffULL) << 56) | \
+ (t_u64)(((t_u64)(x) & 0x000000000000ff00ULL) << 40) | \
+ (t_u64)(((t_u64)(x) & 0x0000000000ff0000ULL) << 24) | \
+ (t_u64)(((t_u64)(x) & 0x00000000ff000000ULL) << 8) | \
+ (t_u64)(((t_u64)(x) & 0x000000ff00000000ULL) >> 8) | \
+ (t_u64)(((t_u64)(x) & 0x0000ff0000000000ULL) >> 24) | \
+ (t_u64)(((t_u64)(x) & 0x00ff000000000000ULL) >> 40) | \
+ (t_u64)(((t_u64)(x) & 0xff00000000000000ULL) >> 56) ))
+
+#ifdef BIG_ENDIAN_SUPPORT
+/** Convert ulong n/w to host */
+#define mlan_ntohl(x) x
+/** Convert host ulong to n/w */
+#define mlan_htonl(x) x
+/** Convert n/w to host */
+#define mlan_ntohs(x) x
+/** Convert host to n/w */
+#define mlan_htons(x) x
+/** Convert from 16 bit little endian format to CPU format */
+#define wlan_le16_to_cpu(x) swap_byte_16(x)
+/** Convert from 32 bit little endian format to CPU format */
+#define wlan_le32_to_cpu(x) swap_byte_32(x)
+/** Convert from 64 bit little endian format to CPU format */
+#define wlan_le64_to_cpu(x) swap_byte_64(x)
+/** Convert to 16 bit little endian format from CPU format */
+#define wlan_cpu_to_le16(x) swap_byte_16(x)
+/** Convert to 32 bit little endian format from CPU format */
+#define wlan_cpu_to_le32(x) swap_byte_32(x)
+/** Convert to 64 bit little endian format from CPU format */
+#define wlan_cpu_to_le64(x) swap_byte_64(x)
+
+/** Convert TxPD to little endian format from CPU format */
+#define endian_convert_TxPD(x) \
+ { \
+ (x)->tx_pkt_length = wlan_cpu_to_le16((x)->tx_pkt_length); \
+ (x)->tx_pkt_offset = wlan_cpu_to_le16((x)->tx_pkt_offset); \
+ (x)->tx_pkt_type = wlan_cpu_to_le16((x)->tx_pkt_type); \
+ (x)->tx_control = wlan_cpu_to_le32((x)->tx_control); \
+ }
+
+/** Convert RxPD from little endian format to CPU format */
+#define endian_convert_RxPD(x) \
+ { \
+ (x)->rx_pkt_length = wlan_le16_to_cpu((x)->rx_pkt_length); \
+ (x)->rx_pkt_offset = wlan_le16_to_cpu((x)->rx_pkt_offset); \
+ (x)->rx_pkt_type = wlan_le16_to_cpu((x)->rx_pkt_type); \
+ (x)->seq_num = wlan_le16_to_cpu((x)->seq_num); \
+ }
+#else
+/** Convert ulong n/w to host */
+#define mlan_ntohl(x) swap_byte_32(x)
+/** Convert host ulong to n/w */
+#define mlan_htonl(x) swap_byte_32(x)
+/** Convert n/w to host */
+#define mlan_ntohs(x) swap_byte_16(x)
+/** Convert host to n/w */
+#define mlan_htons(x) swap_byte_16(x)
+/** Do nothing */
+#define wlan_le16_to_cpu(x) x
+/** Do nothing */
+#define wlan_le32_to_cpu(x) x
+/** Do nothing */
+#define wlan_le64_to_cpu(x) x
+/** Do nothing */
+#define wlan_cpu_to_le16(x) x
+/** Do nothing */
+#define wlan_cpu_to_le32(x) x
+/** Do nothing */
+#define wlan_cpu_to_le64(x) x
+
+/** Convert TxPD to little endian format from CPU format */
+#define endian_convert_TxPD(x) do {} while (0)
+/** Convert RxPD from little endian format to CPU format */
+#define endian_convert_RxPD(x) do {} while (0)
+#endif /* BIG_ENDIAN_SUPPORT */
+
+/** Global moal_assert_callback */
+extern t_void(*assert_callback) (IN t_void * pmoal_handle, IN t_u32 cond);
+
+/** Assertion */
+#define MASSERT(cond) \
+do { \
+ if (!(cond)) { \
+ PRINTM(MFATAL, "ASSERT: %s: %i\n", __FUNCTION__, __LINE__); \
+ if (assert_callback) { \
+ assert_callback(MNULL, (t_ptr)(cond)); \
+ } else { \
+ do {} while(1); \
+ } \
+ } \
+} while(0)
+
+/** Upload size */
+#define WLAN_UPLD_SIZE (2312)
+
+/** Maximum event buffer size */
+#define MAX_EVENT_SIZE 1024
+
+#ifdef STA_SUPPORT
+/** Maximum buffer size for ARP filter */
+#define ARP_FILTER_MAX_BUF_SIZE 68
+#endif /* STA_SUPPORT */
+
+/** 60 seconds */
+#define MRVDRV_TIMER_60S 60000
+/** 10 seconds */
+#define MRVDRV_TIMER_10S 10000
+/** 5 seconds */
+#define MRVDRV_TIMER_5S 5000
+/** 1 second */
+#define MRVDRV_TIMER_1S 1000
+
+/** Maximum size of multicast list */
+#define MRVDRV_MAX_MULTICAST_LIST_SIZE 32
+/** Maximum size of channel */
+#define MRVDRV_MAX_CHANNEL_SIZE 14
+/** Maximum length of SSID */
+#define MRVDRV_MAX_SSID_LENGTH 32
+/** WEP list macros & data structures */
+/** Size of key buffer in bytes */
+#define MRVL_KEY_BUFFER_SIZE_IN_BYTE 16
+/** Maximum length of WPA key */
+#define MRVL_MAX_KEY_WPA_KEY_LENGTH 32
+
+/** Default listen interval */
+#define MLAN_DEFAULT_LISTEN_INTERVAL 10
+
+/** Maximum number of region codes */
+#define MRVDRV_MAX_REGION_CODE 8
+
+/** Default region code */
+#define MRVDRV_DEFAULT_REGION_CODE 0x10
+
+/** Default factor for calculating beacon average */
+#define DEFAULT_BCN_AVG_FACTOR 8
+/** Default factor for calculating data average */
+#define DEFAULT_DATA_AVG_FACTOR 8
+
+/** The first valid channel for use */
+#define FIRST_VALID_CHANNEL 0xff
+/** Default Ad-Hoc channel */
+#define DEFAULT_AD_HOC_CHANNEL 6
+/** Default Ad-Hoc channel A */
+#define DEFAULT_AD_HOC_CHANNEL_A 36
+
+/** Number of WEP keys */
+#define MRVL_NUM_WEP_KEY (4)
+
+/** Default multiple DTIM */
+#define MRVDRV_DEFAULT_MULTIPLE_DTIM 1
+
+/** Default beacon missing timeout */
+#define DEFAULT_BCN_MISS_TIMEOUT 10
+
+/** Maximum buffer space for beacons retrieved from scan responses */
+#define MAX_SCAN_BEACON_BUFFER 16384
+/** Default buffer space for beacons retrieved from scan responses */
+#define DEFAULT_SCAN_BEACON_BUFFER 4096
+
+/**
+ * @brief Buffer pad space for newly allocated beacons/probe responses
+ *
+ * Beacons are typically 6 bytes longer than an equivalent probe response.
+ * For each scan response stored, allocate an extra byte pad at the end to
+ * allow easy expansion to store a beacon in the same memory a probe response
+ * previously contained
+ */
+#define SCAN_BEACON_ENTRY_PAD 6
+
+/** Scan time specified in the channel TLV for each channel for passive scans */
+#define MRVDRV_PASSIVE_SCAN_CHAN_TIME 200
+
+/** Scan time specified in the channel TLV for each channel for active scans */
+#define MRVDRV_ACTIVE_SCAN_CHAN_TIME 200
+
+/** Scan time specified in the channel TLV for each channel for specific scans */
+#define MRVDRV_SPECIFIC_SCAN_CHAN_TIME 110
+
+/**
+ * Max total scan time in milliseconds
+ * The total scan time should be less than scan command timeout value (10s)
+ */
+#define MRVDRV_MAX_TOTAL_SCAN_TIME (MRVDRV_TIMER_10S - MRVDRV_TIMER_1S)
+
+/** Offset for GTK as it has version to skip past for GTK */
+#define RSN_GTK_OUI_OFFSET 2
+
+/** If OUI is not found */
+#define MLAN_OUI_NOT_PRESENT 0
+/** If OUI is found */
+#define MLAN_OUI_PRESENT 1
+
+/** RF antenna selection */
+#define RF_ANTENNA_MASK(n) ((1<<(n))-1)
+/** RF antenna auto select */
+#define RF_ANTENNA_AUTO 0xFFFF
+
+/** Is cmd_resp, event or data packet received? */
+#define IS_CARD_RX_RCVD(adapter) (adapter->cmd_resp_received || \
+ adapter->event_received || \
+ adapter->data_received)
+
+/** Type command */
+#define MLAN_TYPE_CMD 1
+/** Type data */
+#define MLAN_TYPE_DATA 0
+/** Type event */
+#define MLAN_TYPE_EVENT 3
+
+/** Maximum numbfer of registers to read for multiple port */
+#define MAX_MP_REGS 64
+/** Maximum port */
+#define MAX_PORT 16
+/** Multi port aggregation packet limit */
+#define SDIO_MP_AGGR_DEF_PKT_LIMIT (8)
+
+#ifdef SDIO_MULTI_PORT_TX_AGGR
+/** Multi port TX aggregation buffer size */
+#define SDIO_MP_TX_AGGR_DEF_BUF_SIZE (16384) /* 16K */
+#endif /* SDIO_MULTI_PORT_TX_AGGR */
+
+#ifdef SDIO_MULTI_PORT_RX_AGGR
+/** Multi port RX aggregation buffer size */
+#define SDIO_MP_RX_AGGR_DEF_BUF_SIZE (16384) /* 16K */
+#endif /* SDIO_MULTI_PORT_RX_AGGR */
+
+/** High threshold at which to start drop packets */
+#define RX_HIGH_THRESHOLD 1024
+/** Medium threshold at which to disable Rx BA */
+#define RX_MED_THRESHOLD 256
+/** Low threshold to allow Rx BA */
+#define RX_LOW_THRESHOLD 128
+
+/** Debug command number */
+#define DBG_CMD_NUM 5
+
+/** Info for debug purpose */
+typedef struct _wlan_dbg
+{
+ /** Number of host to card command failures */
+ t_u32 num_cmd_host_to_card_failure;
+ /** Number of host to card sleep confirm failures */
+ t_u32 num_cmd_sleep_cfm_host_to_card_failure;
+ /** Number of host to card Tx failures */
+ t_u32 num_tx_host_to_card_failure;
+ /** Number of card to host command/event failures */
+ t_u32 num_cmdevt_card_to_host_failure;
+ /** Number of card to host Rx failures */
+ t_u32 num_rx_card_to_host_failure;
+ /** Number of interrupt read failures */
+ t_u32 num_int_read_failure;
+ /** Last interrupt status */
+ t_u32 last_int_status;
+ /** Number of deauthentication events */
+ t_u32 num_event_deauth;
+ /** Number of disassosiation events */
+ t_u32 num_event_disassoc;
+ /** Number of link lost events */
+ t_u32 num_event_link_lost;
+ /** Number of deauthentication commands */
+ t_u32 num_cmd_deauth;
+ /** Number of association comamnd successes */
+ t_u32 num_cmd_assoc_success;
+ /** Number of association command failures */
+ t_u32 num_cmd_assoc_failure;
+ /** Number of Tx timeouts */
+ t_u32 num_tx_timeout;
+ /** Number of command timeouts */
+ t_u32 num_cmd_timeout;
+ /** Timeout command ID */
+ t_u16 timeout_cmd_id;
+ /** Timeout command action */
+ t_u16 timeout_cmd_act;
+ /** List of last command IDs */
+ t_u16 last_cmd_id[DBG_CMD_NUM];
+ /** List of last command actions */
+ t_u16 last_cmd_act[DBG_CMD_NUM];
+ /** Last command index */
+ t_u16 last_cmd_index;
+ /** List of last command response IDs */
+ t_u16 last_cmd_resp_id[DBG_CMD_NUM];
+ /** Last command response index */
+ t_u16 last_cmd_resp_index;
+ /** List of last events */
+ t_u16 last_event[DBG_CMD_NUM];
+ /** Last event index */
+ t_u16 last_event_index;
+} wlan_dbg;
+
+/** Hardware status codes */
+typedef enum _WLAN_HARDWARE_STATUS
+{
+ WlanHardwareStatusReady,
+ WlanHardwareStatusInitializing,
+ WlanHardwareStatusInitdone,
+ WlanHardwareStatusReset,
+ WlanHardwareStatusClosing,
+ WlanHardwareStatusNotReady
+} WLAN_HARDWARE_STATUS;
+
+/** WLAN_802_11_POWER_MODE */
+typedef enum _WLAN_802_11_POWER_MODE
+{
+ Wlan802_11PowerModeCAM,
+ Wlan802_11PowerModePSP
+} WLAN_802_11_POWER_MODE;
+
+/** tx param */
+typedef struct _mlan_tx_param
+{
+ /** next packet length */
+ t_u32 next_pkt_len;
+} mlan_tx_param;
+
+/** PS_STATE */
+typedef enum _PS_STATE
+{
+ PS_STATE_AWAKE,
+ PS_STATE_PRE_SLEEP,
+ PS_STATE_SLEEP_CFM,
+ PS_STATE_SLEEP
+} PS_STATE;
+
+/** Minimum flush timer for win size of 1 is 50 ms */
+#define MIN_FLUSH_TIMER_MS 50
+/** Tx BA stream table */
+typedef struct _TxBAStreamTbl TxBAStreamTbl;
+
+/** Add BA parameter data structure */
+typedef struct
+{
+ /** Window size for initiator */
+ t_u32 tx_win_size;
+ /** Window size for receiver */
+ t_u32 rx_win_size;
+ /** Block ack timeout */
+ t_u32 timeout;
+ /** amsdu support for ADDBA request */
+ t_u8 tx_amsdu;
+ /** amsdu support for ADDBA response */
+ t_u8 rx_amsdu;
+} add_ba_param_t;
+
+/** Tx aggregation data structure */
+typedef struct _txAggr_t
+{
+ /** AMPDU user */
+ t_u8 ampdu_user;
+ /** AMPDU AP */
+ t_u8 ampdu_ap;
+ /** AMSDU */
+ t_u8 amsdu;
+} tx_aggr_t;
+
+/** RA list table */
+typedef struct _raListTbl raListTbl;
+
+/** RA list table */
+struct _raListTbl
+{
+ /** Pointer to previous node */
+ raListTbl *pprev;
+ /** Pointer to next node */
+ raListTbl *pnext;
+ /** Buffer list head */
+ mlan_list_head buf_head;
+ /** RA list buffer */
+ t_u8 ra[MLAN_MAC_ADDR_LENGTH];
+ /** total packets in RA list */
+ t_u16 total_pkts;
+ /** packets received */
+ t_u16 packet_count;
+ /** packet count threshold to setup BA */
+ t_u8 ba_packet_threshold;
+ /** is 11n enabled */
+ t_u8 is_11n_enabled;
+ /** max amsdu size */
+ t_u16 max_amsdu;
+ /** tx_pause flag */
+ t_u8 tx_pause;
+};
+
+/** TID table */
+typedef struct _tidTbl
+{
+ /** RA list head */
+ mlan_list_head ra_list;
+ /** Current RA list */
+ raListTbl *ra_list_curr;
+} tid_tbl_t;
+
+/** Highest priority setting for a packet (uses voice AC) */
+#define WMM_HIGHEST_PRIORITY 7
+/** Highest priority TID */
+#define HIGH_PRIO_TID 7
+/** Lowest priority TID */
+#define LOW_PRIO_TID 0
+/** No packet priority (< lowest) */
+#define NO_PKT_PRIO_TID -1
+
+/** Struct of WMM DESC */
+typedef struct _wmm_desc
+{
+ /** TID table */
+ tid_tbl_t tid_tbl_ptr[MAX_NUM_TID];
+ /** Packets out */
+ t_u32 packets_out[MAX_NUM_TID];
+ /** Packets queued */
+ t_u32 pkts_queued[MAX_NUM_TID];
+ /** Spin lock to protect ra_list */
+ t_void *ra_list_spinlock;
+
+ /** AC status */
+ WmmAcStatus_t ac_status[MAX_AC_QUEUES];
+ /** AC downgraded values */
+ mlan_wmm_ac_e ac_down_graded_vals[MAX_AC_QUEUES];
+
+ /** Max driver packet delay sent to the firmware for expiry eval */
+ t_u32 drv_pkt_delay_max;
+
+ /** WMM queue priority table */
+ t_u8 queue_priority[MAX_AC_QUEUES];
+ /** User priority packet transmission control */
+ t_u32 user_pri_pkt_tx_ctrl[WMM_HIGHEST_PRIORITY + 1]; /* UP: 0 to 7 */
+
+ /** Number of transmit packets queued */
+ mlan_scalar tx_pkts_queued;
+ /** Tracks highest priority with a packet queued */
+ mlan_scalar highest_queued_prio;
+} wmm_desc_t;
+
+/** Security structure */
+typedef struct _wlan_802_11_security_t
+{
+ /** WPA enabled flag */
+ t_u8 wpa_enabled;
+ /** E-Supplicant enabled flag */
+ t_u8 ewpa_enabled;
+ /** WPA2 enabled flag */
+ t_u8 wpa2_enabled;
+ /** WAPI enabled flag */
+ t_u8 wapi_enabled;
+ /** WAPI key on flag */
+ t_u8 wapi_key_on;
+ /** WEP status */
+ WLAN_802_11_WEP_STATUS wep_status;
+ /** Authentication mode */
+ t_u32 authentication_mode;
+ /** Encryption mode */
+ t_u32 encryption_mode;
+} wlan_802_11_security_t;
+
+/** Current Basic Service Set State Structure */
+typedef struct
+{
+ /** BSS descriptor */
+ BSSDescriptor_t bss_descriptor;
+ /** WMM enable? */
+ t_u8 wmm_enabled;
+ /** Uapsd enable?*/
+ t_u8 wmm_uapsd_enabled;
+ /** Band */
+ t_u8 band;
+ /** Number of rates supported */
+ t_u32 num_of_rates;
+ /** Supported rates*/
+ t_u8 data_rates[WLAN_SUPPORTED_RATES];
+} current_bss_params_t;
+
+/** Sleep_params */
+typedef struct _sleep_params_t
+{
+ /** Sleep parameter error */
+ t_u16 sp_error;
+ /** Sleep parameter offset */
+ t_u16 sp_offset;
+ /** Sleep parameter stable time */
+ t_u16 sp_stable_time;
+ /** Sleep parameter calibration control */
+ t_u8 sp_cal_control;
+ /** Sleep parameter external sleep clock */
+ t_u8 sp_ext_sleep_clk;
+ /** Sleep parameter reserved */
+ t_u16 sp_reserved;
+} sleep_params_t;
+
+/** Sleep_period */
+typedef struct sleep_period_t
+{
+ /** Sleep period */
+ t_u16 period;
+ /** Reserved */
+ t_u16 reserved;
+} sleep_period_t;
+
+/** mrvl_wep_key_t */
+typedef struct _mrvl_wep_key_t
+{
+ /** Length */
+ t_u32 length;
+ /** WEP key index */
+ t_u32 key_index;
+ /** WEP key length */
+ t_u32 key_length;
+ /** WEP keys */
+ t_u8 key_material[MRVL_KEY_BUFFER_SIZE_IN_BYTE];
+} mrvl_wep_key_t;
+
+/** Maximum number of region channel */
+#define MAX_REGION_CHANNEL_NUM 2
+
+/** Chan-Freq-TxPower mapping table*/
+typedef struct _chan_freq_power_t
+{
+ /** Channel Number */
+ t_u16 channel;
+ /** Frequency of this Channel */
+ t_u32 freq;
+ /** Max allowed Tx power level */
+ t_u16 max_tx_power;
+ /** TRUE:radar detect required; FALSE:radar detect not required*/
+ t_bool radar_detect;
+ /** TRUE:channel unsupported; FALSE:supported */
+ t_u8 unsupported;
+} chan_freq_power_t;
+
+/** Region-band mapping table */
+typedef struct _region_chan_t
+{
+ /** TRUE if this entry is valid */
+ t_u8 valid;
+ /** Region code for US, Japan ... */
+ t_u8 region;
+ /** Band B/G/A, used for BAND_CONFIG cmd */
+ t_u8 band;
+ /** Actual No. of elements in the array below */
+ t_u8 num_cfp;
+ /** chan-freq-txpower mapping table */
+ chan_freq_power_t *pcfp;
+} region_chan_t;
+
+/** State of 11d */
+typedef enum _state_11d_t
+{
+ DISABLE_11D = 0,
+ ENABLE_11D = 1,
+} state_11d_t;
+
+#define DEFAULT_11D_STATE DISABLE_11D
+
+/** Domain regulatory information */
+typedef struct _wlan_802_11d_domain_reg
+{
+ /** Country Code */
+ t_u8 country_code[COUNTRY_CODE_LEN];
+ /** band that channels in sub_band belong to */
+ t_u8 band;
+ /** No. of subband in below */
+ t_u8 no_of_sub_band;
+ /** Subband data to send/last sent */
+ IEEEtypes_SubbandSet_t sub_band[MRVDRV_MAX_SUBBAND_802_11D];
+} wlan_802_11d_domain_reg_t;
+
+/** Data for state machine */
+typedef struct _wlan_802_11d_state
+{
+ /** True for enabling 11D */
+ state_11d_t enable_11d;
+ /** True for user enabling 11D */
+ state_11d_t user_enable_11d;
+} wlan_802_11d_state_t;
+
+/** 802.11h State information kept in the 'mlan_private' driver structure */
+typedef struct
+{
+ /** Indicates whether 11h is enabled in the driver */
+ t_bool is_11h_enabled;
+ /** Indicates whether 11h is active in the firmware */
+ t_bool is_11h_active;
+ /** Master device using automatic channel select */
+ t_bool adhoc_auto_sel_chan;
+ /** Set when driver receives a STOP TX event from fw */
+ t_bool tx_disabled;
+} wlan_11h_interface_state_t;
+
+#if defined(UAP_SUPPORT)
+/** UAP get info callback state kept in the 'mlan_private' driver structure */
+typedef struct
+{
+ /** UAP internal callback after wlan_uap_get_channel */
+ /** (parameter is really pointer to mlan_private) */
+ mlan_status(*get_chan_callback) (t_void *);
+ /** current ioctl_req (to be completed in callback) */
+ pmlan_ioctl_req pioctl_req_curr;
+ /** band_cfg from MrvlIEtypes_channel_band_t */
+ t_u8 band_config;
+ /** channel from MrvlIEtypes_channel_band_t */
+ t_u8 channel;
+ /** beacon period (in msec) from MrvlIEtypes_beacon_period_t */
+ t_u16 beacon_period;
+ /** dtim period (no unit) from MrvlIEtypes_dtim_period_t */
+ t_u8 dtim_period;
+} wlan_uap_get_info_cb_t;
+#endif
+
+/** Data structure for WPS information */
+typedef struct
+{
+ /** WPS IE */
+ IEEEtypes_VendorSpecific_t wps_ie;
+ /** Session enable flag */
+ t_u8 session_enable;
+} wps_t;
+
+/** mlan_operations data structure */
+typedef struct _mlan_operations
+{
+ /** cmd init handler */
+ mlan_status(*init_cmd) (IN t_void * priv, IN t_u8 first_bss);
+ /** ioctl handler */
+ mlan_status(*ioctl) (t_void * adapter, pmlan_ioctl_req pioctl_req);
+ /** cmd handler */
+ mlan_status(*prepare_cmd) (IN t_void * priv,
+ IN t_u16 cmd_no,
+ IN t_u16 cmd_action,
+ IN t_u32 cmd_oid,
+ IN t_void * pioctl_buf,
+ IN t_void * pdata_buf, IN t_void * pcmd_buf);
+ /** cmdresp handler */
+ mlan_status(*process_cmdresp) (IN t_void * priv,
+ IN t_u16 cmdresp_no,
+ IN t_void * pcmd_buf, IN t_void * pioctl);
+ /** rx handler */
+ mlan_status(*process_rx_packet) (IN t_void * adapter,
+ IN pmlan_buffer pmbuf);
+ /** event handler */
+ mlan_status(*process_event) (IN t_void * priv);
+ /** txpd handler */
+ t_void *(*process_txpd) (IN t_void * priv, IN pmlan_buffer pmbuf);
+ /** BSS role */
+ mlan_bss_role bss_role;
+} mlan_operations;
+
+/** Private structure for MLAN */
+typedef struct _mlan_private
+{
+ /** Pointer to mlan_adapter */
+ struct _mlan_adapter *adapter;
+ /** BSS index */
+ t_u8 bss_index;
+ /** BSS type */
+ t_u8 bss_type;
+ /** BSS role */
+ t_u8 bss_role;
+ /** BSS Priority */
+ t_u8 bss_priority;
+ /** BSS number */
+ t_u8 bss_num;
+ /** Frame type */
+ t_u8 frame_type;
+ /** MAC address information */
+ t_u8 curr_addr[MLAN_MAC_ADDR_LENGTH];
+ /** Media connection status */
+ t_bool media_connected;
+
+ /** Current packet filter */
+ t_u16 curr_pkt_filter;
+ /** Infrastructure mode */
+ t_u32 bss_mode;
+
+ /** Tx packet control */
+ t_u32 pkt_tx_ctrl;
+
+ /** Tx power level */
+ t_u16 tx_power_level;
+ /** Maximum Tx power level */
+ t_u8 max_tx_power_level;
+ /** Minimum Tx power level */
+ t_u8 min_tx_power_level;
+ /** Tx rate */
+ t_u8 tx_rate;
+ /** tx ht_info */
+ t_u8 tx_htinfo;
+ /** rxpd_htinfo */
+ t_u8 rxpd_htinfo;
+ /** max amsdu size */
+ t_u16 max_amsdu;
+#ifdef UAP_SUPPORT
+ /** UAP 11n flag */
+ t_u8 is_11n_enabled;
+#endif /* UAP_SUPPORT */
+#ifdef UAP_SUPPORT
+#endif /* UAP_SUPPORT */
+#ifdef UAP_SUPPORT
+ /** packet forward control */
+ t_u8 pkt_fwd;
+ /** dropped pkts */
+ t_u32 num_drop_pkts;
+#endif
+ /** TX beamforming capability */
+ t_u32 tx_bf_cap;
+ /** Rx PD rate */
+ t_u8 rxpd_rate;
+ /** Rate bitmap */
+ t_u16 rate_bitmap;
+ /** Bitmap rates */
+ t_u16 bitmap_rates[MAX_BITMAP_RATES_SIZE];
+ /** Data rate */
+ t_u32 data_rate;
+ /** Automatic data rate flag */
+ t_u8 is_data_rate_auto;
+ /** Factor for calculating beacon average */
+ t_u16 bcn_avg_factor;
+ /** Factor for calculating data average */
+ t_u16 data_avg_factor;
+ /** Last data RSSI */
+ t_s16 data_rssi_last;
+ /** Last data Noise Floor */
+ t_s16 data_nf_last;
+ /** Average data RSSI */
+ t_s16 data_rssi_avg;
+ /** Averag data Noise Floor */
+ t_s16 data_nf_avg;
+ /** Last beacon RSSI */
+ t_s16 bcn_rssi_last;
+ /** Last beacon Noise Floor */
+ t_s16 bcn_nf_last;
+ /** Average beacon RSSI */
+ t_s16 bcn_rssi_avg;
+ /** Average beacon Noise Floor */
+ t_s16 bcn_nf_avg;
+
+ /** Attempted BSS descriptor */
+ BSSDescriptor_t *pattempted_bss_desc;
+
+ /** Current SSID/BSSID related parameters*/
+ current_bss_params_t curr_bss_params;
+
+ /** User selected bands */
+ t_u8 config_bands;
+
+ /** Beacon period */
+ t_u16 beacon_period;
+ /** Listen interval */
+ t_u16 listen_interval;
+ /** ATIM window */
+ t_u16 atim_window;
+
+ /** AdHoc channel */
+ t_u8 adhoc_channel;
+ /** AdHoc link sensed flag */
+ t_u8 adhoc_is_link_sensed;
+ /** AdHoc operating state */
+ t_u8 adhoc_state;
+#if defined(STA_SUPPORT)
+ /** AdHoc operating state backup */
+ t_u8 adhoc_state_prev;
+ /** AdHoc previous ssid used for Start */
+ mlan_802_11_ssid adhoc_last_start_ssid;
+#endif
+ /** FSM variable for 11d support */
+ wlan_802_11d_state_t state_11d;
+ /** FSM variable for 11h support */
+ wlan_11h_interface_state_t intf_state_11h;
+#if defined(UAP_SUPPORT)
+ /** Whether UAP interface has started */
+ t_bool uap_bss_started;
+ /** state variable for UAP Get Info callback */
+ wlan_uap_get_info_cb_t uap_state_chan_cb;
+#endif
+
+ /** Security related */
+ /** Encryption parameter */
+ wlan_802_11_security_t sec_info;
+ /** WEP keys */
+ mrvl_wep_key_t wep_key[MRVL_NUM_WEP_KEY];
+ /** Current WEP key index */
+ t_u16 wep_key_curr_index;
+ /** EWPA query 0: disable, 1: enable */
+ t_u8 ewpa_query;
+ /** Encryption Key*/
+ t_u8 wpa_ie[256];
+ /** WPA IE length */
+ t_u8 wpa_ie_len;
+ /** GTK set flag */
+ t_u8 wpa_is_gtk_set;
+ /** AES key material */
+ HostCmd_DS_802_11_KEY_MATERIAL aes_key;
+ /** WAPI IE */
+ t_u8 wapi_ie[256];
+ /** WAPI IE length */
+ t_u8 wapi_ie_len;
+ /** Pointer to the station table */
+ mlan_list_head sta_list;
+
+ /** MGMT IE */
+ custom_ie mgmt_ie[MAX_MGMT_IE_INDEX];
+ /** mgmt frame passthru mask */
+ t_u32 mgmt_frame_passthru_mask;
+ /** Advanced Encryption Standard */
+ t_u8 adhoc_aes_enabled;
+ /** WMM required */
+ t_u8 wmm_required;
+ /** WMM enabled */
+ t_u8 wmm_enabled;
+ /** WMM qos info */
+ t_u8 wmm_qosinfo;
+ /** WMM related variable*/
+ wmm_desc_t wmm;
+
+ /** Pointer to the Transmit BA stream table*/
+ mlan_list_head tx_ba_stream_tbl_ptr;
+ /** Pointer to the priorities for AMSDU/AMPDU table*/
+ tx_aggr_t aggr_prio_tbl[MAX_NUM_TID];
+ /** Pointer to the priorities for AMSDU/AMPDU table*/
+ t_u8 addba_reject[MAX_NUM_TID];
+ /** Struct to store ADDBA parameters */
+ add_ba_param_t add_ba_param;
+ /** last rx_seq */
+ t_u16 rx_seq[MAX_NUM_TID];
+ /** Pointer to the Receive Reordering table*/
+ mlan_list_head rx_reorder_tbl_ptr;
+ /** Lock for Rx packets */
+ t_void *rx_pkt_lock;
+
+#ifdef STA_SUPPORT
+ /** Buffer to store the association response for application retrieval */
+ t_u8 assoc_rsp_buf[MRVDRV_ASSOC_RSP_BUF_SIZE];
+ /** Length of the data stored in assoc_rsp_buf */
+ t_u32 assoc_rsp_size;
+
+ /** Generic IEEE IEs passed from the application to be inserted into the
+ * association request to firmware
+ */
+ t_u8 gen_ie_buf[MRVDRV_GENIE_BUF_SIZE];
+ /** Length of the data stored in gen_ie_buf */
+ t_u8 gen_ie_buf_len;
+
+ t_u8 *pcurr_bcn_buf;
+ t_u32 curr_bcn_size;
+ t_void *curr_bcn_buf_lock;
+
+ /** WPS */
+ wps_t wps;
+#endif /* STA_SUPPORT */
+
+ /** function table */
+ mlan_operations ops;
+
+ /** Port Control mode */
+ t_u8 port_ctrl_mode;
+
+ /** Port open flag */
+ t_u8 port_open;
+
+ /** Port open flag state at time of association attempt */
+ t_u8 prior_port_status;
+
+ /** Scan block flag */
+ t_u8 scan_block;
+ /** IP address operation */
+ t_u32 op_code;
+ /** IP address */
+ t_u8 ip_addr[IPADDR_LEN];
+} mlan_private, *pmlan_private;
+
+/** BA stream status */
+typedef enum _baStatus_e
+{
+ BA_STREAM_NOT_SETUP = 0,
+ BA_STREAM_SETUP_INPROGRESS,
+ BA_STREAM_SETUP_COMPLETE
+} baStatus_e;
+
+/** Tx BA stream table */
+struct _TxBAStreamTbl
+{
+ /** TxBAStreamTbl previous node */
+ TxBAStreamTbl *pprev;
+ /** TxBAStreamTbl next node */
+ TxBAStreamTbl *pnext;
+ /** TID */
+ int tid;
+ /** RA */
+ t_u8 ra[MLAN_MAC_ADDR_LENGTH];
+ /** BA stream status */
+ baStatus_e ba_status;
+ t_u8 amsdu;
+};
+
+/** RX reorder table */
+typedef struct _RxReorderTbl RxReorderTbl;
+
+typedef struct
+{
+ /** Timer for flushing */
+ t_void *timer;
+ /** Timer set flag */
+ t_u8 timer_is_set;
+ /** RxReorderTbl ptr */
+ RxReorderTbl *ptr;
+ /** Priv pointer */
+ mlan_private *priv;
+} reorder_tmr_cnxt_t;
+
+/** RX reorder table */
+struct _RxReorderTbl
+{
+ /** RxReorderTbl previous node */
+ RxReorderTbl *pprev;
+ /** RxReorderTbl next node */
+ RxReorderTbl *pnext;
+ /** TID */
+ int tid;
+ /** TA */
+ t_u8 ta[MLAN_MAC_ADDR_LENGTH];
+ /** Start window */
+ int start_win;
+ /** Window size */
+ int win_size;
+ /** Pointer to pointer to RxReorderTbl */
+ t_void **rx_reorder_ptr;
+ /** Timer context */
+ reorder_tmr_cnxt_t timer_context;
+ /** BA stream status */
+ baStatus_e ba_status;
+ t_u8 amsdu;
+};
+
+/** BSS priority node */
+typedef struct _mlan_bssprio_node mlan_bssprio_node;
+
+/** BSS priority node */
+struct _mlan_bssprio_node
+{
+ /** Pointer to previous node */
+ mlan_bssprio_node *pprev;
+ /** Pointer to next node */
+ mlan_bssprio_node *pnext;
+ /** Pointer to priv */
+ pmlan_private priv;
+};
+
+/** BSS priority table */
+typedef struct _mlan_bssprio_tbl mlan_bssprio_tbl;
+
+/** BSS priority table */
+struct _mlan_bssprio_tbl
+{
+ /** BSS priority list head */
+ mlan_list_head bssprio_head;
+ /** Current priority node */
+ mlan_bssprio_node *bssprio_cur;
+};
+
+/** cmd_ctrl_node */
+typedef struct _cmd_ctrl_node cmd_ctrl_node;
+
+/** _cmd_ctrl_node */
+struct _cmd_ctrl_node
+{
+ /** Pointer to previous node */
+ cmd_ctrl_node *pprev;
+ /** Pointer to next node */
+ cmd_ctrl_node *pnext;
+ /** Pointer to priv */
+ pmlan_private priv;
+ /** Command OID for sub-command use */
+ t_u32 cmd_oid;
+ /** Command flag */
+ t_u32 cmd_flag;
+ /** Pointer to mlan_buffer */
+ mlan_buffer *cmdbuf;
+ /** Pointer to mlan_buffer */
+ mlan_buffer *respbuf;
+ /** Command parameter */
+ t_void *pdata_buf;
+ /** Pointer to mlan_ioctl_req if command is from IOCTL */
+ t_void *pioctl_buf;
+ /** pre_allocated mlan_buffer for cmd */
+ mlan_buffer *pmbuf;
+};
+
+/** station node */
+typedef struct _sta_node sta_node;
+
+/** station node*/
+struct _sta_node
+{
+ /** previous node */
+ sta_node *pprev;
+ /** next node */
+ sta_node *pnext;
+ /** station mac address */
+ t_u8 mac_addr[MLAN_MAC_ADDR_LENGTH];
+ /** 11n flag */
+ t_u8 is_11n_enabled;
+ /** AMPDU STA */
+ t_u8 ampdu_sta[MAX_NUM_TID];
+ /** last rx_seq */
+ t_u16 rx_seq[MAX_NUM_TID];
+ /** max amsdu size */
+ t_u16 max_amsdu;
+ /** wapi key on off flag */
+ t_u8 wapi_key_on;
+ /** tx pause status */
+ t_u8 tx_pause;
+};
+
+/** 802.11h State information kept in the 'mlan_adapter' driver structure */
+typedef struct
+{
+ /** Min TX Power capability sent to FW for 11h use and fw power control */
+ t_s8 min_tx_power_capability;
+ /** Max TX Power capability sent to FW for 11h use and fw power control */
+ t_s8 max_tx_power_capability;
+ /** User provisioned local power constraint sent in association requests */
+ t_s8 usr_def_power_constraint;
+ /** Received CHANNEL_SWITCH_ANN event */
+ t_bool recvd_chanswann_event;
+ /** Indicates an interface wants to enable master radar detection */
+ t_bool master_radar_det_enable_pending;
+ /** Indicates an interface wants to enable slave radar detection */
+ t_bool slave_radar_det_enable_pending;
+ /** Indicates whether master radar detection active in the firmware */
+ t_bool is_master_radar_det_active;
+ /** Indicates whether slave radar detection active in the firmware */
+ t_bool is_slave_radar_det_active;
+ /** Quiet IE */
+ IEEEtypes_Quiet_t quiet_ie;
+} wlan_11h_device_state_t;
+
+/** Enumeration for DFS Timestamp represents field */
+enum _dfs_timestamp_repr_e
+{
+ /** Ignore entry */
+ DFS_TS_REPR_NOT_IN_USE = 0,
+ /** NOP (Non-Occupancy Period) start time */
+ DFS_TS_REPR_NOP_START = 1,
+ /** CAC (Channel Availability Check) completion time */
+ DFS_TS_REPR_CAC_COMPLETION
+};
+
+/** DFS Timestamp type used for marking NOP/CAC events */
+typedef struct _wlan_dfs_timestamp_t wlan_dfs_timestamp_t;
+
+/** DFS Timestamp type used for marking NOP/CAC events */
+struct _wlan_dfs_timestamp_t
+{
+ /** Pointer to previous node */
+ wlan_dfs_timestamp_t *pprev;
+ /** Pointer to next node */
+ wlan_dfs_timestamp_t *pnext;
+ /** WLAN Channel number */
+ t_u8 channel;
+ /** What this timestamp represents */
+ t_u8 represents;
+ /** reserved field */
+ t_u16 reserved;
+ /** timestamp - seconds */
+ t_u32 ts_sec;
+ /** timestamp - microseconds */
+ t_u32 ts_usec;
+};
+
+/** DFS State information kept in the 'mlan_adapter' driver structure */
+typedef struct
+{
+ /** Indicates whether DFS channel check is occurring in firmware */
+ t_bool dfs_check_pending;
+ /** Indicates whether DFS channel check found radar */
+ t_bool dfs_radar_found;
+ /** Channel radar is being checked on. BAND_A is assumed. */
+ t_u8 dfs_check_channel;
+ /** Timestamp when we got last report, to determine if data is old or not. */
+ t_u32 dfs_report_time_sec;
+ /** List for holding dfs_timestamps for NOP/CAC events */
+ mlan_list_head dfs_ts_head;
+} wlan_dfs_device_state_t;
+
+/** Enumeration for mlan_ds_11h_radar_det_hndlg stages */
+enum _mlan_ds_11h_rdh_stages
+{
+ RDH_OFF = 0,
+ RDH_CHK_INTFS = 1,
+ RDH_STOP_TRAFFIC,
+ RDH_GET_INFO_CHANNEL,
+ RDH_GET_INFO_BEACON_DTIM,
+ RDH_SET_CUSTOM_IE,
+ RDH_REM_CUSTOM_IE,
+ RDH_STOP_INTFS,
+ RDH_SET_NEW_CHANNEL,
+ RDH_RESTART_INTFS,
+ RDH_RESTART_TRAFFIC
+};
+
+/** State info for Radar Detected Handling kept in 'mlan_adapter' */
+typedef struct
+{
+ /** Stage (of Operation) */
+ t_u8 stage;
+ /** Number of interfaces to handle */
+ t_u8 priv_list_count;
+ /** Index of interface in process (used by some stages) */
+ t_u8 priv_curr_idx;
+ /** Current Channel (to leave) */
+ t_u8 curr_channel;
+ /** New Channel (to switch to) */
+ t_u8 new_channel;
+ /** UAP band_config */
+ t_u8 uap_band_cfg;
+ /** BEACON*DTIM period (in msec; max of STA/UAP) */
+ t_u16 max_bcn_dtim_ms;
+ /** List of interfaces to handle */
+ mlan_private *priv_list[MLAN_MAX_BSS_NUM];
+} wlan_radar_det_hndlg_state_t;
+
+#ifdef DFS_TESTING_SUPPORT
+/** DFS/RDH testing exception settings kept in 'mlan_adapter' */
+typedef struct
+{
+ /** user-configured CAC period (in msec) */
+ t_u16 user_cac_period_msec;
+ /** user-configured NOP period (in sec) */
+ t_u16 user_nop_period_sec;
+ /** user-configured skip channel change on radar */
+ t_bool no_channel_change_on_radar;
+ /** user-configured new channel to change to on radar */
+ t_u8 fixed_new_channel_on_radar;
+} wlan_dfs_testing_settings_t;
+#endif /* DFS_SUPPORT_TESTING */
+
+/**
+ * @brief Driver measurement state held in 'mlan_adapter' structure
+ *
+ * Used to record a measurement request that the driver is pending on
+ * the result (received measurement report).
+ */
+typedef struct
+{
+ /**
+ * Dialog token of a pending measurement request/report. Used to
+ * block execution while waiting for the specific dialog token
+ */
+ t_u8 meas_rpt_pend_on;
+
+ /**
+ * Measurement report received from the firmware that we were pending on
+ */
+ HostCmd_DS_MEASUREMENT_REPORT meas_rpt_returned;
+
+} wlan_meas_state_t;
+
+#ifdef SDIO_MULTI_PORT_TX_AGGR
+/** data structure for SDIO MPA TX */
+typedef struct _sdio_mpa_tx
+{
+ /** allocated buf for tx aggreation */
+ t_u8 *head_ptr;
+ /** multiport tx aggregation buffer pointer */
+ t_u8 *buf;
+ /** multiport tx aggregation buffer length */
+ t_u32 buf_len;
+ /** multiport tx aggregation packet count */
+ t_u32 pkt_cnt;
+ /** multiport tx aggregation ports */
+ t_u16 ports;
+ /** multiport tx aggregation starting port */
+ t_u16 start_port;
+ /** multiport tx aggregation enable/disable flag */
+ t_u8 enabled;
+ /** multiport tx aggregation buffer size */
+ t_u32 buf_size;
+ /** multiport tx aggregation pkt aggr limit */
+ t_u32 pkt_aggr_limit;
+} sdio_mpa_tx;
+#endif
+
+#ifdef SDIO_MULTI_PORT_RX_AGGR
+/** data structure for SDIO MPA RX */
+typedef struct _sdio_mpa_rx
+{
+ /** allocated buf for rx aggreation */
+ t_u8 *head_ptr;
+ /** multiport rx aggregation buffer pointer */
+ t_u8 *buf;
+ /** multiport rx aggregation buffer length */
+ t_u32 buf_len;
+ /** multiport rx aggregation packet count */
+ t_u32 pkt_cnt;
+ /** multiport rx aggregation ports */
+ t_u16 ports;
+ /** multiport rx aggregation starting port */
+ t_u16 start_port;
+
+ /** multiport rx aggregation mbuf array */
+ pmlan_buffer mbuf_arr[SDIO_MP_AGGR_DEF_PKT_LIMIT];
+ /** multiport rx aggregation pkt len array */
+ t_u32 len_arr[SDIO_MP_AGGR_DEF_PKT_LIMIT];
+
+ /** multiport rx aggregation enable/disable flag */
+ t_u8 enabled;
+ /** multiport rx aggregation buffer size */
+ t_u32 buf_size;
+ /** multiport rx aggregation pkt aggr limit */
+ t_u32 pkt_aggr_limit;
+} sdio_mpa_rx;
+#endif /* SDIO_MULTI_PORT_RX_AGGR */
+
+/** mlan_init_para structure */
+typedef struct _mlan_init_para
+{
+#ifdef MFG_CMD_SUPPORT
+ /** MFG mode */
+ t_u32 mfg_mode;
+#endif
+ /** SDIO interrupt mode (0: INT_MODE_SDIO, 1: INT_MODE_GPIO) */
+ t_u32 int_mode;
+ /** GPIO interrupt pin number */
+ t_u32 gpio_pin;
+#ifdef SDIO_MULTI_PORT_TX_AGGR
+ /** SDIO MPA Tx */
+ t_u32 mpa_tx_cfg;
+#endif
+#ifdef SDIO_MULTI_PORT_RX_AGGR
+ /** SDIO MPA Rx */
+ t_u32 mpa_rx_cfg;
+#endif
+ /** Auto deep sleep */
+ t_u32 auto_ds;
+ /** IEEE PS mode */
+ t_u32 ps_mode;
+ /** Max Tx buffer size */
+ t_u32 max_tx_buf;
+ /** 802.11d configuration */
+ t_u32 cfg_11d;
+ /** 802.11H DFS Master Radar Detect */
+ t_u32 dfs_master_radar_det_en;
+ /** 802.11H DFS Slave Radar Detect */
+ t_u32 dfs_slave_radar_det_en;
+} mlan_init_para, *pmlan_init_para;
+
+/** Adapter data structure for MLAN */
+typedef struct _mlan_adapter
+{
+ /** MOAL handle structure */
+ t_void *pmoal_handle;
+ /** Private pointer */
+ pmlan_private priv[MLAN_MAX_BSS_NUM];
+ /** Total number of Priv number */
+ t_u8 priv_num;
+ /** Priority table for bss */
+ mlan_bssprio_tbl bssprio_tbl[MLAN_MAX_BSS_NUM];
+ /** Callback table */
+ mlan_callbacks callbacks;
+ /** Init parameters */
+ mlan_init_para init_para;
+
+ /** mlan_lock for init/shutdown */
+ t_void *pmlan_lock;
+ /** main_proc_lock for main_process */
+ t_void *pmain_proc_lock;
+ /** mlan_processing */
+ t_u32 mlan_processing;
+ /** Max tx buf size */
+ t_u16 max_tx_buf_size;
+ /** Tx buf size */
+ t_u16 tx_buf_size;
+ /** current tx buf size in fw */
+ t_u16 curr_tx_buf_size;
+ /** IO port */
+ t_u32 ioport;
+
+ /** STATUS variables */
+ WLAN_HARDWARE_STATUS hw_status;
+ /** PnP SUPPORT */
+ t_u8 surprise_removed;
+
+ /** Radio on flag */
+ t_u16 radio_on;
+
+ /** Firmware release number */
+ t_u32 fw_release_number;
+
+ /** Number of antenna used */
+ t_u16 number_of_antenna;
+
+ /** Firmware capability information */
+ t_u32 fw_cap_info;
+ /** pint_lock for interrupt handling */
+ t_void *pint_lock;
+ /** Interrupt status */
+ t_u8 sdio_ireg;
+ /** SDIO multiple port read bitmap */
+ t_u32 mp_rd_bitmap;
+ /** SDIO multiple port write bitmap */
+ t_u32 mp_wr_bitmap;
+ /** SDIO end port from txbufcfg */
+ t_u16 mp_end_port;
+ /** SDIO port mask calculated based on txbufcfg end port */
+ t_u32 mp_data_port_mask;
+ /** Current available port for read */
+ t_u8 curr_rd_port;
+ /** Current available port for write */
+ t_u8 curr_wr_port;
+ /** Array to store values of SDIO multiple port group registers */
+ t_u8 *mp_regs;
+ /** allocated buf to read SDIO multiple port group registers */
+ t_u8 *mp_regs_buf;
+ /** Array to store data transfer eligibility based on tid (QoS-over-SDIO) */
+ t_u8 tx_eligibility[MAX_NUM_TID];
+
+#ifdef SDIO_MULTI_PORT_TX_AGGR
+ /** data structure for SDIO MPA TX */
+ sdio_mpa_tx mpa_tx;
+#endif /* SDIO_MULTI_PORT_TX_AGGR */
+
+#ifdef SDIO_MULTI_PORT_RX_AGGR
+ /** data structure for SDIO MPA RX */
+ sdio_mpa_rx mpa_rx;
+#endif /* SDIO_MULTI_PORT_RX_AGGR */
+
+ /** SDIO interrupt mode (0: INT_MODE_SDIO, 1: INT_MODE_GPIO) */
+ t_u32 int_mode;
+ /** GPIO interrupt pin number */
+ t_u32 gpio_pin;
+
+ /** Event cause */
+ t_u32 event_cause;
+ /** Event buffer */
+ pmlan_buffer pmlan_buffer_event;
+ /** Upload length */
+ t_u32 upld_len;
+ /** Upload buffer*/
+ t_u8 upld_buf[WLAN_UPLD_SIZE];
+ /** Data sent:
+ * TRUE - Data is sent to fw, no Tx Done received
+ * FALSE - Tx done received for previous Tx
+ */
+ t_u8 data_sent;
+ /** CMD sent:
+ * TRUE - CMD is sent to fw, no CMD Done received
+ * FALSE - CMD done received for previous CMD
+ */
+ t_u8 cmd_sent;
+ /** CMD Response received:
+ * TRUE - CMD is response is received from fw, and yet to process
+ * FALSE - No cmd response to process
+ */
+ t_u8 cmd_resp_received;
+ /** Event received:
+ * TRUE - Event received from fw, and yet to process
+ * FALSE - No events to process
+ */
+ t_u8 event_received;
+
+ /** Data received:
+ * TRUE - Data received from fw
+ * FALSE - No Data received
+ */
+ t_u8 data_received;
+
+ /** Command-related variables */
+ /** Command sequence number */
+ t_u16 seq_num;
+ /** Command controller nodes */
+ cmd_ctrl_node *cmd_pool;
+ /** Current Command */
+ cmd_ctrl_node *curr_cmd;
+ /** mlan_lock for command */
+ t_void *pmlan_cmd_lock;
+ /** Number of command timeouts */
+ t_u32 num_cmd_timeout;
+ /** Last init fw command id */
+ t_u16 last_init_cmd;
+ /** Command timer */
+ t_void *pmlan_cmd_timer;
+ /** Command timer set flag */
+ t_u8 cmd_timer_is_set;
+
+ /** Command Queues */
+ /** Free command buffers */
+ mlan_list_head cmd_free_q;
+ /** Pending command buffers */
+ mlan_list_head cmd_pending_q;
+ /** Command queue for scanning */
+ mlan_list_head scan_pending_q;
+ /** mlan_processing */
+ t_u32 scan_processing;
+
+ /** Region code */
+ t_u16 region_code;
+ /** Region Channel data */
+ region_chan_t region_channel[MAX_REGION_CHANNEL_NUM];
+#ifdef STA_SUPPORT
+ /** Universal Channel data */
+ region_chan_t universal_channel[MAX_REGION_CHANNEL_NUM];
+ /** Parsed region channel */
+ parsed_region_chan_11d_t parsed_region_chan;
+#endif /* STA_SUPPORT */
+ /** 11D and Domain Regulatory Data */
+ wlan_802_11d_domain_reg_t domain_reg;
+ /** FSM variable for 11h support */
+ wlan_11h_device_state_t state_11h;
+ /** FSM variable for DFS support */
+ wlan_dfs_device_state_t state_dfs;
+ /** FSM variable for RDH support */
+ wlan_radar_det_hndlg_state_t state_rdh;
+#ifdef DFS_TESTING_SUPPORT
+ /** User configured settings for DFS testing */
+ wlan_dfs_testing_settings_t dfs_test_params;
+#endif
+ /** FSM variable for MEAS support */
+ wlan_meas_state_t state_meas;
+ /** Scan table */
+ BSSDescriptor_t *pscan_table;
+ /** scan age in secs */
+ t_u32 age_in_secs;
+
+ /** Number of records in the scan table */
+ t_u32 num_in_scan_table;
+ /** Scan probes */
+ t_u16 scan_probes;
+
+ /** Scan type */
+ t_u8 scan_type;
+ /** Scan mode */
+ t_u32 scan_mode;
+ /** Specific scan time */
+ t_u16 specific_scan_time;
+ /** Active scan time */
+ t_u16 active_scan_time;
+ /** Passive scan time */
+ t_u16 passive_scan_time;
+ /** Extended scan or legacy scan */
+ t_u8 ext_scan;
+ t_u16 bcn_buf_size;
+ /** Beacon buffer */
+ t_u8 *bcn_buf;
+ /** Pointer to valid beacon buffer end */
+ t_u8 *pbcn_buf_end;
+
+ /** F/W supported bands */
+ t_u8 fw_bands;
+ /** User selected band to start adhoc network */
+ t_u8 adhoc_start_band;
+ /** User selected bands */
+ t_u8 config_bands;
+ /** Pointer to channel list last sent to the firmware for scanning */
+ ChanScanParamSet_t *pscan_channels;
+
+ /** Tx lock flag */
+ t_u8 tx_lock_flag;
+
+ /** sleep_params_t */
+ sleep_params_t sleep_params;
+ /** sleep_period_t (Enhanced Power Save) */
+ sleep_period_t sleep_period;
+
+ /** Power Save mode */
+ /**
+ * Wlan802_11PowerModeCAM = disable
+ * Wlan802_11PowerModePSP = enable
+ */
+ t_u16 ps_mode;
+ /** Power Save state */
+ t_u32 ps_state;
+ /** Need to wakeup flag */
+ t_u8 need_to_wakeup;
+
+ /** Multiple DTIM */
+ t_u16 multiple_dtim;
+ /** Local listen interval */
+ t_u16 local_listen_interval;
+ /** Null packet interval */
+ t_u16 null_pkt_interval;
+
+ /** Power save confirm sleep command buffer */
+ pmlan_buffer psleep_cfm;
+ /** Beacon miss timeout */
+ t_u16 bcn_miss_time_out;
+
+ /** AdHoc awake period */
+ t_u16 adhoc_awake_period;
+
+ /** Deep Sleep flag */
+ t_u8 is_deep_sleep;
+ /** Idle time */
+ t_u16 idle_time;
+ /** Auto Deep Sleep enabled at init time */
+ t_u8 init_auto_ds;
+
+ /** delay null pkt flag */
+ t_u8 delay_null_pkt;
+ /** Delay to PS in milliseconds */
+ t_u16 delay_to_ps;
+ /** Enhanced PS mode */
+ t_u16 enhanced_ps_mode;
+ /** Device wakeup required flag */
+ t_u8 pm_wakeup_card_req;
+
+ /** Gen NULL pkg */
+ t_u16 gen_null_pkt;
+
+ /** PPS/UAPSD mode flag */
+ t_u16 pps_uapsd_mode;
+ /** Number of wakeup tries */
+ t_u32 pm_wakeup_fw_try;
+
+ /** Host Sleep configured flag */
+ t_u8 is_hs_configured;
+ /** Host Sleep configuration */
+ hs_config_param hs_cfg;
+ /** Host Sleep activated flag */
+ t_u8 hs_activated;
+ /** Event body */
+ t_u8 event_body[MAX_EVENT_SIZE];
+ /** 802.11n device capabilities */
+ t_u32 hw_dot_11n_dev_cap;
+ /** Device support for MIMO abstraction of MCSs */
+ t_u8 hw_dev_mcs_support;
+ /** 802.11n Device Capabilities for 2.4GHz */
+ t_u32 usr_dot_11n_dev_cap_bg;
+ /** 802.11n Device Capabilities for 5GHz */
+ t_u32 usr_dot_11n_dev_cap_a;
+ /** MIMO abstraction of MCSs supported by device */
+ t_u8 usr_dev_mcs_support;
+#ifdef STA_SUPPORT
+ /** Enable 11n support for adhoc start */
+ t_u8 adhoc_11n_enabled;
+ /** Adhoc Secondary Channel Bandwidth */
+ t_u8 chan_bandwidth;
+#endif /* STA_SUPPORT */
+
+ /** max mgmt IE index in device */
+ t_u16 max_mgmt_ie_index;
+
+#ifdef MFG_CMD_SUPPORT
+ t_u32 mfg_mode;
+#endif
+ /** Debug */
+ wlan_dbg dbg;
+
+ /** RX pending for forwarding packets */
+ t_u16 pending_bridge_pkts;
+
+#ifdef STA_SUPPORT
+ /** ARP filter buffer */
+ t_u8 arp_filter[ARP_FILTER_MAX_BUF_SIZE];
+ /** ARP filter buffer size */
+ t_u32 arp_filter_size;
+#endif /* STA_SUPPORT */
+
+ /** Bypass TX queue */
+ mlan_list_head bypass_txq;
+#if defined(STA_SUPPORT)
+ /** warm-reset IOCTL request buffer pointer */
+ pmlan_ioctl_req pwarm_reset_ioctl_req;
+#endif
+ /** Extended SCAN IOCTL request buffer pointer */
+ pmlan_ioctl_req pext_scan_ioctl_req;
+ /** Cal data pointer */
+ t_u8 *pcal_data;
+ /** Cal data length */
+ t_u32 cal_data_len;
+
+} mlan_adapter, *pmlan_adapter;
+
+/** Ethernet packet type for EAPOL */
+#define MLAN_ETHER_PKT_TYPE_EAPOL (0x888E)
+/** Ethernet packet type for WAPI */
+#define MLAN_ETHER_PKT_TYPE_WAPI (0x88B4)
+/** Ethernet packet type offset */
+#define MLAN_ETHER_PKT_TYPE_OFFSET (12)
+
+mlan_status wlan_init_lock_list(IN pmlan_adapter pmadapter);
+t_void wlan_free_lock_list(IN pmlan_adapter pmadapter);
+mlan_status wlan_init_timer(IN pmlan_adapter pmadapter);
+t_void wlan_free_timer(IN pmlan_adapter pmadapter);
+
+/* Function prototype */
+/** Download firmware */
+mlan_status wlan_dnld_fw(IN pmlan_adapter pmadapter, IN pmlan_fw_image pmfw);
+
+/** Initialize firmware */
+mlan_status wlan_init_fw(IN pmlan_adapter pmadapter);
+
+/** Initialize firmware complete */
+mlan_status wlan_init_fw_complete(IN pmlan_adapter pmadapter);
+
+/** Shutdown firmware complete */
+mlan_status wlan_shutdown_fw_complete(IN pmlan_adapter pmadapter);
+
+/** Receive event */
+mlan_status wlan_recv_event(pmlan_private priv,
+ mlan_event_id event_id, t_void * pmevent);
+
+/** Initialize mlan_adapter structure */
+t_void wlan_init_adapter(IN pmlan_adapter pmadapter);
+
+/** Initialize mlan_private structure */
+mlan_status wlan_init_priv(IN pmlan_private priv);
+
+/** Process event */
+mlan_status wlan_process_event(pmlan_adapter pmadapter);
+
+/** Prepare command */
+mlan_status wlan_prepare_cmd(IN pmlan_private priv,
+ IN t_u16 cmd_no,
+ IN t_u16 cmd_action,
+ IN t_u32 cmd_oid,
+ IN t_void * pioctl_buf, IN t_void * pdata_buf);
+
+/** cmd timeout handler */
+t_void wlan_cmd_timeout_func(t_void * FunctionContext);
+/** process host cmd */
+mlan_status wlan_misc_ioctl_host_cmd(IN pmlan_adapter pmadapter,
+ IN pmlan_ioctl_req pioctl_req);
+/** process init/shutdown cmd*/
+mlan_status wlan_misc_ioctl_init_shutdown(IN pmlan_adapter pmadapter,
+ IN pmlan_ioctl_req pioctl_req);
+/** process debug info */
+mlan_status wlan_get_info_debug_info(IN pmlan_adapter pmadapter,
+ IN pmlan_ioctl_req pioctl_req);
+
+#if defined(STA_SUPPORT) && defined(UAP_SUPPORT)
+/** Set/Get BSS role */
+mlan_status wlan_bss_ioctl_bss_role(IN pmlan_adapter pmadapter,
+ IN pmlan_ioctl_req pioctl_req);
+#endif
+
+mlan_status wlan_set_ewpa_mode(mlan_private * priv,
+ mlan_ds_passphrase * psec_pp);
+mlan_status wlan_find_bss(mlan_private * pmpriv, pmlan_ioctl_req pioctl_req);
+
+/** Allocate memory for adapter structure members */
+mlan_status wlan_allocate_adapter(pmlan_adapter pmadapter);
+/** Free adapter */
+t_void wlan_free_adapter(pmlan_adapter pmadapter);
+/** Free priv */
+t_void wlan_free_priv(mlan_private * pmpriv);
+/** Allocate command buffer */
+mlan_status wlan_alloc_cmd_buffer(IN mlan_adapter * pmadapter);
+/** Free command buffer */
+mlan_status wlan_free_cmd_buffer(IN mlan_adapter * pmadapter);
+/** Request command lock */
+t_void wlan_request_cmd_lock(mlan_adapter * pmadapter);
+/** Release command lock */
+t_void wlan_release_cmd_lock(mlan_adapter * pmadapter);
+#ifdef STA_SUPPORT
+/** Flush the scan pending queue */
+t_void wlan_flush_scan_queue(pmlan_adapter pmadapter);
+#endif
+/**Cancel pending command */
+t_void wlan_cancel_all_pending_cmd(pmlan_adapter pmadapter);
+/**Cancel pending ioctl */
+t_void wlan_cancel_pending_ioctl(pmlan_adapter pmadapter,
+ pmlan_ioctl_req pioctl_req);
+
+/** Insert command to free queue */
+t_void wlan_insert_cmd_to_free_q(IN mlan_adapter * pmadapter,
+ IN cmd_ctrl_node * pcmd_node);
+
+/** Insert command to pending queue */
+t_void wlan_insert_cmd_to_pending_q(IN mlan_adapter * pmadapter,
+ IN cmd_ctrl_node * pcmd_node,
+ IN t_u32 addtail);
+
+/** Execute next command */
+mlan_status wlan_exec_next_cmd(mlan_adapter * pmadapter);
+/** Proecess command response */
+mlan_status wlan_process_cmdresp(mlan_adapter * pmadapter);
+/** Handle received packet, has extra handling for aggregate packets */
+mlan_status wlan_handle_rx_packet(pmlan_adapter pmadapter, pmlan_buffer pmbuf);
+/** Process transmission */
+mlan_status wlan_process_tx(pmlan_private priv, pmlan_buffer pmbuf,
+ mlan_tx_param * tx_param);
+/** Transmit a null data packet */
+mlan_status wlan_send_null_packet(pmlan_private priv, t_u8 flags);
+
+#if defined(SDIO_MULTI_PORT_TX_AGGR) || defined(SDIO_MULTI_PORT_RX_AGGR)
+mlan_status wlan_alloc_sdio_mpa_buffers(IN mlan_adapter * pmadapter,
+ t_u32 mpa_tx_buf_size,
+ t_u32 mpa_rx_buf_size);
+
+mlan_status wlan_free_sdio_mpa_buffers(IN mlan_adapter * pmadapter);
+#endif
+
+/** Process write data complete */
+mlan_status wlan_write_data_complete(pmlan_adapter pmlan_adapter,
+ pmlan_buffer pmbuf, mlan_status status);
+/** Process receive packet complete */
+mlan_status wlan_recv_packet_complete(pmlan_adapter pmadapter,
+ pmlan_buffer pmbuf, mlan_status status);
+/** Clean Tx Rx queues */
+t_void wlan_clean_txrx(pmlan_private priv);
+
+t_void wlan_add_buf_bypass_txqueue(mlan_adapter * pmadapter,
+ pmlan_buffer pmbuf);
+t_void wlan_process_bypass_tx(mlan_adapter * pmadapter);
+t_void wlan_cleanup_bypass_txq(mlan_adapter * pmadapter);
+t_u8 wlan_bypass_tx_list_empty(mlan_adapter * pmadapter);
+
+/** Check if this is the last packet */
+t_u8 wlan_check_last_packet_indication(pmlan_private priv);
+
+/** function to allocate a mlan_buffer */
+pmlan_buffer wlan_alloc_mlan_buffer(mlan_adapter * pmadapter, t_u32 data_len,
+ t_u32 head_room, t_u32 malloc_flag);
+/** function to free a mlan_buffer */
+t_void wlan_free_mlan_buffer(mlan_adapter * pmadapter, pmlan_buffer pmbuf);
+
+/** command resp handler for version ext */
+mlan_status wlan_ret_ver_ext(pmlan_private pmpriv, HostCmd_DS_COMMAND * resp,
+ mlan_ioctl_req * pioctl_buf);
+
+/** command resp handler for rx mgmt forward registration */
+mlan_status wlan_ret_rx_mgmt_ind(pmlan_private pmpriv,
+ HostCmd_DS_COMMAND * resp,
+ mlan_ioctl_req * pioctl_buf);
+
+/** Check Power Save condition */
+t_void wlan_check_ps_cond(mlan_adapter * pmadapter);
+
+/** handle command for enhanced power save mode */
+mlan_status wlan_cmd_enh_power_mode(pmlan_private pmpriv,
+ IN HostCmd_DS_COMMAND * cmd,
+ IN t_u16 cmd_action,
+ IN t_u16 ps_bitmap, IN t_void * pdata_buf);
+/** handle command resp for enhanced power save mode */
+mlan_status wlan_ret_enh_power_mode(IN pmlan_private pmpriv,
+ IN HostCmd_DS_COMMAND * resp,
+ IN mlan_ioctl_req * pioctl_buf);
+
+/** handle commnand for cfg data */
+mlan_status wlan_cmd_cfg_data(IN pmlan_private pmpriv,
+ IN HostCmd_DS_COMMAND * pcmd,
+ IN t_u16 cmd_action, IN t_void * pdata_buf);
+/** handle command resp for cfg data */
+mlan_status wlan_ret_cfg_data(IN pmlan_private pmpriv,
+ IN HostCmd_DS_COMMAND * resp,
+ IN t_void * pioctl_buf);
+
+/** Process sleep confirm command response */
+void wlan_process_sleep_confirm_resp(pmlan_adapter pmadapter, t_u8 * pbuf,
+ t_u32 len);
+
+/** Perform hs related activities on receving the power up interrupt */
+void wlan_process_hs_config(pmlan_adapter pmadapter);
+
+mlan_status wlan_pm_reset_card(pmlan_adapter adapter);
+mlan_status wlan_pm_wakeup_card(pmlan_adapter pmadapter);
+
+mlan_status wlan_process_802dot11_mgmt_pkt(mlan_private * priv, t_u8 * payload,
+ t_u32 payload_len);
+
+mlan_status wlan_pm_ioctl_hscfg(pmlan_adapter pmadapter,
+ pmlan_ioctl_req pioctl_req);
+
+#ifdef WIFI_DIRECT_SUPPORT
+mlan_status wlan_bss_ioctl_wifi_direct_mode(IN pmlan_adapter pmadapter,
+ IN pmlan_ioctl_req pioctl_req);
+
+mlan_status wlan_cmd_wifi_direct_mode(IN pmlan_private pmpriv,
+ IN HostCmd_DS_COMMAND * cmd,
+ IN t_u16 cmd_action,
+ IN t_void * pdata_buf);
+mlan_status wlan_ret_wifi_direct_mode(IN pmlan_private pmpriv,
+ IN HostCmd_DS_COMMAND * resp,
+ IN mlan_ioctl_req * pioctl_buf);
+
+mlan_status wlan_radio_ioctl_remain_chan_cfg(IN pmlan_adapter pmadapter,
+ IN pmlan_ioctl_req pioctl_req);
+mlan_status wlan_cmd_remain_on_channel(IN pmlan_private pmpriv,
+ IN HostCmd_DS_COMMAND * cmd,
+ IN t_u16 cmd_action,
+ IN t_void * pdata_buf);
+mlan_status wlan_ret_remain_on_channel(IN pmlan_private pmpriv,
+ IN HostCmd_DS_COMMAND * resp,
+ IN mlan_ioctl_req * pioctl_buf);
+#endif
+
+/** get pm info */
+mlan_status wlan_get_pm_info(IN pmlan_adapter pmadapter,
+ IN pmlan_ioctl_req pioctl_req);
+
+mlan_status wlan_radio_ioctl_radio_ctl(IN pmlan_adapter pmadapter,
+ IN pmlan_ioctl_req pioctl_req);
+
+mlan_status wlan_radio_ioctl_ant_cfg(IN pmlan_adapter pmadapter,
+ IN pmlan_ioctl_req pioctl_req);
+
+mlan_status wlan_cmd_tx_rate_cfg(IN pmlan_private pmpriv,
+ IN HostCmd_DS_COMMAND * cmd,
+ IN t_u16 cmd_action, IN t_void * pdata_buf);
+mlan_status wlan_ret_tx_rate_cfg(IN pmlan_private pmpriv,
+ IN HostCmd_DS_COMMAND * resp,
+ IN mlan_ioctl_req * pioctl_buf);
+
+mlan_status wlan_rate_ioctl_cfg(IN pmlan_adapter pmadapter,
+ IN pmlan_ioctl_req pioctl_req);
+mlan_status wlan_ret_802_11_tx_rate_query(IN pmlan_private pmpriv,
+ IN HostCmd_DS_COMMAND * resp,
+ IN mlan_ioctl_req * pioctl_buf);
+
+t_void wlan_host_sleep_activated_event(pmlan_private priv, t_u8 activated);
+/** Handles the command response of hs_cfg */
+mlan_status wlan_ret_802_11_hs_cfg(IN pmlan_private pmpriv,
+ IN HostCmd_DS_COMMAND * resp,
+ IN mlan_ioctl_req * pioctl_buf);
+/** Sends HS_WAKEUP event to applications */
+t_void wlan_host_sleep_wakeup_event(pmlan_private priv);
+
+/** send adapter specific init cmd to firmware */
+mlan_status wlan_adapter_init_cmd(IN pmlan_adapter pmadapter);
+
+#ifdef STA_SUPPORT
+/** Process received packet */
+mlan_status wlan_process_rx_packet(pmlan_adapter pmadapter, pmlan_buffer pmbuf);
+/** ioctl handler for station mode */
+mlan_status wlan_ops_sta_ioctl(t_void * adapter, pmlan_ioctl_req pioctl_req);
+
+/** cmd handler for station mode */
+mlan_status wlan_ops_sta_prepare_cmd(IN t_void * priv,
+ IN t_u16 cmd_no,
+ IN t_u16 cmd_action,
+ IN t_u32 cmd_oid,
+ IN t_void * pioctl_buf,
+ IN t_void * pdata_buf,
+ IN t_void * pcmd_buf);
+
+/** cmdresp handler for station mode */
+mlan_status wlan_ops_sta_process_cmdresp(IN t_void * priv,
+ IN t_u16 cmdresp_no,
+ IN t_void * pcmd_buf,
+ IN t_void * pioctl);
+
+/** rx handler for station mode */
+mlan_status wlan_ops_sta_process_rx_packet(IN t_void * adapter,
+ IN pmlan_buffer pmbuf);
+
+/** event handler for station mode */
+mlan_status wlan_ops_sta_process_event(IN t_void * priv);
+
+/** fill txpd for station mode */
+t_void *wlan_ops_sta_process_txpd(IN t_void * priv, IN pmlan_buffer pmbuf);
+
+/** send init cmd to firmware for station mode */
+mlan_status wlan_ops_sta_init_cmd(IN t_void * priv, IN t_u8 first_bss);
+
+/** Flush the scan table */
+mlan_status wlan_flush_scan_table(IN pmlan_adapter pmadapter);
+
+/** Scan for networks */
+mlan_status wlan_scan_networks(IN mlan_private * pmpriv,
+ IN t_void * pioctl_buf,
+ IN const wlan_user_scan_cfg * puser_scan_in);
+
+/** Scan for specific SSID */
+mlan_status wlan_scan_specific_ssid(IN mlan_private * pmpriv,
+ IN t_void * pioctl_buf,
+ IN mlan_802_11_ssid * preq_ssid);
+
+/** Scan command handler */
+mlan_status wlan_cmd_802_11_scan(IN pmlan_private pmpriv,
+ IN HostCmd_DS_COMMAND * pcmd,
+ IN t_void * pdata_buf);
+
+/** Queue scan command handler */
+t_void wlan_queue_scan_cmd(IN mlan_private * pmpriv,
+ IN cmd_ctrl_node * pcmd_node);
+
+/** Handler for scan command response */
+mlan_status wlan_ret_802_11_scan(IN pmlan_private pmpriv,
+ IN HostCmd_DS_COMMAND * resp,
+ IN t_void * pioctl_buf);
+
+/** Extended scan command handler */
+mlan_status wlan_cmd_802_11_scan_ext(IN pmlan_private pmpriv,
+ IN HostCmd_DS_COMMAND * pcmd,
+ IN t_void * pdata_buf);
+/** Handler for extended scan command response */
+mlan_status wlan_ret_802_11_scan_ext(IN pmlan_private pmpriv,
+ IN HostCmd_DS_COMMAND * resp,
+ IN t_void * pioctl_buf);
+/** Handler event for extended scan report */
+mlan_status wlan_handle_event_ext_scan_report(IN mlan_private * pmpriv,
+ IN mlan_buffer * pmbuf);
+
+/** check network compatibility */
+t_s32 wlan_is_network_compatible(IN mlan_private * pmpriv,
+ IN t_u32 index, IN t_u32 mode);
+
+/** Find an SSID in a list */
+t_s32 wlan_find_ssid_in_list(IN pmlan_private pmpriv,
+ IN mlan_802_11_ssid * ssid,
+ IN t_u8 * bssid, IN t_u32 mode);
+
+/** Find a BSSID in a list */
+t_s32 wlan_find_bssid_in_list(IN mlan_private * pmpriv,
+ IN t_u8 * bssid, IN t_u32 mode);
+
+/** Find best network */
+mlan_status wlan_find_best_network(IN mlan_private * pmpriv,
+ OUT mlan_ssid_bssid * preq_ssid_bssid);
+
+/** Compare two SSIDs */
+t_s32 wlan_ssid_cmp(IN pmlan_adapter pmadapter,
+ IN mlan_802_11_ssid * ssid1, IN mlan_802_11_ssid * ssid2);
+
+/** Associate */
+mlan_status wlan_associate(IN mlan_private * pmpriv,
+ IN t_void * pioctl_buf,
+ IN BSSDescriptor_t * pBSSDesc);
+
+/** Associate command handler */
+mlan_status wlan_cmd_802_11_associate(IN mlan_private * pmpriv,
+ IN HostCmd_DS_COMMAND * cmd,
+ IN t_void * pdata_buf);
+
+/** Handler for association command response */
+mlan_status wlan_ret_802_11_associate(IN mlan_private * pmpriv,
+ IN HostCmd_DS_COMMAND * resp,
+ IN t_void * pioctl_buf);
+
+/** Reset connected state */
+t_void wlan_reset_connect_state(IN pmlan_private priv, IN t_u8 drv_disconnect);
+
+t_void wlan_2040_coex_event(pmlan_private pmpriv);
+
+/** convert band to radio type */
+t_u8 wlan_band_to_radio_type(IN t_u8 band);
+
+/** Disconnect */
+mlan_status wlan_disconnect(IN mlan_private * pmpriv,
+ IN mlan_ioctl_req * pioctl_req,
+ IN mlan_802_11_mac_addr * mac);
+
+/** Ad-Hoc start */
+mlan_status wlan_adhoc_start(IN mlan_private * pmpriv,
+ IN t_void * pioctl_buf,
+ IN mlan_802_11_ssid * padhoc_ssid);
+
+/** Ad-Hoc join */
+mlan_status wlan_adhoc_join(IN mlan_private * pmpriv,
+ IN t_void * pioctl_buf,
+ IN BSSDescriptor_t * pBSSDesc);
+
+/** Ad-Hoc start command handler */
+mlan_status wlan_cmd_802_11_ad_hoc_start(IN mlan_private * pmpriv,
+ IN HostCmd_DS_COMMAND * cmd,
+ IN t_void * pdata_buf);
+
+/** Ad-Hoc command handler */
+mlan_status wlan_cmd_802_11_ad_hoc_join(IN mlan_private * pmpriv,
+ IN HostCmd_DS_COMMAND * cmd,
+ IN t_void * pdata_buf);
+
+/** Handler for Ad-Hoc commands */
+mlan_status wlan_ret_802_11_ad_hoc(IN mlan_private * pmpriv,
+ IN HostCmd_DS_COMMAND * resp,
+ IN t_void * pioctl_buf);
+
+/** Handler for bgscan query commands */
+mlan_status wlan_cmd_802_11_bg_scan_query(IN mlan_private * pmpriv,
+ IN HostCmd_DS_COMMAND * pcmd,
+ IN t_void * pdata_buf);
+/** Handler for bgscan config command */
+mlan_status wlan_cmd_bgscan_config(IN mlan_private * pmpriv,
+ IN HostCmd_DS_COMMAND * pcmd,
+ IN t_void * pdata_buf);
+/** Hander for bgscan config command response */
+mlan_status wlan_ret_bgscan_config(IN mlan_private * pmpriv,
+ IN HostCmd_DS_COMMAND * resp,
+ IN mlan_ioctl_req * pioctl_buf);
+
+/** Get Channel-Frequency-Power by band and channel */
+chan_freq_power_t *wlan_get_cfp_by_band_and_channel(pmlan_adapter pmadapter,
+ t_u8 band, t_u16 channel,
+ region_chan_t *
+ region_channel);
+/** Find Channel-Frequency-Power by band and channel */
+chan_freq_power_t *wlan_find_cfp_by_band_and_channel(mlan_adapter * pmadapter,
+ t_u8 band, t_u16 channel);
+/** Find Channel-Frequency-Power by band and frequency */
+chan_freq_power_t *wlan_find_cfp_by_band_and_freq(mlan_adapter * pmadapter,
+ t_u8 band, t_u32 freq);
+/** Get Tx power of channel from Channel-Frequency-Power */
+t_u8 wlan_get_txpwr_of_chan_from_cfp(mlan_private * pmpriv, t_u8 channel);
+/** find frequency from band and channel */
+t_u32 wlan_find_freq_from_band_chan(t_u8, t_u8);
+
+/* Save a beacon buffer of the current bss descriptor */
+t_void wlan_save_curr_bcn(IN mlan_private * pmpriv);
+/* Free a beacon buffer of the current bss descriptor */
+t_void wlan_free_curr_bcn(IN mlan_private * pmpriv);
+
+#endif /* STA_SUPPORT */
+
+/* Rate related functions */
+/** Convert index into data rate */
+t_u32 wlan_index_to_data_rate(pmlan_adapter pmadapter, t_u8 index,
+ t_u8 ht_info);
+/** Get active data rates */
+t_u32 wlan_get_active_data_rates(mlan_private * pmpriv, t_u32 bss_mode,
+ t_u8 config_bands, WLAN_802_11_RATES rates);
+/** Get supported data rates */
+t_u32 wlan_get_supported_rates(mlan_private * pmpriv, t_u32 bss_mode,
+ t_u8 config_bands, WLAN_802_11_RATES rates);
+/** Convert data rate to index */
+t_u8 wlan_data_rate_to_index(pmlan_adapter pmadapter, t_u32 rate);
+/** Check if rate is auto */
+t_u8 wlan_is_rate_auto(mlan_private * pmpriv);
+/** Get rate index */
+int wlan_get_rate_index(pmlan_adapter pmadapter, t_u16 * rateBitmap, int size);
+
+/* CFP related functions */
+/** Region code index table */
+extern t_u16 region_code_index[MRVDRV_MAX_REGION_CODE];
+/** Set region table */
+mlan_status wlan_set_regiontable(mlan_private * pmpriv, t_u8 region, t_u8 band);
+/** Get radar detection requirements*/
+t_bool wlan_get_cfp_radar_detect(mlan_private * priv, t_u8 chnl);
+
+/* 802.11D related functions */
+/** Initialize 11D */
+t_void wlan_11d_priv_init(mlan_private * pmpriv);
+/** Initialize 11D */
+t_void wlan_11d_init(mlan_adapter * pmadapter);
+/** Enable 11D */
+mlan_status wlan_11d_enable(mlan_private * pmpriv, t_void * pioctl_buf,
+ state_11d_t flag);
+/** Get if 11D is enabled */
+t_bool wlan_11d_is_enabled(mlan_private * pmpriv);
+/** Get if priv is station */
+t_bool wlan_is_station(mlan_private * pmpriv);
+/** Command handler for 11D country info */
+mlan_status wlan_cmd_802_11d_domain_info(mlan_private * pmpriv,
+ HostCmd_DS_COMMAND * pcmd,
+ t_u16 cmd_action);
+/** Handler for 11D country info command response */
+mlan_status wlan_ret_802_11d_domain_info(mlan_private * pmpriv,
+ HostCmd_DS_COMMAND * resp);
+#ifdef STA_SUPPORT
+/** Convert channel to frequency */
+t_u32 wlan_11d_chan_2_freq(pmlan_adapter pmadapter, t_u8 chan, t_u8 band);
+/** Set 11D universal table */
+mlan_status wlan_11d_set_universaltable(mlan_private * pmpriv, t_u8 band);
+/** Clear 11D region table */
+mlan_status wlan_11d_clear_parsedtable(mlan_private * pmpriv);
+/** Create 11D country information for downloading */
+mlan_status wlan_11d_create_dnld_countryinfo(mlan_private * pmpriv, t_u8 band);
+/** Get scan type from 11D info */
+t_u8 wlan_11d_get_scan_type(pmlan_adapter pmadapter, t_u8 band, t_u8 chan,
+ parsed_region_chan_11d_t * parsed_region_chan);
+/** Parse 11D country info */
+mlan_status wlan_11d_parse_dnld_countryinfo(mlan_private * pmpriv,
+ BSSDescriptor_t * pBSSDesc);
+/** Prepare 11D domain information for download */
+mlan_status wlan_11d_prepare_dnld_domain_info_cmd(mlan_private * pmpriv);
+/** Parse 11D country information into domain info */
+mlan_status wlan_11d_parse_domain_info(pmlan_adapter pmadapter,
+ IEEEtypes_CountryInfoFullSet_t *
+ country_info, t_u8 band,
+ parsed_region_chan_11d_t *
+ parsed_region_chan);
+/** Configure 11D domain info command */
+mlan_status wlan_11d_cfg_domain_info(IN pmlan_adapter pmadapter,
+ IN mlan_ioctl_req * pioctl_req);
+#endif /* STA_SUPPORT */
+#ifdef UAP_SUPPORT
+/** Handle 11D domain information from UAP */
+mlan_status wlan_11d_handle_uap_domain_info(mlan_private * pmpriv,
+ t_u8 band,
+ t_u8 * domain_tlv,
+ t_void * pioctl_buf);
+#endif
+
+/** check if station list is empty */
+t_u8 wlan_is_station_list_empty(mlan_private * priv);
+/** get station node */
+sta_node *wlan_get_station_entry(mlan_private * priv, t_u8 * mac);
+/** delete station list */
+t_void wlan_delete_station_list(pmlan_private priv);
+/** delete station entry */
+t_void wlan_delete_station_entry(mlan_private * priv, t_u8 * mac);
+/** add station entry */
+sta_node *wlan_add_station_entry(mlan_private * priv, t_u8 * mac);
+/** process uap rx packet */
+
+/** find specific ie */
+t_u8 *wlan_get_specific_ie(pmlan_private priv, t_u8 * ie_buf, t_u8 ie_len,
+ IEEEtypes_ElementId_e id);
+
+/**
+ * @brief This function checks tx_pause flag for peer
+ *
+ * @param priv A pointer to mlan_private
+ * @param ra Address of the receiver STA
+ *
+ * @return MTRUE or MFALSE
+ */
+static int INLINE
+wlan_is_tx_pause(mlan_private * priv, t_u8 * ra)
+{
+ sta_node *sta_ptr = MNULL;
+ if ((sta_ptr = wlan_get_station_entry(priv, ra))) {
+ return sta_ptr->tx_pause;
+ }
+ return MFALSE;
+}
+
+t_void wlan_updata_ralist_tx_pause(pmlan_private priv, t_u8 * mac,
+ t_u8 tx_pause);
+sta_node *wlan_get_tx_pause_station_entry(mlan_private * priv);
+
+#ifdef UAP_SUPPORT
+mlan_status wlan_process_uap_rx_packet(IN mlan_private * priv,
+ IN pmlan_buffer pmbuf);
+t_void wlan_drop_tx_pkts(pmlan_private priv);
+#endif /* UAP_SUPPORT */
+
+#ifdef UAP_SUPPORT
+/* process the recevied packet and bridge the packet */
+mlan_status wlan_uap_recv_packet(IN mlan_private * priv, IN pmlan_buffer pmbuf);
+#endif /* UAP_SUPPORT */
+
+mlan_status wlan_misc_ioctl_custom_ie_list(IN pmlan_adapter pmadapter,
+ IN pmlan_ioctl_req pioctl_req,
+ IN t_bool send_ioctl);
+
+mlan_status wlan_cmd_get_hw_spec(IN pmlan_private pmpriv,
+ IN HostCmd_DS_COMMAND * pcmd);
+mlan_status wlan_ret_get_hw_spec(IN pmlan_private pmpriv,
+ IN HostCmd_DS_COMMAND * resp,
+ IN t_void * pioctl_buf);
+
+mlan_status wlan_cmd_802_11_radio_control(IN pmlan_private pmpriv,
+ IN HostCmd_DS_COMMAND * cmd,
+ IN t_u16 cmd_action,
+ IN t_void * pdata_buf);
+mlan_status wlan_ret_802_11_radio_control(IN pmlan_private pmpriv,
+ IN HostCmd_DS_COMMAND * resp,
+ IN mlan_ioctl_req * pioctl_buf);
+
+mlan_status wlan_cmd_802_11_rf_antenna(IN pmlan_private pmpriv,
+ IN HostCmd_DS_COMMAND * cmd,
+ IN t_u16 cmd_action,
+ IN t_void * pdata_buf);
+mlan_status wlan_ret_802_11_rf_antenna(IN pmlan_private pmpriv,
+ IN HostCmd_DS_COMMAND * resp,
+ IN mlan_ioctl_req * pioctl_buf);
+
+mlan_status wlan_get_info_ver_ext(IN pmlan_adapter pmadapter,
+ IN pmlan_ioctl_req pioctl_req);
+
+mlan_status wlan_reg_rx_mgmt_ind(IN pmlan_adapter pmadapter,
+ IN pmlan_ioctl_req pioctl_req);
+
+#ifdef DEBUG_LEVEL1
+mlan_status wlan_set_drvdbg(IN pmlan_adapter pmadapter,
+ IN pmlan_ioctl_req pioctl_req);
+#endif
+
+/**
+ * @brief RA based queueing
+ *
+ * @param priv A pointer to mlan_private structure
+ *
+ * @return MTRUE or MFALSE
+ */
+static INLINE t_u8
+queuing_ra_based(pmlan_private priv)
+{
+ /*
+ * Currently we assume if we are in Infra, then DA=RA. This might not be
+ * true in the future
+ */
+ if ((priv->bss_mode == MLAN_BSS_MODE_INFRA) &&
+ (GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_STA))
+ return MFALSE;
+
+ return MTRUE;
+}
+
+/**
+ * @brief Copy Rates
+ *
+ * @param dest A pointer to Dest Buf
+ * @param pos The position for copy
+ * @param src A pointer to Src Buf
+ * @param len The len of Src Buf
+ *
+ * @return Number of Rates copied
+ */
+static INLINE t_u32
+wlan_copy_rates(t_u8 * dest, t_u32 pos, t_u8 * src, int len)
+{
+ int i;
+
+ for (i = 0; i < len && src[i]; i++, pos++) {
+ if (pos >= sizeof(WLAN_802_11_RATES))
+ break;
+ dest[pos] = src[i];
+ }
+
+ return pos;
+}
+
+/**
+ * @brief strlen
+ *
+ * @param str A pointer to string
+ *
+ * @return Length of string
+ */
+static INLINE t_u32
+wlan_strlen(const t_s8 * str)
+{
+ t_u32 i;
+
+ for (i = 0; str[i] != 0; i++) {
+ }
+ return i;
+}
+
+/**
+ * @brief iscdigit
+ *
+ * @param chr A char
+ *
+ * @return Non zero if chr is a hex, else 0
+ */
+static INLINE t_u32
+wlan_isxdigit(t_u8 chr)
+{
+ return ((chr <= 'f' && chr >= 'a') || (chr <= 'F' && chr >= 'A') ||
+ (chr <= '9' && chr >= '0'));
+}
+
+/**
+ * @brief isspace
+ *
+ * @param A chr
+ *
+ * @return Non zero if chr is space etc, else 0
+ */
+static INLINE t_u32
+wlan_isspace(t_u8 chr)
+{
+ return (chr <= ' ' && (chr == ' ' || (chr <= 13 && chr >= 9)));
+}
+
+/** delay unit */
+typedef enum _delay_unit
+{
+ USEC,
+ MSEC,
+ SEC,
+} t_delay_unit;
+
+/** delay function */
+t_void wlan_delay_func(mlan_adapter * pmadapter, t_u32 delay, t_delay_unit u);
+
+/** delay function wrapper */
+#define wlan_delay(p, n) wlan_delay_func(p, n, SEC)
+/** delay function wrapper */
+#define wlan_mdelay(p, n) wlan_delay_func(p, n, MSEC)
+/** delay function wrapper */
+#define wlan_udelay(p, n) wlan_delay_func(p, n, USEC)
+
+/** Function to check if any command is pending in the queue */
+#define IS_COMMAND_PENDING(pmadapter) ((cmd_ctrl_node *)util_peek_list(pmadapter->pmoal_handle, \
+ &pmadapter->cmd_pending_q,\
+ pmadapter->callbacks.moal_spin_lock,\
+ pmadapter->callbacks.moal_spin_unlock))
+
+/** Get BSS number from priv */
+#define GET_BSS_NUM(priv) (priv)->bss_num
+/**
+ * @brief This function returns priv based on the BSS num and BSS type
+ *
+ * @param pmadapter A pointer to mlan_adapter
+ * @param bss_num BSS number
+ * @param bss_type BSS type
+ *
+ * @return Pointer to mlan_private
+ */
+static INLINE mlan_private *
+wlan_get_priv_by_id(mlan_adapter * pmadapter, t_u32 bss_num, t_u32 bss_type)
+{
+ int i;
+
+ for (i = 0; i < MIN(pmadapter->priv_num, MLAN_MAX_BSS_NUM); i++) {
+ if (pmadapter->priv[i]) {
+ if ((pmadapter->priv[i]->bss_num == bss_num) &&
+ (pmadapter->priv[i]->bss_type == bss_type))
+ return (pmadapter->priv[i]);
+ }
+ }
+ return MNULL;
+}
+
+/**
+ * @brief This function returns first available priv
+ * based on the BSS role
+ *
+ * @param pmadapter A pointer to mlan_adapter
+ * @param bss_role BSS role or MLAN_BSS_ROLE_ANY
+ *
+ * @return Pointer to mlan_private
+ */
+static INLINE mlan_private *
+wlan_get_priv(mlan_adapter * pmadapter, mlan_bss_role bss_role)
+{
+ int i;
+
+ for (i = 0; i < MIN(pmadapter->priv_num, MLAN_MAX_BSS_NUM); i++) {
+ if (pmadapter->priv[i]) {
+ if (bss_role == MLAN_BSS_ROLE_ANY ||
+ GET_BSS_ROLE(pmadapter->priv[i]) == bss_role)
+ return (pmadapter->priv[i]);
+ }
+ }
+ return MNULL;
+}
+
+/**
+ * @brief This function counts the number of occurences for a certain
+ * condition among privs. Which privs are checked can be configured
+ * via a second condition.
+ *
+ * @param pmadapter A pointer to mlan_adapter
+ * @param count_cond Function pointer to condition to count on privs
+ * @param check_cond Function pointer to condition to decide whether priv
+ * should be counted or not. Use MNULL to check all privs.
+ *
+ * @return Count of privs where count_cond returned MTRUE.
+ */
+static int INLINE
+wlan_count_priv_cond(mlan_adapter * pmadapter,
+ t_bool(*count_cond) (IN pmlan_private pmpriv),
+ t_bool(*check_cond) (IN pmlan_private pmpriv))
+{
+ pmlan_private pmpriv;
+ int count = 0;
+ int i;
+
+ if (pmadapter == MNULL || count_cond == MNULL)
+ return 0;
+
+ for (i = 0; i < pmadapter->priv_num; i++) {
+ if ((pmpriv = pmadapter->priv[i])) {
+ if ((check_cond == MNULL) || (check_cond && check_cond(pmpriv))) {
+ if (count_cond(pmpriv))
+ count++;
+ }
+ }
+ }
+
+ return count;
+}
+
+/**
+ * @brief This function runs a procedure on each priv.
+ * Which privs it is run on can be configured via a condition.
+ *
+ * @param pmadapter A pointer to mlan_adapter
+ * @param operation Function pointer to produedure to operate on priv
+ * @param check_cond Function pointer to condition to decide whether priv
+ * operated on or not. Use MNULL to run on all privs.
+ *
+ * @return Number of privs that operation was run on.
+ */
+static int INLINE
+wlan_do_task_on_privs(mlan_adapter * pmadapter,
+ t_void(*operation) (IN pmlan_private pmpriv),
+ t_bool(*check_cond) (IN pmlan_private pmpriv))
+{
+ pmlan_private pmpriv;
+ int count = 0;
+ int i;
+
+ if (pmadapter == MNULL || operation == MNULL)
+ return 0;
+
+ for (i = 0; i < pmadapter->priv_num; i++) {
+ if ((pmpriv = pmadapter->priv[i])) {
+ if ((check_cond == MNULL) || (check_cond && check_cond(pmpriv))) {
+ operation(pmpriv);
+ count++;
+ }
+ }
+ }
+
+ return count;
+}
+
+/**
+ * @brief This function builds a list of privs that test for a condition
+ * This is useful if you need to do a number of operations on the same set
+ * of privs. For one-off tasks, the above two functions might be better.
+ *
+ * @param pmadapter A pointer to mlan_adapter
+ * @param check_cond Function pointer to condition to decide whether priv
+ * should be placed in the list.
+ * @param ppriv_list Output param. Externally supplied array of mlan_private*
+ * to hold priv's that test positive with check_cond.
+ * Array size should be at least pmadapter->priv_num.
+ *
+ * @return Number of privs in ppriv_list
+ *
+ * @sa wlan_count_priv_cond
+ */
+static int INLINE
+wlan_get_privs_by_cond(mlan_adapter * pmadapter,
+ t_bool(*check_cond) (IN pmlan_private pmpriv),
+ mlan_private ** ppriv_list)
+{
+ pmlan_private pmpriv;
+ int count = 0;
+ int i;
+
+ if (pmadapter == MNULL || check_cond == MNULL || ppriv_list == MNULL)
+ return 0;
+
+ for (i = 0; i < pmadapter->priv_num; i++) {
+ if ((pmpriv = pmadapter->priv[i])) {
+ if (check_cond(pmpriv)) {
+ ppriv_list[count++] = pmpriv;
+ }
+ }
+ }
+
+ return count;
+}
+
+/**
+ * @brief This function builds a list of privs that test against two conditions
+ * This is useful if you need to do a number of operations on the same set
+ * of privs. Can choose whether both conditions (AND) or either condition (OR)
+ * is required.
+ *
+ * @param pmadapter A pointer to mlan_adapter
+ * @param check_cond Function pointer to condition to decide whether priv
+ * should be placed in the list.
+ * @param check_cond_2 Function pointer to second condition to check.
+ * @param and_conditions If MTRUE, both conditions must be met (AND),
+ * else either condition can be met (OR).
+ * @param ppriv_list Output param. Externally supplied array of mlan_private*
+ * to hold priv's that test positive with check_cond.
+ * Array size should be at least pmadapter->priv_num.
+ *
+ * @return Number of privs in ppriv_list
+ *
+ * @sa wlan_count_priv_cond, wlan_get_privs_by_cond
+ */
+static int INLINE
+wlan_get_privs_by_two_cond(mlan_adapter * pmadapter,
+ t_bool(*check_cond) (IN pmlan_private pmpriv),
+ t_bool(*check_cond_2) (IN pmlan_private pmpriv),
+ t_bool and_conditions, mlan_private ** ppriv_list)
+{
+ pmlan_private pmpriv;
+ int count = 0;
+ int i;
+
+ if (pmadapter == MNULL || check_cond == MNULL ||
+ check_cond_2 == MNULL || ppriv_list == MNULL)
+ return 0;
+
+ for (i = 0; i < pmadapter->priv_num; i++) {
+ if ((pmpriv = pmadapter->priv[i])) {
+ if (and_conditions) {
+ if (check_cond(pmpriv) && check_cond_2(pmpriv)) {
+ ppriv_list[count++] = pmpriv;
+ }
+ } else {
+ if (check_cond(pmpriv) || check_cond_2(pmpriv)) {
+ ppriv_list[count++] = pmpriv;
+ }
+ }
+ }
+ }
+
+ return count;
+}
+
+#endif /* !_MLAN_MAIN_H_ */
diff --git a/drivers/net/wireless/sd8797/mlan/mlan_meas.c b/drivers/net/wireless/sd8797/mlan/mlan_meas.c
new file mode 100644
index 000000000000..d9da9da20756
--- /dev/null
+++ b/drivers/net/wireless/sd8797/mlan/mlan_meas.c
@@ -0,0 +1,464 @@
+/**
+ * @file mlan_meas.c
+ *
+ * @brief Implementation of measurement interface code with the app/firmware
+ *
+ * Driver implementation for sending and retrieving measurement requests
+ * and responses.
+ *
+ * Current use is limited to 802.11h.
+ *
+ * Requires use of the following preprocessor define:
+ * - ENABLE_MEAS
+ *
+ * Copyright (C) 2008-2011, Marvell International Ltd.
+ *
+ * This software file (the "File") is distributed by Marvell International
+ * Ltd. under the terms of the GNU General Public License Version 2, June 1991
+ * (the "License"). You may use, redistribute and/or modify this File in
+ * accordance with the terms and conditions of the License, a copy of which
+ * is available by writing to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
+ * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
+ *
+ * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
+ * ARE EXPRESSLY DISCLAIMED. The License provides additional details about
+ * this warranty disclaimer.
+ */
+
+/*************************************************************
+Change Log:
+ 03/24/2009: initial version
+************************************************************/
+
+#include "mlan.h"
+#include "mlan_join.h"
+#include "mlan_util.h"
+#include "mlan_fw.h"
+#include "mlan_main.h"
+#include "mlan_ioctl.h"
+#include "mlan_meas.h"
+
+/** Default measurement duration when not provided by the application */
+#define WLAN_MEAS_DEFAULT_MEAS_DURATION 1000U /* TUs */
+
+#ifdef DEBUG_LEVEL2
+/** String descriptions of the different measurement enums. Debug display */
+static const char *meas_type_str[WLAN_MEAS_NUM_TYPES] = {
+ "basic",
+};
+
+/********************************************************
+ Local Functions
+********************************************************/
+
+/**
+ * @brief Retrieve the measurement string representation of a meas_type enum
+ * Used for debug display only
+ *
+ * @param meas_type Measurement type enumeration input for string lookup
+ *
+ * @return Constant string representing measurement type
+ */
+static const char *
+wlan_meas_get_meas_type_str(MeasType_t meas_type)
+{
+ if (meas_type <= WLAN_MEAS_11H_MAX_TYPE)
+ return meas_type_str[meas_type];
+
+ return "Invld";
+}
+#endif
+
+/**
+ * @brief Debug print display of the input measurement request
+ *
+ * @param pmeas_req Pointer to the measurement request to display
+ *
+ * @return N/A
+ */
+static void
+wlan_meas_dump_meas_req(const HostCmd_DS_MEASUREMENT_REQUEST * pmeas_req)
+{
+ ENTER();
+
+ PRINTM(MINFO, "Meas: Req: ------------------------------\n");
+
+ PRINTM(MINFO, "Meas: Req: mac_addr: %02x:%02x:%02x:%02x:%02x:%02x\n",
+ pmeas_req->mac_addr[0],
+ pmeas_req->mac_addr[1],
+ pmeas_req->mac_addr[2],
+ pmeas_req->mac_addr[3],
+ pmeas_req->mac_addr[4], pmeas_req->mac_addr[5]);
+
+ PRINTM(MINFO, "Meas: Req: dlgTkn: %d\n", pmeas_req->dialog_token);
+ PRINTM(MINFO, "Meas: Req: mode: dm[%c] rpt[%c] req[%c]\n",
+ pmeas_req->req_mode.duration_mandatory ? 'X' : ' ',
+ pmeas_req->req_mode.report ? 'X' : ' ',
+ pmeas_req->req_mode.request ? 'X' : ' ');
+ PRINTM(MINFO, "Meas: Req: : en[%c] par[%c]\n",
+ pmeas_req->req_mode.enable ? 'X' : ' ',
+ pmeas_req->req_mode.parallel ? 'X' : ' ');
+#ifdef DEBUG_LEVEL2
+ PRINTM(MINFO, "Meas: Req: measTyp: %s\n",
+ wlan_meas_get_meas_type_str(pmeas_req->meas_type));
+#endif
+
+ switch (pmeas_req->meas_type) {
+ case WLAN_MEAS_BASIC:
+ /* Lazy cheat, fields of bas, cca, rpi union match on the request */
+ PRINTM(MINFO, "Meas: Req: chan: %u\n", pmeas_req->req.basic.channel);
+ PRINTM(MINFO, "Meas: Req: strt: %llu\n",
+ wlan_le64_to_cpu(pmeas_req->req.basic.start_time));
+ PRINTM(MINFO, "Meas: Req: dur: %u\n",
+ wlan_le16_to_cpu(pmeas_req->req.basic.duration));
+ break;
+ default:
+ PRINTM(MINFO, "Meas: Req: <unhandled>\n");
+ break;
+ }
+
+ PRINTM(MINFO, "Meas: Req: ------------------------------\n");
+ LEAVE();
+}
+
+/**
+ * @brief Debug print display of the input measurement report
+ *
+ * @param pmeas_rpt Pointer to measurement report to display
+ *
+ * @return N/A
+ */
+static void
+wlan_meas_dump_meas_rpt(const HostCmd_DS_MEASUREMENT_REPORT * pmeas_rpt)
+{
+ ENTER();
+
+ PRINTM(MINFO, "Meas: Rpt: ------------------------------\n");
+ PRINTM(MINFO, "Meas: Rpt: mac_addr: %02x:%02x:%02x:%02x:%02x:%02x\n",
+ pmeas_rpt->mac_addr[0],
+ pmeas_rpt->mac_addr[1],
+ pmeas_rpt->mac_addr[2],
+ pmeas_rpt->mac_addr[3],
+ pmeas_rpt->mac_addr[4], pmeas_rpt->mac_addr[5]);
+
+ PRINTM(MINFO, "Meas: Rpt: dlgTkn: %d\n", pmeas_rpt->dialog_token);
+
+ PRINTM(MINFO, "Meas: Rpt: rptMode: (%x): Rfs[%c] ICp[%c] Lt[%c]\n",
+ *(t_u8 *) & pmeas_rpt->rpt_mode,
+ pmeas_rpt->rpt_mode.refused ? 'X' : ' ',
+ pmeas_rpt->rpt_mode.incapable ? 'X' : ' ',
+ pmeas_rpt->rpt_mode.late ? 'X' : ' ');
+#ifdef DEBUG_LEVEL2
+ PRINTM(MINFO, "Meas: Rpt: measTyp: %s\n",
+ wlan_meas_get_meas_type_str(pmeas_rpt->meas_type));
+#endif
+
+ switch (pmeas_rpt->meas_type) {
+ case WLAN_MEAS_BASIC:
+ PRINTM(MINFO, "Meas: Rpt: chan: %u\n", pmeas_rpt->rpt.basic.channel);
+ PRINTM(MINFO, "Meas: Rpt: strt: %llu\n",
+ wlan_le64_to_cpu(pmeas_rpt->rpt.basic.start_time));
+ PRINTM(MINFO, "Meas: Rpt: dur: %u\n",
+ wlan_le16_to_cpu(pmeas_rpt->rpt.basic.duration));
+ PRINTM(MINFO, "Meas: Rpt: bas: (%x): unmsd[%c], radar[%c]\n",
+ *(t_u8 *) & (pmeas_rpt->rpt.basic.map),
+ pmeas_rpt->rpt.basic.map.unmeasured ? 'X' : ' ',
+ pmeas_rpt->rpt.basic.map.radar ? 'X' : ' ');
+ PRINTM(MINFO, "Meas: Rpt: bas: unidSig[%c] ofdm[%c] bss[%c]\n",
+ pmeas_rpt->rpt.basic.map.unidentified_sig ? 'X' : ' ',
+ pmeas_rpt->rpt.basic.map.ofdm_preamble ? 'X' : ' ',
+ pmeas_rpt->rpt.basic.map.bss ? 'X' : ' ');
+ break;
+ default:
+ PRINTM(MINFO, "Meas: Rpt: <unhandled>\n");
+ break;
+ }
+
+ PRINTM(MINFO, "Meas: Rpt: ------------------------------\n");
+ LEAVE();
+}
+
+/**
+ * @brief Retrieve a measurement report from the firmware
+ *
+ * Callback from command processing when a measurement report is received
+ * from the firmware. Perform the following when a report is received:
+ *
+ * -# Debug displays the report if compiled with the appropriate flags
+ * -# If we are pending on a specific measurement report token, and it
+ * matches the received report's token, store the report and wake up
+ * any pending threads
+ *
+ * @param pmpriv Private driver information structure
+ * @param resp HostCmd_DS_COMMAND struct returned from the firmware command
+ * passing a HostCmd_DS_MEASUREMENT_REPORT structure.
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+static int
+wlan_meas_cmdresp_get_report(mlan_private * pmpriv,
+ const HostCmd_DS_COMMAND * resp)
+{
+ mlan_adapter *pmadapter = pmpriv->adapter;
+ const HostCmd_DS_MEASUREMENT_REPORT *pmeas_rpt = &resp->params.meas_rpt;
+
+ ENTER();
+
+ PRINTM(MINFO, "Meas: Rpt: %#x-%u, Seq=%u, Ret=%u\n",
+ resp->command, resp->size, resp->seq_num, resp->result);
+
+ /* Debug displays the measurement report */
+ wlan_meas_dump_meas_rpt(pmeas_rpt);
+
+ /*
+ * Check if we are pending on a measurement report and it matches
+ * the dialog token of the received report:
+ */
+ if (pmadapter->state_meas.meas_rpt_pend_on
+ && pmadapter->state_meas.meas_rpt_pend_on == pmeas_rpt->dialog_token) {
+ PRINTM(MINFO, "Meas: Rpt: RCV'd Pend on meas #%d\n",
+ pmadapter->state_meas.meas_rpt_pend_on);
+
+ /* Clear the pending report indicator */
+ pmadapter->state_meas.meas_rpt_pend_on = 0;
+
+ /* Copy the received report into the measurement state for retrieval */
+ memcpy(pmadapter, &pmadapter->state_meas.meas_rpt_returned, pmeas_rpt,
+ sizeof(pmadapter->state_meas.meas_rpt_returned));
+
+ /*
+ * Wake up any threads pending on the wait queue
+ */
+ wlan_recv_event(pmpriv, MLAN_EVENT_ID_DRV_MEAS_REPORT, MNULL);
+ }
+
+ LEAVE();
+
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief Prepare CMD_MEASURMENT_REPORT firmware command
+ *
+ * @param pmpriv Private driver information structure
+ * @param pcmd_ptr Output parameter: Pointer to the command being prepared
+ * for the firmware
+ * @param pinfo_buf HostCmd_DS_MEASUREMENT_REQUEST passed as void data block
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+static int
+wlan_meas_cmd_request(mlan_private * pmpriv,
+ HostCmd_DS_COMMAND * pcmd_ptr, const void *pinfo_buf)
+{
+ const HostCmd_DS_MEASUREMENT_REQUEST *pmeas_req =
+ (HostCmd_DS_MEASUREMENT_REQUEST *) pinfo_buf;
+
+ ENTER();
+
+ pcmd_ptr->command = HostCmd_CMD_MEASUREMENT_REQUEST;
+ pcmd_ptr->size = sizeof(HostCmd_DS_MEASUREMENT_REQUEST) + S_DS_GEN;
+
+ memcpy(pmpriv->adapter, &pcmd_ptr->params.meas_req, pmeas_req,
+ sizeof(pcmd_ptr->params.meas_req));
+
+ PRINTM(MINFO, "Meas: Req: %#x-%u, Seq=%u, Ret=%u\n",
+ pcmd_ptr->command, pcmd_ptr->size, pcmd_ptr->seq_num,
+ pcmd_ptr->result);
+
+ wlan_meas_dump_meas_req(pmeas_req);
+
+ LEAVE();
+
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief Retrieve a measurement report from the firmware
+ *
+ * The firmware will send a EVENT_MEAS_REPORT_RDY event when it
+ * completes or receives a measurement report. The event response
+ * handler will then start a HostCmd_CMD_MEASUREMENT_REPORT firmware command
+ * which gets completed for transmission to the firmware in this routine.
+ *
+ * @param pmpriv Private driver information structure
+ * @param pcmd_ptr Output parameter: Pointer to the command being prepared
+ * for the firmware
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+static int
+wlan_meas_cmd_get_report(mlan_private * pmpriv, HostCmd_DS_COMMAND * pcmd_ptr)
+{
+ ENTER();
+
+ pcmd_ptr->command = HostCmd_CMD_MEASUREMENT_REPORT;
+ pcmd_ptr->size = sizeof(HostCmd_DS_MEASUREMENT_REPORT) + S_DS_GEN;
+
+ memset(pmpriv->adapter, &pcmd_ptr->params.meas_rpt, 0x00,
+ sizeof(pcmd_ptr->params.meas_rpt));
+
+ /*
+ * Set the meas_rpt.mac_addr to our mac address to get a meas report,
+ * setting the mac to another STA address instructs the firmware
+ * to transmit this measurement report frame instead
+ */
+ memcpy(pmpriv->adapter, pcmd_ptr->params.meas_rpt.mac_addr,
+ pmpriv->curr_addr, sizeof(pcmd_ptr->params.meas_rpt.mac_addr));
+
+ LEAVE();
+
+ return MLAN_STATUS_SUCCESS;
+}
+
+/********************************************************
+ Global functions
+********************************************************/
+
+/**
+ * @brief Send the input measurement request to the firmware.
+ *
+ * If the dialog token in the measurement request is set to 0, the function
+ * will use an local static auto-incremented token in the measurement
+ * request. This ensures the dialog token is always set.
+ *
+ * If wait_for_resp_timeout is set, the function will block its return on
+ * a timeout or returned measurement report that matches the requests
+ * dialog token.
+ *
+ * @param pmpriv Private driver information structure
+ * @param pmeas_req Pointer to the measurement request to send
+ * @param wait_for_resp_timeout Timeout value of the measurement request
+ * in ms.
+ * @param pioctl_req Pointer to IOCTL request buffer
+ * @param pmeas_rpt Output parameter: Pointer for the resulting
+ * measurement report
+ *
+ * @return
+ * - 0 for success
+ * - -ETIMEDOUT if the measurement report does not return before
+ * the timeout expires
+ * - Error return from wlan_prepare_cmd routine otherwise
+ */
+int
+wlan_meas_util_send_req(mlan_private * pmpriv,
+ HostCmd_DS_MEASUREMENT_REQUEST * pmeas_req,
+ t_u32 wait_for_resp_timeout, pmlan_ioctl_req pioctl_req,
+ HostCmd_DS_MEASUREMENT_REPORT * pmeas_rpt)
+{
+ static t_u8 auto_dialog_tok = 0;
+ wlan_meas_state_t *pmeas_state = &pmpriv->adapter->state_meas;
+ int ret;
+
+ ENTER();
+
+ /* If dialogTok was set to 0 or not provided, autoset */
+ pmeas_req->dialog_token = (pmeas_req->dialog_token ?
+ pmeas_req->dialog_token : ++auto_dialog_tok);
+
+ /* Check for rollover of the dialog token. Avoid using 0 as a token */
+ pmeas_req->dialog_token = (pmeas_req->dialog_token ?
+ pmeas_req->dialog_token : 1);
+
+ /*
+ * If the request is to pend waiting for the result, set the dialog token
+ * of this measurement request in the state structure. The measurement
+ * report handling routines can then check the incoming measurement
+ * reports for a match with this dialog token.
+ */
+ if (wait_for_resp_timeout) {
+ pmeas_state->meas_rpt_pend_on = pmeas_req->dialog_token;
+ PRINTM(MINFO, "Meas: Req: START Pend on meas #%d\n",
+ pmeas_req->dialog_token);
+ }
+
+ /* Send the measurement request to the firmware */
+ ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_MEASUREMENT_REQUEST,
+ HostCmd_ACT_GEN_SET,
+ 0, (t_void *) pioctl_req, (void *) pmeas_req);
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Prepare the HostCmd_DS_Command structure for a measurement command.
+ *
+ * Use the Command field to determine if the command being set up is for
+ * 11h and call one of the local command handlers accordingly for:
+ *
+ * - HostCmd_CMD_MEASUREMENT_REQUEST
+ * - HostCmd_CMD_MEASUREMENT_REPORT
+ *
+ * @param pmpriv Private driver information structure
+ * @param pcmd_ptr Output parameter: Pointer to the command being prepared
+ * for the firmware
+ * @param pinfo_buf Void buffer passthrough with data necessary for a
+ * specific command type
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ *
+ */
+int
+wlan_meas_cmd_process(mlan_private * pmpriv,
+ HostCmd_DS_COMMAND * pcmd_ptr, const void *pinfo_buf)
+{
+ int ret = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+ switch (pcmd_ptr->command) {
+ case HostCmd_CMD_MEASUREMENT_REQUEST:
+ ret = wlan_meas_cmd_request(pmpriv, pcmd_ptr, pinfo_buf);
+ break;
+ case HostCmd_CMD_MEASUREMENT_REPORT:
+ ret = wlan_meas_cmd_get_report(pmpriv, pcmd_ptr);
+ break;
+ default:
+ ret = MLAN_STATUS_FAILURE;
+ }
+
+ pcmd_ptr->command = wlan_cpu_to_le16(pcmd_ptr->command);
+ pcmd_ptr->size = wlan_cpu_to_le16(pcmd_ptr->size);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Handle the command response from the firmware for a measurement
+ * command
+ *
+ * Use the Command field to determine if the command response being
+ * is for meas. Call the local command response handler accordingly for:
+ *
+ * - HostCmd_CMD_802_MEASUREMENT_REQUEST
+ * - HostCmd_CMD_802_MEASUREMENT_REPORT
+ *
+ * @param pmpriv Private driver information structure
+ * @param resp HostCmd_DS_COMMAND struct returned from the firmware command
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+int
+wlan_meas_cmdresp_process(mlan_private * pmpriv,
+ const HostCmd_DS_COMMAND * resp)
+{
+ int ret = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+ switch (resp->command) {
+ case HostCmd_CMD_MEASUREMENT_REQUEST:
+ PRINTM(MINFO, "Meas: Req Resp: Sz=%u, Seq=%u, Ret=%u\n",
+ resp->size, resp->seq_num, resp->result);
+ break;
+ case HostCmd_CMD_MEASUREMENT_REPORT:
+ ret = wlan_meas_cmdresp_get_report(pmpriv, resp);
+ break;
+ default:
+ ret = MLAN_STATUS_FAILURE;
+ }
+
+ LEAVE();
+ return ret;
+}
diff --git a/drivers/net/wireless/sd8797/mlan/mlan_meas.h b/drivers/net/wireless/sd8797/mlan/mlan_meas.h
new file mode 100644
index 000000000000..0eb51d3a3bb2
--- /dev/null
+++ b/drivers/net/wireless/sd8797/mlan/mlan_meas.h
@@ -0,0 +1,54 @@
+/**
+ * @file mlan_meas.h
+ *
+ * @brief Interface for the measurement module implemented in mlan_meas.c
+ *
+ * Driver interface functions and type declarations for the measurement module
+ * implemented in mlan_meas.c
+ *
+ * @sa mlan_meas.c
+ *
+ * Copyright (C) 2008-2011, Marvell International Ltd.
+ *
+ * This software file (the "File") is distributed by Marvell International
+ * Ltd. under the terms of the GNU General Public License Version 2, June 1991
+ * (the "License"). You may use, redistribute and/or modify this File in
+ * accordance with the terms and conditions of the License, a copy of which
+ * is available by writing to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
+ * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
+ *
+ * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
+ * ARE EXPRESSLY DISCLAIMED. The License provides additional details about
+ * this warranty disclaimer.
+ *
+ */
+
+/*************************************************************
+Change Log:
+ 03/25/2009: initial version
+************************************************************/
+
+#ifndef _MLAN_MEAS_H_
+#define _MLAN_MEAS_H_
+
+#include "mlan_fw.h"
+
+/* Send a given measurement request to the firmware, report back the result */
+extern int
+wlan_meas_util_send_req(mlan_private * pmpriv,
+ HostCmd_DS_MEASUREMENT_REQUEST * pmeas_req,
+ t_u32 wait_for_resp_timeout, pmlan_ioctl_req pioctl_req,
+ HostCmd_DS_MEASUREMENT_REPORT * pmeas_rpt);
+
+/* Setup a measurement command before it is sent to the firmware */
+extern int wlan_meas_cmd_process(mlan_private * pmpriv,
+ HostCmd_DS_COMMAND * pcmd_ptr,
+ const t_void * pinfo_buf);
+
+/* Handle a given measurement command response from the firmware */
+extern int wlan_meas_cmdresp_process(mlan_private * pmpriv,
+ const HostCmd_DS_COMMAND * resp);
+
+#endif /* _MLAN_MEAS_H_ */
diff --git a/drivers/net/wireless/sd8797/mlan/mlan_misc.c b/drivers/net/wireless/sd8797/mlan/mlan_misc.c
new file mode 100644
index 000000000000..4054950f58f0
--- /dev/null
+++ b/drivers/net/wireless/sd8797/mlan/mlan_misc.c
@@ -0,0 +1,2153 @@
+/**
+ * @file mlan_misc.c
+ *
+ * @brief This file include miscellaneous functions for MLAN module
+ *
+ * Copyright (C) 2009-2011, Marvell International Ltd.
+ *
+ * This software file (the "File") is distributed by Marvell International
+ * Ltd. under the terms of the GNU General Public License Version 2, June 1991
+ * (the "License"). You may use, redistribute and/or modify this File in
+ * accordance with the terms and conditions of the License, a copy of which
+ * is available by writing to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
+ * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
+ *
+ * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
+ * ARE EXPRESSLY DISCLAIMED. The License provides additional details about
+ * this warranty disclaimer.
+ */
+
+/*************************************************************
+Change Log:
+ 05/11/2009: initial version
+************************************************************/
+#include "mlan.h"
+#ifdef STA_SUPPORT
+#include "mlan_join.h"
+#endif /* STA_SUPPORT */
+#include "mlan_util.h"
+#include "mlan_fw.h"
+#include "mlan_main.h"
+#include "mlan_wmm.h"
+#include "mlan_11n.h"
+#include "mlan_sdio.h"
+#ifdef UAP_SUPPORT
+#include "mlan_uap.h"
+#endif
+
+/********************************************************
+ Local Variables
+********************************************************/
+
+/********************************************************
+ Global Variables
+********************************************************/
+#if defined(STA_SUPPORT) && defined(UAP_SUPPORT)
+extern mlan_operations *mlan_ops[];
+#endif
+extern t_u8 ac_to_tid[4][2];
+
+/********************************************************
+ Local Functions
+********************************************************/
+
+/** Custom IE auto index and mask */
+#define MLAN_CUSTOM_IE_AUTO_IDX_MASK 0xffff
+/** Custom IE mask for delete operation */
+#define MLAN_CUSTOM_IE_DELETE_MASK 0
+/** Custom IE header size */
+#define MLAN_CUSTOM_IE_HDR_SIZE (sizeof(custom_ie)-MAX_IE_SIZE)
+
+/**
+ * @brief Check if current custom IE index is used on other interfaces.
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param idx index to check for in use
+ *
+ * @return MLAN_STATUS_SUCCESS --unused, otherwise used.
+ */
+static mlan_status
+wlan_is_custom_ie_index_unused(IN pmlan_private pmpriv, IN t_u16 idx)
+{
+ t_u8 i = 0;
+ pmlan_adapter pmadapter = pmpriv->adapter;
+ pmlan_private priv;
+ ENTER();
+
+ for (i = 0; i < pmadapter->priv_num; i++) {
+ priv = pmadapter->priv[i];
+ /* Check for other interfaces only */
+ if (priv && priv->bss_index != pmpriv->bss_index) {
+
+ if (priv->mgmt_ie[idx].mgmt_subtype_mask &&
+ priv->mgmt_ie[idx].ie_length) {
+ /* used entry found */
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+ }
+ }
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief Get the custom IE index
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ * @param mask mask value for which the index to be returned
+ * @param ie_data a pointer to custom_ie structure
+ * @param idx will hold the computed index
+ *
+ * @return MLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static mlan_status
+wlan_custom_ioctl_get_autoidx(IN pmlan_private pmpriv,
+ IN pmlan_ioctl_req pioctl_req,
+ IN t_u16 mask,
+ IN custom_ie * ie_data, OUT t_u16 * idx)
+{
+ t_u16 index = 0, insert = MFALSE;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+ /* Determine the index where the IE needs to be inserted */
+ while (!insert) {
+ while (index < pmpriv->adapter->max_mgmt_ie_index) {
+ if (pmpriv->mgmt_ie[index].mgmt_subtype_mask ==
+ MLAN_CUSTOM_IE_AUTO_IDX_MASK) {
+ index++;
+ continue;
+ }
+ if (pmpriv->mgmt_ie[index].mgmt_subtype_mask == mask) {
+ /* Duplicate IE should be avoided */
+ if (pmpriv->mgmt_ie[index].ie_length) {
+ if (!memcmp
+ (pmpriv->adapter, pmpriv->mgmt_ie[index].ie_buffer,
+ ie_data->ie_buffer,
+ pmpriv->mgmt_ie[index].ie_length)) {
+ PRINTM(MERROR,
+ "IE with the same mask exists at index %d\n",
+ index);
+ *idx = MLAN_CUSTOM_IE_AUTO_IDX_MASK;
+ goto done;
+ }
+ }
+ /* Check if enough space is available */
+ if (pmpriv->mgmt_ie[index].ie_length + ie_data->ie_length >
+ MAX_IE_SIZE) {
+ index++;
+ continue;
+ }
+ insert = MTRUE;
+ break;
+ }
+ index++;
+ }
+ if (!insert) {
+ for (index = 0; index < pmpriv->adapter->max_mgmt_ie_index; index++) {
+ if (pmpriv->mgmt_ie[index].ie_length == 0) {
+ /*
+ * Check if this index is in use by other interface
+ * If yes, move ahead to next index
+ */
+ if (MLAN_STATUS_SUCCESS ==
+ wlan_is_custom_ie_index_unused(pmpriv, index)) {
+ insert = MTRUE;
+ break;
+ } else {
+ PRINTM(MINFO, "Skipping IE index %d in use.\n", index);
+ }
+ }
+ }
+ }
+ if (index == pmpriv->adapter->max_mgmt_ie_index && !insert) {
+ PRINTM(MERROR, "Failed to Set the IE buffer\n");
+ if (pioctl_req)
+ pioctl_req->status_code = MLAN_ERROR_IOCTL_FAIL;
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ }
+
+ *idx = index;
+ done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Delete custom IE
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ * @param ie_data a pointer to custom_ie structure
+ * @param idx index supplied
+ *
+ * @return MLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+
+static mlan_status
+wlan_custom_ioctl_auto_delete(IN pmlan_private pmpriv,
+ IN pmlan_ioctl_req pioctl_req,
+ IN custom_ie * ie_data, IN t_u16 idx)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ pmlan_adapter pmadapter = pmpriv->adapter;
+ t_u16 index = 0, insert = MFALSE, del_len;
+ t_u8 del_ie[MAX_IE_SIZE], ie[MAX_IE_SIZE];
+ t_s32 cnt, tmp_len = 0;
+ t_u8 *tmp_ie;
+
+ ENTER();
+ memset(pmpriv->adapter, del_ie, 0, MAX_IE_SIZE);
+ memcpy(pmpriv->adapter, del_ie, ie_data->ie_buffer,
+ MIN(MAX_IE_SIZE, ie_data->ie_length));
+ del_len = MIN(MAX_IE_SIZE, ie_data->ie_length);
+
+ for (index = 0; index < pmadapter->max_mgmt_ie_index; index++) {
+ if (MLAN_CUSTOM_IE_AUTO_IDX_MASK != idx)
+ index = idx;
+ tmp_ie = pmpriv->mgmt_ie[index].ie_buffer;
+ tmp_len = pmpriv->mgmt_ie[index].ie_length;
+ cnt = 0;
+ while (tmp_len) {
+ if (!memcmp(pmpriv->adapter, tmp_ie, del_ie, del_len)) {
+ memcpy(pmpriv->adapter, ie, pmpriv->mgmt_ie[index].ie_buffer,
+ cnt);
+ if (pmpriv->mgmt_ie[index].ie_length > (cnt + del_len))
+ memcpy(pmpriv->adapter, &ie[cnt],
+ &pmpriv->mgmt_ie[index].ie_buffer[cnt + del_len],
+ (pmpriv->mgmt_ie[index].ie_length -
+ (cnt + del_len)));
+ memset(pmpriv->adapter, &pmpriv->mgmt_ie[index].ie_buffer, 0,
+ sizeof(pmpriv->mgmt_ie[index].ie_buffer));
+ memcpy(pmpriv->adapter, &pmpriv->mgmt_ie[index].ie_buffer, ie,
+ pmpriv->mgmt_ie[index].ie_length - del_len);
+ pmpriv->mgmt_ie[index].ie_length -= del_len;
+ insert = MTRUE;
+ tmp_ie = pmpriv->mgmt_ie[index].ie_buffer;
+ tmp_len = pmpriv->mgmt_ie[index].ie_length;
+ cnt = 0;
+ continue;
+ }
+ tmp_ie++;
+ tmp_len--;
+ cnt++;
+ }
+ if (MLAN_CUSTOM_IE_AUTO_IDX_MASK != idx)
+ break;
+ }
+ if (index == pmadapter->max_mgmt_ie_index && !insert) {
+ PRINTM(MERROR, "Failed to Clear IE buffer\n");
+ if (pioctl_req)
+ pioctl_req->status_code = MLAN_ERROR_IOCTL_FAIL;
+ ret = MLAN_STATUS_FAILURE;
+ }
+ LEAVE();
+ return ret;
+}
+
+/********************************************************
+ Global Functions
+********************************************************/
+
+/**
+ * @brief send host cmd
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_PENDING --success, otherwise fail
+ */
+mlan_status
+wlan_misc_ioctl_host_cmd(IN pmlan_adapter pmadapter,
+ IN pmlan_ioctl_req pioctl_req)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
+ mlan_ds_misc_cfg *misc = MNULL;
+
+ ENTER();
+
+ misc = (mlan_ds_misc_cfg *) pioctl_req->pbuf;
+
+ /* Send request to firmware */
+ ret = wlan_prepare_cmd(pmpriv,
+ 0,
+ 0,
+ 0,
+ (t_void *) pioctl_req,
+ (t_void *) & misc->param.hostcmd);
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Send function init/shutdown command to firmware
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_PENDING --success, otherwise fail
+ */
+mlan_status
+wlan_misc_ioctl_init_shutdown(IN pmlan_adapter pmadapter,
+ IN pmlan_ioctl_req pioctl_req)
+{
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_ds_misc_cfg *misc_cfg = MNULL;
+ t_u16 cmd;
+
+ ENTER();
+
+ misc_cfg = (mlan_ds_misc_cfg *) pioctl_req->pbuf;
+ if (misc_cfg->param.func_init_shutdown == MLAN_FUNC_INIT)
+ cmd = HostCmd_CMD_FUNC_INIT;
+ else if (misc_cfg->param.func_init_shutdown == MLAN_FUNC_SHUTDOWN)
+ cmd = HostCmd_CMD_FUNC_SHUTDOWN;
+ else {
+ PRINTM(MERROR, "Unsupported parameter\n");
+ pioctl_req->status_code = MLAN_ERROR_INVALID_PARAMETER;
+ ret = MLAN_STATUS_FAILURE;
+ goto exit;
+ }
+
+ /* Send command to firmware */
+ ret = wlan_prepare_cmd(pmpriv,
+ cmd,
+ HostCmd_ACT_GEN_SET,
+ 0, (t_void *) pioctl_req, MNULL);
+
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+
+ exit:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Get debug information
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_SUCCESS --success
+ */
+mlan_status
+wlan_get_info_debug_info(IN pmlan_adapter pmadapter,
+ IN pmlan_ioctl_req pioctl_req)
+{
+ pmlan_private pmpriv = pmadapter->priv[pioctl_req->bss_index];
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_ds_get_info *info;
+ t_u8 *ptid;
+
+ ENTER();
+
+ info = (mlan_ds_get_info *) pioctl_req->pbuf;
+
+ if (pioctl_req->action == MLAN_ACT_SET) {
+ pmadapter->max_tx_buf_size =
+ (t_u16) info->param.debug_info.max_tx_buf_size;
+ pmadapter->tx_buf_size = (t_u16) info->param.debug_info.tx_buf_size;
+ pmadapter->curr_tx_buf_size =
+ (t_u16) info->param.debug_info.curr_tx_buf_size;
+ pmadapter->ps_mode = info->param.debug_info.ps_mode;
+ pmadapter->ps_state = info->param.debug_info.ps_state;
+#ifdef STA_SUPPORT
+ pmadapter->is_deep_sleep = info->param.debug_info.is_deep_sleep;
+#endif /* STA_SUPPORT */
+ pmadapter->pm_wakeup_card_req =
+ info->param.debug_info.pm_wakeup_card_req;
+ pmadapter->pm_wakeup_fw_try = info->param.debug_info.pm_wakeup_fw_try;
+ pmadapter->is_hs_configured = info->param.debug_info.is_hs_configured;
+ pmadapter->hs_activated = info->param.debug_info.hs_activated;
+ pmadapter->pps_uapsd_mode = info->param.debug_info.pps_uapsd_mode;
+ pmadapter->sleep_period.period = info->param.debug_info.sleep_pd;
+ pmpriv->wmm_qosinfo = info->param.debug_info.qos_cfg;
+ pmadapter->tx_lock_flag = info->param.debug_info.tx_lock_flag;
+ pmpriv->port_open = info->param.debug_info.port_open;
+ pmadapter->scan_processing = info->param.debug_info.scan_processing;
+
+ pmadapter->dbg.num_cmd_host_to_card_failure =
+ info->param.debug_info.num_cmd_host_to_card_failure;
+ pmadapter->dbg.num_cmd_sleep_cfm_host_to_card_failure =
+ info->param.debug_info.num_cmd_sleep_cfm_host_to_card_failure;
+ pmadapter->dbg.num_tx_host_to_card_failure =
+ info->param.debug_info.num_tx_host_to_card_failure;
+ pmadapter->dbg.num_cmdevt_card_to_host_failure =
+ info->param.debug_info.num_cmdevt_card_to_host_failure;
+ pmadapter->dbg.num_rx_card_to_host_failure =
+ info->param.debug_info.num_rx_card_to_host_failure;
+ pmadapter->dbg.num_int_read_failure =
+ info->param.debug_info.num_int_read_failure;
+ pmadapter->dbg.last_int_status = info->param.debug_info.last_int_status;
+ pmadapter->dbg.num_event_deauth =
+ info->param.debug_info.num_event_deauth;
+ pmadapter->dbg.num_event_disassoc =
+ info->param.debug_info.num_event_disassoc;
+ pmadapter->dbg.num_event_link_lost =
+ info->param.debug_info.num_event_link_lost;
+ pmadapter->dbg.num_cmd_deauth = info->param.debug_info.num_cmd_deauth;
+ pmadapter->dbg.num_cmd_assoc_success =
+ info->param.debug_info.num_cmd_assoc_success;
+ pmadapter->dbg.num_cmd_assoc_failure =
+ info->param.debug_info.num_cmd_assoc_failure;
+ pmadapter->dbg.num_tx_timeout = info->param.debug_info.num_tx_timeout;
+ pmadapter->dbg.num_cmd_timeout = info->param.debug_info.num_cmd_timeout;
+ pmadapter->dbg.timeout_cmd_id = info->param.debug_info.timeout_cmd_id;
+ pmadapter->dbg.timeout_cmd_act = info->param.debug_info.timeout_cmd_act;
+ memcpy(pmadapter, pmadapter->dbg.last_cmd_id,
+ info->param.debug_info.last_cmd_id,
+ sizeof(pmadapter->dbg.last_cmd_id));
+ memcpy(pmadapter, pmadapter->dbg.last_cmd_act,
+ info->param.debug_info.last_cmd_act,
+ sizeof(pmadapter->dbg.last_cmd_act));
+ pmadapter->dbg.last_cmd_index = info->param.debug_info.last_cmd_index;
+ memcpy(pmadapter, pmadapter->dbg.last_cmd_resp_id,
+ info->param.debug_info.last_cmd_resp_id,
+ sizeof(pmadapter->dbg.last_cmd_resp_id));
+ pmadapter->dbg.last_cmd_resp_index =
+ info->param.debug_info.last_cmd_resp_index;
+ memcpy(pmadapter, pmadapter->dbg.last_event,
+ info->param.debug_info.last_event,
+ sizeof(pmadapter->dbg.last_event));
+ pmadapter->dbg.last_event_index =
+ info->param.debug_info.last_event_index;
+
+ pmadapter->data_sent = info->param.debug_info.data_sent;
+ pmadapter->cmd_sent = info->param.debug_info.cmd_sent;
+ pmadapter->mp_rd_bitmap = info->param.debug_info.mp_rd_bitmap;
+ pmadapter->mp_wr_bitmap = info->param.debug_info.mp_wr_bitmap;
+ pmadapter->curr_rd_port = info->param.debug_info.curr_rd_port;
+ pmadapter->curr_wr_port = info->param.debug_info.curr_wr_port;
+ pmadapter->cmd_resp_received = info->param.debug_info.cmd_resp_received;
+#ifdef UAP_SUPPORT
+ pmadapter->pending_bridge_pkts = info->param.debug_info.num_bridge_pkts;
+ pmpriv->num_drop_pkts = info->param.debug_info.num_drop_pkts;
+#endif
+ } else { /* MLAN_ACT_GET */
+ ptid = ac_to_tid[WMM_AC_BK];
+ info->param.debug_info.wmm_ac_bk =
+ pmpriv->wmm.packets_out[ptid[0]] + pmpriv->wmm.packets_out[ptid[1]];
+ ptid = ac_to_tid[WMM_AC_BE];
+ info->param.debug_info.wmm_ac_be =
+ pmpriv->wmm.packets_out[ptid[0]] + pmpriv->wmm.packets_out[ptid[1]];
+ ptid = ac_to_tid[WMM_AC_VI];
+ info->param.debug_info.wmm_ac_vi =
+ pmpriv->wmm.packets_out[ptid[0]] + pmpriv->wmm.packets_out[ptid[1]];
+ ptid = ac_to_tid[WMM_AC_VO];
+ info->param.debug_info.wmm_ac_vo =
+ pmpriv->wmm.packets_out[ptid[0]] + pmpriv->wmm.packets_out[ptid[1]];
+ info->param.debug_info.max_tx_buf_size =
+ (t_u32) pmadapter->max_tx_buf_size;
+ info->param.debug_info.tx_buf_size = (t_u32) pmadapter->tx_buf_size;
+ info->param.debug_info.curr_tx_buf_size =
+ (t_u32) pmadapter->curr_tx_buf_size;
+ info->param.debug_info.rx_tbl_num =
+ wlan_get_rxreorder_tbl(pmpriv, info->param.debug_info.rx_tbl);
+ info->param.debug_info.tx_tbl_num =
+ wlan_get_txbastream_tbl(pmpriv, info->param.debug_info.tx_tbl);
+ info->param.debug_info.ps_mode = pmadapter->ps_mode;
+ info->param.debug_info.ps_state = pmadapter->ps_state;
+#ifdef STA_SUPPORT
+ info->param.debug_info.is_deep_sleep = pmadapter->is_deep_sleep;
+#endif /* STA_SUPPORT */
+ info->param.debug_info.pm_wakeup_card_req =
+ pmadapter->pm_wakeup_card_req;
+ info->param.debug_info.pm_wakeup_fw_try = pmadapter->pm_wakeup_fw_try;
+ info->param.debug_info.is_hs_configured = pmadapter->is_hs_configured;
+ info->param.debug_info.hs_activated = pmadapter->hs_activated;
+ info->param.debug_info.pps_uapsd_mode = pmadapter->pps_uapsd_mode;
+ info->param.debug_info.sleep_pd = pmadapter->sleep_period.period;
+ info->param.debug_info.qos_cfg = pmpriv->wmm_qosinfo;
+ info->param.debug_info.tx_lock_flag = pmadapter->tx_lock_flag;
+ info->param.debug_info.port_open = pmpriv->port_open;
+ info->param.debug_info.scan_processing = pmadapter->scan_processing;
+
+ info->param.debug_info.num_cmd_host_to_card_failure
+ = pmadapter->dbg.num_cmd_host_to_card_failure;
+ info->param.debug_info.num_cmd_sleep_cfm_host_to_card_failure
+ = pmadapter->dbg.num_cmd_sleep_cfm_host_to_card_failure;
+ info->param.debug_info.num_tx_host_to_card_failure
+ = pmadapter->dbg.num_tx_host_to_card_failure;
+ info->param.debug_info.num_cmdevt_card_to_host_failure
+ = pmadapter->dbg.num_cmdevt_card_to_host_failure;
+ info->param.debug_info.num_rx_card_to_host_failure
+ = pmadapter->dbg.num_rx_card_to_host_failure;
+ info->param.debug_info.num_int_read_failure =
+ pmadapter->dbg.num_int_read_failure;
+ info->param.debug_info.last_int_status = pmadapter->dbg.last_int_status;
+ info->param.debug_info.num_event_deauth =
+ pmadapter->dbg.num_event_deauth;
+ info->param.debug_info.num_event_disassoc =
+ pmadapter->dbg.num_event_disassoc;
+ info->param.debug_info.num_event_link_lost =
+ pmadapter->dbg.num_event_link_lost;
+ info->param.debug_info.num_cmd_deauth = pmadapter->dbg.num_cmd_deauth;
+ info->param.debug_info.num_cmd_assoc_success =
+ pmadapter->dbg.num_cmd_assoc_success;
+ info->param.debug_info.num_cmd_assoc_failure =
+ pmadapter->dbg.num_cmd_assoc_failure;
+ info->param.debug_info.num_tx_timeout = pmadapter->dbg.num_tx_timeout;
+ info->param.debug_info.num_cmd_timeout = pmadapter->dbg.num_cmd_timeout;
+ info->param.debug_info.timeout_cmd_id = pmadapter->dbg.timeout_cmd_id;
+ info->param.debug_info.timeout_cmd_act = pmadapter->dbg.timeout_cmd_act;
+ memcpy(pmadapter, info->param.debug_info.last_cmd_id,
+ pmadapter->dbg.last_cmd_id, sizeof(pmadapter->dbg.last_cmd_id));
+ memcpy(pmadapter, info->param.debug_info.last_cmd_act,
+ pmadapter->dbg.last_cmd_act,
+ sizeof(pmadapter->dbg.last_cmd_act));
+ info->param.debug_info.last_cmd_index = pmadapter->dbg.last_cmd_index;
+ memcpy(pmadapter, info->param.debug_info.last_cmd_resp_id,
+ pmadapter->dbg.last_cmd_resp_id,
+ sizeof(pmadapter->dbg.last_cmd_resp_id));
+ info->param.debug_info.last_cmd_resp_index =
+ pmadapter->dbg.last_cmd_resp_index;
+ memcpy(pmadapter, info->param.debug_info.last_event,
+ pmadapter->dbg.last_event, sizeof(pmadapter->dbg.last_event));
+ info->param.debug_info.last_event_index =
+ pmadapter->dbg.last_event_index;
+
+ info->param.debug_info.mp_rd_bitmap = pmadapter->mp_rd_bitmap;
+ info->param.debug_info.mp_wr_bitmap = pmadapter->mp_wr_bitmap;
+ info->param.debug_info.curr_rd_port = pmadapter->curr_rd_port;
+ info->param.debug_info.curr_wr_port = pmadapter->curr_wr_port;
+ info->param.debug_info.data_sent = pmadapter->data_sent;
+ info->param.debug_info.cmd_sent = pmadapter->cmd_sent;
+ info->param.debug_info.cmd_resp_received = pmadapter->cmd_resp_received;
+ info->param.debug_info.tx_pkts_queued =
+ util_scalar_read(pmadapter->pmoal_handle,
+ &pmpriv->wmm.tx_pkts_queued, MNULL, MNULL);
+#ifdef UAP_SUPPORT
+ info->param.debug_info.num_bridge_pkts = pmadapter->pending_bridge_pkts;
+ info->param.debug_info.num_drop_pkts = pmpriv->num_drop_pkts;
+#endif
+ }
+
+ pioctl_req->data_read_written =
+ sizeof(mlan_debug_info) + MLAN_SUB_COMMAND_SIZE;
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function wakes up the card.
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status
+wlan_pm_wakeup_card(IN pmlan_adapter pmadapter)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ pmlan_callbacks pcb = &pmadapter->callbacks;
+
+ ENTER();
+ PRINTM(MEVENT, "Wakeup device...\n");
+ ret =
+ pcb->moal_write_reg(pmadapter->pmoal_handle, HOST_TO_CARD_EVENT_REG,
+ HOST_POWER_UP);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function resets the PM setting of the card.
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status
+wlan_pm_reset_card(IN pmlan_adapter pmadapter)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ pmlan_callbacks pcb = &pmadapter->callbacks;
+
+ ENTER();
+
+ ret =
+ pcb->moal_write_reg(pmadapter->pmoal_handle, HOST_TO_CARD_EVENT_REG, 0);
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set/Get HS configuration
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING --success, otherwise fail
+ */
+mlan_status
+wlan_pm_ioctl_hscfg(IN pmlan_adapter pmadapter, IN pmlan_ioctl_req pioctl_req)
+{
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
+ mlan_ds_pm_cfg *pm = MNULL;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+ t_u32 prev_cond = 0;
+
+ ENTER();
+
+ pm = (mlan_ds_pm_cfg *) pioctl_req->pbuf;
+
+ switch (pioctl_req->action) {
+ case MLAN_ACT_SET:
+#ifdef STA_SUPPORT
+ if (pmadapter->pps_uapsd_mode) {
+ PRINTM(MINFO, "Host Sleep IOCTL is blocked in UAPSD/PPS mode\n");
+ pioctl_req->status_code = MLAN_ERROR_IOCTL_INVALID;
+ status = MLAN_STATUS_FAILURE;
+ break;
+ }
+#endif /* STA_SUPPORT */
+ if (pm->param.hs_cfg.is_invoke_hostcmd == MTRUE) {
+ if (pm->param.hs_cfg.conditions == HOST_SLEEP_CFG_CANCEL) {
+ if (pmadapter->is_hs_configured == MFALSE) {
+ /* Already cancelled */
+ break;
+ }
+ /* Save previous condition */
+ prev_cond = pmadapter->hs_cfg.conditions;
+ pmadapter->hs_cfg.conditions = pm->param.hs_cfg.conditions;
+ } else if (pmadapter->hs_cfg.conditions == HOST_SLEEP_CFG_CANCEL) {
+ /* Return failure if no parameters for HS enable */
+ pioctl_req->status_code = MLAN_ERROR_INVALID_PARAMETER;
+ status = MLAN_STATUS_FAILURE;
+ break;
+ }
+ status = wlan_prepare_cmd(pmpriv,
+ HostCmd_CMD_802_11_HS_CFG_ENH,
+ HostCmd_ACT_GEN_SET,
+ 0, (t_void *) pioctl_req,
+ (t_void *) (&pmadapter->hs_cfg));
+ if (status == MLAN_STATUS_SUCCESS)
+ status = MLAN_STATUS_PENDING;
+ if (pm->param.hs_cfg.conditions == HOST_SLEEP_CFG_CANCEL) {
+ /* Restore previous condition */
+ pmadapter->hs_cfg.conditions = prev_cond;
+ }
+ } else {
+ pmadapter->hs_cfg.conditions = pm->param.hs_cfg.conditions;
+ pmadapter->hs_cfg.gpio = (t_u8) pm->param.hs_cfg.gpio;
+ pmadapter->hs_cfg.gap = (t_u8) pm->param.hs_cfg.gap;
+ }
+ break;
+ case MLAN_ACT_GET:
+ pm->param.hs_cfg.conditions = pmadapter->hs_cfg.conditions;
+ pm->param.hs_cfg.gpio = pmadapter->hs_cfg.gpio;
+ pm->param.hs_cfg.gap = pmadapter->hs_cfg.gap;
+ break;
+ default:
+ pioctl_req->status_code = MLAN_ERROR_IOCTL_INVALID;
+ status = MLAN_STATUS_FAILURE;
+ break;
+ }
+
+ LEAVE();
+ return status;
+}
+
+/**
+ * @brief This function allocates a mlan_buffer.
+ *
+ * @param pmadapter Pointer to mlan_adapter
+ * @param data_len Data length
+ * @param head_room head_room reserved in mlan_buffer
+ * @param malloc_flag flag to user moal_malloc
+ * @return mlan_buffer pointer or MNULL
+ */
+pmlan_buffer
+wlan_alloc_mlan_buffer(mlan_adapter * pmadapter, t_u32 data_len,
+ t_u32 head_room, t_u32 malloc_flag)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ pmlan_buffer pmbuf = MNULL;
+ t_u32 buf_size = 0;
+ t_u8 *tmp_buf = MNULL;
+ pmlan_callbacks pcb = &pmadapter->callbacks;
+
+ ENTER();
+
+ /* make sure that the data length is at least SDIO block size */
+ data_len = ALIGN_SZ(data_len, MLAN_SDIO_BLOCK_SIZE);
+
+ /* head_room is not implemented for malloc mlan buffer */
+ if (malloc_flag == MTRUE) {
+ buf_size = sizeof(mlan_buffer) + data_len + DMA_ALIGNMENT;
+ ret =
+ pcb->moal_malloc(pmadapter->pmoal_handle, buf_size,
+ MLAN_MEM_DEF | MLAN_MEM_DMA, (t_u8 **) & pmbuf);
+ if ((ret != MLAN_STATUS_SUCCESS) || !pmbuf) {
+ pmbuf = MNULL;
+ goto exit;
+ }
+ memset(pmadapter, pmbuf, 0, sizeof(mlan_buffer));
+
+ pmbuf->pdesc = MNULL;
+ /* Align address */
+ pmbuf->pbuf =
+ (t_u8 *) ALIGN_ADDR((t_u8 *) pmbuf + sizeof(mlan_buffer),
+ DMA_ALIGNMENT);
+ pmbuf->data_offset = 0;
+ pmbuf->data_len = data_len;
+ pmbuf->flags |= MLAN_BUF_FLAG_MALLOC_BUF;
+ } else {
+ /* use moal_alloc_mlan_buffer, head_room supported */
+ ret = pcb->moal_alloc_mlan_buffer(pmadapter->pmoal_handle,
+ data_len + DMA_ALIGNMENT + head_room,
+ &pmbuf);
+ if ((ret != MLAN_STATUS_SUCCESS) || !pmbuf) {
+ PRINTM(MERROR, "Failed to allocate 'mlan_buffer'\n");
+ goto exit;
+ }
+ pmbuf->data_offset = head_room;
+ tmp_buf =
+ (t_u8 *) ALIGN_ADDR(pmbuf->pbuf + pmbuf->data_offset,
+ DMA_ALIGNMENT);
+ pmbuf->data_offset +=
+ (t_u32) (tmp_buf - (pmbuf->pbuf + pmbuf->data_offset));
+ pmbuf->data_len = data_len;
+ pmbuf->flags = 0;
+ }
+ exit:
+ LEAVE();
+ return pmbuf;
+}
+
+/**
+ * @brief This function frees a mlan_buffer.
+ *
+ * @param pmadapter Pointer to mlan_adapter
+ * @param pmbuf Pointer to mlan_buffer
+ *
+ * @return N/A
+ */
+t_void
+wlan_free_mlan_buffer(mlan_adapter * pmadapter, pmlan_buffer pmbuf)
+{
+ pmlan_callbacks pcb = &pmadapter->callbacks;
+ ENTER();
+
+ if (pcb && pmbuf) {
+ if (pmbuf->flags & MLAN_BUF_FLAG_MALLOC_BUF)
+ pcb->moal_mfree(pmadapter->pmoal_handle, (t_u8 *) pmbuf);
+ else
+ pcb->moal_free_mlan_buffer(pmadapter->pmoal_handle, pmbuf);
+ }
+
+ LEAVE();
+ return;
+}
+
+/**
+ * @brief Delay function implementation
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param delay Delay value
+ * @param u Units of delay (sec, msec or usec)
+ *
+ * @return N/A
+ */
+t_void
+wlan_delay_func(mlan_adapter * pmadapter, t_u32 delay, t_delay_unit u)
+{
+ t_u32 now_tv_sec, now_tv_usec;
+ t_u32 upto_tv_sec, upto_tv_usec;
+ pmlan_callbacks pcb = &pmadapter->callbacks;
+
+ ENTER();
+
+ if (pcb->moal_udelay) {
+ if (u == SEC) {
+ delay *= 1000000;
+ } else if (u == MSEC) {
+ delay *= 1000;
+ }
+ pcb->moal_udelay(pmadapter->pmoal_handle, delay);
+ } else {
+
+ pcb->moal_get_system_time(pmadapter->pmoal_handle, &upto_tv_sec,
+ &upto_tv_usec);
+
+ switch (u) {
+ case SEC:
+ upto_tv_sec += delay;
+ break;
+ case MSEC:
+ delay *= 1000;
+ case USEC:
+ upto_tv_sec += (delay / 1000000);
+ upto_tv_usec += (delay % 1000000);
+ break;
+ }
+
+ do {
+ pcb->moal_get_system_time(pmadapter->pmoal_handle, &now_tv_sec,
+ &now_tv_usec);
+ if (now_tv_sec > upto_tv_sec) {
+ LEAVE();
+ return;
+ }
+
+ if ((now_tv_sec == upto_tv_sec) && (now_tv_usec >= upto_tv_usec)) {
+ LEAVE();
+ return;
+ }
+ } while (MTRUE);
+ }
+
+ LEAVE();
+ return;
+}
+
+#if defined(STA_SUPPORT) && defined(UAP_SUPPORT)
+/**
+ * @brief Set/Get BSS role
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_SUCCESS --success, MLAN_STATUS_PENDING --pending
+ */
+mlan_status
+wlan_bss_ioctl_bss_role(IN pmlan_adapter pmadapter,
+ IN pmlan_ioctl_req pioctl_req)
+{
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
+ mlan_ds_bss *bss = MNULL;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ HostCmd_DS_VERSION_EXT dummy;
+#if defined(WIFI_DIRECT_SUPPORT)
+ t_u8 bss_mode;
+#endif
+ t_u8 i, global_band = 0;
+ int j;
+
+ ENTER();
+
+ bss = (mlan_ds_bss *) pioctl_req->pbuf;
+ if (pioctl_req->action == MLAN_ACT_GET) {
+ bss->param.bss_role = GET_BSS_ROLE(pmpriv);
+ } else {
+ /** Switch BSS role */
+ wlan_free_priv(pmpriv);
+
+ pmpriv->bss_role = bss->param.bss_role;
+ if (pmpriv->bss_type == MLAN_BSS_TYPE_UAP)
+ pmpriv->bss_type = MLAN_BSS_TYPE_STA;
+ else if (pmpriv->bss_type == MLAN_BSS_TYPE_STA)
+ pmpriv->bss_type = MLAN_BSS_TYPE_UAP;
+
+ /* Initialize private structures */
+ wlan_init_priv(pmpriv);
+
+ /* Initialize function table */
+ for (j = 0; mlan_ops[j]; j++) {
+ if (mlan_ops[j]->bss_role == GET_BSS_ROLE(pmpriv)) {
+ memcpy(pmadapter, &pmpriv->ops, mlan_ops[j],
+ sizeof(mlan_operations));
+ }
+ }
+
+ for (i = 0; i < pmadapter->priv_num; i++) {
+ if (pmadapter->priv[i] &&
+ GET_BSS_ROLE(pmadapter->priv[i]) == MLAN_BSS_ROLE_STA)
+ global_band |= pmadapter->priv[i]->config_bands;
+ }
+
+ if (global_band != pmadapter->config_bands) {
+ if (wlan_set_regiontable(pmpriv, (t_u8) pmadapter->region_code,
+ global_band | pmadapter->
+ adhoc_start_band)) {
+ pioctl_req->status_code = MLAN_ERROR_IOCTL_FAIL;
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+
+ if (wlan_11d_set_universaltable
+ (pmpriv, global_band | pmadapter->adhoc_start_band)) {
+ pioctl_req->status_code = MLAN_ERROR_IOCTL_FAIL;
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+ pmadapter->config_bands = global_band;
+ }
+
+ /* Issue commands to initialize firmware */
+#if defined(WIFI_DIRECT_SUPPORT)
+ if (GET_BSS_ROLE(pmpriv) == MLAN_BSS_ROLE_STA)
+ bss_mode = BSS_MODE_WIFIDIRECT_CLIENT;
+ else
+ bss_mode = BSS_MODE_WIFIDIRECT_GO;
+ wlan_prepare_cmd(pmpriv, HostCmd_CMD_SET_BSS_MODE,
+ HostCmd_ACT_GEN_SET, 0, MNULL, &bss_mode);
+#endif
+ pmpriv->ops.init_cmd(pmpriv, MFALSE);
+
+ /* Issue dummy Get command to complete the ioctl */
+ memset(pmadapter, &dummy, 0, sizeof(HostCmd_DS_VERSION_EXT));
+ wlan_prepare_cmd(pmpriv, HostCmd_CMD_VERSION_EXT, HostCmd_ACT_GEN_GET,
+ 0, (t_void *) pioctl_req, (t_void *) & dummy);
+ ret = MLAN_STATUS_PENDING;
+ }
+
+ LEAVE();
+ return ret;
+}
+#endif
+
+/**
+ * @brief Set the custom IE
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ * @param send_ioctl Flag to indicate if ioctl should be sent with cmd
+ * (MTRUE if from moal/user, MFALSE if internal)
+ *
+ * @return MLAN_STATUS_PENDING --success, otherwise fail
+ */
+mlan_status
+wlan_misc_ioctl_custom_ie_list(IN pmlan_adapter pmadapter,
+ IN pmlan_ioctl_req pioctl_req,
+ IN t_bool send_ioctl)
+{
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_ds_misc_cfg *misc = (mlan_ds_misc_cfg *) pioctl_req->pbuf;
+ custom_ie *ie_data = MNULL;
+ t_u16 cmd_action = 0, index, mask, i, len, app_data_len, ioctl_len;
+ t_u8 *tmp_ie;
+
+ ENTER();
+
+ if ((misc->param.cust_ie.len == 0) ||
+ (misc->param.cust_ie.len == sizeof(t_u16))) {
+ pioctl_req->action = MLAN_ACT_GET;
+ /* Get the IE */
+ cmd_action = HostCmd_ACT_GEN_GET;
+ } else {
+ /* ioctl_len : ioctl length from application, start with
+ misc->param.cust_ie.len and reach upto 0 */
+ ioctl_len = misc->param.cust_ie.len;
+
+ /* app_data_len : length from application, start with 0 and reach upto
+ ioctl_len */
+ app_data_len = sizeof(MrvlIEtypesHeader_t);
+ misc->param.cust_ie.len = 0;
+
+ while (ioctl_len > 0) {
+ ie_data = (custom_ie *) (((t_u8 *) & misc->param.cust_ie)
+ + app_data_len);
+ ioctl_len -= (ie_data->ie_length + MLAN_CUSTOM_IE_HDR_SIZE);
+ app_data_len += (ie_data->ie_length + MLAN_CUSTOM_IE_HDR_SIZE);
+
+ index = ie_data->ie_index;
+ mask = ie_data->mgmt_subtype_mask;
+ if (MLAN_CUSTOM_IE_AUTO_IDX_MASK == index) { /* Need to be
+ Autohandled */
+ if (mask == MLAN_CUSTOM_IE_DELETE_MASK) { /* Automatic
+ Deletion */
+ ret =
+ wlan_custom_ioctl_auto_delete(pmpriv, pioctl_req,
+ ie_data, index);
+ /* if IE to delete is not found, return error */
+ if (ret == MLAN_STATUS_FAILURE) {
+ goto done;
+ }
+ memset(pmadapter, ie_data, 0,
+ sizeof(custom_ie) * MAX_MGMT_IE_INDEX);
+ len = 0;
+ for (i = 0; i < pmadapter->max_mgmt_ie_index; i++) {
+ memcpy(pmadapter, (t_u8 *) ie_data + len, &i,
+ sizeof(ie_data->ie_index));
+ len += sizeof(ie_data->ie_index);
+ memcpy(pmadapter, (t_u8 *) ie_data + len,
+ &pmpriv->mgmt_ie[i].mgmt_subtype_mask,
+ sizeof(ie_data->mgmt_subtype_mask));
+ len += sizeof(ie_data->mgmt_subtype_mask);
+ memcpy(pmadapter, (t_u8 *) ie_data + len,
+ &pmpriv->mgmt_ie[i].ie_length,
+ sizeof(ie_data->ie_length));
+ len += sizeof(ie_data->ie_length);
+ if (pmpriv->mgmt_ie[i].ie_length) {
+ memcpy(pmadapter, (t_u8 *) ie_data + len,
+ &pmpriv->mgmt_ie[i].ie_buffer,
+ pmpriv->mgmt_ie[i].ie_length);
+ len += pmpriv->mgmt_ie[i].ie_length;
+ }
+ }
+ misc->param.cust_ie.len += len;
+ pioctl_req->action = MLAN_ACT_SET;
+ cmd_action = HostCmd_ACT_GEN_SET;
+ } else { /* Automatic Addition */
+ if (MLAN_STATUS_FAILURE ==
+ wlan_custom_ioctl_get_autoidx(pmpriv, pioctl_req, mask,
+ ie_data, &index)) {
+ PRINTM(MERROR, "Failed to Set the IE buffer\n");
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ if (MLAN_CUSTOM_IE_AUTO_IDX_MASK == index) {
+ ret = MLAN_STATUS_SUCCESS;
+ goto done;
+ }
+ tmp_ie = (t_u8 *) & pmpriv->mgmt_ie[index].ie_buffer;
+ memcpy(pmadapter, tmp_ie + pmpriv->mgmt_ie[index].ie_length,
+ &ie_data->ie_buffer, ie_data->ie_length);
+ pmpriv->mgmt_ie[index].ie_length += ie_data->ie_length;
+ pmpriv->mgmt_ie[index].ie_index = index;
+ pmpriv->mgmt_ie[index].mgmt_subtype_mask = mask;
+
+ pioctl_req->action = MLAN_ACT_SET;
+ cmd_action = HostCmd_ACT_GEN_SET;
+ ie_data->ie_index = index;
+ ie_data->ie_length = pmpriv->mgmt_ie[index].ie_length;
+ memcpy(pmadapter, &ie_data->ie_buffer,
+ &pmpriv->mgmt_ie[index].ie_buffer,
+ pmpriv->mgmt_ie[index].ie_length);
+ misc->param.cust_ie.len +=
+ pmpriv->mgmt_ie[index].ie_length +
+ MLAN_CUSTOM_IE_HDR_SIZE;
+ }
+ } else {
+ if (index >= pmadapter->max_mgmt_ie_index) {
+ PRINTM(MERROR, "Invalid custom IE index %d\n", index);
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ /* Set/Clear the IE and save it */
+ if (ie_data->mgmt_subtype_mask == MLAN_CUSTOM_IE_DELETE_MASK &&
+ ie_data->ie_length) {
+ PRINTM(MINFO, "Clear the IE buffer\n");
+ ret =
+ wlan_custom_ioctl_auto_delete(pmpriv, pioctl_req,
+ ie_data, index);
+ /* if IE to delete is not found, return error */
+ if (ret == MLAN_STATUS_FAILURE) {
+ goto done;
+ }
+ memset(pmadapter, ie_data, 0,
+ sizeof(custom_ie) * MAX_MGMT_IE_INDEX);
+ memcpy(pmadapter, (t_u8 *) ie_data, &pmpriv->mgmt_ie[index],
+ pmpriv->mgmt_ie[index].ie_length +
+ MLAN_CUSTOM_IE_HDR_SIZE);
+ } else {
+ /*
+ * Check if this index is being used on any other
+ * interfaces. If yes, then the request needs to be rejected.
+ */
+ ret = wlan_is_custom_ie_index_unused(pmpriv, index);
+ if (ret == MLAN_STATUS_FAILURE) {
+ PRINTM(MERROR,
+ "IE index is used by other interface.\n");
+ PRINTM(MERROR,
+ "Set or delete on index %d is not allowed.\n",
+ index);
+ pioctl_req->status_code = MLAN_ERROR_IOCTL_FAIL;
+ goto done;
+ }
+ PRINTM(MINFO, "Set the IE buffer\n");
+ if (ie_data->mgmt_subtype_mask ==
+ MLAN_CUSTOM_IE_DELETE_MASK)
+ ie_data->ie_length = 0;
+ else {
+ if ((pmpriv->mgmt_ie[index].ie_length ==
+ ie_data->ie_length) &&
+ !memcmp(pmpriv->adapter,
+ pmpriv->mgmt_ie[index].ie_buffer,
+ ie_data->ie_buffer,
+ pmpriv->mgmt_ie[index].ie_length)) {
+ PRINTM(MIOCTL,
+ "same customer ie already configured!\n");
+ goto done;
+ }
+ }
+ memset(pmadapter, &pmpriv->mgmt_ie[index], 0,
+ sizeof(custom_ie));
+ memcpy(pmadapter, &pmpriv->mgmt_ie[index], ie_data,
+ sizeof(custom_ie));
+ }
+
+ misc->param.cust_ie.len += pmpriv->mgmt_ie[index].ie_length +
+ MLAN_CUSTOM_IE_HDR_SIZE;
+ pioctl_req->action = MLAN_ACT_SET;
+ cmd_action = HostCmd_ACT_GEN_SET;
+ }
+ }
+ }
+
+ /* Send command to firmware */
+ if (GET_BSS_ROLE(pmpriv) == MLAN_BSS_ROLE_STA) {
+ ret = wlan_prepare_cmd(pmpriv,
+ HostCmd_CMD_MGMT_IE_LIST,
+ cmd_action,
+ 0,
+ (send_ioctl) ? (t_void *) pioctl_req : MNULL,
+ &misc->param.cust_ie);
+ }
+#ifdef UAP_SUPPORT
+ else if (GET_BSS_ROLE(pmpriv) == MLAN_BSS_ROLE_UAP) {
+ ret = wlan_prepare_cmd(pmpriv,
+ HOST_CMD_APCMD_SYS_CONFIGURE,
+ cmd_action,
+ 0,
+ (send_ioctl) ? (t_void *) pioctl_req : MNULL,
+ (send_ioctl) ? MNULL : &misc->param.cust_ie);
+ }
+#endif
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+ done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function will check if station list is empty
+ *
+ * @param priv A pointer to mlan_private
+ *
+ * @return MFALSE/MTRUE
+ */
+t_u8
+wlan_is_station_list_empty(mlan_private * priv)
+{
+ ENTER();
+ if (!(util_peek_list(priv->adapter->pmoal_handle,
+ &priv->sta_list,
+ priv->adapter->callbacks.moal_spin_lock,
+ priv->adapter->callbacks.moal_spin_unlock))) {
+ LEAVE();
+ return MTRUE;
+ }
+ LEAVE();
+ return MFALSE;
+}
+
+/**
+ * @brief This function will return the pointer to station entry in station list
+ * table which matches the give mac address
+ *
+ * @param priv A pointer to mlan_private
+ * @param mac mac address to find in station list table
+ *
+ * @return A pointer to structure sta_node
+ */
+sta_node *
+wlan_get_station_entry(mlan_private * priv, t_u8 * mac)
+{
+ sta_node *sta_ptr;
+
+ ENTER();
+
+ if (!mac) {
+ LEAVE();
+ return MNULL;
+ }
+ if (!(sta_ptr = (sta_node *) util_peek_list(priv->adapter->pmoal_handle,
+ &priv->sta_list,
+ priv->adapter->callbacks.
+ moal_spin_lock,
+ priv->adapter->callbacks.
+ moal_spin_unlock))) {
+ LEAVE();
+ return MNULL;
+ }
+ while (sta_ptr != (sta_node *) & priv->sta_list) {
+ if (!memcmp
+ (priv->adapter, sta_ptr->mac_addr, mac, MLAN_MAC_ADDR_LENGTH)) {
+ LEAVE();
+ return sta_ptr;
+ }
+ sta_ptr = sta_ptr->pnext;
+ }
+ LEAVE();
+ return MNULL;
+}
+
+/**
+ * @brief This function will add a pointer to station entry in station list
+ * table with the give mac address, if it does not exist already
+ *
+ * @param priv A pointer to mlan_private
+ * @param mac mac address to find in station list table
+ *
+ * @return A pointer to structure sta_node
+ */
+sta_node *
+wlan_add_station_entry(mlan_private * priv, t_u8 * mac)
+{
+ sta_node *sta_ptr = MNULL;
+ mlan_adapter *pmadapter = priv->adapter;
+
+ ENTER();
+ pmadapter->callbacks.moal_spin_lock(pmadapter->pmoal_handle,
+ priv->wmm.ra_list_spinlock);
+
+ sta_ptr = wlan_get_station_entry(priv, mac);
+ if (sta_ptr)
+ goto done;
+ if (priv->adapter->callbacks.
+ moal_malloc(priv->adapter->pmoal_handle, sizeof(sta_node), MLAN_MEM_DEF,
+ (t_u8 **) & sta_ptr)) {
+ PRINTM(MERROR, "Failed to allocate memory for station node\n");
+ LEAVE();
+ return MNULL;
+ }
+ memset(priv->adapter, sta_ptr, 0, sizeof(sta_node));
+ memcpy(priv->adapter, sta_ptr->mac_addr, mac, MLAN_MAC_ADDR_LENGTH);
+ util_enqueue_list_tail(priv->adapter->pmoal_handle, &priv->sta_list,
+ (pmlan_linked_list) sta_ptr,
+ priv->adapter->callbacks.moal_spin_lock,
+ priv->adapter->callbacks.moal_spin_unlock);
+ done:
+ pmadapter->callbacks.moal_spin_unlock(pmadapter->pmoal_handle,
+ priv->wmm.ra_list_spinlock);
+ LEAVE();
+ return sta_ptr;
+}
+
+/**
+ * @brief This function will delete a station entry from station list
+ *
+ *
+ * @param priv A pointer to mlan_private
+ * @param mac station's mac address
+ *
+ * @return N/A
+ */
+t_void
+wlan_delete_station_entry(mlan_private * priv, t_u8 * mac)
+{
+ sta_node *sta_ptr = MNULL;
+ mlan_adapter *pmadapter = priv->adapter;
+ ENTER();
+ pmadapter->callbacks.moal_spin_lock(pmadapter->pmoal_handle,
+ priv->wmm.ra_list_spinlock);
+ if ((sta_ptr = wlan_get_station_entry(priv, mac))) {
+ util_unlink_list(priv->adapter->pmoal_handle, &priv->sta_list,
+ (pmlan_linked_list) sta_ptr,
+ priv->adapter->callbacks.moal_spin_lock,
+ priv->adapter->callbacks.moal_spin_unlock);
+ priv->adapter->callbacks.moal_mfree(priv->adapter->pmoal_handle,
+ (t_u8 *) sta_ptr);
+ }
+ pmadapter->callbacks.moal_spin_unlock(pmadapter->pmoal_handle,
+ priv->wmm.ra_list_spinlock);
+ LEAVE();
+ return;
+}
+
+/**
+ * @brief Clean up wapi station list
+ *
+ * @param priv Pointer to the mlan_private driver data struct
+ *
+ * @return N/A
+ */
+t_void
+wlan_delete_station_list(pmlan_private priv)
+{
+ sta_node *sta_ptr;
+
+ ENTER();
+ while ((sta_ptr =
+ (sta_node *) util_dequeue_list(priv->adapter->pmoal_handle,
+ &priv->sta_list,
+ priv->adapter->callbacks.
+ moal_spin_lock,
+ priv->adapter->callbacks.
+ moal_spin_unlock))) {
+ priv->adapter->callbacks.moal_mfree(priv->adapter->pmoal_handle,
+ (t_u8 *) sta_ptr);
+ }
+ LEAVE();
+ return;
+}
+
+/**
+ * @brief This function will return the pointer to station entry in station list
+ * table which in tx_pause state
+ *
+ * @param priv A pointer to mlan_private
+ *
+ * @return A pointer to structure sta_node
+ */
+sta_node *
+wlan_get_tx_pause_station_entry(mlan_private * priv)
+{
+ sta_node *sta_ptr;
+
+ ENTER();
+
+ if (!(sta_ptr = (sta_node *) util_peek_list(priv->adapter->pmoal_handle,
+ &priv->sta_list,
+ priv->adapter->callbacks.
+ moal_spin_lock,
+ priv->adapter->callbacks.
+ moal_spin_unlock))) {
+ LEAVE();
+ return MNULL;
+ }
+ while (sta_ptr != (sta_node *) & priv->sta_list) {
+ if (sta_ptr->tx_pause) {
+ LEAVE();
+ return sta_ptr;
+ }
+ sta_ptr = sta_ptr->pnext;
+ }
+ LEAVE();
+ return MNULL;
+}
+
+/**
+ * @brief Get extended version information
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_PENDING --success, otherwise fail
+ */
+mlan_status
+wlan_get_info_ver_ext(IN pmlan_adapter pmadapter, IN pmlan_ioctl_req pioctl_req)
+{
+ pmlan_private pmpriv = pmadapter->priv[pioctl_req->bss_index];
+ mlan_ds_get_info *pinfo = (mlan_ds_get_info *) pioctl_req->pbuf;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ /* Send request to firmware */
+ ret = wlan_prepare_cmd(pmpriv,
+ HostCmd_CMD_VERSION_EXT,
+ HostCmd_ACT_GEN_GET,
+ 0,
+ (t_void *) pioctl_req,
+ &pinfo->param.ver_ext.version_str_sel);
+
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+
+ LEAVE();
+ return ret;
+}
+
+#ifdef DEBUG_LEVEL1
+/**
+ * @brief Set driver debug bit masks in order to enhance performance
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_PENDING --success, otherwise fail
+ */
+mlan_status
+wlan_set_drvdbg(IN pmlan_adapter pmadapter, IN pmlan_ioctl_req pioctl_req)
+{
+ mlan_ds_misc_cfg *misc = (mlan_ds_misc_cfg *) pioctl_req->pbuf;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ /* Set driver debug bit masks */
+ drvdbg = misc->param.drvdbg;
+
+ LEAVE();
+ return ret;
+}
+#endif
+
+/**
+ * @brief Rx mgmt frame forward register
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_PENDING --success, otherwise fail
+ */
+mlan_status
+wlan_reg_rx_mgmt_ind(IN pmlan_adapter pmadapter, IN pmlan_ioctl_req pioctl_req)
+{
+ pmlan_private pmpriv = pmadapter->priv[pioctl_req->bss_index];
+ mlan_ds_misc_cfg *misc = (mlan_ds_misc_cfg *) pioctl_req->pbuf;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ /* Set passthru mask for mgmt frame */
+ pmpriv->mgmt_frame_passthru_mask = misc->param.mgmt_subtype_mask;
+
+ /* Send request to firmware */
+ ret = wlan_prepare_cmd(pmpriv,
+ HostCmd_CMD_RX_MGMT_IND,
+ pioctl_req->action,
+ 0,
+ (t_void *) pioctl_req,
+ &misc->param.mgmt_subtype_mask);
+
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function processes the 802.11 mgmt Frame
+ *
+ * @param priv A pointer to mlan_private
+ * @param payload A pointer to the received buffer
+ * @param payload_len Length of the received buffer
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status
+wlan_process_802dot11_mgmt_pkt(IN mlan_private * priv,
+ IN t_u8 * payload, IN t_u32 payload_len)
+{
+ pmlan_adapter pmadapter = priv->adapter;
+ pmlan_callbacks pcb = &pmadapter->callbacks;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ wlan_802_11_header *pieee_pkt_hdr = MNULL;
+ t_u16 sub_type = 0;
+ t_u8 *event_buf = MNULL;
+ mlan_event *pevent = MNULL;
+ t_u8 unicast = 0;
+
+ ENTER();
+ if (payload_len > (MAX_EVENT_SIZE - sizeof(mlan_event))) {
+ PRINTM(MERROR, "Dropping large mgmt frame,len =%d\n", payload_len);
+ LEAVE();
+ return ret;
+ }
+ /* Check packet type-subtype and compare with mgmt_passthru_mask If event
+ is needed to host, just eventify it */
+ pieee_pkt_hdr = (wlan_802_11_header *) payload;
+ sub_type = IEEE80211_GET_FC_MGMT_FRAME_SUBTYPE(pieee_pkt_hdr->frm_ctl);
+ if (((1 << sub_type) & priv->mgmt_frame_passthru_mask) == 0) {
+ PRINTM(MINFO, "Dropping mgmt frame for subtype %d.\n", sub_type);
+ LEAVE();
+ return ret;
+ }
+ switch (sub_type) {
+ case SUBTYPE_ASSOC_REQUEST:
+ case SUBTYPE_REASSOC_REQUEST:
+ case SUBTYPE_DISASSOC:
+ case SUBTYPE_DEAUTH:
+ case SUBTYPE_ACTION:
+ case SUBTYPE_AUTH:
+ case SUBTYPE_PROBE_RESP:
+ unicast = MTRUE;
+ break;
+ default:
+ break;
+ }
+ if (unicast == MTRUE) {
+ if (memcmp
+ (pmadapter, pieee_pkt_hdr->addr1, priv->curr_addr,
+ MLAN_MAC_ADDR_LENGTH)) {
+ PRINTM(MINFO,
+ "Dropping mgmt frame for others: type=%d %02x:%02x:%02x:%02x:%02x:%02x\n",
+ sub_type, pieee_pkt_hdr->addr1[0], pieee_pkt_hdr->addr1[1],
+ pieee_pkt_hdr->addr1[2], pieee_pkt_hdr->addr1[3],
+ pieee_pkt_hdr->addr1[4], pieee_pkt_hdr->addr1[5]);
+ LEAVE();
+ return ret;
+ }
+ }
+ /* Allocate memory for event buffer */
+ ret =
+ pcb->moal_malloc(pmadapter->pmoal_handle, MAX_EVENT_SIZE, MLAN_MEM_DEF,
+ &event_buf);
+ if ((ret != MLAN_STATUS_SUCCESS) || !event_buf) {
+ PRINTM(MERROR, "Could not allocate buffer for event buf\n");
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+ pevent = (pmlan_event) event_buf;
+ pevent->bss_index = priv->bss_index;
+ pevent->event_id = MLAN_EVENT_ID_DRV_MGMT_FRAME;
+ pevent->event_len = payload_len + sizeof(pevent->event_id);
+ memcpy(pmadapter, (t_u8 *) pevent->event_buf,
+ (t_u8 *) & pevent->event_id, sizeof(pevent->event_id));
+ memcpy(pmadapter, (t_u8 *) (pevent->event_buf + sizeof(pevent->event_id)),
+ payload, payload_len);
+ wlan_recv_event(priv, MLAN_EVENT_ID_DRV_MGMT_FRAME, pevent);
+
+ if (event_buf)
+ pcb->moal_mfree(pmadapter->pmoal_handle, event_buf);
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function will search for the specific ie
+ *
+ *
+ * @param priv A pointer to mlan_private
+ * @param ie_buf A pointer to ie_buf
+ * @param ie_len total ie length
+ * @param id ie's id
+ *
+ * @return ie's poiner or MNULL
+ */
+t_u8 *
+wlan_get_specific_ie(pmlan_private priv, t_u8 * ie_buf, t_u8 ie_len,
+ IEEEtypes_ElementId_e id)
+{
+ t_u32 bytes_left = ie_len;
+ t_u8 *pcurrent_ptr = ie_buf;
+ t_u16 total_ie_len;
+ t_u8 *ie_ptr = MNULL;
+ IEEEtypes_ElementId_e element_id;
+ t_u8 element_len;
+
+ ENTER();
+
+ DBG_HEXDUMP(MCMD_D, "ie", ie_buf, ie_len);
+ while (bytes_left >= 2) {
+ element_id = (IEEEtypes_ElementId_e) (*((t_u8 *) pcurrent_ptr));
+ element_len = *((t_u8 *) pcurrent_ptr + 1);
+ total_ie_len = element_len + sizeof(IEEEtypes_Header_t);
+ if (bytes_left < total_ie_len) {
+ PRINTM(MERROR, "InterpretIE: Error in processing IE, "
+ "bytes left < IE length\n");
+ break;
+ }
+ if (element_id == id) {
+ PRINTM(MCMND, "Find IE: id=%d\n", id);
+ DBG_HEXDUMP(MCMND, "IE", pcurrent_ptr, total_ie_len);
+ ie_ptr = pcurrent_ptr;
+ break;
+ }
+ pcurrent_ptr += element_len + 2;
+ /* Need to account for IE ID and IE Len */
+ bytes_left -= (element_len + 2);
+ }
+
+ LEAVE();
+
+ return ie_ptr;
+}
+
+/**
+ * @brief Get pm info
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_SUCCESS --success
+ */
+mlan_status
+wlan_get_pm_info(IN pmlan_adapter pmadapter, IN pmlan_ioctl_req pioctl_req)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_ds_pm_cfg *pm_cfg = MNULL;
+ pmlan_callbacks pcb = &pmadapter->callbacks;
+
+ ENTER();
+
+ pm_cfg = (mlan_ds_pm_cfg *) pioctl_req->pbuf;
+ pm_cfg->param.ps_info.is_suspend_allowed = MTRUE;
+ if (util_peek_list(pmadapter->pmoal_handle, &pmadapter->cmd_pending_q,
+ pcb->moal_spin_lock, pcb->moal_spin_unlock)
+ || pmadapter->curr_cmd || !wlan_bypass_tx_list_empty(pmadapter)
+ || !wlan_wmm_lists_empty(pmadapter)
+ || pmadapter->sdio_ireg) {
+ pm_cfg->param.ps_info.is_suspend_allowed = MFALSE;
+ PRINTM(MIOCTL,
+ "PM: cmd_pending_q=%p,curr_cmd=%p,wmm_list_empty=%d, by_pass=%d sdio_ireg=0x%x\n",
+ util_peek_list(pmadapter->pmoal_handle,
+ &pmadapter->cmd_pending_q, pcb->moal_spin_lock,
+ pcb->moal_spin_unlock), pmadapter->curr_cmd,
+ wlan_wmm_lists_empty(pmadapter),
+ wlan_bypass_tx_list_empty(pmadapter), pmadapter->sdio_ireg);
+ }
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set/Get radio status
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+mlan_status
+wlan_radio_ioctl_radio_ctl(IN pmlan_adapter pmadapter,
+ IN pmlan_ioctl_req pioctl_req)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_ds_radio_cfg *radio_cfg = MNULL;
+ t_u16 cmd_action = 0;
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
+
+ ENTER();
+
+ radio_cfg = (mlan_ds_radio_cfg *) pioctl_req->pbuf;
+ if (pioctl_req->action == MLAN_ACT_SET) {
+ if (pmadapter->radio_on == radio_cfg->param.radio_on_off) {
+ ret = MLAN_STATUS_SUCCESS;
+ goto exit;
+ } else {
+ if (pmpriv->media_connected == MTRUE) {
+ ret = MLAN_STATUS_FAILURE;
+ goto exit;
+ }
+ cmd_action = HostCmd_ACT_GEN_SET;
+ }
+ } else
+ cmd_action = HostCmd_ACT_GEN_GET;
+
+ /* Send request to firmware */
+ ret = wlan_prepare_cmd(pmpriv,
+ HostCmd_CMD_802_11_RADIO_CONTROL,
+ cmd_action,
+ 0,
+ (t_void *) pioctl_req,
+ &radio_cfg->param.radio_on_off);
+
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+
+ exit:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set/Get antenna configuration
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_PENDING --success, otherwise fail
+ */
+mlan_status
+wlan_radio_ioctl_ant_cfg(IN pmlan_adapter pmadapter,
+ IN pmlan_ioctl_req pioctl_req)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
+ mlan_ds_radio_cfg *radio_cfg = MNULL;
+ t_u16 cmd_action = 0;
+ mlan_ds_ant_cfg *ant_cfg;
+
+ ENTER();
+
+ radio_cfg = (mlan_ds_radio_cfg *) pioctl_req->pbuf;
+ ant_cfg = &radio_cfg->param.ant_cfg;
+
+ if (pioctl_req->action == MLAN_ACT_SET) {
+ /* User input validation */
+ if (!ant_cfg->tx_antenna ||
+ ant_cfg->tx_antenna & ~RF_ANTENNA_MASK(pmadapter->
+ number_of_antenna)) {
+ PRINTM(MERROR, "Invalid antenna setting\n");
+ pioctl_req->status_code = MLAN_ERROR_INVALID_PARAMETER;
+ ret = MLAN_STATUS_FAILURE;
+ goto exit;
+ }
+ if (ant_cfg->rx_antenna) {
+ if (ant_cfg->
+ rx_antenna & ~RF_ANTENNA_MASK(pmadapter->number_of_antenna)) {
+ PRINTM(MERROR, "Invalid antenna setting\n");
+ pioctl_req->status_code = MLAN_ERROR_INVALID_PARAMETER;
+ ret = MLAN_STATUS_FAILURE;
+ goto exit;
+ }
+ } else
+ ant_cfg->rx_antenna = ant_cfg->tx_antenna;
+ cmd_action = HostCmd_ACT_GEN_SET;
+ } else
+ cmd_action = HostCmd_ACT_GEN_GET;
+
+ /* Send request to firmware */
+ ret = wlan_prepare_cmd(pmpriv,
+ HostCmd_CMD_802_11_RF_ANTENNA,
+ cmd_action,
+ 0, (t_void *) pioctl_req, (t_void *) ant_cfg);
+
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+
+ exit:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Get rate value
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING --success, otherwise fail
+ */
+static mlan_status
+wlan_rate_ioctl_get_rate_value(IN pmlan_adapter pmadapter,
+ IN pmlan_ioctl_req pioctl_req)
+{
+ mlan_ds_rate *rate = MNULL;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
+
+ ENTER();
+
+ rate = (mlan_ds_rate *) pioctl_req->pbuf;
+ rate->param.rate_cfg.is_rate_auto = pmpriv->is_data_rate_auto;
+ pioctl_req->data_read_written =
+ sizeof(mlan_rate_cfg_t) + MLAN_SUB_COMMAND_SIZE;
+
+ /* If not connected, set rate to the lowest in each band */
+ if (pmpriv->media_connected != MTRUE) {
+ if (pmadapter->config_bands & (BAND_B | BAND_G)) {
+ /* Return the lowest supported rate for BG band */
+ rate->param.rate_cfg.rate = SupportedRates_BG[0] & 0x7f;
+ } else if (pmadapter->config_bands & (BAND_A | BAND_B)) {
+ /* Return the lowest supported rate for A band */
+ rate->param.rate_cfg.rate = SupportedRates_BG[0] & 0x7f;
+ } else if (pmadapter->config_bands & BAND_A) {
+ /* Return the lowest supported rate for A band */
+ rate->param.rate_cfg.rate = SupportedRates_A[0] & 0x7f;
+ } else if (pmadapter->config_bands & BAND_G) {
+ /* Return the lowest supported rate for G band */
+ rate->param.rate_cfg.rate = SupportedRates_G[0] & 0x7f;
+ } else if (pmadapter->config_bands & BAND_B) {
+ /* Return the lowest supported rate for B band */
+ rate->param.rate_cfg.rate = SupportedRates_B[0] & 0x7f;
+ } else if (pmadapter->config_bands & BAND_GN) {
+ /* Return the lowest supported rate for N band */
+ rate->param.rate_cfg.rate = SupportedRates_N[0] & 0x7f;
+ } else {
+ PRINTM(MMSG, "Invalid Band 0x%x\n", pmadapter->config_bands);
+ }
+
+ } else {
+ /* Send request to firmware */
+ ret = wlan_prepare_cmd(pmpriv,
+ HostCmd_CMD_802_11_TX_RATE_QUERY,
+ HostCmd_ACT_GEN_GET,
+ 0, (t_void *) pioctl_req, MNULL);
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+ }
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set rate value
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_PENDING --success, otherwise fail
+ */
+static mlan_status
+wlan_rate_ioctl_set_rate_value(IN pmlan_adapter pmadapter,
+ IN pmlan_ioctl_req pioctl_req)
+{
+ mlan_ds_rate *ds_rate = MNULL;
+ WLAN_802_11_RATES rates;
+ t_u8 *rate = MNULL;
+ int rate_index = 0;
+ t_u16 bitmap_rates[MAX_BITMAP_RATES_SIZE];
+ t_u32 i = 0;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
+
+ ENTER();
+
+ ds_rate = (mlan_ds_rate *) pioctl_req->pbuf;
+
+ if (ds_rate->param.rate_cfg.is_rate_auto) {
+ memset(pmadapter, bitmap_rates, 0, sizeof(bitmap_rates));
+ /* Support all HR/DSSS rates */
+ bitmap_rates[0] = 0x000F;
+ /* Support all OFDM rates */
+ bitmap_rates[1] = 0x00FF;
+ /* Support all HT-MCSs rate */
+ for (i = 0; i < NELEMENTS(pmpriv->bitmap_rates) - 3; i++)
+ bitmap_rates[i + 2] = 0xFFFF;
+ bitmap_rates[9] = 0x3FFF;
+ } else {
+ memset(pmadapter, rates, 0, sizeof(rates));
+ wlan_get_active_data_rates(pmpriv, pmpriv->bss_mode,
+ (pmpriv->bss_mode == MLAN_BSS_MODE_INFRA) ?
+ pmadapter->config_bands : pmadapter->
+ adhoc_start_band, rates);
+ rate = rates;
+ for (i = 0; (rate[i] && i < WLAN_SUPPORTED_RATES); i++) {
+ PRINTM(MINFO, "Rate=0x%X Wanted=0x%X\n", rate[i],
+ ds_rate->param.rate_cfg.rate);
+ if ((rate[i] & 0x7f) == (ds_rate->param.rate_cfg.rate & 0x7f))
+ break;
+ }
+ if (!rate[i] || (i == WLAN_SUPPORTED_RATES)) {
+ PRINTM(MERROR, "The fixed data rate 0x%X is out "
+ "of range\n", ds_rate->param.rate_cfg.rate);
+ pioctl_req->status_code = MLAN_ERROR_INVALID_PARAMETER;
+ ret = MLAN_STATUS_FAILURE;
+ goto exit;
+ }
+ memset(pmadapter, bitmap_rates, 0, sizeof(bitmap_rates));
+
+ rate_index =
+ wlan_data_rate_to_index(pmadapter, ds_rate->param.rate_cfg.rate);
+
+ /* Only allow b/g rates to be set */
+ if (rate_index >= MLAN_RATE_INDEX_HRDSSS0 &&
+ rate_index <= MLAN_RATE_INDEX_HRDSSS3)
+ bitmap_rates[0] = 1 << rate_index;
+ else {
+ rate_index -= 1; /* There is a 0x00 in the table */
+ if (rate_index >= MLAN_RATE_INDEX_OFDM0 &&
+ rate_index <= MLAN_RATE_INDEX_OFDM7)
+ bitmap_rates[1] = 1 << (rate_index - MLAN_RATE_INDEX_OFDM0);
+ }
+ }
+
+ /* Send request to firmware */
+ ret = wlan_prepare_cmd(pmpriv,
+ HostCmd_CMD_TX_RATE_CFG,
+ HostCmd_ACT_GEN_SET,
+ 0, (t_void *) pioctl_req, bitmap_rates);
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+
+ exit:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Get rate index
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_PENDING --success, otherwise fail
+ */
+static mlan_status
+wlan_rate_ioctl_get_rate_index(IN pmlan_adapter pmadapter,
+ IN pmlan_ioctl_req pioctl_req)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
+
+ ENTER();
+
+ /* Send request to firmware */
+ ret = wlan_prepare_cmd(pmpriv,
+ HostCmd_CMD_TX_RATE_CFG,
+ HostCmd_ACT_GEN_GET,
+ 0, (t_void *) pioctl_req, MNULL);
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set rate index
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_PENDING --success, otherwise fail
+ */
+static mlan_status
+wlan_rate_ioctl_set_rate_index(IN pmlan_adapter pmadapter,
+ IN pmlan_ioctl_req pioctl_req)
+{
+ t_u32 rate_index;
+ t_u32 i;
+ mlan_ds_rate *ds_rate = MNULL;
+ mlan_status ret = MLAN_STATUS_FAILURE;
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
+ t_u16 bitmap_rates[MAX_BITMAP_RATES_SIZE];
+ int tx_mcs_supp = GET_TXMCSSUPP(pmadapter->usr_dev_mcs_support);
+
+ ENTER();
+
+ ds_rate = (mlan_ds_rate *) pioctl_req->pbuf;
+ rate_index = ds_rate->param.rate_cfg.rate;
+
+ if (ds_rate->param.rate_cfg.is_rate_auto) {
+ memset(pmadapter, bitmap_rates, 0, sizeof(bitmap_rates));
+ /* Rates talbe [0]: HR/DSSS;[1]: OFDM; [2..9] HT; */
+ /* Support all HR/DSSS rates */
+ bitmap_rates[0] = 0x000F;
+ /* Support all OFDM rates */
+ bitmap_rates[1] = 0x00FF;
+ /* Support all HT-MCSs rate */
+ for (i = 2; i < 9; i++)
+ bitmap_rates[i] = 0xFFFF;
+ bitmap_rates[9] = 0x3FFF;
+ } else {
+ PRINTM(MINFO, "Rate index is %d\n", rate_index);
+ if ((rate_index > MLAN_RATE_INDEX_MCS7 &&
+ rate_index <= MLAN_RATE_INDEX_MCS15) && (tx_mcs_supp < 2)) {
+ PRINTM(MERROR,
+ "HW don't support 2x2, rate_index=%d hw_mcs_supp=0x%x\n",
+ rate_index, pmadapter->usr_dev_mcs_support);
+ pioctl_req->status_code = MLAN_ERROR_INVALID_PARAMETER;
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+ memset(pmadapter, bitmap_rates, 0, sizeof(bitmap_rates));
+ /* Bitmap of HR/DSSS rates */
+ if ((rate_index >= MLAN_RATE_INDEX_HRDSSS0) &&
+ (rate_index <= MLAN_RATE_INDEX_HRDSSS3)) {
+ bitmap_rates[0] = 1 << rate_index;
+ ret = MLAN_STATUS_SUCCESS;
+ /* Bitmap of OFDM rates */
+ } else if ((rate_index >= MLAN_RATE_INDEX_OFDM0) &&
+ (rate_index <= MLAN_RATE_INDEX_OFDM7)) {
+ bitmap_rates[1] = 1 << (rate_index - MLAN_RATE_INDEX_OFDM0);
+ ret = MLAN_STATUS_SUCCESS;
+ }
+ if ((rate_index >= MLAN_RATE_INDEX_MCS0) &&
+ (rate_index <= MLAN_RATE_INDEX_MCS32)) {
+ rate_index -= MLAN_RATE_INDEX_MCS0;
+ bitmap_rates[2 + (rate_index / 16)] = 1 << (rate_index % 16);
+ ret = MLAN_STATUS_SUCCESS;
+ }
+
+ if (ret == MLAN_STATUS_FAILURE) {
+ PRINTM(MERROR, "Invalid MCS index=%d. \n", rate_index);
+ pioctl_req->status_code = MLAN_ERROR_INVALID_PARAMETER;
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+ }
+
+ PRINTM(MINFO, "RateBitmap=%04x%04x%04x%04x%04x%04x%04x%04x%04x%04x, "
+ "IsRateAuto=%d, DataRate=%d\n",
+ bitmap_rates[9], bitmap_rates[8],
+ bitmap_rates[7], bitmap_rates[6],
+ bitmap_rates[5], bitmap_rates[4],
+ bitmap_rates[3], bitmap_rates[2],
+ bitmap_rates[1], bitmap_rates[0],
+ pmpriv->is_data_rate_auto, pmpriv->data_rate);
+
+ /* Send request to firmware */
+ ret = wlan_prepare_cmd(pmpriv,
+ HostCmd_CMD_TX_RATE_CFG,
+ HostCmd_ACT_GEN_SET,
+ 0, (t_void *) pioctl_req, (t_void *) bitmap_rates);
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Rate configuration command handler
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING --success, otherwise fail
+ */
+mlan_status
+wlan_rate_ioctl_cfg(IN pmlan_adapter pmadapter, IN pmlan_ioctl_req pioctl_req)
+{
+ mlan_ds_rate *rate = MNULL;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ rate = (mlan_ds_rate *) pioctl_req->pbuf;
+ if (rate->param.rate_cfg.rate_type == MLAN_RATE_VALUE) {
+ if (pioctl_req->action == MLAN_ACT_GET)
+ status = wlan_rate_ioctl_get_rate_value(pmadapter, pioctl_req);
+ else
+ status = wlan_rate_ioctl_set_rate_value(pmadapter, pioctl_req);
+ } else {
+ if (pioctl_req->action == MLAN_ACT_GET)
+ status = wlan_rate_ioctl_get_rate_index(pmadapter, pioctl_req);
+ else
+ status = wlan_rate_ioctl_set_rate_index(pmadapter, pioctl_req);
+ }
+
+ LEAVE();
+ return status;
+}
+
+/**
+ * @brief This function prepares command of rf_antenna.
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param cmd A pointer to HostCmd_DS_COMMAND structure
+ * @param cmd_action The action: GET or SET
+ * @param pdata_buf A pointer to data buffer
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+mlan_status
+wlan_cmd_802_11_rf_antenna(IN pmlan_private pmpriv,
+ IN HostCmd_DS_COMMAND * cmd,
+ IN t_u16 cmd_action, IN t_void * pdata_buf)
+{
+ HostCmd_DS_802_11_RF_ANTENNA *pantenna = &cmd->params.antenna;
+ mlan_ds_ant_cfg *ant_cfg = (mlan_ds_ant_cfg *) pdata_buf;
+
+ ENTER();
+ cmd->command = wlan_cpu_to_le16(HostCmd_CMD_802_11_RF_ANTENNA);
+ cmd->size =
+ wlan_cpu_to_le16(sizeof(HostCmd_DS_802_11_RF_ANTENNA) + S_DS_GEN);
+
+ if (cmd_action == HostCmd_ACT_GEN_SET) {
+ pantenna->action_tx = wlan_cpu_to_le16(HostCmd_ACT_SET_TX);
+ pantenna->tx_antenna_mode =
+ wlan_cpu_to_le16((t_u16) ant_cfg->tx_antenna);
+ pantenna->action_rx = wlan_cpu_to_le16(HostCmd_ACT_SET_RX);
+ pantenna->rx_antenna_mode =
+ wlan_cpu_to_le16((t_u16) ant_cfg->rx_antenna);
+ } else {
+ pantenna->action_tx = wlan_cpu_to_le16(HostCmd_ACT_GET_TX);
+ pantenna->action_rx = wlan_cpu_to_le16(HostCmd_ACT_GET_RX);
+ }
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function handles the command response of rf_antenna
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param resp A pointer to HostCmd_DS_COMMAND
+ * @param pioctl_buf A pointer to mlan_ioctl_req structure
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+mlan_status
+wlan_ret_802_11_rf_antenna(IN pmlan_private pmpriv,
+ IN HostCmd_DS_COMMAND * resp,
+ IN mlan_ioctl_req * pioctl_buf)
+{
+ HostCmd_DS_802_11_RF_ANTENNA *pantenna = &resp->params.antenna;
+ t_u16 tx_ant_mode = wlan_le16_to_cpu(pantenna->tx_antenna_mode);
+ t_u16 rx_ant_mode = wlan_le16_to_cpu(pantenna->rx_antenna_mode);
+ mlan_ds_radio_cfg *radio = MNULL;
+
+ ENTER();
+
+ PRINTM(MINFO, "RF_ANT_RESP: Tx action = 0x%x, Tx Mode = 0x%04x"
+ " Rx action = 0x%x, Rx Mode = 0x%04x\n",
+ wlan_le16_to_cpu(pantenna->action_tx), tx_ant_mode,
+ wlan_le16_to_cpu(pantenna->action_rx), rx_ant_mode);
+
+ if (pioctl_buf) {
+ radio = (mlan_ds_radio_cfg *) pioctl_buf->pbuf;
+ radio->param.ant_cfg.tx_antenna = tx_ant_mode;
+ radio->param.ant_cfg.rx_antenna = rx_ant_mode;
+ }
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+#ifdef WIFI_DIRECT_SUPPORT
+/**
+ * @brief Set/Get wifi_direct_mode
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+mlan_status
+wlan_bss_ioctl_wifi_direct_mode(IN pmlan_adapter pmadapter,
+ IN pmlan_ioctl_req pioctl_req)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_ds_bss *bss = MNULL;
+
+ t_u16 cmd_action = 0;
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
+
+ ENTER();
+
+ bss = (mlan_ds_bss *) pioctl_req->pbuf;
+
+ if (pioctl_req->action == MLAN_ACT_SET)
+ cmd_action = HostCmd_ACT_GEN_SET;
+ else
+ cmd_action = HostCmd_ACT_GEN_GET;
+
+ /* Send request to firmware */
+ ret = wlan_prepare_cmd(pmpriv,
+ HOST_CMD_WIFI_DIRECT_MODE_CONFIG,
+ cmd_action,
+ 0, (t_void *) pioctl_req, &bss->param.wfd_mode);
+
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set/Get remain on channel setting
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+mlan_status
+wlan_radio_ioctl_remain_chan_cfg(IN pmlan_adapter pmadapter,
+ IN pmlan_ioctl_req pioctl_req)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_ds_radio_cfg *radio_cfg = MNULL;
+ t_u16 cmd_action = 0;
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
+
+ ENTER();
+
+ radio_cfg = (mlan_ds_radio_cfg *) pioctl_req->pbuf;
+ if (pioctl_req->action == MLAN_ACT_SET)
+ cmd_action = HostCmd_ACT_GEN_SET;
+ else
+ cmd_action = HostCmd_ACT_GEN_GET;
+
+ /* Send request to firmware */
+ ret = wlan_prepare_cmd(pmpriv,
+ HostCmd_CMD_802_11_REMAIN_ON_CHANNEL,
+ cmd_action,
+ 0,
+ (t_void *) pioctl_req,
+ &radio_cfg->param.remain_chan);
+
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+
+ LEAVE();
+ return ret;
+}
+#endif
diff --git a/drivers/net/wireless/sd8797/mlan/mlan_module.c b/drivers/net/wireless/sd8797/mlan/mlan_module.c
new file mode 100644
index 000000000000..cd0bd0c5fb78
--- /dev/null
+++ b/drivers/net/wireless/sd8797/mlan/mlan_module.c
@@ -0,0 +1,47 @@
+/** @file mlan_module.c
+ *
+ * @brief This file declares the exported symbols from MLAN.
+ *
+ * Copyright (C) 2008-2011, Marvell International Ltd.
+ *
+ * This software file (the "File") is distributed by Marvell International
+ * Ltd. under the terms of the GNU General Public License Version 2, June 1991
+ * (the "License"). You may use, redistribute and/or modify this File in
+ * accordance with the terms and conditions of the License, a copy of which
+ * is available by writing to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
+ * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
+ *
+ * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
+ * ARE EXPRESSLY DISCLAIMED. The License provides additional details about
+ * this warranty disclaimer.
+ */
+
+/******************************************************
+Change log:
+ 12/08/2008: initial version
+******************************************************/
+
+#ifdef LINUX
+#include <linux/module.h>
+#include "mlan_decl.h"
+#include "mlan_ioctl.h"
+
+EXPORT_SYMBOL(mlan_register);
+EXPORT_SYMBOL(mlan_unregister);
+EXPORT_SYMBOL(mlan_init_fw);
+EXPORT_SYMBOL(mlan_set_init_param);
+EXPORT_SYMBOL(mlan_dnld_fw);
+EXPORT_SYMBOL(mlan_shutdown_fw);
+EXPORT_SYMBOL(mlan_send_packet);
+EXPORT_SYMBOL(mlan_ioctl);
+EXPORT_SYMBOL(mlan_main_process);
+EXPORT_SYMBOL(mlan_select_wmm_queue);
+EXPORT_SYMBOL(mlan_interrupt);
+
+MODULE_DESCRIPTION("M-WLAN MLAN Driver");
+MODULE_AUTHOR("Marvell International Ltd.");
+MODULE_VERSION(MLAN_RELEASE_VERSION);
+MODULE_LICENSE("GPL");
+#endif /* LINUX */
diff --git a/drivers/net/wireless/sd8797/mlan/mlan_scan.c b/drivers/net/wireless/sd8797/mlan/mlan_scan.c
new file mode 100644
index 000000000000..6123365422c7
--- /dev/null
+++ b/drivers/net/wireless/sd8797/mlan/mlan_scan.c
@@ -0,0 +1,4155 @@
+/** @file mlan_scan.c
+ *
+ * @brief Functions implementing wlan scan IOCTL and firmware command APIs
+ *
+ * IOCTL handlers as well as command preparation and response routines
+ * for sending scan commands to the firmware.
+ *
+ * Copyright (C) 2008-2011, Marvell International Ltd.
+ *
+ * This software file (the "File") is distributed by Marvell International
+ * Ltd. under the terms of the GNU General Public License Version 2, June 1991
+ * (the "License"). You may use, redistribute and/or modify this File in
+ * accordance with the terms and conditions of the License, a copy of which
+ * is available by writing to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
+ * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
+ *
+ * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
+ * ARE EXPRESSLY DISCLAIMED. The License provides additional details about
+ * this warranty disclaimer.
+ */
+
+/******************************************************
+Change log:
+ 10/28/2008: initial version
+******************************************************/
+
+#include "mlan.h"
+#include "mlan_join.h"
+#include "mlan_util.h"
+#include "mlan_fw.h"
+#include "mlan_main.h"
+#include "mlan_11n.h"
+#include "mlan_11h.h"
+
+/********************************************************
+ Local Constants
+********************************************************/
+
+/** The maximum number of channels the firmware can scan per command */
+#define MRVDRV_MAX_CHANNELS_PER_SPECIFIC_SCAN 14
+
+/**
+ * Number of channels to scan per firmware scan command issuance.
+ *
+ * Number restricted to prevent hitting the limit on the amount of scan data
+ * returned in a single firmware scan command.
+ */
+#define MRVDRV_CHANNELS_PER_SCAN_CMD 4
+
+/** Memory needed to store a max sized Channel List TLV for a firmware scan */
+#define CHAN_TLV_MAX_SIZE (sizeof(MrvlIEtypesHeader_t) \
+ + (MRVDRV_MAX_CHANNELS_PER_SPECIFIC_SCAN \
+ * sizeof(ChanScanParamSet_t)))
+
+/** Memory needed to store supported rate */
+#define RATE_TLV_MAX_SIZE (sizeof(MrvlIEtypes_RatesParamSet_t) + HOSTCMD_SUPPORTED_RATES)
+
+/** Memory needed to store a max number/size WildCard SSID TLV for a firmware scan */
+#define WILDCARD_SSID_TLV_MAX_SIZE \
+ (MRVDRV_MAX_SSID_LIST_LENGTH * (sizeof(MrvlIEtypes_WildCardSsIdParamSet_t) + MRVDRV_MAX_SSID_LENGTH))
+
+/** WPS TLV MAX size is MAX IE size plus 2 bytes for t_u16 MRVL TLV extension */
+#define WPS_TLV_MAX_SIZE (sizeof(IEEEtypes_VendorSpecific_t) + 2)
+/** Maximum memory needed for a wlan_scan_cmd_config with all TLVs at max */
+#define MAX_SCAN_CFG_ALLOC (sizeof(wlan_scan_cmd_config) \
+ + sizeof(MrvlIEtypes_NumProbes_t) \
+ + sizeof(MrvlIETypes_HTCap_t) \
+ + CHAN_TLV_MAX_SIZE \
+ + RATE_TLV_MAX_SIZE \
+ + WILDCARD_SSID_TLV_MAX_SIZE \
+ + WPS_TLV_MAX_SIZE)
+
+/********************************************************
+ Local Variables
+********************************************************/
+
+/**
+ * Interally used to send a configured scan cmd between driver routines
+ */
+typedef union
+{
+ /** Scan configuration (variable length) */
+ wlan_scan_cmd_config config;
+ /** Max allocated block */
+ t_u8 config_alloc_buf[MAX_SCAN_CFG_ALLOC];
+} wlan_scan_cmd_config_tlv;
+
+/********************************************************
+ Global Variables
+********************************************************/
+
+/********************************************************
+ Local Functions
+********************************************************/
+/** Cipher suite definition */
+enum cipher_suite
+{
+ CIPHER_SUITE_TKIP,
+ CIPHER_SUITE_CCMP,
+ CIPHER_SUITE_MAX
+};
+
+static t_u8 wpa_oui[CIPHER_SUITE_MAX][4] = {
+ {0x00, 0x50, 0xf2, 0x02}, /* TKIP */
+ {0x00, 0x50, 0xf2, 0x04}, /* AES */
+};
+
+static t_u8 rsn_oui[CIPHER_SUITE_MAX][4] = {
+ {0x00, 0x0f, 0xac, 0x02}, /* TKIP */
+ {0x00, 0x0f, 0xac, 0x04}, /* AES */
+};
+
+/**
+ * @brief This function will parse a given IE for a given OUI
+ *
+ * Parse a given WPA/RSN IE to find if it has a given oui in PTK,
+ * if no OUI found for PTK it returns 0.
+ *
+ * @param pbss_desc A pointer to current BSS descriptor
+ * @return 0 on failure to find OUI, 1 on success.
+ */
+static t_u8
+search_oui_in_ie(mlan_adapter * pmadapter, IEBody * ie_body, t_u8 * oui)
+{
+ t_u8 count;
+
+ count = ie_body->PtkCnt[0];
+
+ ENTER();
+ /* There could be multiple OUIs for PTK hence 1) Take the length. 2) Check
+ all the OUIs for AES. 3) If one of them is AES then pass success. */
+ while (count) {
+ if (!memcmp(pmadapter, ie_body->PtkBody, oui, sizeof(ie_body->PtkBody))) {
+ LEAVE();
+ return MLAN_OUI_PRESENT;
+ }
+
+ --count;
+ if (count) {
+ ie_body = (IEBody *) ((t_u8 *) ie_body + sizeof(ie_body->PtkBody));
+ }
+ }
+
+ PRINTM(MINFO, "The OUI %x:%x:%x:%x is not found in PTK \n", oui[0], oui[1],
+ oui[2], oui[3]);
+ LEAVE();
+ return MLAN_OUI_NOT_PRESENT;
+}
+
+/**
+ * @brief This function will pass the correct ie and oui to search_oui_in_ie
+ *
+ * Check the pbss_desc for appropriate IE and then check if RSN IE has AES
+ * OUI in it. If RSN IE does not have AES in PTK then return 0;
+ *
+ * @param pbss_desc A pointer to current BSS descriptor
+ * @return 0 on failure to find AES OUI, 1 on success.
+ */
+static t_u8
+is_rsn_oui_present(mlan_adapter * pmadapter, BSSDescriptor_t * pbss_desc,
+ t_u32 cipher_suite)
+{
+ t_u8 *oui = MNULL;
+ IEBody *ie_body = MNULL;
+ t_u8 ret = MLAN_OUI_NOT_PRESENT;
+
+ ENTER();
+ if (((pbss_desc->prsn_ie) &&
+ ((*(pbss_desc->prsn_ie)).ieee_hdr.element_id == RSN_IE))) {
+ ie_body =
+ (IEBody *) (((t_u8 *) pbss_desc->prsn_ie->data) +
+ RSN_GTK_OUI_OFFSET);
+ oui = &rsn_oui[cipher_suite][0];
+ if ((ret = search_oui_in_ie(pmadapter, ie_body, oui))) {
+ LEAVE();
+ return ret;
+ }
+ }
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function will pass the correct ie and oui to search_oui_in_ie
+ *
+ * Check the pbss_desc for appropriate IE and then check if WPA IE has AES
+ * OUI in it. If WPA IE does not have AES in PTK then return 0;
+ *
+ * @param pbss_desc A pointer to current BSS descriptor
+ * @return 0 on failure to find AES OUI, 1 on success.
+ */
+static t_u8
+is_wpa_oui_present(mlan_adapter * pmadapter, BSSDescriptor_t * pbss_desc,
+ t_u32 cipher_suite)
+{
+ t_u8 *oui = MNULL;
+ IEBody *ie_body = MNULL;
+ t_u8 ret = MLAN_OUI_NOT_PRESENT;
+
+ ENTER();
+ if (((pbss_desc->pwpa_ie) &&
+ ((*(pbss_desc->pwpa_ie)).vend_hdr.element_id == WPA_IE))) {
+ ie_body = (IEBody *) pbss_desc->pwpa_ie->data;
+ oui = &wpa_oui[cipher_suite][0];
+ if ((ret = search_oui_in_ie(pmadapter, ie_body, oui))) {
+ LEAVE();
+ return ret;
+ }
+ }
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief compare config band and a band from the scan result,
+ * which is defined by functiion radio_type_to_band(t_u8 radio_type) above
+ *
+ * @param cfg_band: band configured
+ * scan_band: band from scan result
+ *
+ * @return matched: non-zero. unmatched: 0
+ *
+ */
+static t_u8
+wlan_is_band_compatible(t_u8 cfg_band, t_u8 scan_band)
+{
+ t_u8 band;
+ switch (scan_band) {
+ case BAND_A:
+ band = BAND_A | BAND_AN;
+ break;
+ case BAND_G:
+ default:
+ band = BAND_B | BAND_G | BAND_GN;
+ }
+ return cfg_band & band;
+}
+
+/**
+ * @brief This function finds the best SSID in the Scan List
+ *
+ * Search the scan table for the best SSID that also matches the current
+ * adapter network preference (infrastructure or adhoc)
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @return index in BSSID list
+ */
+static t_s32
+wlan_find_best_network_in_list(IN mlan_private * pmpriv)
+{
+ mlan_adapter *pmadapter = pmpriv->adapter;
+ t_u32 mode = pmpriv->bss_mode;
+ t_s32 best_net = -1;
+ t_s32 best_rssi = 0;
+ t_u32 i;
+
+ ENTER();
+
+ PRINTM(MINFO, "Num of BSSIDs = %d\n", pmadapter->num_in_scan_table);
+
+ for (i = 0; i < pmadapter->num_in_scan_table; i++) {
+ switch (mode) {
+ case MLAN_BSS_MODE_INFRA:
+ case MLAN_BSS_MODE_IBSS:
+ if (wlan_is_network_compatible(pmpriv, i, mode) >= 0) {
+ if (SCAN_RSSI(pmadapter->pscan_table[i].rssi) > best_rssi) {
+ best_rssi = SCAN_RSSI(pmadapter->pscan_table[i].rssi);
+ best_net = i;
+ }
+ }
+ break;
+ case MLAN_BSS_MODE_AUTO:
+ default:
+ if (SCAN_RSSI(pmadapter->pscan_table[i].rssi) > best_rssi) {
+ best_rssi = SCAN_RSSI(pmadapter->pscan_table[i].rssi);
+ best_net = i;
+ }
+ break;
+ }
+ }
+
+ LEAVE();
+ return best_net;
+}
+
+/**
+ * @brief Create a channel list for the driver to scan based on region info
+ *
+ * Use the driver region/band information to construct a comprehensive list
+ * of channels to scan. This routine is used for any scan that is not
+ * provided a specific channel list to scan.
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param puser_scan_in MNULL or pointer to scan configuration parameters
+ * @param pscan_chan_list Output parameter: Resulting channel list to scan
+ * @param filtered_scan Flag indicating whether or not a BSSID or SSID filter
+ * is being sent in the command to firmware. Used to
+ * increase the number of channels sent in a scan
+ * command and to disable the firmware channel scan
+ * filter.
+ *
+ * @return N/A
+ */
+static t_void
+wlan_scan_create_channel_list(IN mlan_private * pmpriv,
+ IN const wlan_user_scan_cfg * puser_scan_in,
+ OUT ChanScanParamSet_t * pscan_chan_list,
+ IN t_u8 filtered_scan)
+{
+ mlan_adapter *pmadapter = pmpriv->adapter;
+ region_chan_t *pscan_region;
+ chan_freq_power_t *cfp;
+ t_u32 region_idx;
+ t_u32 chan_idx = 0;
+ t_u32 next_chan;
+ t_u8 scan_type;
+ t_u8 radio_type;
+
+ ENTER();
+
+ for (region_idx = 0;
+ region_idx < NELEMENTS(pmadapter->region_channel); region_idx++) {
+
+ if (wlan_11d_is_enabled(pmpriv) && pmpriv->media_connected != MTRUE) {
+ /* Scan all the supported chan for the first scan */
+ if (!pmadapter->universal_channel[region_idx].valid)
+ continue;
+ pscan_region = &pmadapter->universal_channel[region_idx];
+ } else {
+ if (!pmadapter->region_channel[region_idx].valid)
+ continue;
+ pscan_region = &pmadapter->region_channel[region_idx];
+ }
+
+ if (puser_scan_in && !puser_scan_in->chan_list[0].chan_number &&
+ puser_scan_in->chan_list[0].radio_type & BAND_SPECIFIED) {
+ radio_type =
+ puser_scan_in->chan_list[0].radio_type & ~BAND_SPECIFIED;
+ if (!radio_type && (pscan_region->band != BAND_B) &&
+ (pscan_region->band != BAND_G))
+ continue;
+ if (radio_type && (pscan_region->band != BAND_A))
+ continue;
+ }
+ if (!wlan_is_band_compatible
+ (pmpriv->config_bands | pmadapter->adhoc_start_band,
+ pscan_region->band))
+ continue;
+ for (next_chan = 0;
+ next_chan < pscan_region->num_cfp; next_chan++, chan_idx++) {
+ /* Set the default scan type to the user specified type, will later
+ be changed to passive on a per channel basis if restricted by
+ regulatory requirements (11d or 11h) */
+ scan_type = pmadapter->scan_type;
+ cfp = pscan_region->pcfp + next_chan;
+
+ if (scan_type == MLAN_SCAN_TYPE_ACTIVE
+ && wlan_11d_is_enabled(pmpriv)) {
+ scan_type = wlan_11d_get_scan_type(pmadapter,
+ pscan_region->band,
+ (t_u8) cfp->channel,
+ &pmadapter->
+ parsed_region_chan);
+ }
+
+ switch (pscan_region->band) {
+ case BAND_A:
+ pscan_chan_list[chan_idx].radio_type =
+ HostCmd_SCAN_RADIO_TYPE_A;
+ if (!wlan_11d_is_enabled(pmpriv)) {
+ /* 11D not available... play it safe on DFS channels */
+ if (wlan_11h_radar_detect_required
+ (pmpriv, (t_u8) cfp->channel))
+ scan_type = MLAN_SCAN_TYPE_PASSIVE;
+ }
+ break;
+ case BAND_B:
+ case BAND_G:
+ default:
+ pscan_chan_list[chan_idx].radio_type =
+ HostCmd_SCAN_RADIO_TYPE_BG;
+ break;
+ }
+
+ if (puser_scan_in && puser_scan_in->chan_list[0].scan_time) {
+ pscan_chan_list[chan_idx].max_scan_time =
+ wlan_cpu_to_le16((t_u16) puser_scan_in->chan_list[0].
+ scan_time);
+ } else if (scan_type == MLAN_SCAN_TYPE_PASSIVE) {
+ pscan_chan_list[chan_idx].max_scan_time =
+ wlan_cpu_to_le16(pmadapter->passive_scan_time);
+ } else if (filtered_scan) {
+ pscan_chan_list[chan_idx].max_scan_time =
+ wlan_cpu_to_le16(pmadapter->specific_scan_time);
+ } else {
+ pscan_chan_list[chan_idx].max_scan_time =
+ wlan_cpu_to_le16(pmadapter->active_scan_time);
+ }
+
+ if (scan_type == MLAN_SCAN_TYPE_PASSIVE) {
+ pscan_chan_list[chan_idx].chan_scan_mode.passive_scan = MTRUE;
+ } else {
+ pscan_chan_list[chan_idx].chan_scan_mode.passive_scan = MFALSE;
+ }
+
+ pscan_chan_list[chan_idx].chan_number = (t_u8) cfp->channel;
+
+ if (filtered_scan) {
+ pscan_chan_list[chan_idx].chan_scan_mode.disable_chan_filt =
+ MTRUE;
+ }
+ }
+ }
+
+ LEAVE();
+}
+
+/**
+ * @brief Add WPS IE to probe request frame
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param pptlv_out A pointer to TLV to fill in
+ *
+ * @return N/A
+ */
+static void
+wlan_add_wps_probe_request_ie(IN mlan_private * pmpriv, OUT t_u8 ** pptlv_out)
+{
+ MrvlIEtypesHeader_t *tlv;
+
+ ENTER();
+
+ if (pmpriv->wps.wps_ie.vend_hdr.len) {
+ tlv = (MrvlIEtypesHeader_t *) * pptlv_out;
+ tlv->type = wlan_cpu_to_le16(VENDOR_SPECIFIC_221);
+ tlv->len = wlan_cpu_to_le16(pmpriv->wps.wps_ie.vend_hdr.len);
+ *pptlv_out += sizeof(MrvlIEtypesHeader_t);
+ memcpy(pmpriv->adapter, *pptlv_out,
+ pmpriv->wps.wps_ie.vend_hdr.oui,
+ pmpriv->wps.wps_ie.vend_hdr.len);
+ *pptlv_out += (pmpriv->wps.wps_ie.vend_hdr.len
+ + sizeof(MrvlIEtypesHeader_t));
+ }
+ LEAVE();
+}
+
+/**
+ * @brief Construct and send multiple scan config commands to the firmware
+ *
+ * Previous routines have created a wlan_scan_cmd_config with any requested
+ * TLVs. This function splits the channel TLV into max_chan_per_scan lists
+ * and sends the portion of the channel TLV along with the other TLVs
+ * to the wlan_cmd routines for execution in the firmware.
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param pioctl_buf A pointer to MLAN IOCTL Request buffer
+ * @param max_chan_per_scan Maximum number channels to be included in each
+ * scan command sent to firmware
+ * @param filtered_scan Flag indicating whether or not a BSSID or SSID
+ * filter is being used for the firmware command
+ * scan command sent to firmware
+ * @param pscan_cfg_out Scan configuration used for this scan.
+ * @param pchan_tlv_out Pointer in the pscan_cfg_out where the channel TLV
+ * should start. This is past any other TLVs that
+ * must be sent down in each firmware command.
+ * @param pscan_chan_list List of channels to scan in max_chan_per_scan segments
+ *
+ * @return MLAN_STATUS_SUCCESS or error return otherwise
+ */
+static mlan_status
+wlan_scan_channel_list(IN mlan_private * pmpriv,
+ IN t_void * pioctl_buf,
+ IN t_u32 max_chan_per_scan,
+ IN t_u8 filtered_scan,
+ OUT wlan_scan_cmd_config * pscan_cfg_out,
+ OUT MrvlIEtypes_ChanListParamSet_t * pchan_tlv_out,
+ IN ChanScanParamSet_t * pscan_chan_list)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_adapter *pmadapter = pmpriv->adapter;
+ ChanScanParamSet_t *ptmp_chan_list;
+ ChanScanParamSet_t *pstart_chan;
+ pmlan_ioctl_req pioctl_req = (mlan_ioctl_req *) pioctl_buf;
+
+ t_u32 tlv_idx;
+ t_u32 total_scan_time;
+ t_u32 done_early;
+ t_u32 cmd_no;
+
+ ENTER();
+
+ if (!pscan_cfg_out || !pchan_tlv_out || !pscan_chan_list) {
+ PRINTM(MINFO, "Scan: Null detect: %p, %p, %p\n",
+ pscan_cfg_out, pchan_tlv_out, pscan_chan_list);
+ if (pioctl_req)
+ pioctl_req->status_code = MLAN_ERROR_CMD_SCAN_FAIL;
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+ if (!pscan_chan_list->chan_number) {
+ PRINTM(MERROR, "Scan: No channel configured\n");
+ if (pioctl_req)
+ pioctl_req->status_code = MLAN_ERROR_CMD_SCAN_FAIL;
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+
+ pchan_tlv_out->header.type = wlan_cpu_to_le16(TLV_TYPE_CHANLIST);
+
+ /* Set the temp channel struct pointer to the start of the desired list */
+ ptmp_chan_list = pscan_chan_list;
+
+ /* Loop through the desired channel list, sending a new firmware scan
+ commands for each max_chan_per_scan channels (or for 1,6,11 individually
+ if configured accordingly) */
+ while (ptmp_chan_list->chan_number) {
+
+ tlv_idx = 0;
+ total_scan_time = 0;
+ pchan_tlv_out->header.len = 0;
+ pstart_chan = ptmp_chan_list;
+ done_early = MFALSE;
+
+ /*
+ * Construct the Channel TLV for the scan command. Continue to
+ * insert channel TLVs until:
+ * - the tlv_idx hits the maximum configured per scan command
+ * - the next channel to insert is 0 (end of desired channel list)
+ * - done_early is set (controlling individual scanning of 1,6,11)
+ */
+ while (tlv_idx < max_chan_per_scan && ptmp_chan_list->chan_number &&
+ !done_early) {
+
+ PRINTM(MINFO, "Scan: Chan(%3d), Radio(%d), Mode(%d,%d), Dur(%d)\n",
+ ptmp_chan_list->chan_number,
+ ptmp_chan_list->radio_type,
+ ptmp_chan_list->chan_scan_mode.passive_scan,
+ ptmp_chan_list->chan_scan_mode.disable_chan_filt,
+ wlan_le16_to_cpu(ptmp_chan_list->max_scan_time));
+
+ /* Copy the current channel TLV to the command being prepared */
+ memcpy(pmadapter, pchan_tlv_out->chan_scan_param + tlv_idx,
+ ptmp_chan_list, sizeof(pchan_tlv_out->chan_scan_param));
+
+ /* Increment the TLV header length by the size appended */
+ pchan_tlv_out->header.len += sizeof(pchan_tlv_out->chan_scan_param);
+
+ /*
+ * The tlv buffer length is set to the number of bytes of the
+ * between the channel tlv pointer and the start of the
+ * tlv buffer. This compensates for any TLVs that were appended
+ * before the channel list.
+ */
+ pscan_cfg_out->tlv_buf_len = (t_u32) ((t_u8 *) pchan_tlv_out
+ - pscan_cfg_out->tlv_buf);
+
+ /* Add the size of the channel tlv header and the data length */
+ pscan_cfg_out->tlv_buf_len += (sizeof(pchan_tlv_out->header)
+ + pchan_tlv_out->header.len);
+
+ /* Increment the index to the channel tlv we are constructing */
+ tlv_idx++;
+
+ /* Count the total scan time per command */
+ total_scan_time += wlan_le16_to_cpu(ptmp_chan_list->max_scan_time);
+
+ done_early = MFALSE;
+
+ /* Stop the loop if the *current* channel is in the 1,6,11 set and
+ we are not filtering on a BSSID or SSID. */
+ if (!filtered_scan && (ptmp_chan_list->chan_number == 1 ||
+ ptmp_chan_list->chan_number == 6 ||
+ ptmp_chan_list->chan_number == 11)) {
+ done_early = MTRUE;
+ }
+
+ /* Increment the tmp pointer to the next channel to be scanned */
+ ptmp_chan_list++;
+
+ /* Stop the loop if the *next* channel is in the 1,6,11 set. This
+ will cause it to be the only channel scanned on the next
+ interation */
+ if (!filtered_scan && (ptmp_chan_list->chan_number == 1 ||
+ ptmp_chan_list->chan_number == 6 ||
+ ptmp_chan_list->chan_number == 11)) {
+ done_early = MTRUE;
+ }
+ }
+
+ /* The total scan time should be less than scan command timeout value */
+ if (total_scan_time > MRVDRV_MAX_TOTAL_SCAN_TIME) {
+ PRINTM(MMSG,
+ "Total scan time %d ms is over limit (%d ms), scan skipped\n",
+ total_scan_time, MRVDRV_MAX_TOTAL_SCAN_TIME);
+ if (pioctl_req)
+ pioctl_req->status_code = MLAN_ERROR_CMD_SCAN_FAIL;
+ ret = MLAN_STATUS_FAILURE;
+ break;
+ }
+
+ pchan_tlv_out->header.len = wlan_cpu_to_le16(pchan_tlv_out->header.len);
+
+ pmadapter->pscan_channels = pstart_chan;
+
+ /* Send the scan command to the firmware with the specified cfg */
+ if (pmadapter->ext_scan)
+ cmd_no = HostCmd_CMD_802_11_SCAN_EXT;
+ else
+ cmd_no = HostCmd_CMD_802_11_SCAN;
+ ret = wlan_prepare_cmd(pmpriv,
+ cmd_no,
+ HostCmd_ACT_GEN_SET,
+ 0, pioctl_buf, pscan_cfg_out);
+ if (ret)
+ break;
+ }
+
+ LEAVE();
+
+ if (ret) {
+ return MLAN_STATUS_FAILURE;
+ }
+
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief Construct a wlan_scan_cmd_config structure to use in scan commands
+ *
+ * Application layer or other functions can invoke wlan_scan_networks
+ * with a scan configuration supplied in a wlan_ioctl_user_scan_cfg struct.
+ * This structure is used as the basis of one or many wlan_scan_cmd_config
+ * commands that are sent to the command processing module and sent to
+ * firmware.
+ *
+ * Create a wlan_scan_cmd_config based on the following user supplied
+ * parameters (if present):
+ * - SSID filter
+ * - BSSID filter
+ * - Number of Probes to be sent
+ * - Channel list
+ *
+ * If the SSID or BSSID filter is not present, disable/clear the filter.
+ * If the number of probes is not set, use the adapter default setting
+ * Qualify the channel
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param puser_scan_in MNULL or pointer to scan config parameters
+ * @param pscan_cfg_out Output parameter: Resulting scan configuration
+ * @param ppchan_list_out Output parameter: Pointer to the start of the
+ * channel TLV portion of the output scan config
+ * @param pscan_chan_list Output parameter: Pointer to the resulting
+ * channel list to scan
+ * @param pmax_chan_per_scan Output parameter: Number of channels to scan for
+ * each issuance of the firmware scan command
+ * @param pfiltered_scan Output parameter: Flag indicating whether or not
+ * a BSSID or SSID filter is being sent in the
+ * command to firmware. Used to increase the number
+ * of channels sent in a scan command and to
+ * disable the firmware channel scan filter.
+ * @param pscan_current_only Output parameter: Flag indicating whether or not
+ * we are only scanning our current active channel
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+static mlan_status
+wlan_scan_setup_scan_config(IN mlan_private * pmpriv,
+ IN const wlan_user_scan_cfg * puser_scan_in,
+ OUT wlan_scan_cmd_config * pscan_cfg_out,
+ OUT MrvlIEtypes_ChanListParamSet_t **
+ ppchan_list_out,
+ OUT ChanScanParamSet_t * pscan_chan_list,
+ OUT t_u8 * pmax_chan_per_scan,
+ OUT t_u8 * pfiltered_scan,
+ OUT t_u8 * pscan_current_only)
+{
+ mlan_adapter *pmadapter = pmpriv->adapter;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ MrvlIEtypes_NumProbes_t *pnum_probes_tlv;
+ MrvlIEtypes_WildCardSsIdParamSet_t *pwildcard_ssid_tlv;
+ MrvlIEtypes_RatesParamSet_t *prates_tlv;
+ const t_u8 zero_mac[MLAN_MAC_ADDR_LENGTH] = { 0, 0, 0, 0, 0, 0 };
+ t_u8 *ptlv_pos;
+ t_u32 num_probes;
+ t_u32 ssid_len;
+ t_u32 chan_idx;
+ t_u32 scan_type;
+ t_u16 scan_dur;
+ t_u8 channel;
+ t_u8 radio_type;
+ t_u32 ssid_idx;
+ t_u8 ssid_filter;
+ WLAN_802_11_RATES rates;
+ t_u32 rates_size;
+ MrvlIETypes_HTCap_t *pht_cap;
+
+ ENTER();
+
+ /* The tlv_buf_len is calculated for each scan command. The TLVs added in
+ this routine will be preserved since the routine that sends the command
+ will append channelTLVs at *ppchan_list_out. The difference between the
+ *ppchan_list_out and the tlv_buf start will be used to calculate the
+ size of anything we add in this routine. */
+ pscan_cfg_out->tlv_buf_len = 0;
+
+ /* Running tlv pointer. Assigned to ppchan_list_out at end of function so
+ later routines know where channels can be added to the command buf */
+ ptlv_pos = pscan_cfg_out->tlv_buf;
+
+ /* Initialize the scan as un-filtered; the flag is later set to TRUE below
+ if a SSID or BSSID filter is sent in the command */
+ *pfiltered_scan = MFALSE;
+
+ /* Initialize the scan as not being only on the current channel. If the
+ channel list is customized, only contains one channel, and is the active
+ channel, this is set true and data flow is not halted. */
+ *pscan_current_only = MFALSE;
+
+ if (puser_scan_in) {
+
+ ssid_filter = MFALSE;
+
+ /* Set the bss type scan filter, use Adapter setting if unset */
+ pscan_cfg_out->bss_mode = (puser_scan_in->bss_mode
+ ? (t_u8) puser_scan_in->bss_mode :
+ (t_u8) pmadapter->scan_mode);
+
+ /* Set the number of probes to send, use Adapter setting if unset */
+ num_probes = (puser_scan_in->num_probes ? puser_scan_in->num_probes :
+ pmadapter->scan_probes);
+
+ /*
+ * Set the BSSID filter to the incoming configuration,
+ * if non-zero. If not set, it will remain disabled (all zeros).
+ */
+ memcpy(pmadapter, pscan_cfg_out->specific_bssid,
+ puser_scan_in->specific_bssid,
+ sizeof(pscan_cfg_out->specific_bssid));
+
+ for (ssid_idx = 0; ((ssid_idx < NELEMENTS(puser_scan_in->ssid_list))
+ && (*puser_scan_in->ssid_list[ssid_idx].ssid ||
+ puser_scan_in->ssid_list[ssid_idx].max_len));
+ ssid_idx++) {
+
+ ssid_len =
+ wlan_strlen((t_s8 *) puser_scan_in->ssid_list[ssid_idx].ssid);
+
+ pwildcard_ssid_tlv
+ = (MrvlIEtypes_WildCardSsIdParamSet_t *) ptlv_pos;
+ pwildcard_ssid_tlv->header.type
+ = wlan_cpu_to_le16(TLV_TYPE_WILDCARDSSID);
+ pwildcard_ssid_tlv->header.len
+ = (t_u16) (ssid_len
+ + sizeof(pwildcard_ssid_tlv->max_ssid_length));
+ pwildcard_ssid_tlv->max_ssid_length
+ = puser_scan_in->ssid_list[ssid_idx].max_len;
+
+ memcpy(pmadapter, pwildcard_ssid_tlv->ssid,
+ puser_scan_in->ssid_list[ssid_idx].ssid,
+ MIN(MLAN_MAX_SSID_LENGTH, ssid_len));
+
+ ptlv_pos += (sizeof(pwildcard_ssid_tlv->header)
+ + pwildcard_ssid_tlv->header.len);
+
+ pwildcard_ssid_tlv->header.len
+ = wlan_cpu_to_le16(pwildcard_ssid_tlv->header.len);
+
+ PRINTM(MINFO, "Scan: ssid_list[%d]: %s, %d\n",
+ ssid_idx,
+ pwildcard_ssid_tlv->ssid,
+ pwildcard_ssid_tlv->max_ssid_length);
+
+ if (ssid_len) {
+ ssid_filter = MTRUE;
+ }
+ }
+
+ /*
+ * The default number of channels sent in the command is low to
+ * ensure the response buffer from the firmware does not truncate
+ * scan results. That is not an issue with an SSID or BSSID
+ * filter applied to the scan results in the firmware.
+ */
+ if ((ssid_idx && ssid_filter) ||
+ memcmp(pmadapter, pscan_cfg_out->specific_bssid, &zero_mac,
+ sizeof(zero_mac))) {
+ *pfiltered_scan = MTRUE;
+ }
+
+ } else {
+ pscan_cfg_out->bss_mode = (t_u8) pmadapter->scan_mode;
+ num_probes = pmadapter->scan_probes;
+ }
+
+ /*
+ * If a specific BSSID or SSID is used, the number of channels in the
+ * scan command will be increased to the absolute maximum.
+ */
+ if (*pfiltered_scan)
+ *pmax_chan_per_scan = MRVDRV_MAX_CHANNELS_PER_SPECIFIC_SCAN;
+ else
+ *pmax_chan_per_scan = MRVDRV_CHANNELS_PER_SCAN_CMD;
+
+ /* If the input config or adapter has the number of Probes set, add tlv */
+ if (num_probes) {
+
+ PRINTM(MINFO, "Scan: num_probes = %d\n", num_probes);
+
+ pnum_probes_tlv = (MrvlIEtypes_NumProbes_t *) ptlv_pos;
+ pnum_probes_tlv->header.type = wlan_cpu_to_le16(TLV_TYPE_NUMPROBES);
+ pnum_probes_tlv->header.len = sizeof(pnum_probes_tlv->num_probes);
+ pnum_probes_tlv->num_probes = wlan_cpu_to_le16((t_u16) num_probes);
+
+ ptlv_pos +=
+ sizeof(pnum_probes_tlv->header) + pnum_probes_tlv->header.len;
+
+ pnum_probes_tlv->header.len =
+ wlan_cpu_to_le16(pnum_probes_tlv->header.len);
+ }
+
+ /* Append rates tlv */
+ memset(pmadapter, rates, 0, sizeof(rates));
+
+ rates_size = wlan_get_supported_rates(pmpriv, pmpriv->bss_mode,
+ (pmpriv->bss_mode ==
+ MLAN_BSS_MODE_INFRA) ? pmadapter->
+ config_bands : pmadapter->
+ adhoc_start_band, rates);
+
+ prates_tlv = (MrvlIEtypes_RatesParamSet_t *) ptlv_pos;
+ prates_tlv->header.type = wlan_cpu_to_le16(TLV_TYPE_RATES);
+ prates_tlv->header.len = wlan_cpu_to_le16((t_u16) rates_size);
+ memcpy(pmadapter, prates_tlv->rates, rates, rates_size);
+ ptlv_pos += sizeof(prates_tlv->header) + rates_size;
+
+ PRINTM(MINFO, "SCAN_CMD: Rates size = %d\n", rates_size);
+
+ if (ISSUPP_11NENABLED(pmpriv->adapter->fw_cap_info)
+ && (pmpriv->adapter->config_bands & BAND_GN
+ || pmpriv->adapter->config_bands & BAND_AN)) {
+ pht_cap = (MrvlIETypes_HTCap_t *) ptlv_pos;
+ memset(pmadapter, pht_cap, 0, sizeof(MrvlIETypes_HTCap_t));
+ pht_cap->header.type = wlan_cpu_to_le16(HT_CAPABILITY);
+ pht_cap->header.len = sizeof(HTCap_t);
+ wlan_fill_ht_cap_tlv(pmpriv, pht_cap, pmpriv->adapter->config_bands);
+ HEXDUMP("SCAN: HT_CAPABILITIES IE", (t_u8 *) pht_cap,
+ sizeof(MrvlIETypes_HTCap_t));
+ ptlv_pos += sizeof(MrvlIETypes_HTCap_t);
+ pht_cap->header.len = wlan_cpu_to_le16(pht_cap->header.len);
+ }
+
+ wlan_add_wps_probe_request_ie(pmpriv, &ptlv_pos);
+
+ /*
+ * Set the output for the channel TLV to the address in the tlv buffer
+ * past any TLVs that were added in this function (SSID, num_probes).
+ * Channel TLVs will be added past this for each scan command, preserving
+ * the TLVs that were previously added.
+ */
+ *ppchan_list_out = (MrvlIEtypes_ChanListParamSet_t *) ptlv_pos;
+
+ if (puser_scan_in && puser_scan_in->chan_list[0].chan_number) {
+
+ PRINTM(MINFO, "Scan: Using supplied channel list\n");
+
+ for (chan_idx = 0;
+ chan_idx < WLAN_USER_SCAN_CHAN_MAX
+ && puser_scan_in->chan_list[chan_idx].chan_number; chan_idx++) {
+
+ channel = puser_scan_in->chan_list[chan_idx].chan_number;
+ (pscan_chan_list + chan_idx)->chan_number = channel;
+
+ radio_type = puser_scan_in->chan_list[chan_idx].radio_type;
+ (pscan_chan_list + chan_idx)->radio_type = radio_type;
+
+ scan_type = puser_scan_in->chan_list[chan_idx].scan_type;
+ if (scan_type == MLAN_SCAN_TYPE_UNCHANGED)
+ scan_type = pmadapter->scan_type;
+
+ if (radio_type == HostCmd_SCAN_RADIO_TYPE_A) {
+ if (pmadapter->fw_bands & BAND_A)
+ PRINTM(MINFO, "UserScan request for A Band channel %d!!\n",
+ channel);
+ else {
+ PRINTM(MERROR, "Scan in A band is not allowed!!\n");
+ ret = MLAN_STATUS_FAILURE;
+ LEAVE();
+ return ret;
+
+ }
+ }
+
+ /* Prevent active scanning on a radar controlled channel */
+ if (radio_type == HostCmd_SCAN_RADIO_TYPE_A) {
+ if (wlan_11h_radar_detect_required(pmpriv, channel)) {
+ scan_type = MLAN_SCAN_TYPE_PASSIVE;
+ }
+ }
+ if (scan_type == MLAN_SCAN_TYPE_PASSIVE) {
+ (pscan_chan_list + chan_idx)->chan_scan_mode.passive_scan =
+ MTRUE;
+ } else {
+ (pscan_chan_list + chan_idx)->chan_scan_mode.passive_scan =
+ MFALSE;
+ }
+
+ if (puser_scan_in->chan_list[chan_idx].scan_time) {
+ scan_dur = (t_u16) puser_scan_in->chan_list[chan_idx].scan_time;
+ } else {
+ if (scan_type == MLAN_SCAN_TYPE_PASSIVE) {
+ scan_dur = pmadapter->passive_scan_time;
+ } else if (*pfiltered_scan) {
+ scan_dur = pmadapter->specific_scan_time;
+ } else {
+ scan_dur = pmadapter->active_scan_time;
+ }
+ }
+
+ (pscan_chan_list + chan_idx)->min_scan_time =
+ wlan_cpu_to_le16(scan_dur);
+ (pscan_chan_list + chan_idx)->max_scan_time =
+ wlan_cpu_to_le16(scan_dur);
+ }
+
+ /* Check if we are only scanning the current channel */
+ if ((chan_idx == 1)
+ && (puser_scan_in->chan_list[0].chan_number
+ == pmpriv->curr_bss_params.bss_descriptor.channel)) {
+ *pscan_current_only = MTRUE;
+ PRINTM(MINFO, "Scan: Scanning current channel only\n");
+ }
+
+ } else {
+ PRINTM(MINFO, "Scan: Creating full region channel list\n");
+ wlan_scan_create_channel_list(pmpriv, puser_scan_in, pscan_chan_list,
+ *pfiltered_scan);
+ }
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Inspect the scan response buffer for pointers to expected TLVs
+ *
+ * TLVs can be included at the end of the scan response BSS information.
+ * Parse the data in the buffer for pointers to TLVs that can potentially
+ * be passed back in the response
+ *
+ * @param pmadapter Pointer to the mlan_adapter structure
+ * @param ptlv Pointer to the start of the TLV buffer to parse
+ * @param tlv_buf_size Size of the TLV buffer
+ * @param req_tlv_type Request TLV's type
+ * @param pptlv Output parameter: Pointer to the request TLV if found
+ *
+ * @return N/A
+ */
+static t_void
+wlan_ret_802_11_scan_get_tlv_ptrs(IN pmlan_adapter pmadapter,
+ IN MrvlIEtypes_Data_t * ptlv,
+ IN t_u32 tlv_buf_size,
+ IN t_u32 req_tlv_type,
+ OUT MrvlIEtypes_Data_t ** pptlv)
+{
+ MrvlIEtypes_Data_t *pcurrent_tlv;
+ t_u32 tlv_buf_left;
+ t_u32 tlv_type;
+ t_u32 tlv_len;
+
+ ENTER();
+
+ pcurrent_tlv = ptlv;
+ tlv_buf_left = tlv_buf_size;
+ *pptlv = MNULL;
+
+ PRINTM(MINFO, "SCAN_RESP: tlv_buf_size = %d\n", tlv_buf_size);
+
+ while (tlv_buf_left >= sizeof(MrvlIEtypesHeader_t)) {
+
+ tlv_type = wlan_le16_to_cpu(pcurrent_tlv->header.type);
+ tlv_len = wlan_le16_to_cpu(pcurrent_tlv->header.len);
+
+ if (sizeof(ptlv->header) + tlv_len > tlv_buf_left) {
+ PRINTM(MERROR, "SCAN_RESP: TLV buffer corrupt\n");
+ break;
+ }
+
+ if (req_tlv_type == tlv_type) {
+ switch (tlv_type) {
+ case TLV_TYPE_TSFTIMESTAMP:
+ PRINTM(MINFO, "SCAN_RESP: TSF Timestamp TLV, len = %d\n",
+ tlv_len);
+ *pptlv = (MrvlIEtypes_Data_t *) pcurrent_tlv;
+ break;
+ case TLV_TYPE_CHANNELBANDLIST:
+ PRINTM(MINFO, "SCAN_RESP: CHANNEL BAND LIST TLV, len = %d\n",
+ tlv_len);
+ *pptlv = (MrvlIEtypes_Data_t *) pcurrent_tlv;
+ break;
+ default:
+ PRINTM(MERROR, "SCAN_RESP: Unhandled TLV = %d\n", tlv_type);
+ /* Give up, this seems corrupted */
+ LEAVE();
+ return;
+ }
+ }
+
+ if (*pptlv) {
+ // HEXDUMP("SCAN_RESP: TLV Buf", (t_u8 *)*pptlv+4, tlv_len);
+ break;
+ }
+
+ tlv_buf_left -= (sizeof(ptlv->header) + tlv_len);
+ pcurrent_tlv = (MrvlIEtypes_Data_t *) (pcurrent_tlv->data + tlv_len);
+
+ } /* while */
+
+ LEAVE();
+}
+
+/**
+ * @brief Interpret a BSS scan response returned from the firmware
+ *
+ * Parse the various fixed fields and IEs passed back for a BSS probe
+ * response or beacon from the scan command. Record information as needed
+ * in the scan table BSSDescriptor_t for that entry.
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pbss_entry Output parameter: Pointer to the BSS Entry
+ * @param pbeacon_info Pointer to the Beacon information
+ * @param bytes_left Number of bytes left to parse
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+static mlan_status
+wlan_interpret_bss_desc_with_ie(IN pmlan_adapter pmadapter,
+ OUT BSSDescriptor_t * pbss_entry,
+ IN t_u8 ** pbeacon_info, IN t_u32 * bytes_left)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ IEEEtypes_ElementId_e element_id;
+ IEEEtypes_FhParamSet_t *pfh_param_set;
+ IEEEtypes_DsParamSet_t *pds_param_set;
+ IEEEtypes_CfParamSet_t *pcf_param_set;
+ IEEEtypes_IbssParamSet_t *pibss_param_set;
+ IEEEtypes_CapInfo_t *pcap_info;
+ WLAN_802_11_FIXED_IEs fixed_ie;
+ t_u8 *pcurrent_ptr;
+ t_u8 *prate;
+ t_u8 element_len;
+ t_u16 total_ie_len;
+ t_u8 bytes_to_copy;
+ t_u8 rate_size;
+ t_u16 beacon_size;
+ t_u8 found_data_rate_ie;
+ t_u32 bytes_left_for_current_beacon;
+ IEEEtypes_ERPInfo_t *perp_info;
+
+ IEEEtypes_VendorSpecific_t *pvendor_ie;
+ const t_u8 wpa_oui[4] = { 0x00, 0x50, 0xf2, 0x01 };
+ const t_u8 wmm_oui[4] = { 0x00, 0x50, 0xf2, 0x02 };
+
+ IEEEtypes_CountryInfoSet_t *pcountry_info;
+
+ ENTER();
+
+ found_data_rate_ie = MFALSE;
+ rate_size = 0;
+ beacon_size = 0;
+
+ if (*bytes_left >= sizeof(beacon_size)) {
+ /* Extract & convert beacon size from the command buffer */
+ memcpy(pmadapter, &beacon_size, *pbeacon_info, sizeof(beacon_size));
+ beacon_size = wlan_le16_to_cpu(beacon_size);
+ *bytes_left -= sizeof(beacon_size);
+ *pbeacon_info += sizeof(beacon_size);
+ }
+
+ if (!beacon_size || beacon_size > *bytes_left) {
+
+ *pbeacon_info += *bytes_left;
+ *bytes_left = 0;
+
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+
+ /* Initialize the current working beacon pointer for this BSS iteration */
+ pcurrent_ptr = *pbeacon_info;
+
+ /* Advance the return beacon pointer past the current beacon */
+ *pbeacon_info += beacon_size;
+ *bytes_left -= beacon_size;
+
+ bytes_left_for_current_beacon = beacon_size;
+
+ if (bytes_left_for_current_beacon <
+ (MLAN_MAC_ADDR_LENGTH + sizeof(t_u8) + sizeof(WLAN_802_11_FIXED_IEs))) {
+ PRINTM(MERROR, "InterpretIE: Not enough bytes left\n");
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+
+ memcpy(pmadapter, pbss_entry->mac_address, pcurrent_ptr,
+ MLAN_MAC_ADDR_LENGTH);
+ PRINTM(MINFO, "InterpretIE: AP MAC Addr-%02x:%02x:%02x:%02x:%02x:%02x\n",
+ pbss_entry->mac_address[0], pbss_entry->mac_address[1],
+ pbss_entry->mac_address[2], pbss_entry->mac_address[3],
+ pbss_entry->mac_address[4], pbss_entry->mac_address[5]);
+
+ pcurrent_ptr += MLAN_MAC_ADDR_LENGTH;
+ bytes_left_for_current_beacon -= MLAN_MAC_ADDR_LENGTH;
+
+ /*
+ * Next 4 fields are RSSI (for legacy scan only), time stamp,
+ * beacon interval, and capability information
+ */
+ if (!pmadapter->ext_scan) {
+ /* RSSI is 1 byte long */
+ pbss_entry->rssi = (t_s32) (*pcurrent_ptr);
+ PRINTM(MINFO, "InterpretIE: RSSI=%02X\n", *pcurrent_ptr);
+ pcurrent_ptr += 1;
+ bytes_left_for_current_beacon -= 1;
+ }
+
+ /*
+ * The RSSI is not part of the beacon/probe response. After we have
+ * advanced pcurrent_ptr past the RSSI field, save the remaining
+ * data for use at the application layer
+ */
+ pbss_entry->pbeacon_buf = pcurrent_ptr;
+ pbss_entry->beacon_buf_size = bytes_left_for_current_beacon;
+
+ /* Time stamp is 8 bytes long */
+ memcpy(pmadapter, fixed_ie.time_stamp, pcurrent_ptr, 8);
+ memcpy(pmadapter, pbss_entry->time_stamp, pcurrent_ptr, 8);
+ pcurrent_ptr += 8;
+ bytes_left_for_current_beacon -= 8;
+
+ /* Beacon interval is 2 bytes long */
+ memcpy(pmadapter, &fixed_ie.beacon_interval, pcurrent_ptr, 2);
+ pbss_entry->beacon_period = wlan_le16_to_cpu(fixed_ie.beacon_interval);
+ pcurrent_ptr += 2;
+ bytes_left_for_current_beacon -= 2;
+
+ /* Capability information is 2 bytes long */
+ memcpy(pmadapter, &fixed_ie.capabilities, pcurrent_ptr, 2);
+ PRINTM(MINFO, "InterpretIE: fixed_ie.capabilities=0x%X\n",
+ fixed_ie.capabilities);
+ fixed_ie.capabilities = wlan_le16_to_cpu(fixed_ie.capabilities);
+ pcap_info = (IEEEtypes_CapInfo_t *) & fixed_ie.capabilities;
+ memcpy(pmadapter, &pbss_entry->cap_info, pcap_info,
+ sizeof(IEEEtypes_CapInfo_t));
+ pcurrent_ptr += 2;
+ bytes_left_for_current_beacon -= 2;
+
+ /* Rest of the current buffer are IE's */
+ PRINTM(MINFO, "InterpretIE: IELength for this AP = %d\n",
+ bytes_left_for_current_beacon);
+
+ HEXDUMP("InterpretIE: IE info", (t_u8 *) pcurrent_ptr,
+ bytes_left_for_current_beacon);
+
+ if (pcap_info->privacy) {
+ PRINTM(MINFO, "InterpretIE: AP WEP enabled\n");
+ pbss_entry->privacy = Wlan802_11PrivFilter8021xWEP;
+ } else {
+ pbss_entry->privacy = Wlan802_11PrivFilterAcceptAll;
+ }
+
+ if (pcap_info->ibss == 1) {
+ pbss_entry->bss_mode = MLAN_BSS_MODE_IBSS;
+ } else {
+ pbss_entry->bss_mode = MLAN_BSS_MODE_INFRA;
+ }
+
+ if (pcap_info->spectrum_mgmt == 1) {
+ PRINTM(MINFO, "InterpretIE: 11h- Spectrum Management "
+ "capability bit found\n");
+ pbss_entry->wlan_11h_bss_info.sensed_11h = 1;
+ }
+
+ /* Process variable IE */
+ while (bytes_left_for_current_beacon >= 2) {
+ element_id = (IEEEtypes_ElementId_e) (*((t_u8 *) pcurrent_ptr));
+ element_len = *((t_u8 *) pcurrent_ptr + 1);
+ total_ie_len = element_len + sizeof(IEEEtypes_Header_t);
+
+ if (bytes_left_for_current_beacon < total_ie_len) {
+ PRINTM(MERROR, "InterpretIE: Error in processing IE, "
+ "bytes left < IE length\n");
+ bytes_left_for_current_beacon = 0;
+ continue;
+ }
+
+ switch (element_id) {
+
+ case SSID:
+ if (element_len > MRVDRV_MAX_SSID_LENGTH) {
+ bytes_left_for_current_beacon = 0;
+ continue;
+ }
+ pbss_entry->ssid.ssid_len = element_len;
+ memcpy(pmadapter, pbss_entry->ssid.ssid, (pcurrent_ptr + 2),
+ element_len);
+ PRINTM(MINFO, "InterpretIE: ssid: %-32s\n", pbss_entry->ssid.ssid);
+ break;
+
+ case SUPPORTED_RATES:
+ if (element_len > WLAN_SUPPORTED_RATES) {
+ bytes_left_for_current_beacon = 0;
+ continue;
+ }
+ memcpy(pmadapter, pbss_entry->data_rates, pcurrent_ptr + 2,
+ element_len);
+ memcpy(pmadapter, pbss_entry->supported_rates, pcurrent_ptr + 2,
+ element_len);
+ HEXDUMP("InterpretIE: SupportedRates:", pbss_entry->supported_rates,
+ element_len);
+ rate_size = element_len;
+ found_data_rate_ie = MTRUE;
+ break;
+
+ case FH_PARAM_SET:
+ pfh_param_set = (IEEEtypes_FhParamSet_t *) pcurrent_ptr;
+ pbss_entry->network_type_use = Wlan802_11FH;
+ memcpy(pmadapter, &pbss_entry->phy_param_set.fh_param_set,
+ pfh_param_set, MIN(total_ie_len,
+ sizeof(IEEEtypes_FhParamSet_t)));
+ pbss_entry->phy_param_set.fh_param_set.len =
+ MIN(element_len, (sizeof(IEEEtypes_FhParamSet_t)
+ - sizeof(IEEEtypes_Header_t)));
+ pbss_entry->phy_param_set.fh_param_set.dwell_time
+ =
+ wlan_le16_to_cpu(pbss_entry->phy_param_set.fh_param_set.
+ dwell_time);
+ break;
+
+ case DS_PARAM_SET:
+ pds_param_set = (IEEEtypes_DsParamSet_t *) pcurrent_ptr;
+
+ pbss_entry->network_type_use = Wlan802_11DS;
+ pbss_entry->channel = pds_param_set->current_chan;
+
+ memcpy(pmadapter, &pbss_entry->phy_param_set.ds_param_set,
+ pds_param_set, MIN(total_ie_len,
+ sizeof(IEEEtypes_DsParamSet_t)));
+ pbss_entry->phy_param_set.ds_param_set.len =
+ MIN(element_len, (sizeof(IEEEtypes_DsParamSet_t)
+ - sizeof(IEEEtypes_Header_t)));
+ break;
+
+ case CF_PARAM_SET:
+ pcf_param_set = (IEEEtypes_CfParamSet_t *) pcurrent_ptr;
+ memcpy(pmadapter, &pbss_entry->ss_param_set.cf_param_set,
+ pcf_param_set, MIN(total_ie_len,
+ sizeof(IEEEtypes_CfParamSet_t)));
+ pbss_entry->ss_param_set.cf_param_set.len =
+ MIN(element_len, (sizeof(IEEEtypes_CfParamSet_t)
+ - sizeof(IEEEtypes_Header_t)));
+ break;
+
+ case IBSS_PARAM_SET:
+ pibss_param_set = (IEEEtypes_IbssParamSet_t *) pcurrent_ptr;
+ pbss_entry->atim_window =
+ wlan_le16_to_cpu(pibss_param_set->atim_window);
+ memcpy(pmadapter, &pbss_entry->ss_param_set.ibss_param_set,
+ pibss_param_set, MIN(total_ie_len,
+ sizeof(IEEEtypes_IbssParamSet_t)));
+ pbss_entry->ss_param_set.ibss_param_set.len =
+ MIN(element_len, (sizeof(IEEEtypes_IbssParamSet_t)
+ - sizeof(IEEEtypes_Header_t)));
+ break;
+
+ /* Handle Country Info IE */
+ case COUNTRY_INFO:
+ pcountry_info = (IEEEtypes_CountryInfoSet_t *) pcurrent_ptr;
+
+ if (pcountry_info->len < sizeof(pcountry_info->country_code) ||
+ (unsigned) (pcountry_info->len + 2) >
+ sizeof(IEEEtypes_CountryInfoFullSet_t)) {
+ PRINTM(MERROR,
+ "InterpretIE: 11D- Err "
+ "country_info len =%d min=%d max=%d\n",
+ pcountry_info->len, sizeof(pcountry_info->country_code),
+ sizeof(IEEEtypes_CountryInfoFullSet_t));
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+
+ memcpy(pmadapter, &pbss_entry->country_info,
+ pcountry_info, pcountry_info->len + 2);
+ HEXDUMP("InterpretIE: 11D- country_info:",
+ (t_u8 *) pcountry_info, (t_u32) (pcountry_info->len + 2));
+ break;
+
+ case ERP_INFO:
+ perp_info = (IEEEtypes_ERPInfo_t *) pcurrent_ptr;
+ pbss_entry->erp_flags = perp_info->erp_flags;
+ break;
+
+ case POWER_CONSTRAINT:
+ case POWER_CAPABILITY:
+ case TPC_REPORT:
+ case CHANNEL_SWITCH_ANN:
+ case QUIET:
+ case IBSS_DFS:
+ case SUPPORTED_CHANNELS:
+ case TPC_REQUEST:
+ wlan_11h_process_bss_elem(pmadapter, &pbss_entry->wlan_11h_bss_info,
+ pcurrent_ptr);
+ break;
+ case EXTENDED_SUPPORTED_RATES:
+ /*
+ * Only process extended supported rate
+ * if data rate is already found.
+ * Data rate IE should come before
+ * extended supported rate IE
+ */
+ if (found_data_rate_ie) {
+ if ((element_len + rate_size) > WLAN_SUPPORTED_RATES) {
+ bytes_to_copy = (WLAN_SUPPORTED_RATES - rate_size);
+ } else {
+ bytes_to_copy = element_len;
+ }
+
+ prate = (t_u8 *) pbss_entry->data_rates;
+ prate += rate_size;
+ memcpy(pmadapter, prate, pcurrent_ptr + 2, bytes_to_copy);
+
+ prate = (t_u8 *) pbss_entry->supported_rates;
+ prate += rate_size;
+ memcpy(pmadapter, prate, pcurrent_ptr + 2, bytes_to_copy);
+ }
+ HEXDUMP("InterpretIE: ExtSupportedRates:",
+ pbss_entry->supported_rates, element_len + rate_size);
+ break;
+
+ case VENDOR_SPECIFIC_221:
+ pvendor_ie = (IEEEtypes_VendorSpecific_t *) pcurrent_ptr;
+
+ if (!memcmp
+ (pmadapter, pvendor_ie->vend_hdr.oui, wpa_oui,
+ sizeof(wpa_oui))) {
+ pbss_entry->pwpa_ie =
+ (IEEEtypes_VendorSpecific_t *) pcurrent_ptr;
+ pbss_entry->wpa_offset =
+ (t_u16) (pcurrent_ptr - pbss_entry->pbeacon_buf);
+ HEXDUMP("InterpretIE: Resp WPA_IE",
+ (t_u8 *) pbss_entry->pwpa_ie,
+ ((*(pbss_entry->pwpa_ie)).vend_hdr.len +
+ sizeof(IEEEtypes_Header_t)));
+ } else
+ if (!memcmp
+ (pmadapter, pvendor_ie->vend_hdr.oui, wmm_oui,
+ sizeof(wmm_oui))) {
+ if (total_ie_len == sizeof(IEEEtypes_WmmParameter_t)
+ || total_ie_len == sizeof(IEEEtypes_WmmInfo_t)) {
+
+ /*
+ * Only accept and copy the WMM IE if it matches
+ * the size expected for the WMM Info IE or the
+ * WMM Parameter IE.
+ */
+ memcpy(pmadapter, (t_u8 *) & pbss_entry->wmm_ie,
+ pcurrent_ptr, total_ie_len);
+ HEXDUMP("InterpretIE: Resp WMM_IE",
+ (t_u8 *) & pbss_entry->wmm_ie, total_ie_len);
+ }
+ }
+ break;
+ case RSN_IE:
+ pbss_entry->prsn_ie = (IEEEtypes_Generic_t *) pcurrent_ptr;
+ pbss_entry->rsn_offset =
+ (t_u16) (pcurrent_ptr - pbss_entry->pbeacon_buf);
+ HEXDUMP("InterpretIE: Resp RSN_IE", (t_u8 *) pbss_entry->prsn_ie,
+ (*(pbss_entry->prsn_ie)).ieee_hdr.len +
+ sizeof(IEEEtypes_Header_t));
+ break;
+ case WAPI_IE:
+ pbss_entry->pwapi_ie = (IEEEtypes_Generic_t *) pcurrent_ptr;
+ pbss_entry->wapi_offset =
+ (t_u16) (pcurrent_ptr - pbss_entry->pbeacon_buf);
+ HEXDUMP("InterpretIE: Resp WAPI_IE", (t_u8 *) pbss_entry->pwapi_ie,
+ (*(pbss_entry->pwapi_ie)).ieee_hdr.len +
+ sizeof(IEEEtypes_Header_t));
+ break;
+ case HT_CAPABILITY:
+ pbss_entry->pht_cap = (IEEEtypes_HTCap_t *) pcurrent_ptr;
+ pbss_entry->ht_cap_offset =
+ (t_u16) (pcurrent_ptr - pbss_entry->pbeacon_buf);
+ HEXDUMP("InterpretIE: Resp HTCAP_IE", (t_u8 *) pbss_entry->pht_cap,
+ (*(pbss_entry->pht_cap)).ieee_hdr.len +
+ sizeof(IEEEtypes_Header_t));
+ break;
+ case HT_OPERATION:
+ pbss_entry->pht_info = (IEEEtypes_HTInfo_t *) pcurrent_ptr;
+ pbss_entry->ht_info_offset =
+ (t_u16) (pcurrent_ptr - pbss_entry->pbeacon_buf);
+ HEXDUMP("InterpretIE: Resp HTINFO_IE",
+ (t_u8 *) pbss_entry->pht_info,
+ (*(pbss_entry->pht_info)).ieee_hdr.len +
+ sizeof(IEEEtypes_Header_t));
+ break;
+ case BSSCO_2040:
+ pbss_entry->pbss_co_2040 = (IEEEtypes_2040BSSCo_t *) pcurrent_ptr;
+ pbss_entry->bss_co_2040_offset =
+ (t_u16) (pcurrent_ptr - pbss_entry->pbeacon_buf);
+ HEXDUMP("InterpretIE: Resp 2040BSSCOEXISTANCE_IE",
+ (t_u8 *) pbss_entry->pbss_co_2040,
+ (*(pbss_entry->pbss_co_2040)).ieee_hdr.len +
+ sizeof(IEEEtypes_Header_t));
+ break;
+ case EXT_CAPABILITY:
+ pbss_entry->pext_cap = (IEEEtypes_ExtCap_t *) pcurrent_ptr;
+ pbss_entry->ext_cap_offset =
+ (t_u16) (pcurrent_ptr - pbss_entry->pbeacon_buf);
+ HEXDUMP("InterpretIE: Resp EXTCAP_IE",
+ (t_u8 *) pbss_entry->pext_cap,
+ (*(pbss_entry->pext_cap)).ieee_hdr.len +
+ sizeof(IEEEtypes_Header_t));
+ break;
+ case OVERLAPBSSSCANPARAM:
+ pbss_entry->poverlap_bss_scan_param =
+ (IEEEtypes_OverlapBSSScanParam_t *) pcurrent_ptr;
+ pbss_entry->overlap_bss_offset =
+ (t_u16) (pcurrent_ptr - pbss_entry->pbeacon_buf);
+ HEXDUMP("InterpretIE: Resp HTCAP_IE",
+ (t_u8 *) pbss_entry->poverlap_bss_scan_param,
+ (*(pbss_entry->poverlap_bss_scan_param)).ieee_hdr.len +
+ sizeof(IEEEtypes_Header_t));
+ break;
+ }
+
+ pcurrent_ptr += element_len + 2;
+
+ /* Need to account for IE ID and IE Len */
+ bytes_left_for_current_beacon -= (element_len + 2);
+
+ } /* while (bytes_left_for_current_beacon > 2) */
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Adjust ie's position in BSSDescriptor_t
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param pbss_entry A pointer to BSSDescriptor_t structure
+ *
+ * @return N/A
+ */
+static t_void
+wlan_adjust_ie_in_bss_entry(IN mlan_private * pmpriv,
+ IN BSSDescriptor_t * pbss_entry)
+{
+ ENTER();
+ if (pbss_entry->pbeacon_buf) {
+ if (pbss_entry->pwpa_ie) {
+ pbss_entry->pwpa_ie = (IEEEtypes_VendorSpecific_t *)
+ (pbss_entry->pbeacon_buf + pbss_entry->wpa_offset);
+ }
+ if (pbss_entry->prsn_ie) {
+ pbss_entry->prsn_ie = (IEEEtypes_Generic_t *)
+ (pbss_entry->pbeacon_buf + pbss_entry->rsn_offset);
+ }
+ if (pbss_entry->pwapi_ie) {
+ pbss_entry->pwapi_ie = (IEEEtypes_Generic_t *)
+ (pbss_entry->pbeacon_buf + pbss_entry->wapi_offset);
+ }
+ if (pbss_entry->pht_cap) {
+ pbss_entry->pht_cap = (IEEEtypes_HTCap_t *)
+ (pbss_entry->pbeacon_buf + pbss_entry->ht_cap_offset);
+ }
+ if (pbss_entry->pht_info) {
+ pbss_entry->pht_info = (IEEEtypes_HTInfo_t *)
+ (pbss_entry->pbeacon_buf + pbss_entry->ht_info_offset);
+ }
+ if (pbss_entry->pbss_co_2040) {
+ pbss_entry->pbss_co_2040 = (IEEEtypes_2040BSSCo_t *)
+ (pbss_entry->pbeacon_buf + pbss_entry->bss_co_2040_offset);
+ }
+ if (pbss_entry->pext_cap) {
+ pbss_entry->pext_cap = (IEEEtypes_ExtCap_t *)
+ (pbss_entry->pbeacon_buf + pbss_entry->ext_cap_offset);
+ }
+ if (pbss_entry->poverlap_bss_scan_param) {
+ pbss_entry->poverlap_bss_scan_param =
+ (IEEEtypes_OverlapBSSScanParam_t *)
+ (pbss_entry->pbeacon_buf + pbss_entry->overlap_bss_offset);
+ }
+ } else {
+ pbss_entry->pwpa_ie = MNULL;
+ pbss_entry->wpa_offset = 0;
+ pbss_entry->prsn_ie = MNULL;
+ pbss_entry->rsn_offset = 0;
+ pbss_entry->pwapi_ie = MNULL;
+ pbss_entry->wapi_offset = 0;
+ pbss_entry->pht_cap = MNULL;
+ pbss_entry->ht_cap_offset = 0;
+ pbss_entry->pht_info = MNULL;
+ pbss_entry->ht_info_offset = 0;
+ pbss_entry->pbss_co_2040 = MNULL;
+ pbss_entry->bss_co_2040_offset = 0;
+ pbss_entry->pext_cap = MNULL;
+ pbss_entry->ext_cap_offset = 0;
+ pbss_entry->poverlap_bss_scan_param = MNULL;
+ pbss_entry->overlap_bss_offset = 0;
+ }
+ LEAVE();
+ return;
+}
+
+/**
+ * @brief Store a beacon or probe response for a BSS returned in the scan
+ *
+ * Store a new scan response or an update for a previous scan response. New
+ * entries need to verify that they do not exceed the total amount of
+ * memory allocated for the table.
+
+ * Replacement entries need to take into consideration the amount of space
+ * currently allocated for the beacon/probe response and adjust the entry
+ * as needed.
+ *
+ * A small amount of extra pad (SCAN_BEACON_ENTRY_PAD) is generally reserved
+ * for an entry in case it is a beacon since a probe response for the
+ * network will by larger per the standard. This helps to reduce the
+ * amount of memory copying to fit a new probe response into an entry
+ * already occupied by a network's previously stored beacon.
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param beacon_idx Index in the scan table to store this entry; may be
+ * replacing an older duplicate entry for this BSS
+ * @param num_of_ent Number of entries currently in the table
+ * @param pnew_beacon Pointer to the new beacon/probe response to save
+ *
+ * @return N/A
+ */
+static t_void
+wlan_ret_802_11_scan_store_beacon(IN mlan_private * pmpriv,
+ IN t_u32 beacon_idx,
+ IN t_u32 num_of_ent,
+ IN BSSDescriptor_t * pnew_beacon)
+{
+ mlan_adapter *pmadapter = pmpriv->adapter;
+ t_u8 *pbcn_store;
+ t_u32 new_bcn_size;
+ t_u32 old_bcn_size;
+ t_u32 bcn_space;
+ t_u32 adj_idx;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ t_u8 *tmp_buf;
+ t_u16 bcn_size = 0;
+ t_u32 bcn_offset = 0;
+
+ ENTER();
+
+ if (pmadapter->pscan_table[beacon_idx].pbeacon_buf) {
+
+ new_bcn_size = pnew_beacon->beacon_buf_size;
+ old_bcn_size = pmadapter->pscan_table[beacon_idx].beacon_buf_size;
+ bcn_space = pmadapter->pscan_table[beacon_idx].beacon_buf_size_max;
+ pbcn_store = pmadapter->pscan_table[beacon_idx].pbeacon_buf;
+
+ /* Set the max to be the same as current entry unless changed below */
+ pnew_beacon->beacon_buf_size_max = bcn_space;
+
+ if (new_bcn_size == old_bcn_size) {
+ /*
+ * Beacon is the same size as the previous entry.
+ * Replace the previous contents with the scan result
+ */
+ memcpy(pmadapter, pbcn_store,
+ pnew_beacon->pbeacon_buf, pnew_beacon->beacon_buf_size);
+
+ } else if (new_bcn_size <= bcn_space) {
+ /*
+ * New beacon size will fit in the amount of space
+ * we have previously allocated for it
+ */
+
+ /* Copy the new beacon buffer entry over the old one */
+ memcpy(pmadapter, pbcn_store, pnew_beacon->pbeacon_buf,
+ new_bcn_size);
+
+ /*
+ * If the old beacon size was less than the maximum
+ * we had allotted for the entry, and the new entry
+ * is even smaller, reset the max size to the old beacon
+ * entry and compress the storage space (leaving a new
+ * pad space of (old_bcn_size - new_bcn_size).
+ */
+ if (old_bcn_size < bcn_space && new_bcn_size <= old_bcn_size) {
+ /*
+ * Old Beacon size is smaller than the allotted storage size.
+ * Shrink the allotted storage space.
+ */
+ PRINTM(MINFO, "AppControl: Smaller Duplicate Beacon (%d), "
+ "old = %d, new = %d, space = %d, left = %d\n",
+ beacon_idx, old_bcn_size, new_bcn_size, bcn_space,
+ (pmadapter->bcn_buf_size -
+ (pmadapter->pbcn_buf_end - pmadapter->bcn_buf)));
+
+ /*
+ * memmove (since the memory overlaps) the data
+ * after the beacon we just stored to the end of
+ * the current beacon. This cleans up any unused
+ * space the old larger beacon was using in the buffer
+ */
+ memmove(pmadapter,
+ (void *) ((t_ptr) pbcn_store + (t_ptr) old_bcn_size),
+ (void *) ((t_ptr) pbcn_store + (t_ptr) bcn_space),
+ (t_u32) ((t_ptr) pmadapter->pbcn_buf_end -
+ ((t_ptr) pbcn_store + (t_ptr) bcn_space)));
+
+ /*
+ * Decrement the end pointer by the difference between
+ * the old larger size and the new smaller size since
+ * we are using less space due to the new beacon being
+ * smaller
+ */
+ pmadapter->pbcn_buf_end -= (bcn_space - old_bcn_size);
+
+ /* Set the maximum storage size to the old beacon size */
+ pnew_beacon->beacon_buf_size_max = old_bcn_size;
+
+ /* Adjust beacon buffer pointers that are past the current */
+ for (adj_idx = 0; adj_idx < num_of_ent; adj_idx++) {
+ if (pmadapter->pscan_table[adj_idx].pbeacon_buf >
+ pbcn_store) {
+ pmadapter->pscan_table[adj_idx].pbeacon_buf -=
+ (bcn_space - old_bcn_size);
+ wlan_adjust_ie_in_bss_entry(pmpriv,
+ &pmadapter->
+ pscan_table[adj_idx]);
+ }
+ }
+ }
+ } else if (pmadapter->pbcn_buf_end + (new_bcn_size - bcn_space)
+ < (pmadapter->bcn_buf + pmadapter->bcn_buf_size)) {
+ /*
+ * Beacon is larger than space previously allocated (bcn_space)
+ * and there is enough space left in the beaconBuffer to store
+ * the additional data
+ */
+ PRINTM(MINFO, "AppControl: Larger Duplicate Beacon (%d), "
+ "old = %d, new = %d, space = %d, left = %d\n",
+ beacon_idx, old_bcn_size, new_bcn_size, bcn_space,
+ (pmadapter->bcn_buf_size -
+ (pmadapter->pbcn_buf_end - pmadapter->bcn_buf)));
+
+ /*
+ * memmove (since the memory overlaps) the data
+ * after the beacon we just stored to the end of
+ * the current beacon. This moves the data for
+ * the beacons after this further in memory to
+ * make space for the new larger beacon we are
+ * about to copy in.
+ */
+ memmove(pmadapter,
+ (void *) ((t_ptr) pbcn_store + (t_ptr) new_bcn_size),
+ (void *) ((t_ptr) pbcn_store + (t_ptr) bcn_space),
+ (t_u32) ((t_ptr) pmadapter->pbcn_buf_end -
+ ((t_ptr) pbcn_store + (t_ptr) bcn_space)));
+
+ /* Copy the new beacon buffer entry over the old one */
+ memcpy(pmadapter, pbcn_store, pnew_beacon->pbeacon_buf,
+ new_bcn_size);
+
+ /* Move the beacon end pointer by the amount of new beacon data we
+ are adding */
+ pmadapter->pbcn_buf_end += (new_bcn_size - bcn_space);
+
+ /*
+ * This entry is bigger than the allotted max space
+ * previously reserved. Increase the max space to
+ * be equal to the new beacon size
+ */
+ pnew_beacon->beacon_buf_size_max = new_bcn_size;
+
+ /* Adjust beacon buffer pointers that are past the current */
+ for (adj_idx = 0; adj_idx < num_of_ent; adj_idx++) {
+ if (pmadapter->pscan_table[adj_idx].pbeacon_buf > pbcn_store) {
+ pmadapter->pscan_table[adj_idx].pbeacon_buf
+ += (new_bcn_size - bcn_space);
+ wlan_adjust_ie_in_bss_entry(pmpriv,
+ &pmadapter->
+ pscan_table[adj_idx]);
+ }
+ }
+ } else {
+ /*
+ * Beacon is larger than the previously allocated space, but
+ * there is not enough free space to store the additional data
+ */
+ PRINTM(MERROR,
+ "AppControl: Failed: Larger Duplicate Beacon (%d),"
+ " old = %d, new = %d, space = %d, left = %d\n",
+ beacon_idx, old_bcn_size, new_bcn_size, bcn_space,
+ (pmadapter->bcn_buf_size -
+ (pmadapter->pbcn_buf_end - pmadapter->bcn_buf)));
+
+ /* Storage failure, keep old beacon intact */
+ pnew_beacon->beacon_buf_size = old_bcn_size;
+ if (pnew_beacon->pwpa_ie)
+ pnew_beacon->wpa_offset =
+ pmadapter->pscan_table[beacon_idx].wpa_offset;
+ if (pnew_beacon->prsn_ie)
+ pnew_beacon->rsn_offset =
+ pmadapter->pscan_table[beacon_idx].rsn_offset;
+ if (pnew_beacon->pwapi_ie)
+ pnew_beacon->wapi_offset =
+ pmadapter->pscan_table[beacon_idx].wapi_offset;
+ if (pnew_beacon->pht_cap)
+ pnew_beacon->ht_cap_offset =
+ pmadapter->pscan_table[beacon_idx].ht_cap_offset;
+ if (pnew_beacon->pht_info)
+ pnew_beacon->ht_info_offset =
+ pmadapter->pscan_table[beacon_idx].ht_info_offset;
+ if (pnew_beacon->pbss_co_2040)
+ pnew_beacon->bss_co_2040_offset =
+ pmadapter->pscan_table[beacon_idx].bss_co_2040_offset;
+ if (pnew_beacon->pext_cap)
+ pnew_beacon->ext_cap_offset =
+ pmadapter->pscan_table[beacon_idx].ext_cap_offset;
+ if (pnew_beacon->poverlap_bss_scan_param)
+ pnew_beacon->overlap_bss_offset =
+ pmadapter->pscan_table[beacon_idx].overlap_bss_offset;
+ }
+ /* Point the new entry to its permanent storage space */
+ pnew_beacon->pbeacon_buf = pbcn_store;
+ wlan_adjust_ie_in_bss_entry(pmpriv, pnew_beacon);
+ } else {
+ if ((pmadapter->pbcn_buf_end + pnew_beacon->beacon_buf_size +
+ SCAN_BEACON_ENTRY_PAD > (pmadapter->bcn_buf +
+ pmadapter->bcn_buf_size)) &&
+ (pmadapter->bcn_buf_size < MAX_SCAN_BEACON_BUFFER)) {
+ /* no space for this entry, realloc bcn buffer */
+ ret = pmadapter->callbacks.moal_malloc(pmadapter->pmoal_handle,
+ pmadapter->bcn_buf_size +
+ DEFAULT_SCAN_BEACON_BUFFER,
+ MLAN_MEM_DEF,
+ (t_u8 **) & tmp_buf);
+ if ((ret == MLAN_STATUS_SUCCESS) && (tmp_buf)) {
+ PRINTM(MCMND,
+ "Realloc Beacon buffer, old size=%d, new_size=%d\n",
+ pmadapter->bcn_buf_size,
+ pmadapter->bcn_buf_size + DEFAULT_SCAN_BEACON_BUFFER);
+ bcn_size = pmadapter->pbcn_buf_end - pmadapter->bcn_buf;
+ memcpy(pmadapter, tmp_buf, pmadapter->bcn_buf, bcn_size);
+ /* Adjust beacon buffer pointers that are past the current */
+ for (adj_idx = 0; adj_idx < num_of_ent; adj_idx++) {
+ bcn_offset =
+ pmadapter->pscan_table[adj_idx].pbeacon_buf -
+ pmadapter->bcn_buf;
+ pmadapter->pscan_table[adj_idx].pbeacon_buf =
+ tmp_buf + bcn_offset;
+ wlan_adjust_ie_in_bss_entry(pmpriv,
+ &pmadapter->
+ pscan_table[adj_idx]);
+ }
+ pmadapter->pbcn_buf_end = tmp_buf + bcn_size;
+ pmadapter->callbacks.moal_mfree(pmadapter->pmoal_handle,
+ (t_u8 *) pmadapter->bcn_buf);
+ pmadapter->bcn_buf = tmp_buf;
+ pmadapter->bcn_buf_size += DEFAULT_SCAN_BEACON_BUFFER;
+ }
+ }
+ /*
+ * No existing beacon data exists for this entry, check to see
+ * if we can fit it in the remaining space
+ */
+ if (pmadapter->pbcn_buf_end + pnew_beacon->beacon_buf_size +
+ SCAN_BEACON_ENTRY_PAD < (pmadapter->bcn_buf +
+ pmadapter->bcn_buf_size)) {
+
+ /*
+ * Copy the beacon buffer data from the local entry to the
+ * adapter dev struct buffer space used to store the raw
+ * beacon data for each entry in the scan table
+ */
+ memcpy(pmadapter, pmadapter->pbcn_buf_end, pnew_beacon->pbeacon_buf,
+ pnew_beacon->beacon_buf_size);
+
+ /* Update the beacon ptr to point to the table save area */
+ pnew_beacon->pbeacon_buf = pmadapter->pbcn_buf_end;
+ pnew_beacon->beacon_buf_size_max = (pnew_beacon->beacon_buf_size
+ + SCAN_BEACON_ENTRY_PAD);
+ wlan_adjust_ie_in_bss_entry(pmpriv, pnew_beacon);
+
+ /* Increment the end pointer by the size reserved */
+ pmadapter->pbcn_buf_end += pnew_beacon->beacon_buf_size_max;
+
+ PRINTM(MINFO, "AppControl: Beacon[%02d] sz=%03d,"
+ " used = %04d, left = %04d\n",
+ beacon_idx,
+ pnew_beacon->beacon_buf_size,
+ (pmadapter->pbcn_buf_end - pmadapter->bcn_buf),
+ (pmadapter->bcn_buf_size -
+ (pmadapter->pbcn_buf_end - pmadapter->bcn_buf)));
+ } else {
+ /*
+ * No space for new beacon
+ */
+ PRINTM(MCMND, "AppControl: No space beacon (%d): "
+ "%02x:%02x:%02x:%02x:%02x:%02x; sz=%03d, left=%03d\n",
+ beacon_idx,
+ pnew_beacon->mac_address[0], pnew_beacon->mac_address[1],
+ pnew_beacon->mac_address[2], pnew_beacon->mac_address[3],
+ pnew_beacon->mac_address[4], pnew_beacon->mac_address[5],
+ pnew_beacon->beacon_buf_size,
+ (pmadapter->bcn_buf_size -
+ (pmadapter->pbcn_buf_end - pmadapter->bcn_buf)));
+
+ /* Storage failure; clear storage records for this bcn */
+ pnew_beacon->pbeacon_buf = MNULL;
+ pnew_beacon->beacon_buf_size = 0;
+ pnew_beacon->beacon_buf_size_max = 0;
+ wlan_adjust_ie_in_bss_entry(pmpriv, pnew_beacon);
+ }
+ }
+
+ LEAVE();
+}
+
+/**
+ * @brief Restore a beacon buffer of the current bss descriptor
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ *
+ * @return N/A
+ */
+static t_void
+wlan_restore_curr_bcn(IN mlan_private * pmpriv)
+{
+ mlan_adapter *pmadapter = pmpriv->adapter;
+ mlan_callbacks *pcb = (pmlan_callbacks) & pmadapter->callbacks;
+ BSSDescriptor_t *pcurr_bss = &pmpriv->curr_bss_params.bss_descriptor;
+
+ ENTER();
+
+ if (pmpriv->pcurr_bcn_buf &&
+ ((pmadapter->pbcn_buf_end + pmpriv->curr_bcn_size) <
+ (pmadapter->bcn_buf + pmadapter->bcn_buf_size))) {
+
+ pcb->moal_spin_lock(pmadapter->pmoal_handle, pmpriv->curr_bcn_buf_lock);
+
+ /* restore the current beacon buffer */
+ memcpy(pmadapter, pmadapter->pbcn_buf_end, pmpriv->pcurr_bcn_buf,
+ pmpriv->curr_bcn_size);
+ pcurr_bss->pbeacon_buf = pmadapter->pbcn_buf_end;
+ pcurr_bss->beacon_buf_size = pmpriv->curr_bcn_size;
+ pmadapter->pbcn_buf_end += pmpriv->curr_bcn_size;
+
+ /* adjust the pointers in the current bss descriptor */
+ if (pcurr_bss->pwpa_ie) {
+ pcurr_bss->pwpa_ie = (IEEEtypes_VendorSpecific_t *)
+ (pcurr_bss->pbeacon_buf + pcurr_bss->wpa_offset);
+ }
+ if (pcurr_bss->prsn_ie) {
+ pcurr_bss->prsn_ie = (IEEEtypes_Generic_t *)
+ (pcurr_bss->pbeacon_buf + pcurr_bss->rsn_offset);
+ }
+ if (pcurr_bss->pht_cap) {
+ pcurr_bss->pht_cap = (IEEEtypes_HTCap_t *)
+ (pcurr_bss->pbeacon_buf + pcurr_bss->ht_cap_offset);
+ }
+
+ if (pcurr_bss->pht_info) {
+ pcurr_bss->pht_info = (IEEEtypes_HTInfo_t *)
+ (pcurr_bss->pbeacon_buf + pcurr_bss->ht_info_offset);
+ }
+
+ if (pcurr_bss->pbss_co_2040) {
+ pcurr_bss->pbss_co_2040 = (IEEEtypes_2040BSSCo_t *)
+ (pcurr_bss->pbeacon_buf + pcurr_bss->bss_co_2040_offset);
+ }
+
+ if (pcurr_bss->pext_cap) {
+ pcurr_bss->pext_cap = (IEEEtypes_ExtCap_t *)
+ (pcurr_bss->pbeacon_buf + pcurr_bss->ext_cap_offset);
+ }
+
+ if (pcurr_bss->poverlap_bss_scan_param) {
+ pcurr_bss->poverlap_bss_scan_param =
+ (IEEEtypes_OverlapBSSScanParam_t *)
+ (pcurr_bss->pbeacon_buf + pcurr_bss->overlap_bss_offset);
+ }
+
+ pcb->moal_spin_unlock(pmadapter->pmoal_handle,
+ pmpriv->curr_bcn_buf_lock);
+
+ PRINTM(MINFO, "current beacon restored %d\n", pmpriv->curr_bcn_size);
+ } else {
+ PRINTM(MWARN, "curr_bcn_buf not saved or bcn_buf has no space\n");
+ }
+
+ LEAVE();
+}
+
+/**
+ * @brief Post process the scan table after a new scan command has completed
+ *
+ * Inspect each entry of the scan table and try to find an entry that
+ * matches our current associated/joined network from the scan. If
+ * one is found, update the stored copy of the BSSDescriptor for our
+ * current network.
+ *
+ * Debug dump the current scan table contents if compiled accordingly.
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ *
+ * @return N/A
+ */
+static t_void
+wlan_scan_process_results(IN mlan_private * pmpriv)
+{
+ mlan_adapter *pmadapter = pmpriv->adapter;
+ t_s32 j;
+ t_u32 i;
+
+ ENTER();
+
+ if (pmpriv->media_connected == MTRUE) {
+
+ j = wlan_find_ssid_in_list(pmpriv,
+ &pmpriv->curr_bss_params.bss_descriptor.ssid,
+ pmpriv->curr_bss_params.bss_descriptor.
+ mac_address, pmpriv->bss_mode);
+
+ if (j >= 0) {
+ pmadapter->callbacks.moal_spin_lock(pmadapter->pmoal_handle,
+ pmpriv->curr_bcn_buf_lock);
+ pmpriv->curr_bss_params.bss_descriptor.pwpa_ie = MNULL;
+ pmpriv->curr_bss_params.bss_descriptor.wpa_offset = 0;
+ pmpriv->curr_bss_params.bss_descriptor.prsn_ie = MNULL;
+ pmpriv->curr_bss_params.bss_descriptor.rsn_offset = 0;
+ pmpriv->curr_bss_params.bss_descriptor.pwapi_ie = MNULL;
+ pmpriv->curr_bss_params.bss_descriptor.wapi_offset = 0;
+ pmpriv->curr_bss_params.bss_descriptor.pht_cap = MNULL;
+ pmpriv->curr_bss_params.bss_descriptor.ht_cap_offset = 0;
+ pmpriv->curr_bss_params.bss_descriptor.pht_info = MNULL;
+ pmpriv->curr_bss_params.bss_descriptor.ht_info_offset = 0;
+ pmpriv->curr_bss_params.bss_descriptor.pbss_co_2040 = MNULL;
+ pmpriv->curr_bss_params.bss_descriptor.bss_co_2040_offset = 0;
+ pmpriv->curr_bss_params.bss_descriptor.pext_cap = MNULL;
+ pmpriv->curr_bss_params.bss_descriptor.ext_cap_offset = 0;
+ pmpriv->curr_bss_params.bss_descriptor.poverlap_bss_scan_param =
+ MNULL;
+ pmpriv->curr_bss_params.bss_descriptor.overlap_bss_offset = 0;
+ pmpriv->curr_bss_params.bss_descriptor.pbeacon_buf = MNULL;
+ pmpriv->curr_bss_params.bss_descriptor.beacon_buf_size = 0;
+ pmpriv->curr_bss_params.bss_descriptor.beacon_buf_size_max = 0;
+
+ PRINTM(MINFO, "Found current ssid/bssid in list @ index #%d\n", j);
+ /* Make a copy of current BSSID descriptor */
+ memcpy(pmadapter, &pmpriv->curr_bss_params.bss_descriptor,
+ &pmadapter->pscan_table[j],
+ sizeof(pmpriv->curr_bss_params.bss_descriptor));
+
+ wlan_save_curr_bcn(pmpriv);
+ pmadapter->callbacks.moal_spin_unlock(pmadapter->pmoal_handle,
+ pmpriv->curr_bcn_buf_lock);
+ } else {
+ wlan_restore_curr_bcn(pmpriv);
+ }
+ }
+
+ for (i = 0; i < pmadapter->num_in_scan_table; i++)
+ PRINTM(MINFO, "Scan:(%02d) %02x:%02x:%02x:%02x:%02x:%02x, "
+ "RSSI[%03d], SSID[%s]\n",
+ i,
+ pmadapter->pscan_table[i].mac_address[0],
+ pmadapter->pscan_table[i].mac_address[1],
+ pmadapter->pscan_table[i].mac_address[2],
+ pmadapter->pscan_table[i].mac_address[3],
+ pmadapter->pscan_table[i].mac_address[4],
+ pmadapter->pscan_table[i].mac_address[5],
+ (t_s32) pmadapter->pscan_table[i].rssi,
+ pmadapter->pscan_table[i].ssid.ssid);
+
+ /*
+ * Prepares domain info from scan table and downloads the
+ * domain info command to the FW.
+ */
+ wlan_11d_prepare_dnld_domain_info_cmd(pmpriv);
+
+ LEAVE();
+}
+
+/**
+ * @brief Convert radio type scan parameter to a band config used in join cmd
+ *
+ * @param radio_type Scan parameter indicating the radio used for a channel
+ * in a scan command.
+ *
+ * @return Band type conversion of scanBand used in join/assoc cmds
+ *
+ */
+static t_u8
+radio_type_to_band(t_u8 radio_type)
+{
+ t_u8 ret_band;
+
+ switch (radio_type) {
+ case HostCmd_SCAN_RADIO_TYPE_A:
+ ret_band = BAND_A;
+ break;
+ case HostCmd_SCAN_RADIO_TYPE_BG:
+ default:
+ ret_band = BAND_G;
+ break;
+ }
+
+ return ret_band;
+}
+
+/**
+ * @brief Delete a specific indexed entry from the scan table.
+ *
+ * Delete the scan table entry indexed by table_idx. Compact the remaining
+ * entries and adjust any buffering of beacon/probe response data
+ * if needed.
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param table_idx Scan table entry index to delete from the table
+ *
+ * @return N/A
+ *
+ * @pre table_idx must be an index to a valid entry
+ */
+static t_void
+wlan_scan_delete_table_entry(IN mlan_private * pmpriv, IN t_s32 table_idx)
+{
+ mlan_adapter *pmadapter = pmpriv->adapter;
+ t_u32 del_idx;
+ t_u32 beacon_buf_adj;
+ t_u8 *pbeacon_buf;
+
+ ENTER();
+
+ /*
+ * Shift the saved beacon buffer data for the scan table back over the
+ * entry being removed. Update the end of buffer pointer. Save the
+ * deleted buffer allocation size for pointer adjustments for entries
+ * compacted after the deleted index.
+ */
+ beacon_buf_adj = pmadapter->pscan_table[table_idx].beacon_buf_size_max;
+
+ PRINTM(MINFO, "Scan: Delete Entry %d, beacon buffer removal = %d bytes\n",
+ table_idx, beacon_buf_adj);
+
+ /* Check if the table entry had storage allocated for its beacon */
+ if (beacon_buf_adj) {
+ pbeacon_buf = pmadapter->pscan_table[table_idx].pbeacon_buf;
+
+ /*
+ * Remove the entry's buffer space, decrement the table end pointer
+ * by the amount we are removing
+ */
+ pmadapter->pbcn_buf_end -= beacon_buf_adj;
+
+ PRINTM(MINFO,
+ "Scan: Delete Entry %d, compact data: %p <- %p (sz = %d)\n",
+ table_idx,
+ pbeacon_buf,
+ pbeacon_buf + beacon_buf_adj,
+ pmadapter->pbcn_buf_end - pbeacon_buf);
+
+ /*
+ * Compact data storage. Copy all data after the deleted entry's
+ * end address (pbeacon_buf + beacon_buf_adj) back to the original
+ * start address (pbeacon_buf).
+ *
+ * Scan table entries affected by the move will have their entry
+ * pointer adjusted below.
+ *
+ * Use memmove since the dest/src memory regions overlap.
+ */
+ memmove(pmadapter, pbeacon_buf,
+ (void *) ((t_ptr) pbeacon_buf + (t_ptr) beacon_buf_adj),
+ (t_u32) ((t_ptr) pmadapter->pbcn_buf_end -
+ (t_ptr) pbeacon_buf));
+ }
+
+ PRINTM(MINFO, "Scan: Delete Entry %d, num_in_scan_table = %d\n",
+ table_idx, pmadapter->num_in_scan_table);
+
+ /* Shift all of the entries after the table_idx back by one, compacting the
+ table and removing the requested entry */
+ for (del_idx = table_idx; (del_idx + 1) < pmadapter->num_in_scan_table;
+ del_idx++) {
+ /* Copy the next entry over this one */
+ memcpy(pmadapter, pmadapter->pscan_table + del_idx,
+ pmadapter->pscan_table + del_idx + 1, sizeof(BSSDescriptor_t));
+
+ /*
+ * Adjust this entry's pointer to its beacon buffer based on the
+ * removed/compacted entry from the deleted index. Don't decrement
+ * if the buffer pointer is MNULL (no data stored for this entry).
+ */
+ if (pmadapter->pscan_table[del_idx].pbeacon_buf) {
+ pmadapter->pscan_table[del_idx].pbeacon_buf -= beacon_buf_adj;
+ if (pmadapter->pscan_table[del_idx].pwpa_ie) {
+ pmadapter->pscan_table[del_idx].pwpa_ie =
+ (IEEEtypes_VendorSpecific_t *)
+ (pmadapter->pscan_table[del_idx].pbeacon_buf +
+ pmadapter->pscan_table[del_idx].wpa_offset);
+ }
+ if (pmadapter->pscan_table[del_idx].prsn_ie) {
+ pmadapter->pscan_table[del_idx].prsn_ie =
+ (IEEEtypes_Generic_t *)
+ (pmadapter->pscan_table[del_idx].pbeacon_buf +
+ pmadapter->pscan_table[del_idx].rsn_offset);
+ }
+ if (pmadapter->pscan_table[del_idx].pwapi_ie) {
+ pmadapter->pscan_table[del_idx].pwapi_ie =
+ (IEEEtypes_Generic_t *)
+ (pmadapter->pscan_table[del_idx].pbeacon_buf +
+ pmadapter->pscan_table[del_idx].wapi_offset);
+ }
+ if (pmadapter->pscan_table[del_idx].pht_cap) {
+ pmadapter->pscan_table[del_idx].pht_cap =
+ (IEEEtypes_HTCap_t *) (pmadapter->pscan_table[del_idx].
+ pbeacon_buf +
+ pmadapter->pscan_table[del_idx].
+ ht_cap_offset);
+ }
+
+ if (pmadapter->pscan_table[del_idx].pht_info) {
+ pmadapter->pscan_table[del_idx].pht_info =
+ (IEEEtypes_HTInfo_t *) (pmadapter->pscan_table[del_idx].
+ pbeacon_buf +
+ pmadapter->pscan_table[del_idx].
+ ht_info_offset);
+ }
+ if (pmadapter->pscan_table[del_idx].pbss_co_2040) {
+ pmadapter->pscan_table[del_idx].pbss_co_2040 =
+ (IEEEtypes_2040BSSCo_t *) (pmadapter->pscan_table[del_idx].
+ pbeacon_buf +
+ pmadapter->pscan_table[del_idx].
+ bss_co_2040_offset);
+ }
+ if (pmadapter->pscan_table[del_idx].pext_cap) {
+ pmadapter->pscan_table[del_idx].pext_cap =
+ (IEEEtypes_ExtCap_t *) (pmadapter->pscan_table[del_idx].
+ pbeacon_buf +
+ pmadapter->pscan_table[del_idx].
+ ext_cap_offset);
+ }
+ if (pmadapter->pscan_table[del_idx].poverlap_bss_scan_param) {
+ pmadapter->pscan_table[del_idx].poverlap_bss_scan_param =
+ (IEEEtypes_OverlapBSSScanParam_t *) (pmadapter->
+ pscan_table[del_idx].
+ pbeacon_buf +
+ pmadapter->
+ pscan_table[del_idx].
+ overlap_bss_offset);
+ }
+
+ }
+ }
+
+ /* The last entry is invalid now that it has been deleted or moved back */
+ memset(pmadapter, pmadapter->pscan_table + pmadapter->num_in_scan_table - 1,
+ 0x00, sizeof(BSSDescriptor_t));
+
+ pmadapter->num_in_scan_table--;
+
+ LEAVE();
+}
+
+/**
+ * @brief Delete all occurrences of a given SSID from the scan table
+ *
+ * Iterate through the scan table and delete all entries that match a given
+ * SSID. Compact the remaining scan table entries.
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param pdel_ssid Pointer to an SSID to be used in deleting all
+ * matching SSIDs from the scan table
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+static mlan_status
+wlan_scan_delete_ssid_table_entry(IN mlan_private * pmpriv,
+ IN mlan_802_11_ssid * pdel_ssid)
+{
+ mlan_status ret = MLAN_STATUS_FAILURE;
+ t_s32 table_idx;
+
+ ENTER();
+
+ PRINTM(MINFO, "Scan: Delete Ssid Entry: %-32s\n", pdel_ssid->ssid);
+
+ /* If the requested SSID is found in the table, delete it. Then keep
+ searching the table for multiple entries for the SSID until no more are
+ found */
+ while ((table_idx = wlan_find_ssid_in_list(pmpriv,
+ pdel_ssid,
+ MNULL,
+ MLAN_BSS_MODE_AUTO)) >= 0) {
+ PRINTM(MINFO, "Scan: Delete SSID Entry: Found Idx = %d\n", table_idx);
+ ret = MLAN_STATUS_SUCCESS;
+ wlan_scan_delete_table_entry(pmpriv, table_idx);
+ }
+
+ LEAVE();
+ return ret;
+}
+
+/********************************************************
+ Global Functions
+********************************************************/
+
+/**
+ * @brief Check if a scanned network compatible with the driver settings
+ *
+ * WEP WPA WPA2 ad-hoc encrypt Network
+ * enabled enabled enabled AES mode Privacy WPA WPA2 Compatible
+ * 0 0 0 0 NONE 0 0 0 yes No security
+ * 0 1 0 0 x 1x 1 x yes WPA (disable HT if no AES)
+ * 0 0 1 0 x 1x x 1 yes WPA2 (disable HT if no AES)
+ * 0 0 0 1 NONE 1 0 0 yes Ad-hoc AES
+ * 1 0 0 0 NONE 1 0 0 yes Static WEP (disable HT)
+ * 0 0 0 0 !=NONE 1 0 0 yes Dynamic WEP
+ *
+ * @param pmpriv A pointer to mlan_private
+ * @param index Index in scan table to check against current driver settings
+ * @param mode Network mode: Infrastructure or IBSS
+ *
+ * @return Index in ScanTable, or negative value if error
+ */
+t_s32
+wlan_is_network_compatible(IN mlan_private * pmpriv,
+ IN t_u32 index, IN t_u32 mode)
+{
+ mlan_adapter *pmadapter = pmpriv->adapter;
+ BSSDescriptor_t *pbss_desc;
+
+ ENTER();
+
+ pbss_desc = &pmadapter->pscan_table[index];
+ pbss_desc->disable_11n = MFALSE;
+
+ /* Don't check for compatibility if roaming */
+ if ((pmpriv->media_connected == MTRUE)
+ && (pmpriv->bss_mode == MLAN_BSS_MODE_INFRA)
+ && (pbss_desc->bss_mode == MLAN_BSS_MODE_INFRA)) {
+ LEAVE();
+ return index;
+ }
+
+ if (pbss_desc->wlan_11h_bss_info.chan_switch_ann.element_id ==
+ CHANNEL_SWITCH_ANN) {
+ PRINTM(MINFO, "Don't connect to AP with CHANNEL_SWITCH_ANN IE.\n");
+ LEAVE();
+ return -1;
+ }
+
+ if (pmpriv->wps.session_enable == MTRUE) {
+ PRINTM(MINFO, "Return success directly in WPS period\n");
+ LEAVE();
+ return index;
+ }
+
+ if ((pbss_desc->bss_mode == mode) &&
+ (pmpriv->sec_info.ewpa_enabled == MTRUE)) {
+ if (((pbss_desc->pwpa_ie) &&
+ ((*(pbss_desc->pwpa_ie)).vend_hdr.element_id == WPA_IE)) ||
+ ((pbss_desc->prsn_ie) &&
+ ((*(pbss_desc->prsn_ie)).ieee_hdr.element_id == RSN_IE))) {
+ if (((pmpriv->adapter->config_bands & BAND_GN ||
+ pmpriv->adapter->config_bands & BAND_AN) &&
+ pbss_desc->pht_cap)
+ && (pmpriv->bss_mode == MLAN_BSS_MODE_INFRA)
+ && !is_wpa_oui_present(pmpriv->adapter, pbss_desc,
+ CIPHER_SUITE_CCMP)
+ && !is_rsn_oui_present(pmpriv->adapter, pbss_desc,
+ CIPHER_SUITE_CCMP)) {
+
+ if (is_wpa_oui_present
+ (pmpriv->adapter, pbss_desc, CIPHER_SUITE_TKIP)
+ || is_rsn_oui_present(pmpriv->adapter, pbss_desc,
+ CIPHER_SUITE_TKIP)) {
+ PRINTM(MINFO,
+ "Disable 11n if AES is not supported by AP\n");
+ pbss_desc->disable_11n = MTRUE;
+ } else {
+ LEAVE();
+ return -1;
+ }
+ }
+ LEAVE();
+ return index;
+ } else {
+ PRINTM(MINFO, "ewpa_enabled: Ignore none WPA/WPA2 AP\n");
+ LEAVE();
+ return -1;
+ }
+ }
+
+ if (pmpriv->sec_info.wapi_enabled &&
+ (pbss_desc->pwapi_ie &&
+ ((*(pbss_desc->pwapi_ie)).ieee_hdr.element_id == WAPI_IE))) {
+ PRINTM(MINFO, "Return success for WAPI AP\n");
+ LEAVE();
+ return index;
+ }
+
+ if (pbss_desc->bss_mode == mode) {
+ if (pmpriv->sec_info.wep_status == Wlan802_11WEPDisabled
+ && !pmpriv->sec_info.wpa_enabled
+ && !pmpriv->sec_info.wpa2_enabled
+ && ((!pbss_desc->pwpa_ie) ||
+ ((*(pbss_desc->pwpa_ie)).vend_hdr.element_id != WPA_IE))
+ && ((!pbss_desc->prsn_ie) ||
+ ((*(pbss_desc->prsn_ie)).ieee_hdr.element_id != RSN_IE))
+ && !pmpriv->adhoc_aes_enabled &&
+ pmpriv->sec_info.encryption_mode == MLAN_ENCRYPTION_MODE_NONE &&
+ !pbss_desc->privacy) {
+ /* No security */
+ LEAVE();
+ return index;
+ } else if (pmpriv->sec_info.wep_status == Wlan802_11WEPEnabled
+ && !pmpriv->sec_info.wpa_enabled
+ && !pmpriv->sec_info.wpa2_enabled
+ && !pmpriv->adhoc_aes_enabled && pbss_desc->privacy) {
+ /* Static WEP enabled */
+ PRINTM(MINFO, "Disable 11n in WEP mode\n");
+ pbss_desc->disable_11n = MTRUE;
+ LEAVE();
+ return index;
+ } else if (pmpriv->sec_info.wep_status == Wlan802_11WEPDisabled
+ && pmpriv->sec_info.wpa_enabled
+ && !pmpriv->sec_info.wpa2_enabled
+ && ((pbss_desc->pwpa_ie) &&
+ ((*(pbss_desc->pwpa_ie)).vend_hdr.element_id == WPA_IE))
+ && !pmpriv->adhoc_aes_enabled
+ /*
+ * Privacy bit may NOT be set in some APs like LinkSys WRT54G
+ * && pbss_desc->privacy
+ */
+ ) {
+ /* WPA enabled */
+ PRINTM(MINFO,
+ "wlan_is_network_compatible() WPA: index=%d wpa_ie=%#x "
+ "rsn_ie=%#x WEP=%s WPA=%s WPA2=%s EncMode=%#x "
+ "privacy=%#x\n", index,
+ (pbss_desc->pwpa_ie) ? (*(pbss_desc->pwpa_ie)).vend_hdr.
+ element_id : 0,
+ (pbss_desc->prsn_ie) ? (*(pbss_desc->prsn_ie)).ieee_hdr.
+ element_id : 0,
+ (pmpriv->sec_info.wep_status ==
+ Wlan802_11WEPEnabled) ? "e" : "d",
+ (pmpriv->sec_info.wpa_enabled) ? "e" : "d",
+ (pmpriv->sec_info.wpa2_enabled) ? "e" : "d",
+ pmpriv->sec_info.encryption_mode, pbss_desc->privacy);
+ if (((pmpriv->adapter->config_bands & BAND_GN ||
+ pmpriv->adapter->config_bands & BAND_AN) &&
+ pbss_desc->pht_cap)
+ && (pmpriv->bss_mode == MLAN_BSS_MODE_INFRA)
+ && !is_wpa_oui_present(pmpriv->adapter, pbss_desc,
+ CIPHER_SUITE_CCMP)) {
+ if (is_wpa_oui_present
+ (pmpriv->adapter, pbss_desc, CIPHER_SUITE_TKIP)) {
+ PRINTM(MINFO,
+ "Disable 11n if AES is not supported by AP\n");
+ pbss_desc->disable_11n = MTRUE;
+ } else {
+ LEAVE();
+ return -1;
+ }
+ }
+ LEAVE();
+ return index;
+ } else if (pmpriv->sec_info.wep_status == Wlan802_11WEPDisabled
+ && !pmpriv->sec_info.wpa_enabled
+ && pmpriv->sec_info.wpa2_enabled
+ && ((pbss_desc->prsn_ie) &&
+ ((*(pbss_desc->prsn_ie)).ieee_hdr.element_id == RSN_IE))
+ && !pmpriv->adhoc_aes_enabled
+ /*
+ * Privacy bit may NOT be set in some APs like LinkSys WRT54G
+ * && pbss_desc->privacy
+ */
+ ) {
+ /* WPA2 enabled */
+ PRINTM(MINFO,
+ "wlan_is_network_compatible() WPA2: index=%d wpa_ie=%#x "
+ "rsn_ie=%#x WEP=%s WPA=%s WPA2=%s EncMode=%#x "
+ "privacy=%#x\n", index,
+ (pbss_desc->pwpa_ie) ? (*(pbss_desc->pwpa_ie)).vend_hdr.
+ element_id : 0,
+ (pbss_desc->prsn_ie) ? (*(pbss_desc->prsn_ie)).ieee_hdr.
+ element_id : 0,
+ (pmpriv->sec_info.wep_status ==
+ Wlan802_11WEPEnabled) ? "e" : "d",
+ (pmpriv->sec_info.wpa_enabled) ? "e" : "d",
+ (pmpriv->sec_info.wpa2_enabled) ? "e" : "d",
+ pmpriv->sec_info.encryption_mode, pbss_desc->privacy);
+ if (((pmpriv->adapter->config_bands & BAND_GN ||
+ pmpriv->adapter->config_bands & BAND_AN) &&
+ pbss_desc->pht_cap)
+ && (pmpriv->bss_mode == MLAN_BSS_MODE_INFRA)
+ && !is_rsn_oui_present(pmpriv->adapter, pbss_desc,
+ CIPHER_SUITE_CCMP)) {
+ if (is_rsn_oui_present
+ (pmpriv->adapter, pbss_desc, CIPHER_SUITE_TKIP)) {
+ PRINTM(MINFO,
+ "Disable 11n if AES is not supported by AP\n");
+ pbss_desc->disable_11n = MTRUE;
+ } else {
+ LEAVE();
+ return -1;
+ }
+ }
+ LEAVE();
+ return index;
+ } else if (pmpriv->sec_info.wep_status == Wlan802_11WEPDisabled
+ && !pmpriv->sec_info.wpa_enabled
+ && !pmpriv->sec_info.wpa2_enabled
+ && ((!pbss_desc->pwpa_ie) ||
+ ((*(pbss_desc->pwpa_ie)).vend_hdr.element_id != WPA_IE))
+ && ((!pbss_desc->prsn_ie) ||
+ ((*(pbss_desc->prsn_ie)).ieee_hdr.element_id != RSN_IE))
+ && pmpriv->adhoc_aes_enabled &&
+ pmpriv->sec_info.encryption_mode == MLAN_ENCRYPTION_MODE_NONE
+ && pbss_desc->privacy) {
+ /* Ad-hoc AES enabled */
+ LEAVE();
+ return index;
+ } else if (pmpriv->sec_info.wep_status == Wlan802_11WEPDisabled
+ && !pmpriv->sec_info.wpa_enabled
+ && !pmpriv->sec_info.wpa2_enabled
+ && ((!pbss_desc->pwpa_ie) ||
+ ((*(pbss_desc->pwpa_ie)).vend_hdr.element_id != WPA_IE))
+ && ((!pbss_desc->prsn_ie) ||
+ ((*(pbss_desc->prsn_ie)).ieee_hdr.element_id != RSN_IE))
+ && !pmpriv->adhoc_aes_enabled &&
+ pmpriv->sec_info.encryption_mode != MLAN_ENCRYPTION_MODE_NONE
+ && pbss_desc->privacy) {
+ /* Dynamic WEP enabled */
+ PRINTM(MINFO, "wlan_is_network_compatible() dynamic WEP: index=%d "
+ "wpa_ie=%#x rsn_ie=%#x EncMode=%#x privacy=%#x\n",
+ index,
+ (pbss_desc->pwpa_ie) ? (*(pbss_desc->pwpa_ie)).vend_hdr.
+ element_id : 0,
+ (pbss_desc->prsn_ie) ? (*(pbss_desc->prsn_ie)).ieee_hdr.
+ element_id : 0, pmpriv->sec_info.encryption_mode,
+ pbss_desc->privacy);
+ LEAVE();
+ return index;
+ }
+
+ /* Security doesn't match */
+ PRINTM(MINFO,
+ "wlan_is_network_compatible() FAILED: index=%d wpa_ie=%#x "
+ "rsn_ie=%#x WEP=%s WPA=%s WPA2=%s EncMode=%#x privacy=%#x\n",
+ index,
+ (pbss_desc->pwpa_ie) ? (*(pbss_desc->pwpa_ie)).vend_hdr.
+ element_id : 0,
+ (pbss_desc->prsn_ie) ? (*(pbss_desc->prsn_ie)).ieee_hdr.
+ element_id : 0,
+ (pmpriv->sec_info.wep_status ==
+ Wlan802_11WEPEnabled) ? "e" : "d",
+ (pmpriv->sec_info.wpa_enabled) ? "e" : "d",
+ (pmpriv->sec_info.wpa2_enabled) ? "e" : "d",
+ pmpriv->sec_info.encryption_mode, pbss_desc->privacy);
+ LEAVE();
+ return -1;
+ }
+
+ /* Mode doesn't match */
+ LEAVE();
+ return -1;
+}
+
+/**
+ * @brief Internal function used to flush the scan list
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+mlan_status
+wlan_flush_scan_table(IN pmlan_adapter pmadapter)
+{
+ ENTER();
+
+ PRINTM(MINFO, "Flushing scan table\n");
+
+ memset(pmadapter, pmadapter->pscan_table, 0,
+ (sizeof(BSSDescriptor_t) * MRVDRV_MAX_BSSID_LIST));
+ pmadapter->num_in_scan_table = 0;
+
+ memset(pmadapter, pmadapter->bcn_buf, 0, pmadapter->bcn_buf_size);
+ pmadapter->pbcn_buf_end = pmadapter->bcn_buf;
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief Internal function used to start a scan based on an input config
+ *
+ * Use the input user scan configuration information when provided in
+ * order to send the appropriate scan commands to firmware to populate or
+ * update the internal driver scan table
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param pioctl_buf A pointer to MLAN IOCTL Request buffer
+ * @param puser_scan_in Pointer to the input configuration for the requested
+ * scan.
+ *
+ * @return MLAN_STATUS_SUCCESS or < 0 if error
+ */
+mlan_status
+wlan_scan_networks(IN mlan_private * pmpriv,
+ IN t_void * pioctl_buf,
+ IN const wlan_user_scan_cfg * puser_scan_in)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_adapter *pmadapter = pmpriv->adapter;
+ mlan_callbacks *pcb = (mlan_callbacks *) & pmadapter->callbacks;
+ cmd_ctrl_node *pcmd_node = MNULL;
+ pmlan_ioctl_req pioctl_req = (mlan_ioctl_req *) pioctl_buf;
+
+ wlan_scan_cmd_config_tlv *pscan_cfg_out = MNULL;
+ MrvlIEtypes_ChanListParamSet_t *pchan_list_out;
+ t_u32 buf_size;
+ ChanScanParamSet_t *pscan_chan_list;
+
+ t_u8 keep_previous_scan;
+ t_u8 filtered_scan;
+ t_u8 scan_current_chan_only;
+ t_u8 max_chan_per_scan;
+
+ ENTER();
+
+ ret =
+ pcb->moal_malloc(pmadapter->pmoal_handle,
+ sizeof(wlan_scan_cmd_config_tlv), MLAN_MEM_DEF,
+ (t_u8 **) & pscan_cfg_out);
+ if (ret != MLAN_STATUS_SUCCESS || !pscan_cfg_out) {
+ PRINTM(MERROR, "Memory allocation for pscan_cfg_out failed!\n");
+ if (pioctl_req)
+ pioctl_req->status_code = MLAN_ERROR_NO_MEM;
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+
+ buf_size = sizeof(ChanScanParamSet_t) * WLAN_USER_SCAN_CHAN_MAX;
+ ret =
+ pcb->moal_malloc(pmadapter->pmoal_handle, buf_size, MLAN_MEM_DEF,
+ (t_u8 **) & pscan_chan_list);
+ if (ret != MLAN_STATUS_SUCCESS || !pscan_chan_list) {
+ PRINTM(MERROR, "Failed to allocate scan_chan_list\n");
+ if (pscan_cfg_out)
+ pcb->moal_mfree(pmadapter->pmoal_handle, (t_u8 *) pscan_cfg_out);
+ if (pioctl_req)
+ pioctl_req->status_code = MLAN_ERROR_NO_MEM;
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+
+ memset(pmadapter, pscan_chan_list, 0x00, buf_size);
+ memset(pmadapter, pscan_cfg_out, 0x00, sizeof(wlan_scan_cmd_config_tlv));
+
+ keep_previous_scan = MFALSE;
+
+ ret = wlan_scan_setup_scan_config(pmpriv,
+ puser_scan_in,
+ &pscan_cfg_out->config,
+ &pchan_list_out,
+ pscan_chan_list,
+ &max_chan_per_scan,
+ &filtered_scan, &scan_current_chan_only);
+ if (ret != MLAN_STATUS_SUCCESS) {
+
+ PRINTM(MERROR, "Failed to setup scan config\n");
+ if (pscan_cfg_out)
+ pcb->moal_mfree(pmadapter->pmoal_handle, (t_u8 *) pscan_cfg_out);
+ if (pscan_chan_list)
+ pcb->moal_mfree(pmadapter->pmoal_handle, (t_u8 *) pscan_chan_list);
+ if (pioctl_req)
+ pioctl_req->status_code = MLAN_ERROR_INVALID_PARAMETER;
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+
+ if (puser_scan_in) {
+ keep_previous_scan = puser_scan_in->keep_previous_scan;
+ }
+
+ if (keep_previous_scan == MFALSE) {
+ memset(pmadapter, pmadapter->pscan_table, 0x00,
+ sizeof(BSSDescriptor_t) * MRVDRV_MAX_BSSID_LIST);
+ pmadapter->num_in_scan_table = 0;
+ pmadapter->pbcn_buf_end = pmadapter->bcn_buf;
+ }
+
+ ret = wlan_scan_channel_list(pmpriv,
+ pioctl_buf,
+ max_chan_per_scan,
+ filtered_scan,
+ &pscan_cfg_out->config,
+ pchan_list_out, pscan_chan_list);
+
+ /* Get scan command from scan_pending_q and put to cmd_pending_q */
+ if (ret == MLAN_STATUS_SUCCESS) {
+ if (util_peek_list
+ (pmadapter->pmoal_handle, &pmadapter->scan_pending_q,
+ pcb->moal_spin_lock, pcb->moal_spin_unlock)) {
+ pcmd_node =
+ (cmd_ctrl_node *) util_dequeue_list(pmadapter->pmoal_handle,
+ &pmadapter->scan_pending_q,
+ pcb->moal_spin_lock,
+ pcb->moal_spin_unlock);
+ pmadapter->pext_scan_ioctl_req = pioctl_req;
+ wlan_request_cmd_lock(pmadapter);
+ pmadapter->scan_processing = MTRUE;
+ wlan_release_cmd_lock(pmadapter);
+ wlan_insert_cmd_to_pending_q(pmadapter, pcmd_node, MTRUE);
+ }
+ }
+ if (pscan_cfg_out)
+ pcb->moal_mfree(pmadapter->pmoal_handle, (t_u8 *) pscan_cfg_out);
+
+ if (pscan_chan_list)
+ pcb->moal_mfree(pmadapter->pmoal_handle, (t_u8 *) pscan_chan_list);
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Prepare a scan command to be sent to the firmware
+ *
+ * Use the wlan_scan_cmd_config sent to the command processing module in
+ * the wlan_prepare_cmd to configure a HostCmd_DS_802_11_SCAN command
+ * struct to send to firmware.
+ *
+ * The fixed fields specifying the BSS type and BSSID filters as well as a
+ * variable number/length of TLVs are sent in the command to firmware.
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param pcmd A pointer to HostCmd_DS_COMMAND structure to be sent to
+ * firmware with the HostCmd_DS_801_11_SCAN structure
+ * @param pdata_buf Void pointer cast of a wlan_scan_cmd_config struct used
+ * to set the fields/TLVs for the command sent to firmware
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+mlan_status
+wlan_cmd_802_11_scan(IN mlan_private * pmpriv,
+ IN HostCmd_DS_COMMAND * pcmd, IN t_void * pdata_buf)
+{
+ HostCmd_DS_802_11_SCAN *pscan_cmd = &pcmd->params.scan;
+ wlan_scan_cmd_config *pscan_cfg;
+
+ ENTER();
+
+ pscan_cfg = (wlan_scan_cmd_config *) pdata_buf;
+
+ /* Set fixed field variables in scan command */
+ pscan_cmd->bss_mode = pscan_cfg->bss_mode;
+ memcpy(pmpriv->adapter, pscan_cmd->bssid, pscan_cfg->specific_bssid,
+ sizeof(pscan_cmd->bssid));
+ memcpy(pmpriv->adapter, pscan_cmd->tlv_buffer, pscan_cfg->tlv_buf,
+ pscan_cfg->tlv_buf_len);
+
+ pcmd->command = wlan_cpu_to_le16(HostCmd_CMD_802_11_SCAN);
+
+ /* Size is equal to the sizeof(fixed portions) + the TLV len + header */
+ pcmd->size = (t_u16) wlan_cpu_to_le16((t_u16) (sizeof(pscan_cmd->bss_mode)
+ + sizeof(pscan_cmd->bssid)
+ + pscan_cfg->tlv_buf_len
+ + S_DS_GEN));
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function handles the command response of scan
+ *
+ * The response buffer for the scan command has the following
+ * memory layout:
+ *
+ * .-------------------------------------------------------------.
+ * | Header (4 * sizeof(t_u16)): Standard command response hdr |
+ * .-------------------------------------------------------------.
+ * | BufSize (t_u16) : sizeof the BSS Description data |
+ * .-------------------------------------------------------------.
+ * | NumOfSet (t_u8) : Number of BSS Descs returned |
+ * .-------------------------------------------------------------.
+ * | BSSDescription data (variable, size given in BufSize) |
+ * .-------------------------------------------------------------.
+ * | TLV data (variable, size calculated using Header->Size, |
+ * | BufSize and sizeof the fixed fields above) |
+ * .-------------------------------------------------------------.
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param resp A pointer to HostCmd_DS_COMMAND
+ * @param pioctl_buf A pointer to mlan_ioctl_req structure
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status
+wlan_ret_802_11_scan(IN mlan_private * pmpriv,
+ IN HostCmd_DS_COMMAND * resp, IN t_void * pioctl_buf)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_adapter *pmadapter = pmpriv->adapter;
+ mlan_callbacks *pcb = MNULL;
+ mlan_ioctl_req *pioctl_req = (mlan_ioctl_req *) pioctl_buf;
+ cmd_ctrl_node *pcmd_node = MNULL;
+ HostCmd_DS_802_11_SCAN_RSP *pscan_rsp = MNULL;
+ BSSDescriptor_t *bss_new_entry = MNULL;
+ MrvlIEtypes_Data_t *ptlv;
+ MrvlIEtypes_TsfTimestamp_t *ptsf_tlv = MNULL;
+ t_u8 *pbss_info;
+ t_u32 scan_resp_size;
+ t_u32 bytes_left;
+ t_u32 num_in_table;
+ t_u32 bss_idx;
+ t_u32 idx;
+ t_u32 tlv_buf_size;
+ t_u64 tsf_val;
+ chan_freq_power_t *cfp;
+ MrvlIEtypes_ChanBandListParamSet_t *pchan_band_tlv = MNULL;
+ ChanBandParamSet_t *pchan_band;
+ t_u8 band;
+ t_u8 is_bgscan_resp;
+ t_u32 age_ts_usec;
+
+ ENTER();
+ pcb = (pmlan_callbacks) & pmadapter->callbacks;
+
+ is_bgscan_resp = (resp->command == HostCmd_CMD_802_11_BG_SCAN_QUERY);
+ if (is_bgscan_resp) {
+ pscan_rsp = &resp->params.bg_scan_query_resp.scan_resp;
+ } else {
+ pscan_rsp = &resp->params.scan_resp;
+ }
+
+ if (pscan_rsp->number_of_sets > MRVDRV_MAX_BSSID_LIST) {
+ PRINTM(MERROR, "SCAN_RESP: Invalid number of AP returned (%d)!!\n",
+ pscan_rsp->number_of_sets);
+ if (pioctl_req)
+ pioctl_req->status_code = MLAN_ERROR_CMD_SCAN_FAIL;
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ bytes_left = wlan_le16_to_cpu(pscan_rsp->bss_descript_size);
+ PRINTM(MINFO, "SCAN_RESP: bss_descript_size %d\n", bytes_left);
+
+ scan_resp_size = resp->size;
+
+ PRINTM(MINFO, "SCAN_RESP: returned %d APs before parsing\n",
+ pscan_rsp->number_of_sets);
+
+ num_in_table = pmadapter->num_in_scan_table;
+ pbss_info = pscan_rsp->bss_desc_and_tlv_buffer;
+
+ /*
+ * The size of the TLV buffer is equal to the entire command response
+ * size (scan_resp_size) minus the fixed fields (sizeof()'s), the
+ * BSS Descriptions (bss_descript_size as bytesLef) and the command
+ * response header (S_DS_GEN)
+ */
+ tlv_buf_size = scan_resp_size - (bytes_left
+ + sizeof(pscan_rsp->bss_descript_size)
+ + sizeof(pscan_rsp->number_of_sets)
+ + S_DS_GEN);
+
+ ptlv =
+ (MrvlIEtypes_Data_t *) (pscan_rsp->bss_desc_and_tlv_buffer +
+ bytes_left);
+
+ /* Search the TLV buffer space in the scan response for any valid TLVs */
+ wlan_ret_802_11_scan_get_tlv_ptrs(pmadapter,
+ ptlv,
+ tlv_buf_size,
+ TLV_TYPE_TSFTIMESTAMP,
+ (MrvlIEtypes_Data_t **) & ptsf_tlv);
+
+ /* Search the TLV buffer space in the scan response for any valid TLVs */
+ wlan_ret_802_11_scan_get_tlv_ptrs(pmadapter,
+ ptlv,
+ tlv_buf_size,
+ TLV_TYPE_CHANNELBANDLIST,
+ (MrvlIEtypes_Data_t **) & pchan_band_tlv);
+
+ /*
+ * Process each scan response returned (pscan_rsp->number_of_sets). Save
+ * the information in the bss_new_entry and then insert into the
+ * driver scan table either as an update to an existing entry
+ * or as an addition at the end of the table
+ */
+ ret =
+ pcb->moal_malloc(pmadapter->pmoal_handle, sizeof(BSSDescriptor_t),
+ MLAN_MEM_DEF, (t_u8 **) & bss_new_entry);
+
+ if (ret != MLAN_STATUS_SUCCESS || !bss_new_entry) {
+ PRINTM(MERROR, "Memory allocation for bss_new_entry failed!\n");
+ if (pioctl_req)
+ pioctl_req->status_code = MLAN_ERROR_NO_MEM;
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ for (idx = 0; idx < pscan_rsp->number_of_sets && bytes_left; idx++) {
+ /* Zero out the bss_new_entry we are about to store info in */
+ memset(pmadapter, bss_new_entry, 0x00, sizeof(BSSDescriptor_t));
+
+ /* Process the data fields and IEs returned for this BSS */
+ if (wlan_interpret_bss_desc_with_ie(pmadapter,
+ bss_new_entry,
+ &pbss_info,
+ &bytes_left) ==
+ MLAN_STATUS_SUCCESS) {
+ PRINTM(MINFO, "SCAN_RESP: BSSID = %02x:%02x:%02x:%02x:%02x:%02x\n",
+ bss_new_entry->mac_address[0], bss_new_entry->mac_address[1],
+ bss_new_entry->mac_address[2], bss_new_entry->mac_address[3],
+ bss_new_entry->mac_address[4],
+ bss_new_entry->mac_address[5]);
+ /*
+ * Search the scan table for the same bssid
+ */
+ for (bss_idx = 0; bss_idx < num_in_table; bss_idx++) {
+ if (!memcmp(pmadapter, bss_new_entry->mac_address,
+ pmadapter->pscan_table[bss_idx].mac_address,
+ sizeof(bss_new_entry->mac_address))) {
+ /*
+ * If the SSID matches as well, it is a duplicate of
+ * this entry. Keep the bss_idx set to this
+ * entry so we replace the old contents in the table
+ */
+ if ((bss_new_entry->ssid.ssid_len ==
+ pmadapter->pscan_table[bss_idx].ssid.ssid_len)
+ && (!memcmp(pmadapter, bss_new_entry->ssid.ssid,
+ pmadapter->pscan_table[bss_idx].ssid.ssid,
+ bss_new_entry->ssid.ssid_len))) {
+ PRINTM(MINFO, "SCAN_RESP: Duplicate of index: %d\n",
+ bss_idx);
+ break;
+ }
+ }
+ }
+ /*
+ * If the bss_idx is equal to the number of entries in the table,
+ * the new entry was not a duplicate; append it to the scan
+ * table
+ */
+ if (bss_idx == num_in_table) {
+ /* Range check the bss_idx, keep it limited to the last entry */
+ if (bss_idx == MRVDRV_MAX_BSSID_LIST) {
+ bss_idx--;
+ } else {
+ num_in_table++;
+ }
+ }
+
+ /*
+ * Save the beacon/probe response returned for later application
+ * retrieval. Duplicate beacon/probe responses are updated if
+ * possible
+ */
+ wlan_ret_802_11_scan_store_beacon(pmpriv,
+ bss_idx,
+ num_in_table, bss_new_entry);
+ if (bss_new_entry->pbeacon_buf == MNULL) {
+ PRINTM(MCMND, "No space for beacon, drop this entry\n");
+ num_in_table--;
+ continue;
+ }
+ /*
+ * If the TSF TLV was appended to the scan results, save
+ * this entry's TSF value in the networkTSF field. The
+ * networkTSF is the firmware's TSF value at the time the
+ * beacon or probe response was received.
+ */
+ if (ptsf_tlv) {
+ memcpy(pmpriv->adapter, &tsf_val,
+ &ptsf_tlv->tsf_data[idx * TSF_DATA_SIZE],
+ sizeof(tsf_val));
+ tsf_val = wlan_le64_to_cpu(tsf_val);
+ memcpy(pmpriv->adapter, &bss_new_entry->network_tsf,
+ &tsf_val, sizeof(bss_new_entry->network_tsf));
+ }
+ band = BAND_G;
+ if (pchan_band_tlv) {
+ pchan_band = &pchan_band_tlv->chan_band_param[idx];
+ band =
+ radio_type_to_band(pchan_band->
+ radio_type & (MBIT(0) | MBIT(1)));
+ }
+
+ /* Save the band designation for this entry for use in join */
+ bss_new_entry->bss_band = band;
+ cfp =
+ wlan_find_cfp_by_band_and_channel(pmadapter,
+ (t_u8) bss_new_entry->
+ bss_band,
+ (t_u16) bss_new_entry->
+ channel);
+
+ if (cfp)
+ bss_new_entry->freq = cfp->freq;
+ else
+ bss_new_entry->freq = 0;
+
+ /* Copy the locally created bss_new_entry to the scan table */
+ memcpy(pmadapter, &pmadapter->pscan_table[bss_idx],
+ bss_new_entry, sizeof(pmadapter->pscan_table[bss_idx]));
+
+ } else {
+
+ /* Error parsing/interpreting the scan response, skipped */
+ PRINTM(MERROR,
+ "SCAN_RESP: wlan_interpret_bss_desc_with_ie returned error\n");
+ }
+ }
+
+ PRINTM(MINFO, "SCAN_RESP: Scanned %2d APs, %d valid, %d total\n",
+ pscan_rsp->number_of_sets,
+ num_in_table - pmadapter->num_in_scan_table, num_in_table);
+
+ /* Update the total number of BSSIDs in the scan table */
+ pmadapter->num_in_scan_table = num_in_table;
+ /* Update the age_in_second */
+ pmadapter->callbacks.moal_get_system_time(pmadapter->pmoal_handle,
+ &pmadapter->age_in_secs,
+ &age_ts_usec);
+
+ if (!util_peek_list
+ (pmadapter->pmoal_handle, &pmadapter->scan_pending_q,
+ pcb->moal_spin_lock, pcb->moal_spin_unlock)) {
+ wlan_request_cmd_lock(pmadapter);
+ pmadapter->scan_processing = MFALSE;
+ wlan_release_cmd_lock(pmadapter);
+ /*
+ * Process the resulting scan table:
+ * - Remove any bad ssids
+ * - Update our current BSS information from scan data
+ */
+ wlan_scan_process_results(pmpriv);
+
+ /* Need to indicate IOCTL complete */
+ if (pioctl_req != MNULL) {
+ pioctl_req->status_code = MLAN_ERROR_NO_ERROR;
+
+ /* Indicate ioctl complete */
+ pcb->moal_ioctl_complete(pmadapter->pmoal_handle,
+ (pmlan_ioctl_req) pioctl_buf,
+ MLAN_STATUS_SUCCESS);
+ }
+ wlan_recv_event(pmpriv, MLAN_EVENT_ID_DRV_SCAN_REPORT, MNULL);
+ } else {
+ /* If firmware not ready, do not issue any more scan commands */
+ if (pmadapter->hw_status != WlanHardwareStatusReady) {
+ /* Flush all pending scan commands */
+ wlan_flush_scan_queue(pmadapter);
+ /* Indicate IOCTL complete */
+ if (pioctl_req != MNULL) {
+ pioctl_req->status_code = MLAN_ERROR_FW_NOT_READY;
+
+ /* Indicate ioctl complete */
+ pcb->moal_ioctl_complete(pmadapter->pmoal_handle,
+ (pmlan_ioctl_req) pioctl_buf,
+ MLAN_STATUS_FAILURE);
+ }
+ } else {
+ /* Get scan command from scan_pending_q and put to cmd_pending_q */
+ pcmd_node =
+ (cmd_ctrl_node *) util_dequeue_list(pmadapter->pmoal_handle,
+ &pmadapter->scan_pending_q,
+ pcb->moal_spin_lock,
+ pcb->moal_spin_unlock);
+
+ wlan_insert_cmd_to_pending_q(pmadapter, pcmd_node, MTRUE);
+ }
+ }
+
+ done:
+ if (bss_new_entry)
+ pcb->moal_mfree(pmadapter->pmoal_handle, (t_u8 *) bss_new_entry);
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Prepare an extended scan command to be sent to the firmware
+ *
+ * Use the wlan_scan_cmd_config sent to the command processing module in
+ * the wlan_prepare_cmd to configure a HostCmd_DS_802_11_SCAN_EXT command
+ * struct to send to firmware.
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param pcmd A pointer to HostCmd_DS_COMMAND structure to be sent to
+ * firmware with the HostCmd_DS_802_11_SCAN_EXT structure
+ * @param pdata_buf Void pointer cast of a wlan_scan_cmd_config struct used
+ * to set the fields/TLVs for the command sent to firmware
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+mlan_status
+wlan_cmd_802_11_scan_ext(IN mlan_private * pmpriv,
+ IN HostCmd_DS_COMMAND * pcmd, IN t_void * pdata_buf)
+{
+ HostCmd_DS_802_11_SCAN_EXT *pext_scan_cmd = &pcmd->params.ext_scan;
+ wlan_scan_cmd_config *pscan_cfg = MNULL;
+
+ ENTER();
+
+ pscan_cfg = (wlan_scan_cmd_config *) pdata_buf;
+
+ memcpy(pmpriv->adapter, pext_scan_cmd->tlv_buffer,
+ pscan_cfg->tlv_buf, pscan_cfg->tlv_buf_len);
+
+ pcmd->command = wlan_cpu_to_le16(HostCmd_CMD_802_11_SCAN_EXT);
+
+ /* Size is equal to the sizeof(fixed portions) + the TLV len + header */
+ pcmd->size = wlan_cpu_to_le16((t_u16) (sizeof(pext_scan_cmd->reserved)
+ + pscan_cfg->tlv_buf_len
+ + S_DS_GEN));
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function handles the command response of extended scan
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param resp A pointer to HostCmd_DS_COMMAND
+ * @param pioctl_buf A pointer to mlan_ioctl_req structure
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status
+wlan_ret_802_11_scan_ext(IN mlan_private * pmpriv,
+ IN HostCmd_DS_COMMAND * resp, IN t_void * pioctl_buf)
+{
+ ENTER();
+
+ PRINTM(MINFO, "EXT scan returns successfully\n");
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function parse and store the extended scan results
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param number_of_sets Number of BSS
+ * @param pscan_resp A pointer to scan response buffer
+ * @param scan_resp_size Size of scan response buffer
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+static mlan_status
+wlan_parse_ext_scan_result(IN mlan_private * pmpriv,
+ IN t_u8 number_of_sets,
+ IN t_u8 * pscan_resp, IN t_u16 scan_resp_size)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_adapter *pmadapter = pmpriv->adapter;
+ mlan_callbacks *pcb = MNULL;
+ BSSDescriptor_t *bss_new_entry = MNULL;
+ t_u8 *pbss_info;
+ t_u32 bytes_left;
+ t_u32 bytes_left_for_tlv;
+ t_u32 num_in_table;
+ t_u32 bss_idx;
+ t_u32 idx;
+ t_u64 tsf_val;
+ chan_freq_power_t *cfp;
+ t_u16 tlv_type, tlv_len;
+ MrvlIEtypes_Data_t *ptlv = MNULL;
+ MrvlIEtypes_Bss_Scan_Rsp_t *pscan_rsp_tlv = MNULL;
+ MrvlIEtypes_Bss_Scan_Info_t *pscan_info_tlv = MNULL;
+ t_u8 band;
+ t_u32 age_ts_usec;
+
+ ENTER();
+ pcb = (pmlan_callbacks) & pmadapter->callbacks;
+
+ if (number_of_sets > MRVDRV_MAX_BSSID_LIST) {
+ PRINTM(MERROR, "EXT_SCAN: Invalid number of AP returned (%d)!!\n",
+ number_of_sets);
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ bytes_left = scan_resp_size;
+ PRINTM(MINFO, "EXT_SCAN: bss_descript_size %d\n", scan_resp_size);
+ PRINTM(MINFO, "EXT_SCAN: returned %d APs before parsing\n", number_of_sets);
+
+ num_in_table = pmadapter->num_in_scan_table;
+ ptlv = (MrvlIEtypes_Data_t *) pscan_resp;
+
+ /*
+ * Process each scan response returned number_of_sets. Save
+ * the information in the bss_new_entry and then insert into the
+ * driver scan table either as an update to an existing entry
+ * or as an addition at the end of the table
+ */
+ ret =
+ pcb->moal_malloc(pmadapter->pmoal_handle, sizeof(BSSDescriptor_t),
+ MLAN_MEM_DEF, (t_u8 **) & bss_new_entry);
+
+ if (ret != MLAN_STATUS_SUCCESS || !bss_new_entry) {
+ PRINTM(MERROR, "Memory allocation for bss_new_entry failed!\n");
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ for (idx = 0; idx < number_of_sets && bytes_left >
+ sizeof(MrvlIEtypesHeader_t); idx++) {
+ tlv_type = wlan_le16_to_cpu(ptlv->header.type);
+ tlv_len = wlan_le16_to_cpu(ptlv->header.len);
+ if (bytes_left < sizeof(MrvlIEtypesHeader_t) + tlv_len) {
+ PRINTM(MERROR, "EXT_SCAN: Error bytes left < TLV length\n");
+ break;
+ }
+ pscan_rsp_tlv = MNULL;
+ pscan_info_tlv = MNULL;
+ bytes_left_for_tlv = bytes_left;
+ /* BSS response TLV with beacon or probe response buffer at the initial
+ position of each descriptor */
+ if (tlv_type == TLV_TYPE_BSS_SCAN_RSP) {
+ pbss_info = (t_u8 *) ptlv;
+ pscan_rsp_tlv = (MrvlIEtypes_Bss_Scan_Rsp_t *) ptlv;
+ ptlv = (MrvlIEtypes_Data_t *) (ptlv->data + tlv_len);
+ bytes_left_for_tlv -= (tlv_len + sizeof(MrvlIEtypesHeader_t));
+ } else
+ break;
+
+ /* Process variable TLV */
+ while (bytes_left_for_tlv >= sizeof(MrvlIEtypesHeader_t) &&
+ wlan_le16_to_cpu(ptlv->header.type) != TLV_TYPE_BSS_SCAN_RSP) {
+ tlv_type = wlan_le16_to_cpu(ptlv->header.type);
+ tlv_len = wlan_le16_to_cpu(ptlv->header.len);
+ if (bytes_left_for_tlv < sizeof(MrvlIEtypesHeader_t) + tlv_len) {
+ PRINTM(MERROR, "EXT_SCAN: Error in processing TLV, "
+ "bytes left < TLV length\n");
+ pscan_rsp_tlv = MNULL;
+ bytes_left_for_tlv = 0;
+ continue;
+ }
+ switch (tlv_type) {
+ case TLV_TYPE_BSS_SCAN_INFO:
+ pscan_info_tlv = (MrvlIEtypes_Bss_Scan_Info_t *) ptlv;
+ if (tlv_len != sizeof(MrvlIEtypes_Bss_Scan_Info_t) -
+ sizeof(MrvlIEtypesHeader_t)) {
+ bytes_left_for_tlv = 0;
+ continue;
+ }
+ break;
+ default:
+ break;
+ }
+ ptlv = (MrvlIEtypes_Data_t *) (ptlv->data + tlv_len);
+ bytes_left -= (tlv_len + sizeof(MrvlIEtypesHeader_t));
+ bytes_left_for_tlv -= (tlv_len + sizeof(MrvlIEtypesHeader_t));
+ }
+ /* No BSS response TLV */
+ if (pscan_rsp_tlv == MNULL)
+ break;
+
+ /* Advance pointer to the beacon buffer length and update the bytes
+ count so that the function wlan_interpret_bss_desc_with_ie() can
+ handle the scan buffer withut any change */
+ pbss_info += sizeof(t_u16);
+ bytes_left -= sizeof(t_u16);
+
+ /* Zero out the bss_new_entry we are about to store info in */
+ memset(pmadapter, bss_new_entry, 0x00, sizeof(BSSDescriptor_t));
+
+ /* Process the data fields and IEs returned for this BSS */
+ if (wlan_interpret_bss_desc_with_ie(pmadapter,
+ bss_new_entry,
+ &pbss_info,
+ &bytes_left) ==
+ MLAN_STATUS_SUCCESS) {
+ PRINTM(MINFO, "EXT_SCAN: BSSID = %02x:%02x:%02x:%02x:%02x:%02x\n",
+ bss_new_entry->mac_address[0], bss_new_entry->mac_address[1],
+ bss_new_entry->mac_address[2], bss_new_entry->mac_address[3],
+ bss_new_entry->mac_address[4],
+ bss_new_entry->mac_address[5]);
+ /*
+ * Search the scan table for the same bssid
+ */
+ for (bss_idx = 0; bss_idx < num_in_table; bss_idx++) {
+ if (!memcmp(pmadapter, bss_new_entry->mac_address,
+ pmadapter->pscan_table[bss_idx].mac_address,
+ sizeof(bss_new_entry->mac_address))) {
+ /*
+ * If the SSID matches as well, it is a duplicate of
+ * this entry. Keep the bss_idx set to this
+ * entry so we replace the old contents in the table
+ */
+ if ((bss_new_entry->ssid.ssid_len ==
+ pmadapter->pscan_table[bss_idx].ssid.ssid_len)
+ && (!memcmp(pmadapter, bss_new_entry->ssid.ssid,
+ pmadapter->pscan_table[bss_idx].ssid.ssid,
+ bss_new_entry->ssid.ssid_len))) {
+ PRINTM(MINFO, "EXT_SCAN: Duplicate of index: %d\n",
+ bss_idx);
+ break;
+ }
+ }
+ }
+ /*
+ * If the bss_idx is equal to the number of entries in the table,
+ * the new entry was not a duplicate; append it to the scan
+ * table
+ */
+ if (bss_idx == num_in_table) {
+ /* Range check the bss_idx, keep it limited to the last entry */
+ if (bss_idx == MRVDRV_MAX_BSSID_LIST) {
+ bss_idx--;
+ } else {
+ num_in_table++;
+ }
+ }
+
+ band = BAND_G;
+ /*
+ * If the BSS info TLV was appended to the scan results, save
+ * this entry's TSF value in the networkTSF field. The
+ * networkTSF is the firmware's TSF value at the time the
+ * beacon or probe response was received.
+ */
+ if (pscan_info_tlv) {
+ /* RSSI is 2 byte long */
+ bss_new_entry->rssi =
+ -(t_s32) (wlan_le16_to_cpu(pscan_info_tlv->rssi));
+ PRINTM(MINFO, "EXT_SCAN: RSSI=%d\n", bss_new_entry->rssi);
+ memcpy(pmpriv->adapter, &tsf_val, &pscan_info_tlv->tsf,
+ sizeof(tsf_val));
+ tsf_val = wlan_le64_to_cpu(tsf_val);
+ memcpy(pmpriv->adapter, &bss_new_entry->network_tsf,
+ &tsf_val, sizeof(bss_new_entry->network_tsf));
+ band = radio_type_to_band(pscan_info_tlv->band);
+ }
+ /*
+ * Save the beacon/probe response returned for later application
+ * retrieval. Duplicate beacon/probe responses are updated if
+ * possible
+ */
+ wlan_ret_802_11_scan_store_beacon(pmpriv,
+ bss_idx,
+ num_in_table, bss_new_entry);
+ if (bss_new_entry->pbeacon_buf == MNULL) {
+ PRINTM(MCMND, "No space for beacon, drop this entry\n");
+ num_in_table--;
+ continue;
+ }
+ /* Save the band designation for this entry for use in join */
+ bss_new_entry->bss_band = band;
+ cfp = wlan_find_cfp_by_band_and_channel(pmadapter,
+ (t_u8) bss_new_entry->
+ bss_band,
+ (t_u16) bss_new_entry->
+ channel);
+
+ if (cfp)
+ bss_new_entry->freq = cfp->freq;
+ else
+ bss_new_entry->freq = 0;
+
+ /* Copy the locally created bss_new_entry to the scan table */
+ memcpy(pmadapter, &pmadapter->pscan_table[bss_idx],
+ bss_new_entry, sizeof(pmadapter->pscan_table[bss_idx]));
+ } else {
+ /* Error parsing/interpreting the scan response, skipped */
+ PRINTM(MERROR,
+ "EXT_SCAN: wlan_interpret_bss_desc_with_ie returned error\n");
+ }
+ }
+
+ PRINTM(MINFO, "EXT_SCAN: Scanned %2d APs, %d valid, %d total\n",
+ number_of_sets, num_in_table - pmadapter->num_in_scan_table,
+ num_in_table);
+
+ /* Update the total number of BSSIDs in the scan table */
+ pmadapter->num_in_scan_table = num_in_table;
+ /* Update the age_in_second */
+ pmadapter->callbacks.moal_get_system_time(pmadapter->pmoal_handle,
+ &pmadapter->age_in_secs,
+ &age_ts_usec);
+
+ done:
+ if (bss_new_entry)
+ pcb->moal_mfree(pmadapter->pmoal_handle, (t_u8 *) bss_new_entry);
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function handles the event extended scan report
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param pmbuf A pointer to mlan_buffer
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status
+wlan_handle_event_ext_scan_report(IN mlan_private * pmpriv,
+ IN mlan_buffer * pmbuf)
+{
+ mlan_adapter *pmadapter = pmpriv->adapter;
+ mlan_callbacks *pcb = &pmadapter->callbacks;
+ mlan_ioctl_req *pioctl_req = MNULL;
+ cmd_ctrl_node *pcmd_node = MNULL;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+
+ mlan_event_scan_result *pevent_scan = (pmlan_event_scan_result)
+ (pmbuf->pbuf + pmbuf->data_offset);
+ t_u8 *ptlv = (pmbuf->pbuf + pmbuf->data_offset
+ + sizeof(mlan_event_scan_result));
+ t_u16 tlv_buf_left = wlan_cpu_to_le16(pevent_scan->buf_size);
+
+ DBG_HEXDUMP(MCMD_D, "EVENT EXT_SCAN", pmbuf->pbuf +
+ pmbuf->data_offset, pmbuf->data_len);
+ wlan_parse_ext_scan_result(pmpriv, pevent_scan->num_of_set,
+ ptlv, tlv_buf_left);
+ if (!pevent_scan->more_event) {
+ pioctl_req = pmadapter->pext_scan_ioctl_req;
+ if (!util_peek_list(pmadapter->pmoal_handle,
+ &pmadapter->scan_pending_q, pcb->moal_spin_lock,
+ pcb->moal_spin_unlock)) {
+ pmadapter->pext_scan_ioctl_req = MNULL;
+ wlan_request_cmd_lock(pmadapter);
+ pmadapter->scan_processing = MFALSE;
+ wlan_release_cmd_lock(pmadapter);
+ /*
+ * Process the resulting scan table:
+ * - Remove any bad ssids
+ * - Update our current BSS information from scan data
+ */
+ wlan_scan_process_results(pmpriv);
+
+ /* Need to indicate IOCTL complete */
+ if (pioctl_req != MNULL) {
+ pioctl_req->status_code = MLAN_ERROR_NO_ERROR;
+ /* Indicate ioctl complete */
+ pcb->moal_ioctl_complete(pmadapter->pmoal_handle,
+ (pmlan_ioctl_req) pioctl_req,
+ MLAN_STATUS_SUCCESS);
+ }
+ wlan_recv_event(pmpriv, MLAN_EVENT_ID_DRV_SCAN_REPORT, MNULL);
+ } else {
+ /* If firmware not ready, do not issue any more scan commands */
+ if (pmadapter->hw_status != WlanHardwareStatusReady) {
+ /* Flush all pending scan commands */
+ wlan_flush_scan_queue(pmadapter);
+ /* Indicate IOCTL complete */
+ if (pioctl_req != MNULL) {
+ pioctl_req->status_code = MLAN_ERROR_FW_NOT_READY;
+
+ /* Indicate ioctl complete */
+ pcb->moal_ioctl_complete(pmadapter->pmoal_handle,
+ (pmlan_ioctl_req) pioctl_req,
+ MLAN_STATUS_FAILURE);
+ }
+ } else {
+ /* Get scan command from scan_pending_q and put to
+ cmd_pending_q */
+ pcmd_node =
+ (cmd_ctrl_node *) util_dequeue_list(pmadapter->pmoal_handle,
+ &pmadapter->
+ scan_pending_q,
+ pcb->moal_spin_lock,
+ pcb->moal_spin_unlock);
+ wlan_insert_cmd_to_pending_q(pmadapter, pcmd_node, MTRUE);
+ }
+ }
+ }
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function prepares command of bg_scan_query.
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param pcmd A pointer to HostCmd_DS_COMMAND structure
+ * @param pdata_buf Void pointer cast of a wlan_scan_cmd_config struct used
+ * to set the fields/TLVs for the command sent to firmware
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+mlan_status
+wlan_cmd_802_11_bg_scan_query(IN mlan_private * pmpriv,
+ IN HostCmd_DS_COMMAND * pcmd,
+ IN t_void * pdata_buf)
+{
+ HostCmd_DS_802_11_BG_SCAN_QUERY *bg_query = &pcmd->params.bg_scan_query;
+
+ ENTER();
+
+ pcmd->command = wlan_cpu_to_le16(HostCmd_CMD_802_11_BG_SCAN_QUERY);
+ pcmd->size =
+ wlan_cpu_to_le16(sizeof(HostCmd_DS_802_11_BG_SCAN_QUERY) + S_DS_GEN);
+
+ bg_query->flush = MTRUE;
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief Create a channel list for the driver to scan based on region info
+ *
+ * Use the driver region/band information to construct a comprehensive list
+ * of channels to scan. This routine is used for any scan that is not
+ * provided a specific channel list to scan.
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param pbg_scan_in pointer to scan configuration parameters
+ * @param tlv_chan_list A pointer to structure MrvlIEtypes_ChanListParamSet_t
+ *
+ * @return channel number
+ */
+static t_u8
+wlan_bgscan_create_channel_list(IN mlan_private * pmpriv,
+ IN const wlan_bgscan_cfg * pbg_scan_in,
+ MrvlIEtypes_ChanListParamSet_t * tlv_chan_list)
+{
+ mlan_adapter *pmadapter = pmpriv->adapter;
+ region_chan_t *pscan_region;
+ chan_freq_power_t *cfp;
+ t_u32 region_idx;
+ t_u32 chan_idx = 0;
+ t_u32 next_chan;
+ t_u8 scan_type;
+ t_u8 radio_type;
+
+ ENTER();
+
+ for (region_idx = 0;
+ region_idx < NELEMENTS(pmadapter->region_channel); region_idx++) {
+
+ if (wlan_11d_is_enabled(pmpriv) && pmpriv->media_connected != MTRUE) {
+ /* Scan all the supported chan for the first scan */
+ if (!pmadapter->universal_channel[region_idx].valid)
+ continue;
+ pscan_region = &pmadapter->universal_channel[region_idx];
+ } else {
+ if (!pmadapter->region_channel[region_idx].valid)
+ continue;
+ pscan_region = &pmadapter->region_channel[region_idx];
+ }
+
+ if (pbg_scan_in && !pbg_scan_in->chan_list[0].chan_number &&
+ pbg_scan_in->chan_list[0].radio_type & BAND_SPECIFIED) {
+ radio_type = pbg_scan_in->chan_list[0].radio_type & ~BAND_SPECIFIED;
+ if (!radio_type && (pscan_region->band != BAND_B) &&
+ (pscan_region->band != BAND_G))
+ continue;
+ if (radio_type && (pscan_region->band != BAND_A))
+ continue;
+ }
+ if (!wlan_is_band_compatible
+ (pmpriv->config_bands | pmadapter->adhoc_start_band,
+ pscan_region->band))
+ continue;
+ for (next_chan = 0;
+ next_chan < pscan_region->num_cfp; next_chan++, chan_idx++) {
+ if (chan_idx >= WLAN_BG_SCAN_CHAN_MAX)
+ break;
+ /* Set the default scan type to ACTIVE SCAN type, will later be
+ changed to passive on a per channel basis if restricted by
+ regulatory requirements (11d or 11h) */
+ scan_type = MLAN_SCAN_TYPE_ACTIVE;
+ cfp = pscan_region->pcfp + next_chan;
+ if (scan_type == MLAN_SCAN_TYPE_ACTIVE
+ && wlan_11d_is_enabled(pmpriv)) {
+ scan_type = wlan_11d_get_scan_type(pmadapter,
+ pscan_region->band,
+ (t_u8) cfp->channel,
+ &pmadapter->
+ parsed_region_chan);
+ }
+ switch (pscan_region->band) {
+ case BAND_A:
+ tlv_chan_list->chan_scan_param[chan_idx].radio_type =
+ HostCmd_SCAN_RADIO_TYPE_A;
+ if (!wlan_11d_is_enabled(pmpriv)) {
+ /* 11D not available... play it safe on DFS channels */
+ if (wlan_11h_radar_detect_required
+ (pmpriv, (t_u8) cfp->channel))
+ scan_type = MLAN_SCAN_TYPE_PASSIVE;
+ }
+ break;
+ case BAND_B:
+ case BAND_G:
+ default:
+ tlv_chan_list->chan_scan_param[chan_idx].radio_type =
+ HostCmd_SCAN_RADIO_TYPE_BG;
+ break;
+ }
+
+ if (pbg_scan_in && pbg_scan_in->chan_list[0].scan_time) {
+ tlv_chan_list->chan_scan_param[chan_idx].max_scan_time =
+ wlan_cpu_to_le16((t_u16) pbg_scan_in->chan_list[0].
+ scan_time);
+ tlv_chan_list->chan_scan_param[chan_idx].min_scan_time =
+ wlan_cpu_to_le16((t_u16) pbg_scan_in->chan_list[0].
+ scan_time);
+ } else if (scan_type == MLAN_SCAN_TYPE_PASSIVE) {
+ tlv_chan_list->chan_scan_param[chan_idx].max_scan_time =
+ wlan_cpu_to_le16(pmadapter->passive_scan_time);
+ tlv_chan_list->chan_scan_param[chan_idx].min_scan_time =
+ wlan_cpu_to_le16(pmadapter->passive_scan_time);
+ } else {
+ tlv_chan_list->chan_scan_param[chan_idx].max_scan_time =
+ wlan_cpu_to_le16(pmadapter->specific_scan_time);
+ tlv_chan_list->chan_scan_param[chan_idx].min_scan_time =
+ wlan_cpu_to_le16(pmadapter->specific_scan_time);
+ }
+
+ if (scan_type == MLAN_SCAN_TYPE_PASSIVE) {
+ tlv_chan_list->chan_scan_param[chan_idx].chan_scan_mode.
+ passive_scan = MTRUE;
+ } else {
+ tlv_chan_list->chan_scan_param[chan_idx].chan_scan_mode.
+ passive_scan = MFALSE;
+ }
+
+ tlv_chan_list->chan_scan_param[chan_idx].chan_number =
+ (t_u8) cfp->channel;
+ tlv_chan_list->chan_scan_param[chan_idx].chan_scan_mode.
+ disable_chan_filt = MTRUE;
+ }
+ }
+
+ LEAVE();
+ return chan_idx;
+}
+
+/**
+ * @brief This function prepares command of bg_scan_config
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param pcmd A pointer to HostCmd_DS_COMMAND structure
+ * @param pdata_buf Void pointer cast of a wlan_scan_cmd_config struct used
+ * to set the fields/TLVs for the command sent to firmware
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+mlan_status
+wlan_cmd_bgscan_config(IN mlan_private * pmpriv,
+ IN HostCmd_DS_COMMAND * pcmd, IN t_void * pdata_buf)
+{
+ mlan_adapter *pmadapter = pmpriv->adapter;
+ HostCmd_DS_802_11_BG_SCAN_CONFIG *bg_scan = &pcmd->params.bg_scan_config;
+ wlan_bgscan_cfg *bg_scan_in = (wlan_bgscan_cfg *) pdata_buf;
+ t_u16 cmd_size = 0;
+ MrvlIEtypes_NumProbes_t *pnum_probes_tlv = MNULL;
+ MrvlIEtypes_BeaconLowRssiThreshold_t *rssi_tlv = MNULL;
+ MrvlIEtypes_BeaconLowSnrThreshold_t *snr_tlv = MNULL;
+ MrvlIEtypes_WildCardSsIdParamSet_t *pwildcard_ssid_tlv = MNULL;
+ MrvlIEtypes_ChanListParamSet_t *tlv_chan_list = MNULL;
+ t_u8 *tlv = MNULL;
+ t_u16 num_probes = 0;
+ t_u32 ssid_idx;
+ t_u32 ssid_len = 0;
+ t_u32 chan_idx;
+ t_u32 chan_num;
+ t_u8 radio_type;
+ t_u16 scan_dur;
+ t_u8 scan_type;
+
+ ENTER();
+
+ pcmd->command = wlan_cpu_to_le16(HostCmd_CMD_802_11_BG_SCAN_CONFIG);
+ bg_scan->action = wlan_cpu_to_le16(bg_scan_in->action);
+ bg_scan->enable = bg_scan_in->enable;
+ bg_scan->bss_type = bg_scan_in->bss_type;
+ cmd_size = sizeof(HostCmd_DS_802_11_BG_SCAN_CONFIG) + S_DS_GEN;
+ if (bg_scan_in->chan_per_scan)
+ bg_scan->chan_per_scan = bg_scan_in->chan_per_scan;
+ else
+ bg_scan->chan_per_scan = MRVDRV_MAX_CHANNELS_PER_SPECIFIC_SCAN;
+ if (bg_scan_in->scan_interval)
+ bg_scan->scan_interval = wlan_cpu_to_le32(bg_scan_in->scan_interval);
+ else
+ bg_scan->scan_interval = wlan_cpu_to_le32(DEFAULT_BGSCAN_INTERVAL);
+ bg_scan->report_condition = wlan_cpu_to_le32(bg_scan_in->report_condition);
+
+ if ((bg_scan_in->action == BG_SCAN_ACT_GET) ||
+ (bg_scan_in->action == BG_SCAN_ACT_GET_PPS_UAPSD) || (!bg_scan->enable))
+ goto done;
+
+ tlv = (t_u8 *) bg_scan + sizeof(HostCmd_DS_802_11_BG_SCAN_CONFIG);
+ num_probes = (bg_scan_in->num_probes ? bg_scan_in->num_probes :
+ pmadapter->scan_probes);
+ if (num_probes) {
+ pnum_probes_tlv = (MrvlIEtypes_NumProbes_t *) tlv;
+ pnum_probes_tlv->header.type = wlan_cpu_to_le16(TLV_TYPE_NUMPROBES);
+ pnum_probes_tlv->header.len =
+ wlan_cpu_to_le16(sizeof(pnum_probes_tlv->num_probes));
+ pnum_probes_tlv->num_probes = wlan_cpu_to_le16((t_u16) num_probes);
+ tlv += sizeof(MrvlIEtypes_NumProbes_t);
+ cmd_size += sizeof(MrvlIEtypes_NumProbes_t);
+ }
+ if (bg_scan_in->rssi_threshold) {
+ rssi_tlv = (MrvlIEtypes_BeaconLowRssiThreshold_t *) tlv;
+ rssi_tlv->header.type = wlan_cpu_to_le16(TLV_TYPE_RSSI_LOW);
+ rssi_tlv->header.len =
+ wlan_cpu_to_le16(sizeof(MrvlIEtypes_BeaconLowRssiThreshold_t) -
+ sizeof(MrvlIEtypesHeader_t));
+ rssi_tlv->value = bg_scan_in->rssi_threshold;
+ rssi_tlv->frequency = 0;
+ tlv += sizeof(MrvlIEtypes_BeaconLowRssiThreshold_t);
+ cmd_size += sizeof(MrvlIEtypes_BeaconLowRssiThreshold_t);
+ }
+ if (bg_scan_in->snr_threshold) {
+ snr_tlv = (MrvlIEtypes_BeaconLowSnrThreshold_t *) tlv;
+ snr_tlv->header.type = wlan_cpu_to_le16(TLV_TYPE_SNR_LOW);
+ snr_tlv->header.len =
+ wlan_cpu_to_le16(sizeof(MrvlIEtypes_BeaconLowSnrThreshold_t) -
+ sizeof(MrvlIEtypesHeader_t));
+ snr_tlv->value = bg_scan_in->snr_threshold;
+ snr_tlv->frequency = 0;
+ tlv += sizeof(MrvlIEtypes_BeaconLowRssiThreshold_t);
+ cmd_size += sizeof(MrvlIEtypes_BeaconLowRssiThreshold_t);
+ }
+ for (ssid_idx = 0; ((ssid_idx < NELEMENTS(bg_scan_in->ssid_list))
+ && (*bg_scan_in->ssid_list[ssid_idx].ssid ||
+ bg_scan_in->ssid_list[ssid_idx].max_len));
+ ssid_idx++) {
+ ssid_len = wlan_strlen((t_s8 *) bg_scan_in->ssid_list[ssid_idx].ssid);
+ pwildcard_ssid_tlv = (MrvlIEtypes_WildCardSsIdParamSet_t *) tlv;
+ pwildcard_ssid_tlv->header.type =
+ wlan_cpu_to_le16(TLV_TYPE_WILDCARDSSID);
+ pwildcard_ssid_tlv->header.len =
+ (t_u16) (ssid_len + sizeof(pwildcard_ssid_tlv->max_ssid_length));
+ pwildcard_ssid_tlv->max_ssid_length =
+ bg_scan_in->ssid_list[ssid_idx].max_len;
+ memcpy(pmadapter, pwildcard_ssid_tlv->ssid,
+ bg_scan_in->ssid_list[ssid_idx].ssid, MIN(MLAN_MAX_SSID_LENGTH,
+ ssid_len));
+ tlv +=
+ sizeof(pwildcard_ssid_tlv->header) + pwildcard_ssid_tlv->header.len;
+ cmd_size +=
+ sizeof(pwildcard_ssid_tlv->header) + pwildcard_ssid_tlv->header.len;
+ pwildcard_ssid_tlv->header.len =
+ wlan_cpu_to_le16(pwildcard_ssid_tlv->header.len);
+ PRINTM(MINFO, "Scan: ssid_list[%d]: %s, %d\n", ssid_idx,
+ pwildcard_ssid_tlv->ssid, pwildcard_ssid_tlv->max_ssid_length);
+ }
+ if (bg_scan_in->chan_list[0].chan_number) {
+ tlv_chan_list = (MrvlIEtypes_ChanListParamSet_t *) tlv;
+ PRINTM(MINFO, "Scan: Using supplied channel list\n");
+ chan_num = 0;
+ for (chan_idx = 0; chan_idx < WLAN_BG_SCAN_CHAN_MAX
+ && bg_scan_in->chan_list[chan_idx].chan_number; chan_idx++) {
+ radio_type = bg_scan_in->chan_list[chan_idx].radio_type;
+ if (!wlan_is_band_compatible
+ (pmpriv->config_bands | pmadapter->adhoc_start_band,
+ radio_type_to_band(radio_type)))
+ continue;
+ scan_type = bg_scan_in->chan_list[chan_idx].scan_type;
+ /* Prevent active scanning on a radar controlled channel */
+ if (radio_type == HostCmd_SCAN_RADIO_TYPE_A) {
+ if (wlan_11h_radar_detect_required
+ (pmpriv, bg_scan_in->chan_list[chan_idx].chan_number)) {
+ scan_type = MLAN_SCAN_TYPE_PASSIVE;
+ }
+ }
+ tlv_chan_list->chan_scan_param[chan_num].chan_number =
+ bg_scan_in->chan_list[chan_idx].chan_number;
+ tlv_chan_list->chan_scan_param[chan_num].radio_type =
+ bg_scan_in->chan_list[chan_idx].radio_type;
+
+ if (scan_type == MLAN_SCAN_TYPE_PASSIVE) {
+ tlv_chan_list->chan_scan_param[chan_num].chan_scan_mode.
+ passive_scan = MTRUE;
+ } else {
+ tlv_chan_list->chan_scan_param[chan_num].chan_scan_mode.
+ passive_scan = MFALSE;
+ }
+ if (bg_scan_in->chan_list[chan_idx].scan_time) {
+ scan_dur = (t_u16) bg_scan_in->chan_list[chan_idx].scan_time;
+ } else {
+ if (scan_type == MLAN_SCAN_TYPE_PASSIVE) {
+ scan_dur = pmadapter->passive_scan_time;
+ } else {
+ scan_dur = pmadapter->specific_scan_time;
+ }
+ }
+ tlv_chan_list->chan_scan_param[chan_num].min_scan_time =
+ wlan_cpu_to_le16(scan_dur);
+ tlv_chan_list->chan_scan_param[chan_num].max_scan_time =
+ wlan_cpu_to_le16(scan_dur);
+ chan_num++;
+ }
+ tlv_chan_list->header.type = wlan_cpu_to_le16(TLV_TYPE_CHANLIST);
+ tlv_chan_list->header.len =
+ wlan_cpu_to_le16(sizeof(ChanScanParamSet_t) * chan_num);
+ tlv +=
+ sizeof(MrvlIEtypesHeader_t) + sizeof(ChanScanParamSet_t) * chan_num;
+ cmd_size +=
+ sizeof(MrvlIEtypesHeader_t) + sizeof(ChanScanParamSet_t) * chan_num;
+ } else {
+ tlv_chan_list = (MrvlIEtypes_ChanListParamSet_t *) tlv;
+ chan_num =
+ wlan_bgscan_create_channel_list(pmpriv, bg_scan_in, tlv_chan_list);
+ tlv_chan_list->header.type = wlan_cpu_to_le16(TLV_TYPE_CHANLIST);
+ tlv_chan_list->header.len =
+ wlan_cpu_to_le16(sizeof(ChanScanParamSet_t) * chan_num);
+ tlv +=
+ sizeof(MrvlIEtypesHeader_t) + sizeof(ChanScanParamSet_t) * chan_num;
+ cmd_size +=
+ sizeof(MrvlIEtypesHeader_t) + sizeof(ChanScanParamSet_t) * chan_num;
+ }
+ done:
+ pcmd->size = wlan_cpu_to_le16(cmd_size);
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function handles the command response of extended scan
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param resp A pointer to HostCmd_DS_COMMAND
+ * @param pioctl_buf A pointer to mlan_ioctl_req structure
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status
+wlan_ret_bgscan_config(IN mlan_private * pmpriv,
+ IN HostCmd_DS_COMMAND * resp,
+ IN mlan_ioctl_req * pioctl_buf)
+{
+ mlan_ds_scan *pscan = MNULL;
+ HostCmd_DS_802_11_BG_SCAN_CONFIG *bg_scan = &resp->params.bg_scan_config;
+ wlan_bgscan_cfg *bg_scan_out = MNULL;
+
+ ENTER();
+ if (pioctl_buf) {
+ pscan = (mlan_ds_scan *) pioctl_buf->pbuf;
+ bg_scan_out = (wlan_bgscan_cfg *) pscan->param.user_scan.scan_cfg_buf;
+ bg_scan_out->action = wlan_le16_to_cpu(bg_scan->action);
+ if ((bg_scan_out->action == BG_SCAN_ACT_GET) &&
+ (bg_scan_out->action == BG_SCAN_ACT_GET_PPS_UAPSD)) {
+ bg_scan_out->enable = bg_scan->enable;
+ bg_scan_out->bss_type = bg_scan->bss_type;
+ bg_scan_out->chan_per_scan = bg_scan->chan_per_scan;
+ bg_scan_out->scan_interval =
+ wlan_le32_to_cpu(bg_scan->scan_interval);
+ bg_scan_out->report_condition =
+ wlan_le32_to_cpu(bg_scan->report_condition);
+ pioctl_buf->data_read_written =
+ sizeof(mlan_ds_scan) + MLAN_SUB_COMMAND_SIZE;
+ }
+ }
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function finds ssid in ssid list.
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param ssid SSID to find in the list
+ * @param bssid BSSID to qualify the SSID selection (if provided)
+ * @param mode Network mode: Infrastructure or IBSS
+ *
+ * @return index in BSSID list or < 0 if error
+ */
+t_s32
+wlan_find_ssid_in_list(IN mlan_private * pmpriv,
+ IN mlan_802_11_ssid * ssid,
+ IN t_u8 * bssid, IN t_u32 mode)
+{
+ mlan_adapter *pmadapter = pmpriv->adapter;
+ t_s32 net = -1, j;
+ t_u8 best_rssi = 0;
+ t_u32 i;
+
+ ENTER();
+ PRINTM(MINFO, "Num of entries in scan table = %d\n",
+ pmadapter->num_in_scan_table);
+
+ /*
+ * Loop through the table until the maximum is reached or until a match
+ * is found based on the bssid field comparison
+ */
+ for (i = 0;
+ i < pmadapter->num_in_scan_table && (!bssid || (bssid && net < 0));
+ i++) {
+ if (!wlan_ssid_cmp(pmadapter, &pmadapter->pscan_table[i].ssid, ssid) &&
+ (!bssid
+ || !memcmp(pmadapter, pmadapter->pscan_table[i].mac_address, bssid,
+ MLAN_MAC_ADDR_LENGTH))) {
+
+ if (((mode == MLAN_BSS_MODE_INFRA) &&
+ !wlan_is_band_compatible(pmadapter->config_bands,
+ pmadapter->pscan_table[i].bss_band))
+ ||
+ (wlan_find_cfp_by_band_and_channel
+ (pmadapter, (t_u8) pmadapter->pscan_table[i].bss_band,
+ (t_u16) pmadapter->pscan_table[i].channel) == MNULL)) {
+ continue;
+ }
+
+ switch (mode) {
+ case MLAN_BSS_MODE_INFRA:
+ case MLAN_BSS_MODE_IBSS:
+ j = wlan_is_network_compatible(pmpriv, i, mode);
+
+ if (j >= 0) {
+ if (SCAN_RSSI(pmadapter->pscan_table[i].rssi) > best_rssi) {
+ best_rssi = SCAN_RSSI(pmadapter->pscan_table[i].rssi);
+ net = i;
+ }
+ } else {
+ if (net == -1) {
+ net = j;
+ }
+ }
+ break;
+ case MLAN_BSS_MODE_AUTO:
+ default:
+ /*
+ * Do not check compatibility if the mode requested is
+ * Auto/Unknown. Allows generic find to work without
+ * verifying against the Adapter security settings
+ */
+ if (SCAN_RSSI(pmadapter->pscan_table[i].rssi) > best_rssi) {
+ best_rssi = SCAN_RSSI(pmadapter->pscan_table[i].rssi);
+ net = i;
+ }
+ break;
+ }
+ }
+ }
+
+ LEAVE();
+ return net;
+}
+
+/**
+ * @brief This function finds a specific compatible BSSID in the scan list
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param bssid BSSID to find in the scan list
+ * @param mode Network mode: Infrastructure or IBSS
+ *
+ * @return index in BSSID list or < 0 if error
+ */
+t_s32
+wlan_find_bssid_in_list(IN mlan_private * pmpriv,
+ IN t_u8 * bssid, IN t_u32 mode)
+{
+ mlan_adapter *pmadapter = pmpriv->adapter;
+ t_s32 net = -1;
+ t_u32 i;
+
+ ENTER();
+
+ if (!bssid) {
+ LEAVE();
+ return -1;
+ }
+
+ PRINTM(MINFO, "FindBSSID: Num of BSSIDs = %d\n",
+ pmadapter->num_in_scan_table);
+
+ /*
+ * Look through the scan table for a compatible match. The ret return
+ * variable will be equal to the index in the scan table (greater
+ * than zero) if the network is compatible. The loop will continue
+ * past a matched bssid that is not compatible in case there is an
+ * AP with multiple SSIDs assigned to the same BSSID
+ */
+ for (i = 0; net < 0 && i < pmadapter->num_in_scan_table; i++) {
+ if (!memcmp
+ (pmadapter, pmadapter->pscan_table[i].mac_address, bssid,
+ MLAN_MAC_ADDR_LENGTH)) {
+ if (((mode == MLAN_BSS_MODE_INFRA) &&
+ !wlan_is_band_compatible(pmadapter->config_bands,
+ pmadapter->pscan_table[i].bss_band))
+ ||
+ (wlan_find_cfp_by_band_and_channel
+ (pmadapter, (t_u8) pmadapter->pscan_table[i].bss_band,
+ (t_u16) pmadapter->pscan_table[i].channel) == MNULL)) {
+ continue;
+ }
+ switch (mode) {
+ case MLAN_BSS_MODE_INFRA:
+ case MLAN_BSS_MODE_IBSS:
+ net = wlan_is_network_compatible(pmpriv, i, mode);
+ break;
+ default:
+ net = i;
+ break;
+ }
+ }
+ }
+
+ LEAVE();
+ return net;
+}
+
+/**
+ * @brief Compare two SSIDs
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param ssid1 A pointer to ssid to compare
+ * @param ssid2 A pointer to ssid to compare
+ *
+ * @return 0--ssid is same, otherwise is different
+ */
+t_s32
+wlan_ssid_cmp(IN pmlan_adapter pmadapter,
+ IN mlan_802_11_ssid * ssid1, IN mlan_802_11_ssid * ssid2)
+{
+ ENTER();
+
+ if (!ssid1 || !ssid2) {
+ LEAVE();
+ return -1;
+ }
+
+ if (ssid1->ssid_len != ssid2->ssid_len) {
+ LEAVE();
+ return -1;
+ }
+
+ LEAVE();
+ return memcmp(pmadapter, ssid1->ssid, ssid2->ssid, ssid1->ssid_len);
+}
+
+/**
+ * @brief This function inserts scan command node to scan_pending_q.
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param pcmd_node A pointer to cmd_ctrl_node structure
+ * @return N/A
+ */
+t_void
+wlan_queue_scan_cmd(IN mlan_private * pmpriv, IN cmd_ctrl_node * pcmd_node)
+{
+ mlan_adapter *pmadapter = pmpriv->adapter;
+
+ ENTER();
+
+ if (pcmd_node == MNULL)
+ goto done;
+ util_enqueue_list_tail(pmadapter->pmoal_handle, &pmadapter->scan_pending_q,
+ (pmlan_linked_list) pcmd_node,
+ pmadapter->callbacks.moal_spin_lock,
+ pmadapter->callbacks.moal_spin_unlock);
+
+ done:
+ LEAVE();
+}
+
+/**
+ * @brief Find the AP with specific ssid in the scan list
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param preq_ssid_bssid A pointer to AP's ssid returned
+ *
+ * @return MLAN_STATUS_SUCCESS--success, otherwise--fail
+ */
+mlan_status
+wlan_find_best_network(IN mlan_private * pmpriv,
+ OUT mlan_ssid_bssid * preq_ssid_bssid)
+{
+ mlan_adapter *pmadapter = pmpriv->adapter;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ BSSDescriptor_t *preq_bss;
+ t_s32 i;
+
+ ENTER();
+
+ memset(pmadapter, preq_ssid_bssid, 0, sizeof(mlan_ssid_bssid));
+
+ i = wlan_find_best_network_in_list(pmpriv);
+
+ if (i >= 0) {
+ preq_bss = &pmadapter->pscan_table[i];
+ memcpy(pmadapter, &preq_ssid_bssid->ssid, &preq_bss->ssid,
+ sizeof(mlan_802_11_ssid));
+ memcpy(pmadapter, (t_u8 *) & preq_ssid_bssid->bssid,
+ (t_u8 *) & preq_bss->mac_address, MLAN_MAC_ADDR_LENGTH);
+
+ /* Make sure we are in the right mode */
+ if (pmpriv->bss_mode == MLAN_BSS_MODE_AUTO)
+ pmpriv->bss_mode = preq_bss->bss_mode;
+ }
+
+ if (!preq_ssid_bssid->ssid.ssid_len) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ PRINTM(MINFO, "Best network found = [%s], "
+ "[%02x:%02x:%02x:%02x:%02x:%02x]\n",
+ preq_ssid_bssid->ssid.ssid,
+ preq_ssid_bssid->bssid[0], preq_ssid_bssid->bssid[1],
+ preq_ssid_bssid->bssid[2], preq_ssid_bssid->bssid[3],
+ preq_ssid_bssid->bssid[4], preq_ssid_bssid->bssid[5]);
+
+ done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Send a scan command for all available channels filtered on a spec
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param pioctl_buf A pointer to MLAN IOCTL Request buffer
+ * @param preq_ssid A pointer to AP's ssid returned
+ *
+ * @return MLAN_STATUS_SUCCESS--success, otherwise--fail
+ */
+mlan_status
+wlan_scan_specific_ssid(IN mlan_private * pmpriv,
+ IN t_void * pioctl_buf, IN mlan_802_11_ssid * preq_ssid)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_callbacks *pcb = (mlan_callbacks *) & pmpriv->adapter->callbacks;
+ wlan_user_scan_cfg *pscan_cfg;
+ pmlan_ioctl_req pioctl_req = (mlan_ioctl_req *) pioctl_buf;
+
+ ENTER();
+
+ if (!preq_ssid) {
+ if (pioctl_req)
+ pioctl_req->status_code = MLAN_ERROR_CMD_SCAN_FAIL;
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ wlan_scan_delete_ssid_table_entry(pmpriv, preq_ssid);
+
+ ret =
+ pcb->moal_malloc(pmpriv->adapter->pmoal_handle,
+ sizeof(wlan_user_scan_cfg), MLAN_MEM_DEF,
+ (t_u8 **) & pscan_cfg);
+
+ if (ret != MLAN_STATUS_SUCCESS || !pscan_cfg) {
+ PRINTM(MERROR, "Memory allocation for pscan_cfg failed!\n");
+ if (pioctl_req)
+ pioctl_req->status_code = MLAN_ERROR_NO_MEM;
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ memset(pmpriv->adapter, pscan_cfg, 0x00, sizeof(wlan_user_scan_cfg));
+
+ memcpy(pmpriv->adapter, pscan_cfg->ssid_list[0].ssid,
+ preq_ssid->ssid, preq_ssid->ssid_len);
+ pscan_cfg->keep_previous_scan = MTRUE;
+
+ ret = wlan_scan_networks(pmpriv, pioctl_buf, pscan_cfg);
+
+ if (pscan_cfg)
+ pcb->moal_mfree(pmpriv->adapter->pmoal_handle, (t_u8 *) pscan_cfg);
+
+ done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Save a beacon buffer of the current bss descriptor
+ * Save the current beacon buffer to restore in the following cases that
+ * makes the bcn_buf not to contain the current ssid's beacon buffer.
+ * - the current ssid was not found somehow in the last scan.
+ * - the current ssid was the last entry of the scan table and overloaded.
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ *
+ * @return N/A
+ */
+t_void
+wlan_save_curr_bcn(IN mlan_private * pmpriv)
+{
+ mlan_adapter *pmadapter = pmpriv->adapter;
+ mlan_callbacks *pcb = (pmlan_callbacks) & pmadapter->callbacks;
+ BSSDescriptor_t *pcurr_bss = &pmpriv->curr_bss_params.bss_descriptor;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+ /* save the beacon buffer if it is not saved or updated */
+ if ((pmpriv->pcurr_bcn_buf == MNULL) ||
+ (pmpriv->curr_bcn_size != pcurr_bss->beacon_buf_size) ||
+ (memcmp(pmpriv->adapter, pmpriv->pcurr_bcn_buf, pcurr_bss->pbeacon_buf,
+ pcurr_bss->beacon_buf_size))) {
+
+ if (pmpriv->pcurr_bcn_buf) {
+ pcb->moal_mfree(pmadapter->pmoal_handle, pmpriv->pcurr_bcn_buf);
+ pmpriv->pcurr_bcn_buf = MNULL;
+ }
+ pmpriv->curr_bcn_size = pcurr_bss->beacon_buf_size;
+
+ if (pmpriv->curr_bcn_size) {
+ ret =
+ pcb->moal_malloc(pmadapter->pmoal_handle,
+ pcurr_bss->beacon_buf_size, MLAN_MEM_DEF,
+ &pmpriv->pcurr_bcn_buf);
+
+ if ((ret == MLAN_STATUS_SUCCESS) && pmpriv->pcurr_bcn_buf) {
+ memcpy(pmpriv->adapter, pmpriv->pcurr_bcn_buf,
+ pcurr_bss->pbeacon_buf, pcurr_bss->beacon_buf_size);
+ PRINTM(MINFO, "current beacon saved %d\n",
+ pmpriv->curr_bcn_size);
+ }
+ }
+ }
+ LEAVE();
+}
+
+/**
+ * @brief Free a beacon buffer of the current bss descriptor
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ *
+ * @return N/A
+ */
+t_void
+wlan_free_curr_bcn(IN mlan_private * pmpriv)
+{
+ mlan_adapter *pmadapter = pmpriv->adapter;
+ mlan_callbacks *pcb = (pmlan_callbacks) & pmadapter->callbacks;
+
+ ENTER();
+ if (pmpriv->pcurr_bcn_buf) {
+ pcb->moal_mfree(pmadapter->pmoal_handle, pmpriv->pcurr_bcn_buf);
+ pmpriv->pcurr_bcn_buf = MNULL;
+ }
+ LEAVE();
+}
diff --git a/drivers/net/wireless/sd8797/mlan/mlan_sdio.c b/drivers/net/wireless/sd8797/mlan/mlan_sdio.c
new file mode 100644
index 000000000000..4812797c6361
--- /dev/null
+++ b/drivers/net/wireless/sd8797/mlan/mlan_sdio.c
@@ -0,0 +1,1661 @@
+/** @file mlan_sdio.c
+ *
+ * @brief This file contains SDIO specific code
+ *
+ * Copyright (C) 2008-2011, Marvell International Ltd.
+ *
+ * This software file (the "File") is distributed by Marvell International
+ * Ltd. under the terms of the GNU General Public License Version 2, June 1991
+ * (the "License"). You may use, redistribute and/or modify this File in
+ * accordance with the terms and conditions of the License, a copy of which
+ * is available by writing to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
+ * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
+ *
+ * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
+ * ARE EXPRESSLY DISCLAIMED. The License provides additional details about
+ * this warranty disclaimer.
+ */
+
+/********************************************************
+Change log:
+ 10/27/2008: initial version
+********************************************************/
+
+#include "mlan.h"
+#ifdef STA_SUPPORT
+#include "mlan_join.h"
+#endif
+#include "mlan_util.h"
+#include "mlan_fw.h"
+#include "mlan_main.h"
+#include "mlan_init.h"
+#include "mlan_wmm.h"
+#include "mlan_11n.h"
+#include "mlan_sdio.h"
+
+/********************************************************
+ Local Variables
+********************************************************/
+
+/********************************************************
+ Global Variables
+********************************************************/
+
+/********************************************************
+ Local Functions
+********************************************************/
+
+/**
+ * @brief This function initialize the SDIO port
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+static mlan_status
+wlan_sdio_init_ioport(mlan_adapter * pmadapter)
+{
+ t_u32 reg;
+ pmlan_callbacks pcb = &pmadapter->callbacks;
+
+ ENTER();
+ pmadapter->ioport = 0;
+
+ /* Read the IO port */
+ if (MLAN_STATUS_SUCCESS ==
+ pcb->moal_read_reg(pmadapter->pmoal_handle, IO_PORT_0_REG, &reg))
+ pmadapter->ioport |= (reg & 0xff);
+ else {
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+
+ if (MLAN_STATUS_SUCCESS ==
+ pcb->moal_read_reg(pmadapter->pmoal_handle, IO_PORT_1_REG, &reg))
+ pmadapter->ioport |= ((reg & 0xff) << 8);
+ else {
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+
+ if (MLAN_STATUS_SUCCESS ==
+ pcb->moal_read_reg(pmadapter->pmoal_handle, IO_PORT_2_REG, &reg))
+ pmadapter->ioport |= ((reg & 0xff) << 16);
+ else {
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+
+ PRINTM(MINFO, "SDIO FUNC1 IO port: 0x%x\n", pmadapter->ioport);
+
+ /* Set Host interrupt reset to read to clear */
+ if (MLAN_STATUS_SUCCESS ==
+ pcb->moal_read_reg(pmadapter->pmoal_handle, HOST_INT_RSR_REG, &reg)) {
+ pcb->moal_write_reg(pmadapter->pmoal_handle, HOST_INT_RSR_REG,
+ reg | HOST_INT_RSR_MASK);
+ } else {
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+
+ /* Dnld/Upld ready set to auto reset */
+ if (MLAN_STATUS_SUCCESS ==
+ pcb->moal_read_reg(pmadapter->pmoal_handle, CARD_MISC_CFG_REG, &reg)) {
+ pcb->moal_write_reg(pmadapter->pmoal_handle, CARD_MISC_CFG_REG,
+ reg | AUTO_RE_ENABLE_INT);
+ } else {
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function sends data to the card.
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pmbuf A pointer to mlan_buffer (pmbuf->data_len should include SDIO header)
+ * @param port Port
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+static mlan_status
+wlan_write_data_sync(mlan_adapter * pmadapter, mlan_buffer * pmbuf, t_u32 port)
+{
+ t_u32 i = 0;
+ pmlan_callbacks pcb = &pmadapter->callbacks;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ do {
+ ret =
+ pcb->moal_write_data_sync(pmadapter->pmoal_handle, pmbuf, port, 0);
+ if (ret != MLAN_STATUS_SUCCESS) {
+ i++;
+ PRINTM(MERROR, "host_to_card, write iomem (%d) failed: %d\n", i,
+ ret);
+ if (MLAN_STATUS_SUCCESS !=
+ pcb->moal_write_reg(pmadapter->pmoal_handle,
+ HOST_TO_CARD_EVENT_REG, 0x04)) {
+ PRINTM(MERROR, "write CFG reg failed\n");
+ }
+ ret = MLAN_STATUS_FAILURE;
+ if (i > MAX_WRITE_IOMEM_RETRY) {
+ pmbuf->status_code = MLAN_ERROR_DATA_TX_FAIL;
+ goto exit;
+ }
+ }
+ } while (ret == MLAN_STATUS_FAILURE);
+ exit:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function gets available SDIO port for reading cmd/data
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pport A pointer to port number
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+static mlan_status
+wlan_get_rd_port(mlan_adapter * pmadapter, t_u8 * pport)
+{
+ t_u32 rd_bitmap = pmadapter->mp_rd_bitmap;
+
+ ENTER();
+
+ PRINTM(MIF_D, "wlan_get_rd_port: mp_rd_bitmap=0x%08x\n", rd_bitmap);
+
+ if (!(rd_bitmap & (CTRL_PORT_MASK | DATA_PORT_MASK))) {
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+
+ if (pmadapter->mp_rd_bitmap & CTRL_PORT_MASK) {
+ pmadapter->mp_rd_bitmap &= (t_u32) (~CTRL_PORT_MASK);
+ *pport = CTRL_PORT;
+ PRINTM(MIF_D, "wlan_get_rd_port: port=%d mp_rd_bitmap=0x%08x\n", *pport,
+ pmadapter->mp_rd_bitmap);
+ } else {
+ if (pmadapter->mp_rd_bitmap & (1 << pmadapter->curr_rd_port)) {
+ pmadapter->mp_rd_bitmap &=
+ (t_u32) (~(1 << pmadapter->curr_rd_port));
+ *pport = pmadapter->curr_rd_port;
+
+ /* hw rx wraps round only after port (MAX_PORT-1) */
+ if (++pmadapter->curr_rd_port == MAX_PORT)
+ /* port 0 is reserved for cmd port */
+ pmadapter->curr_rd_port = 1;
+ } else {
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+
+ PRINTM(MIF_D, "port=%d mp_rd_bitmap=0x%08x -> 0x%08x\n",
+ *pport, rd_bitmap, pmadapter->mp_rd_bitmap);
+ }
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function gets available SDIO port for writing data
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pport A pointer to port number
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+static mlan_status
+wlan_get_wr_port_data(mlan_adapter * pmadapter, t_u8 * pport)
+{
+ t_u32 wr_bitmap = pmadapter->mp_wr_bitmap;
+
+ ENTER();
+
+ PRINTM(MIF_D, "wlan_get_wr_port_data: mp_wr_bitmap=0x%08x\n", wr_bitmap);
+
+ if (!(wr_bitmap & pmadapter->mp_data_port_mask)) {
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+
+ if (pmadapter->mp_wr_bitmap & (1 << pmadapter->curr_wr_port)) {
+ pmadapter->mp_wr_bitmap &= (t_u32) (~(1 << pmadapter->curr_wr_port));
+ *pport = pmadapter->curr_wr_port;
+ if (++pmadapter->curr_wr_port == pmadapter->mp_end_port)
+ pmadapter->curr_wr_port = 1;
+ } else {
+ pmadapter->data_sent = MTRUE;
+ LEAVE();
+ return MLAN_STATUS_RESOURCE;
+ }
+
+ if (*pport == CTRL_PORT) {
+ PRINTM(MERROR,
+ "Invalid data port=%d cur port=%d mp_wr_bitmap=0x%08x -> 0x%08x\n",
+ *pport, pmadapter->curr_wr_port, wr_bitmap,
+ pmadapter->mp_wr_bitmap);
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+
+ PRINTM(MIF_D, "port=%d mp_wr_bitmap=0x%08x -> 0x%08x\n",
+ *pport, wr_bitmap, pmadapter->mp_wr_bitmap);
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function polls the card status register.
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param bits the bit mask
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+static mlan_status
+wlan_sdio_poll_card_status(mlan_adapter * pmadapter, t_u8 bits)
+{
+ pmlan_callbacks pcb = &pmadapter->callbacks;
+ t_u32 tries;
+ t_u32 cs = 0;
+
+ ENTER();
+
+ for (tries = 0; tries < MAX_POLL_TRIES; tries++) {
+ if (pcb->
+ moal_read_reg(pmadapter->pmoal_handle, CARD_TO_HOST_EVENT_REG,
+ &cs) != MLAN_STATUS_SUCCESS)
+ break;
+ else if ((cs & bits) == bits) {
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+ }
+ wlan_udelay(pmadapter, 10);
+ }
+
+ PRINTM(MERROR, "wlan_sdio_poll_card_status failed, tries = %d, cs = 0x%x\n",
+ tries, cs);
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+}
+
+/**
+ * @brief This function reads firmware status registers
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param dat A pointer to keep returned data
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+static mlan_status
+wlan_sdio_read_fw_status(mlan_adapter * pmadapter, t_u16 * dat)
+{
+ pmlan_callbacks pcb = &pmadapter->callbacks;
+ t_u32 fws0 = 0, fws1 = 0;
+
+ ENTER();
+ if (MLAN_STATUS_SUCCESS !=
+ pcb->moal_read_reg(pmadapter->pmoal_handle, CARD_FW_STATUS0_REG,
+ &fws0)) {
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+
+ if (MLAN_STATUS_SUCCESS !=
+ pcb->moal_read_reg(pmadapter->pmoal_handle, CARD_FW_STATUS1_REG,
+ &fws1)) {
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+
+ *dat = (t_u16) ((fws1 << 8) | fws0);
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/** @brief This function disables the host interrupts mask.
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param mask the interrupt mask
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+static mlan_status
+wlan_sdio_disable_host_int_mask(pmlan_adapter pmadapter, t_u8 mask)
+{
+ t_u32 host_int_mask = 0;
+ pmlan_callbacks pcb = &pmadapter->callbacks;
+
+ ENTER();
+
+ /* Read back the host_int_mask register */
+ if (MLAN_STATUS_SUCCESS !=
+ pcb->moal_read_reg(pmadapter->pmoal_handle, HOST_INT_MASK_REG,
+ &host_int_mask)) {
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+
+ /* Update with the mask and write back to the register */
+ host_int_mask &= ~mask;
+
+ if (MLAN_STATUS_SUCCESS !=
+ pcb->moal_write_reg(pmadapter->pmoal_handle, HOST_INT_MASK_REG,
+ host_int_mask)) {
+ PRINTM(MWARN, "Disable host interrupt failed\n");
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function enables the host interrupts mask
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param mask the interrupt mask
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+static mlan_status
+wlan_sdio_enable_host_int_mask(pmlan_adapter pmadapter, t_u8 mask)
+{
+ pmlan_callbacks pcb = &pmadapter->callbacks;
+
+ ENTER();
+
+ /* Simply write the mask to the register */
+ if (MLAN_STATUS_SUCCESS !=
+ pcb->moal_write_reg(pmadapter->pmoal_handle, HOST_INT_MASK_REG, mask)) {
+ PRINTM(MWARN, "Enable host interrupt failed\n");
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function reads data from the card.
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param type A pointer to keep type as data or command
+ * @param nb A pointer to keep the data/cmd length returned in buffer
+ * @param pmbuf A pointer to the SDIO data/cmd buffer
+ * @param npayload the length of data/cmd buffer
+ * @param ioport the SDIO ioport
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+static mlan_status
+wlan_sdio_card_to_host(mlan_adapter * pmadapter,
+ t_u32 * type, t_u32 * nb, pmlan_buffer pmbuf,
+ t_u32 npayload, t_u32 ioport)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ pmlan_callbacks pcb = &pmadapter->callbacks;
+
+ ENTER();
+
+ if (!pmbuf) {
+ PRINTM(MWARN, "pmbuf is NULL!\n");
+ ret = MLAN_STATUS_FAILURE;
+ goto exit;
+ }
+
+ ret = pcb->moal_read_data_sync(pmadapter->pmoal_handle, pmbuf, ioport, 0);
+
+ if (ret != MLAN_STATUS_SUCCESS) {
+ PRINTM(MERROR, "card_to_host, read iomem failed: %d\n", ret);
+ pmbuf->status_code = MLAN_ERROR_DATA_RX_FAIL;
+ ret = MLAN_STATUS_FAILURE;
+ goto exit;
+ }
+ *nb = wlan_le16_to_cpu(*(t_u16 *) (pmbuf->pbuf + pmbuf->data_offset));
+ if (*nb > npayload) {
+ PRINTM(MERROR, "invalid packet, *nb=%d, npayload=%d\n", *nb, npayload);
+ pmbuf->status_code = MLAN_ERROR_PKT_SIZE_INVALID;
+ ret = MLAN_STATUS_FAILURE;
+ goto exit;
+ }
+
+ DBG_HEXDUMP(MIF_D, "SDIO Blk Rd", pmbuf->pbuf + pmbuf->data_offset,
+ MIN(*nb, MAX_DATA_DUMP_LEN));
+
+ *type = wlan_le16_to_cpu(*(t_u16 *) (pmbuf->pbuf + pmbuf->data_offset + 2));
+
+ exit:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function downloads FW blocks to device
+ *
+ * @param pmadapter A pointer to mlan_adapter
+ * @param pmfw A pointer to firmware image
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+static mlan_status
+wlan_prog_fw_w_helper(IN pmlan_adapter pmadapter, IN pmlan_fw_image pmfw)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ pmlan_callbacks pcb = &pmadapter->callbacks;
+ t_u8 *firmware = pmfw->pfw_buf;
+ t_u32 firmwarelen = pmfw->fw_len;
+ t_u32 offset = 0;
+ t_u32 base0, base1;
+ t_void *tmpfwbuf = MNULL;
+ t_u32 tmpfwbufsz;
+ t_u8 *fwbuf;
+ mlan_buffer mbuf;
+ t_u16 len = 0;
+ t_u32 txlen = 0, tx_blocks = 0, tries = 0;
+ t_u32 i = 0;
+
+ ENTER();
+
+ if (!firmware && !pcb->moal_get_fw_data) {
+ PRINTM(MMSG, "No firmware image found! Terminating download\n");
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+
+ PRINTM(MINFO, "WLAN: Downloading FW image (%d bytes)\n", firmwarelen);
+
+ tmpfwbufsz = ALIGN_SZ(WLAN_UPLD_SIZE, DMA_ALIGNMENT);
+ ret =
+ pcb->moal_malloc(pmadapter->pmoal_handle, tmpfwbufsz,
+ MLAN_MEM_DEF | MLAN_MEM_DMA, (t_u8 **) & tmpfwbuf);
+ if ((ret != MLAN_STATUS_SUCCESS) || !tmpfwbuf) {
+ PRINTM(MERROR,
+ "Unable to allocate buffer for firmware. Terminating download\n");
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ memset(pmadapter, tmpfwbuf, 0, tmpfwbufsz);
+ /* Ensure 8-byte aligned firmware buffer */
+ fwbuf = (t_u8 *) ALIGN_ADDR(tmpfwbuf, DMA_ALIGNMENT);
+
+ /* Perform firmware data transfer */
+ do {
+ /* The host polls for the DN_LD_CARD_RDY and CARD_IO_READY bits */
+ ret =
+ wlan_sdio_poll_card_status(pmadapter,
+ CARD_IO_READY | DN_LD_CARD_RDY);
+ if (ret != MLAN_STATUS_SUCCESS) {
+ PRINTM(MFATAL,
+ "WLAN: FW download with helper poll status timeout @ %d\n",
+ offset);
+ goto done;
+ }
+
+ /* More data? */
+ if (firmwarelen && offset >= firmwarelen)
+ break;
+
+ for (tries = 0; tries < MAX_POLL_TRIES; tries++) {
+ if ((ret = pcb->moal_read_reg(pmadapter->pmoal_handle,
+ READ_BASE_0_REG,
+ &base0)) != MLAN_STATUS_SUCCESS) {
+ PRINTM(MERROR,
+ "Dev BASE0 register read failed:"
+ " base0=0x%04X(%d). Terminating download\n", base0,
+ base0);
+ goto done;
+ }
+ if ((ret = pcb->moal_read_reg(pmadapter->pmoal_handle,
+ READ_BASE_1_REG,
+ &base1)) != MLAN_STATUS_SUCCESS) {
+ PRINTM(MERROR,
+ "Dev BASE1 register read failed:"
+ " base1=0x%04X(%d). Terminating download\n", base1,
+ base1);
+ goto done;
+ }
+ len = (t_u16) (((base1 & 0xff) << 8) | (base0 & 0xff));
+
+ if (len)
+ break;
+ wlan_udelay(pmadapter, 10);
+ }
+
+ if (!len)
+ break;
+ else if (len > WLAN_UPLD_SIZE) {
+ PRINTM(MFATAL,
+ "WLAN: FW download failure @ %d, invalid length %d\n",
+ offset, len);
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ txlen = len;
+
+ if (len & MBIT(0)) {
+ i++;
+ if (i > MAX_WRITE_IOMEM_RETRY) {
+ PRINTM(MFATAL,
+ "WLAN: FW download failure @ %d, over max retry count\n",
+ offset);
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ PRINTM(MERROR, "WLAN: FW CRC error indicated by the helper:"
+ " len = 0x%04X, txlen = %d\n", len, txlen);
+ len &= ~MBIT(0);
+
+ PRINTM(MERROR, "WLAN: retry: %d, offset %d\n", i, offset);
+ DBG_HEXDUMP(MERROR, "WLAN: FW block:", mbuf.pbuf, len);
+
+ /* Setting this to 0 to resend from same offset */
+ txlen = 0;
+ } else {
+ i = 0;
+
+ /* Set blocksize to transfer - checking for last block */
+ if (firmwarelen && firmwarelen - offset < txlen) {
+ txlen = firmwarelen - offset;
+ }
+ PRINTM(MINFO, ".");
+
+ tx_blocks =
+ (txlen + MLAN_SDIO_BLOCK_SIZE_FW_DNLD -
+ 1) / MLAN_SDIO_BLOCK_SIZE_FW_DNLD;
+
+ /* Copy payload to buffer */
+ if (firmware)
+ memmove(pmadapter, fwbuf, &firmware[offset], txlen);
+ else
+ pcb->moal_get_fw_data(pmadapter->pmoal_handle, offset, txlen,
+ fwbuf);
+ }
+
+ /* Send data */
+ memset(pmadapter, &mbuf, 0, sizeof(mlan_buffer));
+ mbuf.pbuf = (t_u8 *) fwbuf;
+ mbuf.data_len = tx_blocks * MLAN_SDIO_BLOCK_SIZE_FW_DNLD;
+
+ ret =
+ pcb->moal_write_data_sync(pmadapter->pmoal_handle, &mbuf,
+ pmadapter->ioport, 0);
+ if (ret != MLAN_STATUS_SUCCESS) {
+ PRINTM(MERROR, "WLAN: FW download, write iomem (%d) failed @ %d\n",
+ i, offset);
+ if (pcb->
+ moal_write_reg(pmadapter->pmoal_handle, HOST_TO_CARD_EVENT_REG,
+ 0x04) != MLAN_STATUS_SUCCESS) {
+ PRINTM(MERROR, "write CFG reg failed\n");
+ }
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ offset += txlen;
+ } while (MTRUE);
+
+ PRINTM(MINFO, "\nFW download over, size %d bytes\n", offset);
+
+ ret = MLAN_STATUS_SUCCESS;
+ done:
+ if (tmpfwbuf)
+ pcb->moal_mfree(pmadapter->pmoal_handle, (t_u8 *) tmpfwbuf);
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function disables the host interrupts.
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+static mlan_status
+wlan_disable_host_int(pmlan_adapter pmadapter)
+{
+ mlan_status ret;
+
+ ENTER();
+ ret = wlan_sdio_disable_host_int_mask(pmadapter, HIM_DISABLE);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function decodes the rx packet &
+ * calls corresponding handlers according to the packet type
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pmbuf A pointer to the SDIO data/cmd buffer
+ * @param upld_typ Type of rx packet
+ * @return MLAN_STATUS_SUCCESS
+ */
+static mlan_status
+wlan_decode_rx_packet(mlan_adapter * pmadapter, mlan_buffer * pmbuf,
+ t_u32 upld_typ)
+{
+ t_u8 *cmdBuf;
+ t_u32 event;
+
+ ENTER();
+
+ switch (upld_typ) {
+ case MLAN_TYPE_DATA:
+ PRINTM(MINFO, "--- Rx: Data packet ---\n");
+ pmbuf->data_len = (pmadapter->upld_len - INTF_HEADER_LEN);
+ pmbuf->data_offset += INTF_HEADER_LEN;
+ wlan_handle_rx_packet(pmadapter, pmbuf);
+ pmadapter->data_received = MTRUE;
+ break;
+
+ case MLAN_TYPE_CMD:
+ PRINTM(MINFO, "--- Rx: Cmd Response ---\n");
+ /* take care of curr_cmd = NULL case */
+ if (!pmadapter->curr_cmd) {
+ cmdBuf = pmadapter->upld_buf;
+ if (pmadapter->ps_state == PS_STATE_SLEEP_CFM) {
+ wlan_process_sleep_confirm_resp(pmadapter,
+ pmbuf->pbuf +
+ pmbuf->data_offset +
+ INTF_HEADER_LEN,
+ pmadapter->upld_len -
+ INTF_HEADER_LEN);
+ }
+ pmadapter->upld_len -= INTF_HEADER_LEN;
+ memcpy(pmadapter, cmdBuf,
+ pmbuf->pbuf + pmbuf->data_offset + INTF_HEADER_LEN,
+ MIN(MRVDRV_SIZE_OF_CMD_BUFFER,
+ pmadapter->upld_len - INTF_HEADER_LEN));
+ wlan_free_mlan_buffer(pmadapter, pmbuf);
+ } else {
+ pmadapter->cmd_resp_received = MTRUE;
+ pmadapter->upld_len -= INTF_HEADER_LEN;
+ pmbuf->data_len = pmadapter->upld_len;
+ pmbuf->data_offset += INTF_HEADER_LEN;
+ pmadapter->curr_cmd->respbuf = pmbuf;
+ }
+ break;
+
+ case MLAN_TYPE_EVENT:
+ PRINTM(MINFO, "--- Rx: Event ---\n");
+ event = *(t_u32 *) & pmbuf->pbuf[pmbuf->data_offset + INTF_HEADER_LEN];
+ pmadapter->event_cause = wlan_le32_to_cpu(event);
+ if ((pmadapter->upld_len > MLAN_EVENT_HEADER_LEN) &&
+ ((pmadapter->upld_len - MLAN_EVENT_HEADER_LEN) < MAX_EVENT_SIZE)) {
+ memcpy(pmadapter, pmadapter->event_body,
+ pmbuf->pbuf + pmbuf->data_offset + MLAN_EVENT_HEADER_LEN,
+ pmadapter->upld_len - MLAN_EVENT_HEADER_LEN);
+ }
+
+ /* event cause has been saved to adapter->event_cause */
+ pmadapter->event_received = MTRUE;
+ pmbuf->data_len = pmadapter->upld_len;
+ pmadapter->pmlan_buffer_event = pmbuf;
+
+ /* remove SDIO header */
+ pmbuf->data_offset += INTF_HEADER_LEN;
+ pmbuf->data_len -= INTF_HEADER_LEN;
+ break;
+
+ default:
+ PRINTM(MERROR, "SDIO unknown upload type = 0x%x\n", upld_typ);
+ wlan_free_mlan_buffer(pmadapter, pmbuf);
+ break;
+ }
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+#ifdef SDIO_MULTI_PORT_RX_AGGR
+/**
+ * @brief This function receives data from the card in aggregate mode.
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pmbuf A pointer to the SDIO data/cmd buffer
+ * @param port Current port on which packet needs to be rxed
+ * @param rx_len Length of received packet
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+static mlan_status
+wlan_sdio_card_to_host_mp_aggr(mlan_adapter * pmadapter, mlan_buffer
+ * pmbuf, t_u8 port, t_u16 rx_len)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ pmlan_callbacks pcb = &pmadapter->callbacks;
+ t_s32 f_do_rx_aggr = 0;
+ t_s32 f_do_rx_cur = 0;
+ t_s32 f_aggr_cur = 0;
+ mlan_buffer mbuf_aggr;
+ mlan_buffer *mbuf_deaggr;
+ t_u32 pind = 0;
+ t_u32 pkt_len, pkt_type = 0;
+ t_u8 *curr_ptr;
+ t_u32 cmd53_port = 0;
+
+ ENTER();
+
+ if (port == CTRL_PORT) {
+ /* Read the command response or event without aggr */
+ PRINTM(MINFO, "card_2_host_mp_aggr: No aggr for control port\n");
+
+ f_do_rx_cur = 1;
+ goto rx_curr_single;
+ }
+
+ if (!pmadapter->mpa_rx.enabled) {
+ PRINTM(MINFO, "card_2_host_mp_aggr: rx aggregation disabled !\n");
+
+ f_do_rx_cur = 1;
+ goto rx_curr_single;
+ }
+
+ if (pmadapter->mp_rd_bitmap & (~((t_u32) CTRL_PORT_MASK))) {
+ /* Some more data RX pending */
+ PRINTM(MINFO, "card_2_host_mp_aggr: Not last packet\n");
+
+ if (MP_RX_AGGR_IN_PROGRESS(pmadapter)) {
+ if (MP_RX_AGGR_BUF_HAS_ROOM(pmadapter, rx_len)) {
+ f_aggr_cur = 1;
+ } else {
+ /* No room in Aggr buf, do rx aggr now */
+ f_do_rx_aggr = 1;
+ f_do_rx_cur = 1;
+ }
+ } else {
+ /* Rx aggr not in progress */
+ f_aggr_cur = 1;
+ }
+
+ } else {
+ /* No more data RX pending */
+ PRINTM(MINFO, "card_2_host_mp_aggr: Last packet\n");
+
+ if (MP_RX_AGGR_IN_PROGRESS(pmadapter)) {
+ f_do_rx_aggr = 1;
+ if (MP_RX_AGGR_BUF_HAS_ROOM(pmadapter, rx_len)) {
+ f_aggr_cur = 1;
+ } else {
+ /* No room in Aggr buf, do rx aggr now */
+ f_do_rx_cur = 1;
+ }
+ } else {
+ f_do_rx_cur = 1;
+ }
+
+ }
+
+ if (f_aggr_cur) {
+ PRINTM(MINFO, "Current packet aggregation.\n");
+ /* Curr pkt can be aggregated */
+ MP_RX_AGGR_SETUP(pmadapter, pmbuf, port, rx_len);
+
+ if (MP_RX_AGGR_PKT_LIMIT_REACHED(pmadapter) ||
+ MP_RX_AGGR_PORT_LIMIT_REACHED(pmadapter)) {
+ PRINTM(MINFO,
+ "card_2_host_mp_aggr: Aggregation Packet limit reached\n");
+ /* No more pkts allowed in Aggr buf, rx it */
+ f_do_rx_aggr = 1;
+ }
+ }
+
+ if (f_do_rx_aggr) {
+ /* do aggr RX now */
+ PRINTM(MINFO, "do_rx_aggr: num of packets: %d\n",
+ pmadapter->mpa_rx.pkt_cnt);
+
+ memset(pmadapter, &mbuf_aggr, 0, sizeof(mlan_buffer));
+
+ mbuf_aggr.pbuf = (t_u8 *) pmadapter->mpa_rx.buf;
+ mbuf_aggr.data_len = pmadapter->mpa_rx.buf_len;
+ cmd53_port = (pmadapter->ioport | SDIO_MPA_ADDR_BASE |
+ (pmadapter->mpa_rx.ports << 4)) +
+ pmadapter->mpa_rx.start_port;
+ if (MLAN_STATUS_SUCCESS !=
+ pcb->moal_read_data_sync(pmadapter->pmoal_handle, &mbuf_aggr,
+ cmd53_port, 0)) {
+ pmbuf->status_code = MLAN_ERROR_DATA_RX_FAIL;
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ DBG_HEXDUMP(MIF_D, "SDIO MP-A Blk Rd", pmadapter->mpa_rx.buf,
+ MIN(pmadapter->mpa_rx.buf_len, MAX_DATA_DUMP_LEN));
+
+ curr_ptr = pmadapter->mpa_rx.buf;
+
+ for (pind = 0; pind < pmadapter->mpa_rx.pkt_cnt; pind++) {
+
+ /* get curr PKT len & type */
+ pkt_len = wlan_le16_to_cpu(*(t_u16 *) & curr_ptr[0]);
+ pkt_type = wlan_le16_to_cpu(*(t_u16 *) & curr_ptr[2]);
+
+ PRINTM(MINFO, "RX: [%d] pktlen: %d pkt_type: 0x%x\n", pind,
+ pkt_len, pkt_type);
+
+ /* copy pkt to deaggr buf */
+ mbuf_deaggr = pmadapter->mpa_rx.mbuf_arr[pind];
+ if ((pkt_type == MLAN_TYPE_DATA) &&
+ (pkt_len <= pmadapter->mpa_rx.len_arr[pind])) {
+ memcpy(pmadapter, mbuf_deaggr->pbuf + mbuf_deaggr->data_offset,
+ curr_ptr, pkt_len);
+ pmadapter->upld_len = pkt_len;
+ /* Process de-aggr packet */
+ wlan_decode_rx_packet(pmadapter, mbuf_deaggr, pkt_type);
+ } else {
+ PRINTM(MERROR,
+ "Wrong aggr packet: type=%d, len=%d, max_len=%d\n",
+ pkt_type, pkt_len, pmadapter->mpa_rx.len_arr[pind]);
+ wlan_free_mlan_buffer(pmadapter, mbuf_deaggr);
+ }
+ curr_ptr += pmadapter->mpa_rx.len_arr[pind];
+ }
+ MP_RX_AGGR_BUF_RESET(pmadapter);
+ }
+
+ rx_curr_single:
+ if (f_do_rx_cur) {
+ PRINTM(MINFO, "RX: f_do_rx_cur: port: %d rx_len: %d\n", port, rx_len);
+
+ if (MLAN_STATUS_SUCCESS != wlan_sdio_card_to_host(pmadapter, &pkt_type,
+ (t_u32 *) &
+ pmadapter->upld_len,
+ pmbuf, rx_len,
+ pmadapter->ioport +
+ port)) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ if ((port == CTRL_PORT) && ((pkt_type != MLAN_TYPE_EVENT) &&
+ (pkt_type != MLAN_TYPE_CMD))) {
+ PRINTM(MERROR, "Wrong pkt from CTRL PORT: type=%d, len=%dd\n",
+ pkt_type, pmbuf->data_len);
+ pmbuf->status_code = MLAN_ERROR_DATA_RX_FAIL;
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ wlan_decode_rx_packet(pmadapter, pmbuf, pkt_type);
+ }
+
+ done:
+ if (ret == MLAN_STATUS_FAILURE) {
+ if (MP_RX_AGGR_IN_PROGRESS(pmadapter)) {
+ /* MP-A transfer failed - cleanup */
+ for (pind = 0; pind < pmadapter->mpa_rx.pkt_cnt; pind++) {
+ wlan_free_mlan_buffer(pmadapter,
+ pmadapter->mpa_rx.mbuf_arr[pind]);
+ }
+ MP_RX_AGGR_BUF_RESET(pmadapter);
+ }
+
+ if (f_do_rx_cur) {
+ /* Single Transfer pending */
+ /* Free curr buff also */
+ wlan_free_mlan_buffer(pmadapter, pmbuf);
+ }
+ }
+
+ LEAVE();
+ return ret;
+
+}
+#endif
+
+#ifdef SDIO_MULTI_PORT_TX_AGGR
+/**
+ * @brief This function sends data to the card in SDIO aggregated mode.
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param mbuf A pointer to the SDIO data/cmd buffer
+ * @param port current port for aggregation
+ * @param next_pkt_len Length of next packet used for multiport aggregation
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+static mlan_status
+wlan_host_to_card_mp_aggr(mlan_adapter * pmadapter, mlan_buffer * mbuf,
+ t_u8 port, t_u32 next_pkt_len)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ t_s32 f_send_aggr_buf = 0;
+ t_s32 f_send_cur_buf = 0;
+ t_s32 f_precopy_cur_buf = 0;
+ t_s32 f_postcopy_cur_buf = 0;
+ t_u32 cmd53_port = 0;
+ mlan_buffer mbuf_aggr;
+
+ ENTER();
+
+ PRINTM(MIF_D, "host_2_card_mp_aggr: next_pkt_len: %d curr_port:%d\n",
+ next_pkt_len, port);
+
+ if (!pmadapter->mpa_tx.enabled) {
+ PRINTM(MINFO, "host_2_card_mp_aggr: tx aggregation disabled !\n");
+
+ f_send_cur_buf = 1;
+ goto tx_curr_single;
+ }
+
+ if (next_pkt_len) {
+ /* More pkt in TX queue */
+ PRINTM(MINFO, "host_2_card_mp_aggr: More packets in Queue.\n");
+
+ if (MP_TX_AGGR_IN_PROGRESS(pmadapter)) {
+ if (!MP_TX_AGGR_PORT_LIMIT_REACHED(pmadapter) &&
+ MP_TX_AGGR_BUF_HAS_ROOM(pmadapter, mbuf, mbuf->data_len)) {
+ f_precopy_cur_buf = 1;
+
+ if (!(pmadapter->mp_wr_bitmap & (1 << pmadapter->curr_wr_port))
+ || !MP_TX_AGGR_BUF_HAS_ROOM(pmadapter, mbuf,
+ mbuf->data_len +
+ next_pkt_len)) {
+ f_send_aggr_buf = 1;
+ }
+ } else {
+ /* No room in Aggr buf, send it */
+ f_send_aggr_buf = 1;
+
+ if (MP_TX_AGGR_PORT_LIMIT_REACHED(pmadapter) ||
+ !(pmadapter->
+ mp_wr_bitmap & (1 << pmadapter->curr_wr_port))) {
+ f_send_cur_buf = 1;
+ } else {
+ f_postcopy_cur_buf = 1;
+ }
+ }
+ } else {
+ if (MP_TX_AGGR_BUF_HAS_ROOM(pmadapter, mbuf, mbuf->data_len) &&
+ (pmadapter->mp_wr_bitmap & (1 << pmadapter->curr_wr_port)))
+ f_precopy_cur_buf = 1;
+ else
+ f_send_cur_buf = 1;
+ }
+ } else {
+ /* Last pkt in TX queue */
+ PRINTM(MINFO, "host_2_card_mp_aggr: Last packet in Tx Queue.\n");
+
+ if (MP_TX_AGGR_IN_PROGRESS(pmadapter)) {
+ /* some packs in Aggr buf already */
+ f_send_aggr_buf = 1;
+
+ if (MP_TX_AGGR_BUF_HAS_ROOM(pmadapter, mbuf, mbuf->data_len)) {
+ f_precopy_cur_buf = 1;
+ } else {
+ /* No room in Aggr buf, send it */
+ f_send_cur_buf = 1;
+ }
+ } else {
+ f_send_cur_buf = 1;
+ }
+ }
+
+ if (f_precopy_cur_buf) {
+ PRINTM(MINFO, "host_2_card_mp_aggr: Precopy current buffer\n");
+ MP_TX_AGGR_BUF_PUT(pmadapter, mbuf, port);
+
+ if (MP_TX_AGGR_PKT_LIMIT_REACHED(pmadapter) ||
+ MP_TX_AGGR_PORT_LIMIT_REACHED(pmadapter)) {
+ PRINTM(MIF_D,
+ "host_2_card_mp_aggr: Aggregation Pkt limit reached\n");
+ /* No more pkts allowed in Aggr buf, send it */
+ f_send_aggr_buf = 1;
+ }
+ }
+
+ if (f_send_aggr_buf) {
+ PRINTM(MINFO, "host_2_card_mp_aggr: Send aggregation buffer."
+ "%d %d\n", pmadapter->mpa_tx.start_port,
+ pmadapter->mpa_tx.ports);
+
+ memset(pmadapter, &mbuf_aggr, 0, sizeof(mlan_buffer));
+
+ mbuf_aggr.pbuf = (t_u8 *) pmadapter->mpa_tx.buf;
+ mbuf_aggr.data_len = pmadapter->mpa_tx.buf_len;
+ cmd53_port = (pmadapter->ioport | SDIO_MPA_ADDR_BASE |
+ (pmadapter->mpa_tx.ports << 4)) +
+ pmadapter->mpa_tx.start_port;
+ ret = wlan_write_data_sync(pmadapter, &mbuf_aggr, cmd53_port);
+ MP_TX_AGGR_BUF_RESET(pmadapter);
+ }
+
+ tx_curr_single:
+ if (f_send_cur_buf) {
+ PRINTM(MINFO, "host_2_card_mp_aggr: writing to port #%d\n", port);
+ ret = wlan_write_data_sync(pmadapter, mbuf, pmadapter->ioport + port);
+ }
+ if (f_postcopy_cur_buf) {
+ PRINTM(MINFO, "host_2_card_mp_aggr: Postcopy current buffer\n");
+ MP_TX_AGGR_BUF_PUT(pmadapter, mbuf, port);
+ }
+
+ LEAVE();
+ return ret;
+}
+#endif /* SDIO_MULTI_PORT_TX_AGGR */
+
+/********************************************************
+ Global functions
+********************************************************/
+
+/**
+ * @brief This function checks if the interface is ready to download
+ * or not while other download interface is present
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param val Winner status (0: winner)
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ *
+ */
+mlan_status
+wlan_check_winner_status(mlan_adapter * pmadapter, t_u32 * val)
+{
+ t_u32 winner = 0;
+ pmlan_callbacks pcb;
+
+ ENTER();
+
+ pcb = &pmadapter->callbacks;
+
+ if (MLAN_STATUS_SUCCESS !=
+ pcb->moal_read_reg(pmadapter->pmoal_handle, CARD_FW_STATUS0_REG,
+ &winner)) {
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+ *val = winner;
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function checks if the firmware is ready to accept
+ * command or not.
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pollnum Maximum polling number
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status
+wlan_check_fw_status(mlan_adapter * pmadapter, t_u32 pollnum)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ t_u16 firmwarestat;
+ t_u32 tries;
+
+ ENTER();
+
+ /* Wait for firmware initialization event */
+ for (tries = 0; tries < pollnum; tries++) {
+ if (MLAN_STATUS_SUCCESS !=
+ (ret = wlan_sdio_read_fw_status(pmadapter, &firmwarestat)))
+ continue;
+ if (firmwarestat == FIRMWARE_READY) {
+ ret = MLAN_STATUS_SUCCESS;
+ break;
+ } else {
+ wlan_mdelay(pmadapter, 100);
+ ret = MLAN_STATUS_FAILURE;
+ }
+ }
+
+ if (ret != MLAN_STATUS_SUCCESS)
+ goto done;
+
+ done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function downloads firmware to card
+ *
+ * @param pmadapter A pointer to mlan_adapter
+ * @param pmfw A pointer to firmware image
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status
+wlan_dnld_fw(IN pmlan_adapter pmadapter, IN pmlan_fw_image pmfw)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ /* Download the firmware image via helper */
+ ret = wlan_prog_fw_w_helper(pmadapter, pmfw);
+ if (ret != MLAN_STATUS_SUCCESS) {
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function probes the driver
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status
+wlan_sdio_probe(pmlan_adapter pmadapter)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ t_u32 sdio_ireg = 0;
+ pmlan_callbacks pcb = &pmadapter->callbacks;
+
+ ENTER();
+ /*
+ * Read the HOST_INT_STATUS_REG for ACK the first interrupt got
+ * from the bootloader. If we don't do this we get a interrupt
+ * as soon as we register the irq.
+ */
+ pcb->moal_read_reg(pmadapter->pmoal_handle, HOST_INT_STATUS_REG,
+ &sdio_ireg);
+
+ /* Disable host interrupt mask register for SDIO */
+ ret = wlan_disable_host_int(pmadapter);
+ if (ret != MLAN_STATUS_SUCCESS) {
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+
+ /* Get SDIO ioport */
+ ret = wlan_sdio_init_ioport(pmadapter);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function gets interrupt status.
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @return N/A
+ */
+t_void
+wlan_interrupt(pmlan_adapter pmadapter)
+{
+ pmlan_callbacks pcb = &pmadapter->callbacks;
+ mlan_buffer mbuf;
+ t_u32 sdio_ireg = 0;
+
+ ENTER();
+
+ memset(pmadapter, &mbuf, 0, sizeof(mlan_buffer));
+ mbuf.pbuf = pmadapter->mp_regs;
+ mbuf.data_len = MAX_MP_REGS;
+
+ if (MLAN_STATUS_SUCCESS !=
+ pcb->moal_read_data_sync(pmadapter->pmoal_handle, &mbuf,
+ REG_PORT | MLAN_SDIO_BYTE_MODE_MASK, 0)) {
+ PRINTM(MERROR, "moal_read_data_sync: read registers failed\n");
+ pmadapter->dbg.num_int_read_failure++;
+ goto done;
+ }
+
+ DBG_HEXDUMP(MIF_D, "SDIO MP Registers", pmadapter->mp_regs, MAX_MP_REGS);
+ sdio_ireg = pmadapter->mp_regs[HOST_INT_STATUS_REG];
+ pmadapter->dbg.last_int_status = pmadapter->sdio_ireg | sdio_ireg;
+ if (sdio_ireg) {
+ /*
+ * DN_LD_HOST_INT_STATUS and/or UP_LD_HOST_INT_STATUS
+ * DN_LD_CMD_PORT_HOST_INT_STATUS and/or
+ * UP_LD_CMD_PORT_HOST_INT_STATUS
+ * Clear the interrupt status register
+ */
+ PRINTM(MINTR, "wlan_interrupt: sdio_ireg = 0x%x\n", sdio_ireg);
+ pcb->moal_spin_lock(pmadapter->pmoal_handle, pmadapter->pint_lock);
+ pmadapter->sdio_ireg |= sdio_ireg;
+ pcb->moal_spin_unlock(pmadapter->pmoal_handle, pmadapter->pint_lock);
+ } else {
+ PRINTM(MMSG, "wlan_interrupt: sdio_ireg = 0x%x\n", sdio_ireg);
+ }
+ done:
+ LEAVE();
+}
+
+/**
+ * @brief This function enables the host interrupts.
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status
+wlan_enable_host_int(pmlan_adapter pmadapter)
+{
+ mlan_status ret;
+
+ ENTER();
+ ret = wlan_sdio_enable_host_int_mask(pmadapter, HIM_ENABLE);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function checks the interrupt status and handle it accordingly.
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status
+wlan_process_int_status(mlan_adapter * pmadapter)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ pmlan_callbacks pcb = &pmadapter->callbacks;
+ t_u8 sdio_ireg;
+ mlan_buffer *pmbuf = MNULL;
+ t_u8 port = 0;
+ t_u32 len_reg_l, len_reg_u;
+ t_u32 rx_blocks;
+ t_u32 ps_state = pmadapter->ps_state;
+ t_u16 rx_len;
+#if !defined(SDIO_MULTI_PORT_RX_AGGR)
+ t_u32 upld_typ = 0;
+#endif
+ t_u32 cr = 0;
+
+ ENTER();
+
+ pcb->moal_spin_lock(pmadapter->pmoal_handle, pmadapter->pint_lock);
+ sdio_ireg = pmadapter->sdio_ireg;
+ pmadapter->sdio_ireg = 0;
+ pcb->moal_spin_unlock(pmadapter->pmoal_handle, pmadapter->pint_lock);
+
+ if (!sdio_ireg)
+ goto done;
+
+ if (sdio_ireg & DN_LD_HOST_INT_STATUS) {
+ pmadapter->mp_wr_bitmap = (t_u32) pmadapter->mp_regs[WR_BITMAP_L];
+ pmadapter->mp_wr_bitmap |=
+ ((t_u32) pmadapter->mp_regs[WR_BITMAP_U]) << 8;
+ PRINTM(MINTR, "DNLD: wr_bitmap=0x%08x\n", pmadapter->mp_wr_bitmap);
+ if (pmadapter->data_sent &&
+ (pmadapter->mp_wr_bitmap & pmadapter->mp_data_port_mask)) {
+ PRINTM(MINFO, " <--- Tx DONE Interrupt --->\n");
+ pmadapter->data_sent = MFALSE;
+ }
+ }
+
+ /* As firmware will not generate download ready interrupt if the port
+ updated is command port only, cmd_sent should be done for any SDIO
+ interrupt. */
+ if (pmadapter->cmd_sent == MTRUE) {
+ /* Check if firmware has attach buffer at command port and update just
+ that in wr_bit_map. */
+ pmadapter->mp_wr_bitmap |=
+ (t_u32) pmadapter->mp_regs[WR_BITMAP_L] & CTRL_PORT_MASK;
+ if (pmadapter->mp_wr_bitmap & CTRL_PORT_MASK)
+ pmadapter->cmd_sent = MFALSE;
+ }
+
+ PRINTM(MINFO, "cmd_sent=%d, data_sent=%d\n", pmadapter->cmd_sent,
+ pmadapter->data_sent);
+
+ if (sdio_ireg & UP_LD_HOST_INT_STATUS) {
+ pmadapter->mp_rd_bitmap = (t_u32) pmadapter->mp_regs[RD_BITMAP_L];
+ pmadapter->mp_rd_bitmap |=
+ ((t_u32) pmadapter->mp_regs[RD_BITMAP_U]) << 8;
+ PRINTM(MINTR, "UPLD: rd_bitmap=0x%08x\n", pmadapter->mp_rd_bitmap);
+
+ while (MTRUE) {
+ ret = wlan_get_rd_port(pmadapter, &port);
+ if (ret != MLAN_STATUS_SUCCESS) {
+ PRINTM(MINFO, "no more rd_port to be handled\n");
+ break;
+ }
+ len_reg_l = RD_LEN_P0_L + (port << 1);
+ len_reg_u = RD_LEN_P0_U + (port << 1);
+ rx_len = ((t_u16) pmadapter->mp_regs[len_reg_u]) << 8;
+ rx_len |= (t_u16) pmadapter->mp_regs[len_reg_l];
+ PRINTM(MINFO, "RX: port=%d rx_len=%u\n", port, rx_len);
+ rx_blocks =
+ (rx_len + MLAN_SDIO_BLOCK_SIZE - 1) / MLAN_SDIO_BLOCK_SIZE;
+ if (rx_len <= INTF_HEADER_LEN ||
+ (rx_blocks * MLAN_SDIO_BLOCK_SIZE) > ALLOC_BUF_SIZE) {
+ PRINTM(MERROR, "invalid rx_len=%d\n", rx_len);
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ rx_len = (t_u16) (rx_blocks * MLAN_SDIO_BLOCK_SIZE);
+ if (port == CTRL_PORT)
+ pmbuf = wlan_alloc_mlan_buffer(pmadapter, rx_len, 0, MTRUE);
+ else
+ pmbuf =
+ wlan_alloc_mlan_buffer(pmadapter, rx_len,
+ MLAN_RX_HEADER_LEN, MFALSE);
+ if (pmbuf == MNULL) {
+ PRINTM(MERROR, "Failed to allocate 'mlan_buffer'\n");
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ PRINTM(MINFO, "rx_len = %d\n", rx_len);
+#ifdef SDIO_MULTI_PORT_RX_AGGR
+ if (MLAN_STATUS_SUCCESS !=
+ wlan_sdio_card_to_host_mp_aggr(pmadapter, pmbuf, port,
+ rx_len)) {
+#else
+ /* Transfer data from card */
+ if (MLAN_STATUS_SUCCESS !=
+ wlan_sdio_card_to_host(pmadapter, &upld_typ,
+ (t_u32 *) & pmadapter->upld_len, pmbuf,
+ rx_len, pmadapter->ioport + port)) {
+#endif /* SDIO_MULTI_PORT_RX_AGGR */
+
+ if (port == CTRL_PORT)
+ pmadapter->dbg.num_cmdevt_card_to_host_failure++;
+ else
+ pmadapter->dbg.num_rx_card_to_host_failure++;
+
+ PRINTM(MERROR, "Card to host failed: int status=0x%x\n",
+ sdio_ireg);
+#ifndef SDIO_MULTI_PORT_RX_AGGR
+ wlan_free_mlan_buffer(pmadapter, pmbuf);
+#endif
+ ret = MLAN_STATUS_FAILURE;
+ goto term_cmd53;
+ }
+#ifndef SDIO_MULTI_PORT_RX_AGGR
+ wlan_decode_rx_packet(pmadapter, pmbuf, upld_typ);
+#endif
+ }
+ /* We might receive data/sleep_cfm at the same time */
+ /* reset data_receive flag to avoid ps_state change */
+ if ((ps_state == PS_STATE_SLEEP_CFM) &&
+ (pmadapter->ps_state == PS_STATE_SLEEP))
+ pmadapter->data_received = MFALSE;
+ }
+
+ ret = MLAN_STATUS_SUCCESS;
+ goto done;
+
+ term_cmd53:
+ /* terminate cmd53 */
+ if (MLAN_STATUS_SUCCESS != pcb->moal_read_reg(pmadapter->pmoal_handle,
+ HOST_TO_CARD_EVENT_REG, &cr))
+ PRINTM(MERROR, "read CFG reg failed\n");
+ PRINTM(MINFO, "Config Reg val = %d\n", cr);
+ if (MLAN_STATUS_SUCCESS != pcb->moal_write_reg(pmadapter->pmoal_handle,
+ HOST_TO_CARD_EVENT_REG,
+ (cr | HOST_TERM_CMD53)))
+ PRINTM(MERROR, "write CFG reg failed\n");
+ PRINTM(MINFO, "write success\n");
+ if (MLAN_STATUS_SUCCESS != pcb->moal_read_reg(pmadapter->pmoal_handle,
+ HOST_TO_CARD_EVENT_REG, &cr))
+ PRINTM(MERROR, "read CFG reg failed\n");
+ PRINTM(MINFO, "Config reg val =%x\n", cr);
+
+ done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function sends data to the card.
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param type data or command
+ * @param pmbuf A pointer to mlan_buffer (pmbuf->data_len should include SDIO header)
+ * @param tx_param A pointer to mlan_tx_param
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status
+wlan_sdio_host_to_card(mlan_adapter * pmadapter, t_u8 type, mlan_buffer * pmbuf,
+ mlan_tx_param * tx_param)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ t_u32 buf_block_len;
+ t_u32 blksz;
+ t_u8 port = 0;
+ t_u32 cmd53_port = 0;
+ t_u8 *payload = pmbuf->pbuf + pmbuf->data_offset;
+
+ ENTER();
+
+ /* Allocate buffer and copy payload */
+ blksz = MLAN_SDIO_BLOCK_SIZE;
+ buf_block_len = (pmbuf->data_len + blksz - 1) / blksz;
+ *(t_u16 *) & payload[0] = wlan_cpu_to_le16((t_u16) pmbuf->data_len);
+ *(t_u16 *) & payload[2] = wlan_cpu_to_le16(type);
+
+ /*
+ * This is SDIO specific header
+ * t_u16 length,
+ * t_u16 type (MLAN_TYPE_DATA = 0, MLAN_TYPE_CMD = 1, MLAN_TYPE_EVENT = 3)
+ */
+ if (type == MLAN_TYPE_DATA) {
+ ret = wlan_get_wr_port_data(pmadapter, &port);
+ if (ret != MLAN_STATUS_SUCCESS) {
+ PRINTM(MERROR, "no wr_port available: %d\n", ret);
+ pmbuf->status_code = MLAN_ERROR_PKT_INVALID;
+ goto exit;
+ }
+ /* Transfer data to card */
+ pmbuf->data_len = buf_block_len * blksz;
+
+#ifdef SDIO_MULTI_PORT_TX_AGGR
+ if (tx_param)
+ ret =
+ wlan_host_to_card_mp_aggr(pmadapter, pmbuf, port,
+ tx_param->next_pkt_len);
+ else
+ ret = wlan_host_to_card_mp_aggr(pmadapter, pmbuf, port, 0);
+#else
+ ret = wlan_write_data_sync(pmadapter, pmbuf, pmadapter->ioport + port);
+#endif /* SDIO_MULTI_PORT_TX_AGGR */
+
+ } else {
+ /* Type must be MLAN_TYPE_CMD */
+ pmadapter->cmd_sent = MTRUE;
+ /* clear CTRL PORT */
+ pmadapter->mp_wr_bitmap &= (t_u32) (~(1 << CTRL_PORT));
+ if (pmbuf->data_len <= INTF_HEADER_LEN ||
+ pmbuf->data_len > WLAN_UPLD_SIZE)
+ PRINTM(MWARN,
+ "wlan_sdio_host_to_card(): Error: payload=%p, nb=%d\n",
+ payload, pmbuf->data_len);
+ /* Transfer data to card */
+ pmbuf->data_len = buf_block_len * blksz;
+ cmd53_port = pmadapter->ioport + CTRL_PORT;
+ ret = wlan_write_data_sync(pmadapter, pmbuf, cmd53_port);
+ }
+
+ if (ret != MLAN_STATUS_SUCCESS) {
+ if (type == MLAN_TYPE_CMD)
+ pmadapter->cmd_sent = MFALSE;
+ if (type == MLAN_TYPE_DATA)
+ pmadapter->data_sent = MFALSE;
+ } else {
+ if (type == MLAN_TYPE_DATA) {
+ if (!(pmadapter->mp_wr_bitmap & (1 << pmadapter->curr_wr_port)))
+ pmadapter->data_sent = MTRUE;
+ else
+ pmadapter->data_sent = MFALSE;
+ }
+ DBG_HEXDUMP(MIF_D, "SDIO Blk Wr", pmbuf->pbuf + pmbuf->data_offset,
+ MIN(pmbuf->data_len, MAX_DATA_DUMP_LEN));
+ }
+ exit:
+ LEAVE();
+ return ret;
+}
+
+#if defined(SDIO_MULTI_PORT_TX_AGGR) || defined(SDIO_MULTI_PORT_RX_AGGR)
+/**
+ * @brief This function allocates buffer for the SDIO aggregation buffer
+ * related members of adapter structure
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param mpa_tx_buf_size Tx buffer size to allocate
+ * @param mpa_rx_buf_size Rx buffer size to allocate
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status
+wlan_alloc_sdio_mpa_buffers(IN mlan_adapter * pmadapter,
+ t_u32 mpa_tx_buf_size, t_u32 mpa_rx_buf_size)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ pmlan_callbacks pcb = &pmadapter->callbacks;
+
+ ENTER();
+
+#ifdef SDIO_MULTI_PORT_TX_AGGR
+ ret =
+ pcb->moal_malloc(pmadapter->pmoal_handle,
+ mpa_tx_buf_size + DMA_ALIGNMENT,
+ MLAN_MEM_DEF | MLAN_MEM_DMA,
+ (t_u8 **) & pmadapter->mpa_tx.head_ptr);
+ if (ret != MLAN_STATUS_SUCCESS || !pmadapter->mpa_tx.head_ptr) {
+ PRINTM(MERROR, "Could not allocate buffer for SDIO MP TX aggr\n");
+ ret = MLAN_STATUS_FAILURE;
+ goto error;
+ }
+ pmadapter->mpa_tx.buf =
+ (t_u8 *) ALIGN_ADDR(pmadapter->mpa_tx.head_ptr, DMA_ALIGNMENT);
+ pmadapter->mpa_tx.buf_size = mpa_tx_buf_size;
+#endif /* SDIO_MULTI_PORT_TX_AGGR */
+
+#ifdef SDIO_MULTI_PORT_RX_AGGR
+ ret =
+ pcb->moal_malloc(pmadapter->pmoal_handle,
+ mpa_rx_buf_size + DMA_ALIGNMENT,
+ MLAN_MEM_DEF | MLAN_MEM_DMA,
+ (t_u8 **) & pmadapter->mpa_rx.head_ptr);
+ if (ret != MLAN_STATUS_SUCCESS || !pmadapter->mpa_rx.head_ptr) {
+ PRINTM(MERROR, "Could not allocate buffer for SDIO MP RX aggr\n");
+ ret = MLAN_STATUS_FAILURE;
+ goto error;
+ }
+ pmadapter->mpa_rx.buf =
+ (t_u8 *) ALIGN_ADDR(pmadapter->mpa_rx.head_ptr, DMA_ALIGNMENT);
+ pmadapter->mpa_rx.buf_size = mpa_rx_buf_size;
+#endif /* SDIO_MULTI_PORT_RX_AGGR */
+ error:
+ if (ret != MLAN_STATUS_SUCCESS) {
+ wlan_free_sdio_mpa_buffers(pmadapter);
+ }
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function frees buffers for the SDIO aggregation
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+mlan_status
+wlan_free_sdio_mpa_buffers(IN mlan_adapter * pmadapter)
+{
+ pmlan_callbacks pcb = &pmadapter->callbacks;
+
+ ENTER();
+
+#ifdef SDIO_MULTI_PORT_TX_AGGR
+ if (pmadapter->mpa_tx.buf) {
+ pcb->moal_mfree(pmadapter->pmoal_handle,
+ (t_u8 *) pmadapter->mpa_tx.head_ptr);
+ pmadapter->mpa_tx.head_ptr = MNULL;
+ pmadapter->mpa_tx.buf = MNULL;
+ pmadapter->mpa_tx.buf_size = 0;
+ }
+#endif /* SDIO_MULTI_PORT_TX_AGGR */
+
+#ifdef SDIO_MULTI_PORT_RX_AGGR
+ if (pmadapter->mpa_rx.buf) {
+ pcb->moal_mfree(pmadapter->pmoal_handle,
+ (t_u8 *) pmadapter->mpa_rx.head_ptr);
+ pmadapter->mpa_rx.head_ptr = MNULL;
+ pmadapter->mpa_rx.buf = MNULL;
+ pmadapter->mpa_rx.buf_size = 0;
+ }
+#endif /* SDIO_MULTI_PORT_RX_AGGR */
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+#endif /* SDIO_MULTI_PORT_TX_AGGR || SDIO_MULTI_PORT_RX_AGGR */
+
+/**
+ * @brief This function issues commands to initialize firmware
+ *
+ * @param priv A pointer to mlan_private structure
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status
+wlan_set_sdio_gpio_int(IN pmlan_private priv)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ pmlan_adapter pmadapter = priv->adapter;
+ HostCmd_DS_SDIO_GPIO_INT_CONFIG sdio_int_cfg;
+
+ ENTER();
+
+ if (pmadapter->int_mode == INT_MODE_GPIO) {
+ PRINTM(MINFO, "SDIO_GPIO_INT_CONFIG: interrupt mode is GPIO\n");
+ sdio_int_cfg.action = HostCmd_ACT_GEN_SET;
+ sdio_int_cfg.gpio_pin = pmadapter->gpio_pin;
+ sdio_int_cfg.gpio_int_edge = INT_FALLING_EDGE;
+ sdio_int_cfg.gpio_pulse_width = DELAY_1_US;
+ ret = wlan_prepare_cmd(priv, HostCmd_CMD_SDIO_GPIO_INT_CONFIG,
+ HostCmd_ACT_GEN_SET, 0, MNULL, &sdio_int_cfg);
+
+ if (ret) {
+ PRINTM(MERROR, "SDIO_GPIO_INT_CONFIG: send command fail\n");
+ ret = MLAN_STATUS_FAILURE;
+ }
+ } else {
+ PRINTM(MINFO, "SDIO_GPIO_INT_CONFIG: interrupt mode is SDIO\n");
+ }
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function prepares command of SDIO GPIO interrupt
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param cmd A pointer to HostCmd_DS_COMMAND structure
+ * @param cmd_action The action: GET or SET
+ * @param pdata_buf A pointer to data buffer
+ * @return MLAN_STATUS_SUCCESS
+ */
+mlan_status
+wlan_cmd_sdio_gpio_int(pmlan_private pmpriv,
+ IN HostCmd_DS_COMMAND * cmd,
+ IN t_u16 cmd_action, IN t_void * pdata_buf)
+{
+ HostCmd_DS_SDIO_GPIO_INT_CONFIG *psdio_gpio_int =
+ &cmd->params.sdio_gpio_int;
+
+ ENTER();
+
+ cmd->command = wlan_cpu_to_le16(HostCmd_CMD_SDIO_GPIO_INT_CONFIG);
+ cmd->size =
+ wlan_cpu_to_le16((sizeof(HostCmd_DS_SDIO_GPIO_INT_CONFIG)) + S_DS_GEN);
+
+ memset(pmpriv->adapter, psdio_gpio_int, 0,
+ sizeof(HostCmd_DS_SDIO_GPIO_INT_CONFIG));
+ if (cmd_action == HostCmd_ACT_GEN_SET) {
+ memcpy(pmpriv->adapter, psdio_gpio_int, pdata_buf,
+ sizeof(HostCmd_DS_SDIO_GPIO_INT_CONFIG));
+ psdio_gpio_int->action = wlan_cpu_to_le16(psdio_gpio_int->action);
+ psdio_gpio_int->gpio_pin = wlan_cpu_to_le16(psdio_gpio_int->gpio_pin);
+ psdio_gpio_int->gpio_int_edge =
+ wlan_cpu_to_le16(psdio_gpio_int->gpio_int_edge);
+ psdio_gpio_int->gpio_pulse_width =
+ wlan_cpu_to_le16(psdio_gpio_int->gpio_pulse_width);
+ }
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
diff --git a/drivers/net/wireless/sd8797/mlan/mlan_sdio.h b/drivers/net/wireless/sd8797/mlan/mlan_sdio.h
new file mode 100644
index 000000000000..f77397d66eb4
--- /dev/null
+++ b/drivers/net/wireless/sd8797/mlan/mlan_sdio.h
@@ -0,0 +1,307 @@
+/** @file mlan_sdio.h
+ *
+ * @brief This file contains definitions for SDIO interface.
+ * driver.
+ *
+ * Copyright (C) 2008-2011, Marvell International Ltd.
+ *
+ * This software file (the "File") is distributed by Marvell International
+ * Ltd. under the terms of the GNU General Public License Version 2, June 1991
+ * (the "License"). You may use, redistribute and/or modify this File in
+ * accordance with the terms and conditions of the License, a copy of which
+ * is available by writing to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
+ * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
+ *
+ * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
+ * ARE EXPRESSLY DISCLAIMED. The License provides additional details about
+ * this warranty disclaimer.
+ *
+ */
+/****************************************************
+Change log:
+****************************************************/
+
+#ifndef _MLAN_SDIO_H
+#define _MLAN_SDIO_H
+
+/** Block mode */
+#define BLOCK_MODE 1
+/** Fixed address mode */
+#define FIXED_ADDRESS 0
+
+/* Host Control Registers */
+/** Host Control Registers : Host to Card Event */
+#define HOST_TO_CARD_EVENT_REG 0x00
+/** Host Control Registers : Host terminates Command 53 */
+#define HOST_TERM_CMD53 (0x1U << 2)
+/** Host Control Registers : Host without Command 53 finish host */
+#define HOST_WO_CMD53_FINISH_HOST (0x1U << 2)
+/** Host Control Registers : Host power up */
+#define HOST_POWER_UP (0x1U << 1)
+/** Host Control Registers : Host power down */
+#define HOST_POWER_DOWN (0x1U << 0)
+
+/** Host Control Registers : Host interrupt RSR */
+#define HOST_INT_RSR_REG 0x01
+/** Host Control Registers : Upload host interrupt RSR */
+#define UP_LD_HOST_INT_RSR (0x1U)
+#define HOST_INT_RSR_MASK 0x3F
+
+/** Host Control Registers : Host interrupt mask */
+#define HOST_INT_MASK_REG 0x02
+/** Host Control Registers : Upload host interrupt mask */
+#define UP_LD_HOST_INT_MASK (0x1U)
+/** Host Control Registers : Download host interrupt mask */
+#define DN_LD_HOST_INT_MASK (0x2U)
+/** Enable Host interrupt mask */
+#define HIM_ENABLE (UP_LD_HOST_INT_MASK | DN_LD_HOST_INT_MASK)
+/** Disable Host interrupt mask */
+#define HIM_DISABLE 0xff
+
+/** Host Control Registers : Host interrupt status */
+#define HOST_INT_STATUS_REG 0x03
+/** Host Control Registers : Upload host interrupt status */
+#define UP_LD_HOST_INT_STATUS (0x1U)
+/** Host Control Registers : Download host interrupt status */
+#define DN_LD_HOST_INT_STATUS (0x2U)
+
+/** Port for registers */
+#define REG_PORT 0
+/** LSB of read bitmap */
+#define RD_BITMAP_L 0x04
+/** MSB of read bitmap */
+#define RD_BITMAP_U 0x05
+/** LSB of write bitmap */
+#define WR_BITMAP_L 0x06
+/** MSB of write bitmap */
+#define WR_BITMAP_U 0x07
+/** LSB of read length for port 0 */
+#define RD_LEN_P0_L 0x08
+/** MSB of read length for port 0 */
+#define RD_LEN_P0_U 0x09
+/** Ctrl port */
+#define CTRL_PORT 0
+/** Ctrl port mask */
+#define CTRL_PORT_MASK 0x0001
+/** Data port mask */
+#define DATA_PORT_MASK 0xfffe
+/** Misc. Config Register : Auto Re-enable interrupts */
+#define AUTO_RE_ENABLE_INT MBIT(4)
+
+/** Host Control Registers : Host transfer status */
+#define HOST_RESTART_REG 0x28
+/** Host Control Registers : Download CRC error */
+#define DN_LD_CRC_ERR (0x1U << 2)
+/** Host Control Registers : Upload restart */
+#define UP_LD_RESTART (0x1U << 1)
+/** Host Control Registers : Download restart */
+#define DN_LD_RESTART (0x1U << 0)
+
+/* Card Control Registers */
+/** Card Control Registers : Card to host event */
+#define CARD_TO_HOST_EVENT_REG 0x30
+/** Card Control Registers : Card I/O ready */
+#define CARD_IO_READY (0x1U << 3)
+/** Card Control Registers : CIS card ready */
+#define CIS_CARD_RDY (0x1U << 2)
+/** Card Control Registers : Upload card ready */
+#define UP_LD_CARD_RDY (0x1U << 1)
+/** Card Control Registers : Download card ready */
+#define DN_LD_CARD_RDY (0x1U << 0)
+
+/** Card Control Registers : Host interrupt mask register */
+#define HOST_INTERRUPT_MASK_REG 0x34
+/** Card Control Registers : Host power interrupt mask */
+#define HOST_POWER_INT_MASK (0x1U << 3)
+/** Card Control Registers : Abort card interrupt mask */
+#define ABORT_CARD_INT_MASK (0x1U << 2)
+/** Card Control Registers : Upload card interrupt mask */
+#define UP_LD_CARD_INT_MASK (0x1U << 1)
+/** Card Control Registers : Download card interrupt mask */
+#define DN_LD_CARD_INT_MASK (0x1U << 0)
+
+/** Card Control Registers : Card interrupt status register */
+#define CARD_INTERRUPT_STATUS_REG 0x38
+/** Card Control Registers : Power up interrupt */
+#define POWER_UP_INT (0x1U << 4)
+/** Card Control Registers : Power down interrupt */
+#define POWER_DOWN_INT (0x1U << 3)
+
+/** Card Control Registers : Card interrupt RSR register */
+#define CARD_INTERRUPT_RSR_REG 0x3c
+/** Card Control Registers : Power up RSR */
+#define POWER_UP_RSR (0x1U << 4)
+/** Card Control Registers : Power down RSR */
+#define POWER_DOWN_RSR (0x1U << 3)
+
+/** Card Control Registers : SQ Read base address 0 register */
+#define READ_BASE_0_REG 0x40
+/** Card Control Registers : SQ Read base address 1 register */
+#define READ_BASE_1_REG 0x41
+
+/** Card Control Registers : Card revision register */
+#define CARD_REVISION_REG 0x5c
+
+/** Firmware status 0 register (SCRATCH0_0) */
+#define CARD_FW_STATUS0_REG 0x60
+/** Firmware status 1 register (SCRATCH0_1) */
+#define CARD_FW_STATUS1_REG 0x61
+/** Rx length register (SCRATCH0_2) */
+#define CARD_RX_LEN_REG 0x62
+/** Rx unit register (SCRATCH0_3) */
+#define CARD_RX_UNIT_REG 0x63
+
+/** Card Control Registers : Card OCR 0 register */
+#define CARD_OCR_0_REG 0x68
+/** Card Control Registers : Card OCR 1 register */
+#define CARD_OCR_1_REG 0x69
+/** Card Control Registers : Card OCR 3 register */
+#define CARD_OCR_3_REG 0x6A
+/** Card Control Registers : Card config register */
+#define CARD_CONFIG_REG 0x6B
+/** Card Control Registers : Miscellaneous Configuration Register */
+#define CARD_MISC_CFG_REG 0x6C
+
+/** Card Control Registers : Debug 0 register */
+#define DEBUG_0_REG 0x70
+/** Card Control Registers : SD test BUS 0 */
+#define SD_TESTBUS0 (0x1U)
+/** Card Control Registers : Debug 1 register */
+#define DEBUG_1_REG 0x71
+/** Card Control Registers : SD test BUS 1 */
+#define SD_TESTBUS1 (0x1U)
+/** Card Control Registers : Debug 2 register */
+#define DEBUG_2_REG 0x72
+/** Card Control Registers : SD test BUS 2 */
+#define SD_TESTBUS2 (0x1U)
+/** Card Control Registers : Debug 3 register */
+#define DEBUG_3_REG 0x73
+/** Card Control Registers : SD test BUS 3 */
+#define SD_TESTBUS3 (0x1U)
+
+/** Host Control Registers : I/O port 0 */
+#define IO_PORT_0_REG 0x78
+/** Host Control Registers : I/O port 1 */
+#define IO_PORT_1_REG 0x79
+/** Host Control Registers : I/O port 2 */
+#define IO_PORT_2_REG 0x7A
+
+/** Event header Len*/
+#define MLAN_EVENT_HEADER_LEN 8
+
+/** SDIO byte mode size */
+#define MAX_BYTE_MODE_SIZE 512
+
+#if defined(SDIO_MULTI_PORT_TX_AGGR) || defined(SDIO_MULTI_PORT_RX_AGGR)
+/** The base address for packet with multiple ports aggregation */
+#define SDIO_MPA_ADDR_BASE 0x1000
+#endif
+
+#ifdef SDIO_MULTI_PORT_TX_AGGR
+
+/** SDIO Tx aggregation in progress ? */
+#define MP_TX_AGGR_IN_PROGRESS(a) (a->mpa_tx.pkt_cnt>0)
+
+/** SDIO Tx aggregation buffer room for next packet ? */
+#define MP_TX_AGGR_BUF_HAS_ROOM(a,mbuf, len) ((a->mpa_tx.buf_len+len)<= a->mpa_tx.buf_size)
+
+/** Copy current packet (SDIO Tx aggregation buffer) to SDIO buffer */
+#define MP_TX_AGGR_BUF_PUT(a, mbuf, port) do{ \
+ pmadapter->callbacks.moal_memmove(a->pmoal_handle, &a->mpa_tx.buf[a->mpa_tx.buf_len],mbuf->pbuf+mbuf->data_offset,mbuf->data_len);\
+ a->mpa_tx.buf_len += mbuf->data_len; \
+ if(!a->mpa_tx.pkt_cnt){ \
+ a->mpa_tx.start_port = port; \
+ } \
+ if(a->mpa_tx.start_port<=port){ \
+ a->mpa_tx.ports |= (1<<(a->mpa_tx.pkt_cnt)); \
+ }else{ \
+ a->mpa_tx.ports |= (1<<(a->mpa_tx.pkt_cnt+1+(MAX_PORT - a->mp_end_port))); \
+ } \
+ a->mpa_tx.pkt_cnt++; \
+}while(0);
+
+/** SDIO Tx aggregation limit ? */
+#define MP_TX_AGGR_PKT_LIMIT_REACHED(a) (a->mpa_tx.pkt_cnt==a->mpa_tx.pkt_aggr_limit)
+
+/** SDIO Tx aggregation port limit ? */
+#define MP_TX_AGGR_PORT_LIMIT_REACHED(a) ((a->curr_wr_port < \
+ a->mpa_tx.start_port) && (((MAX_PORT - \
+ a->mpa_tx.start_port) + a->curr_wr_port) >= \
+ SDIO_MP_AGGR_DEF_PKT_LIMIT))
+
+/** Reset SDIO Tx aggregation buffer parameters */
+#define MP_TX_AGGR_BUF_RESET(a) do{ \
+ a->mpa_tx.pkt_cnt = 0; \
+ a->mpa_tx.buf_len = 0; \
+ a->mpa_tx.ports = 0; \
+ a->mpa_tx.start_port = 0; \
+} while(0);
+
+#endif /* SDIO_MULTI_PORT_TX_AGGR */
+
+#ifdef SDIO_MULTI_PORT_RX_AGGR
+
+/** SDIO Rx aggregation limit ? */
+#define MP_RX_AGGR_PKT_LIMIT_REACHED(a) (a->mpa_rx.pkt_cnt== a->mpa_rx.pkt_aggr_limit)
+
+/** SDIO Rx aggregation port limit ? */
+#define MP_RX_AGGR_PORT_LIMIT_REACHED(a) ((a->curr_rd_port < \
+ a->mpa_rx.start_port) && (((MAX_PORT - \
+ a->mpa_rx.start_port) + a->curr_rd_port) >= \
+ SDIO_MP_AGGR_DEF_PKT_LIMIT))
+
+/** SDIO Rx aggregation in progress ? */
+#define MP_RX_AGGR_IN_PROGRESS(a) (a->mpa_rx.pkt_cnt>0)
+
+/** SDIO Rx aggregation buffer room for next packet ? */
+#define MP_RX_AGGR_BUF_HAS_ROOM(a,rx_len) ((a->mpa_rx.buf_len+rx_len)<=a->mpa_rx.buf_size)
+
+/** Prepare to copy current packet from card to SDIO Rx aggregation buffer */
+#define MP_RX_AGGR_SETUP(a, mbuf, port, rx_len) do{ \
+ a->mpa_rx.buf_len += rx_len; \
+ if(!a->mpa_rx.pkt_cnt){ \
+ a->mpa_rx.start_port = port; \
+ } \
+ if(a->mpa_rx.start_port<=port){ \
+ a->mpa_rx.ports |= (1<<(a->mpa_rx.pkt_cnt)); \
+ }else{ \
+ a->mpa_rx.ports |= (1<<(a->mpa_rx.pkt_cnt+1)); \
+ } \
+ a->mpa_rx.mbuf_arr[a->mpa_rx.pkt_cnt] = mbuf; \
+ a->mpa_rx.len_arr[a->mpa_rx.pkt_cnt] = rx_len; \
+ a->mpa_rx.pkt_cnt++; \
+}while(0);
+
+/** Reset SDIO Rx aggregation buffer parameters */
+#define MP_RX_AGGR_BUF_RESET(a) do{ \
+ a->mpa_rx.pkt_cnt = 0; \
+ a->mpa_rx.buf_len = 0; \
+ a->mpa_rx.ports = 0; \
+ a->mpa_rx.start_port = 0; \
+} while(0);
+
+#endif /* SDIO_MULTI_PORT_RX_AGGR */
+
+/** Enable host interrupt */
+mlan_status wlan_enable_host_int(pmlan_adapter pmadapter);
+/** Probe and initialization function */
+mlan_status wlan_sdio_probe(pmlan_adapter pmadapter);
+/** multi interface download check */
+mlan_status wlan_check_winner_status(mlan_adapter * pmadapter, t_u32 * val);
+/** Firmware status check */
+mlan_status wlan_check_fw_status(mlan_adapter * pmadapter, t_u32 pollnum);
+/** Read interrupt status */
+t_void wlan_interrupt(pmlan_adapter pmadapter);
+/** Process Interrupt Status */
+mlan_status wlan_process_int_status(mlan_adapter * pmadapter);
+/** Transfer data to card */
+mlan_status wlan_sdio_host_to_card(mlan_adapter * pmadapter, t_u8 type,
+ mlan_buffer * mbuf,
+ mlan_tx_param * tx_param);
+mlan_status wlan_set_sdio_gpio_int(IN pmlan_private priv);
+mlan_status wlan_cmd_sdio_gpio_int(pmlan_private pmpriv,
+ IN HostCmd_DS_COMMAND * cmd,
+ IN t_u16 cmd_action, IN t_void * pdata_buf);
+#endif /* _MLAN_SDIO_H */
diff --git a/drivers/net/wireless/sd8797/mlan/mlan_shim.c b/drivers/net/wireless/sd8797/mlan/mlan_shim.c
new file mode 100644
index 000000000000..c17b8e21c482
--- /dev/null
+++ b/drivers/net/wireless/sd8797/mlan/mlan_shim.c
@@ -0,0 +1,939 @@
+/** @file mlan_shim.c
+ *
+ * @brief This file contains APIs to MOAL module.
+ *
+ * Copyright (C) 2008-2011, Marvell International Ltd.
+ *
+ * This software file (the "File") is distributed by Marvell International
+ * Ltd. under the terms of the GNU General Public License Version 2, June 1991
+ * (the "License"). You may use, redistribute and/or modify this File in
+ * accordance with the terms and conditions of the License, a copy of which
+ * is available by writing to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
+ * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
+ *
+ * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
+ * ARE EXPRESSLY DISCLAIMED. The License provides additional details about
+ * this warranty disclaimer.
+ */
+
+/********************************************************
+Change log:
+ 10/13/2008: initial version
+********************************************************/
+
+#include "mlan.h"
+#ifdef STA_SUPPORT
+#include "mlan_join.h"
+#endif
+#include "mlan_util.h"
+#include "mlan_fw.h"
+#include "mlan_main.h"
+#include "mlan_wmm.h"
+#include "mlan_sdio.h"
+#ifdef UAP_SUPPORT
+#include "mlan_uap.h"
+#endif
+#include "mlan_11h.h"
+
+/********************************************************
+ Local Variables
+********************************************************/
+
+/********************************************************
+ Global Variables
+********************************************************/
+#ifdef STA_SUPPORT
+mlan_operations mlan_sta_ops = {
+ /* init cmd handler */
+ wlan_ops_sta_init_cmd,
+ /* ioctl handler */
+ wlan_ops_sta_ioctl,
+ /* cmd handler */
+ wlan_ops_sta_prepare_cmd,
+ /* cmdresp handler */
+ wlan_ops_sta_process_cmdresp,
+ /* rx handler */
+ wlan_ops_sta_process_rx_packet,
+ /* Event handler */
+ wlan_ops_sta_process_event,
+ /* txpd handler */
+ wlan_ops_sta_process_txpd,
+ /* BSS role: STA */
+ MLAN_BSS_ROLE_STA,
+};
+#endif
+#ifdef UAP_SUPPORT
+mlan_operations mlan_uap_ops = {
+ /* init cmd handler */
+ wlan_ops_uap_init_cmd,
+ /* ioctl handler */
+ wlan_ops_uap_ioctl,
+ /* cmd handler */
+ wlan_ops_uap_prepare_cmd,
+ /* cmdresp handler */
+ wlan_ops_uap_process_cmdresp,
+ /* rx handler */
+ wlan_ops_uap_process_rx_packet,
+ /* Event handler */
+ wlan_ops_uap_process_event,
+ /* txpd handler */
+ wlan_ops_uap_process_txpd,
+ /* BSS role: uAP */
+ MLAN_BSS_ROLE_UAP,
+};
+#endif
+
+/** mlan function table */
+mlan_operations *mlan_ops[] = {
+#ifdef STA_SUPPORT
+ &mlan_sta_ops,
+#endif
+#ifdef UAP_SUPPORT
+ &mlan_uap_ops,
+#endif
+ MNULL,
+};
+
+/** Global moal_assert callback */
+t_void(*assert_callback) (IN t_void * pmoal_handle, IN t_u32 cond) = MNULL;
+#ifdef DEBUG_LEVEL1
+#ifdef DEBUG_LEVEL2
+#define DEFAULT_DEBUG_MASK (0xffffffff)
+#else
+#define DEFAULT_DEBUG_MASK (MMSG | MFATAL | MERROR)
+#endif
+
+/** Global moal_print callback */
+t_void(*print_callback) (IN t_void * pmoal_handle,
+ IN t_u32 level, IN t_s8 * pformat, IN ...) = MNULL;
+/** Global driver debug mit masks */
+t_u32 drvdbg = DEFAULT_DEBUG_MASK;
+#endif
+
+/********************************************************
+ Local Functions
+*******************************************************/
+
+/********************************************************
+ Global Functions
+********************************************************/
+
+/**
+ * @brief This function registers MOAL to MLAN module.
+ *
+ * @param pmdevice A pointer to a mlan_device structure
+ * allocated in MOAL
+ * @param ppmlan_adapter A pointer to a t_void pointer to store
+ * mlan_adapter structure pointer as the context
+ *
+ * @return MLAN_STATUS_SUCCESS
+ * The registration succeeded.
+ * MLAN_STATUS_FAILURE
+ * The registration failed.
+ *
+ * mlan_status mlan_register (
+ * IN pmlan_device pmdevice,
+ * OUT t_void **ppmlan_adapter
+ * );
+ *
+ * Comments
+ * MOAL constructs mlan_device data structure to pass moal_handle and
+ * mlan_callback table to MLAN. MLAN returns mlan_adapter pointer to
+ * the ppmlan_adapter buffer provided by MOAL.
+ * Headers:
+ * declared in mlan_decl.h
+ * See Also
+ * mlan_unregister
+ */
+mlan_status
+mlan_register(IN pmlan_device pmdevice, OUT t_void ** ppmlan_adapter)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ pmlan_adapter pmadapter = MNULL;
+ pmlan_callbacks pcb = MNULL;
+ t_u8 i = 0;
+ t_u32 j = 0;
+
+ MASSERT(pmdevice);
+ MASSERT(ppmlan_adapter);
+ MASSERT(pmdevice->callbacks.moal_print);
+#ifdef DEBUG_LEVEL1
+ print_callback = pmdevice->callbacks.moal_print;
+#endif
+ assert_callback = pmdevice->callbacks.moal_assert;
+
+ ENTER();
+
+ MASSERT(pmdevice->callbacks.moal_malloc);
+ MASSERT(pmdevice->callbacks.moal_memset);
+ MASSERT(pmdevice->callbacks.moal_memmove);
+
+ /* Allocate memory for adapter structure */
+ if ((pmdevice->callbacks.
+ moal_malloc(pmdevice->pmoal_handle, sizeof(mlan_adapter), MLAN_MEM_DEF,
+ (t_u8 **) & pmadapter) != MLAN_STATUS_SUCCESS)
+ || !pmadapter) {
+ ret = MLAN_STATUS_FAILURE;
+ goto exit_register;
+ }
+
+ pmdevice->callbacks.moal_memset(pmadapter, pmadapter,
+ 0, sizeof(mlan_adapter));
+
+ pcb = &pmadapter->callbacks;
+
+ /* Save callback functions */
+ pmdevice->callbacks.moal_memmove(pmadapter->pmoal_handle, pcb,
+ &pmdevice->callbacks,
+ sizeof(mlan_callbacks));
+
+ /* Assertion for all callback functions */
+ MASSERT(pcb->moal_init_fw_complete);
+ MASSERT(pcb->moal_shutdown_fw_complete);
+ MASSERT(pcb->moal_send_packet_complete);
+ MASSERT(pcb->moal_recv_packet);
+ MASSERT(pcb->moal_recv_event);
+ MASSERT(pcb->moal_ioctl_complete);
+ MASSERT(pcb->moal_write_reg);
+ MASSERT(pcb->moal_read_reg);
+ MASSERT(pcb->moal_alloc_mlan_buffer);
+ MASSERT(pcb->moal_free_mlan_buffer);
+ MASSERT(pcb->moal_write_data_sync);
+ MASSERT(pcb->moal_read_data_sync);
+ MASSERT(pcb->moal_mfree);
+ MASSERT(pcb->moal_memcpy);
+ MASSERT(pcb->moal_memcmp);
+ MASSERT(pcb->moal_get_system_time);
+ MASSERT(pcb->moal_init_timer);
+ MASSERT(pcb->moal_free_timer);
+ MASSERT(pcb->moal_start_timer);
+ MASSERT(pcb->moal_stop_timer);
+ MASSERT(pcb->moal_init_lock);
+ MASSERT(pcb->moal_free_lock);
+ MASSERT(pcb->moal_spin_lock);
+ MASSERT(pcb->moal_spin_unlock);
+
+ /* Save pmoal_handle */
+ pmadapter->pmoal_handle = pmdevice->pmoal_handle;
+
+ if ((pmdevice->int_mode == INT_MODE_GPIO) && (pmdevice->gpio_pin == 0)) {
+ PRINTM(MERROR, "SDIO_GPIO_INT_CONFIG: Invalid GPIO Pin\n");
+ ret = MLAN_STATUS_FAILURE;
+ goto error;
+ }
+ pmadapter->init_para.int_mode = pmdevice->int_mode;
+ pmadapter->init_para.gpio_pin = pmdevice->gpio_pin;
+ /* card specific probing has been deferred until now .. */
+ if (MLAN_STATUS_SUCCESS != (ret = wlan_sdio_probe(pmadapter))) {
+ ret = MLAN_STATUS_FAILURE;
+ goto error;
+ }
+#ifdef DEBUG_LEVEL1
+ drvdbg = pmdevice->drvdbg;
+#endif
+
+#ifdef MFG_CMD_SUPPORT
+ pmadapter->init_para.mfg_mode = pmdevice->mfg_mode;
+#endif
+#ifdef SDIO_MULTI_PORT_TX_AGGR
+ pmadapter->init_para.mpa_tx_cfg = pmdevice->mpa_tx_cfg;
+#endif
+#ifdef SDIO_MULTI_PORT_RX_AGGR
+ pmadapter->init_para.mpa_rx_cfg = pmdevice->mpa_rx_cfg;
+#endif
+ pmadapter->init_para.auto_ds = pmdevice->auto_ds;
+ pmadapter->init_para.ps_mode = pmdevice->ps_mode;
+ if (pmdevice->max_tx_buf == MLAN_TX_DATA_BUF_SIZE_2K ||
+ pmdevice->max_tx_buf == MLAN_TX_DATA_BUF_SIZE_4K ||
+ pmdevice->max_tx_buf == MLAN_TX_DATA_BUF_SIZE_8K)
+ pmadapter->init_para.max_tx_buf = pmdevice->max_tx_buf;
+#ifdef STA_SUPPORT
+ pmadapter->init_para.cfg_11d = pmdevice->cfg_11d;
+#else
+ pmadapter->init_para.cfg_11d = 0;
+#endif
+ pmadapter->init_para.dfs_master_radar_det_en = DFS_MASTER_RADAR_DETECT_EN;
+ pmadapter->init_para.dfs_slave_radar_det_en = DFS_SLAVE_RADAR_DETECT_EN;
+
+ pmadapter->priv_num = 0;
+ for (i = 0; i < MLAN_MAX_BSS_NUM; i++) {
+ pmadapter->priv[i] = MNULL;
+ if (pmdevice->bss_attr[i].active == MTRUE) {
+ /* For valid bss_attr, allocate memory for private structure */
+ if ((pcb->
+ moal_malloc(pmadapter->pmoal_handle, sizeof(mlan_private),
+ MLAN_MEM_DEF,
+ (t_u8 **) & pmadapter->priv[i]) !=
+ MLAN_STATUS_SUCCESS)
+ || !pmadapter->priv[i]) {
+ ret = MLAN_STATUS_FAILURE;
+ goto error;
+ }
+
+ pmadapter->priv_num++;
+ memset(pmadapter, pmadapter->priv[i], 0, sizeof(mlan_private));
+
+ pmadapter->priv[i]->adapter = pmadapter;
+
+ /* Save bss_type, frame_type & bss_priority */
+ pmadapter->priv[i]->bss_type =
+ (t_u8) pmdevice->bss_attr[i].bss_type;
+ pmadapter->priv[i]->frame_type =
+ (t_u8) pmdevice->bss_attr[i].frame_type;
+ pmadapter->priv[i]->bss_priority =
+ (t_u8) pmdevice->bss_attr[i].bss_priority;
+ if (pmdevice->bss_attr[i].bss_type == MLAN_BSS_TYPE_STA)
+ pmadapter->priv[i]->bss_role = MLAN_BSS_ROLE_STA;
+ else if (pmdevice->bss_attr[i].bss_type == MLAN_BSS_TYPE_UAP)
+ pmadapter->priv[i]->bss_role = MLAN_BSS_ROLE_UAP;
+#ifdef WIFI_DIRECT_SUPPORT
+ else if (pmdevice->bss_attr[i].bss_type == MLAN_BSS_TYPE_WIFIDIRECT)
+ pmadapter->priv[i]->bss_role = MLAN_BSS_ROLE_STA;
+#endif
+ /* Save bss_index and bss_num */
+ pmadapter->priv[i]->bss_index = i;
+ pmadapter->priv[i]->bss_num = (t_u8) pmdevice->bss_attr[i].bss_num;
+
+ /* init function table */
+ for (j = 0; mlan_ops[j]; j++) {
+ if (mlan_ops[j]->bss_role == GET_BSS_ROLE(pmadapter->priv[i])) {
+ memcpy(pmadapter, &pmadapter->priv[i]->ops, mlan_ops[j],
+ sizeof(mlan_operations));
+ }
+ }
+ }
+ }
+
+ /* Initialize lock variables */
+ if (wlan_init_lock_list(pmadapter) != MLAN_STATUS_SUCCESS) {
+ ret = MLAN_STATUS_FAILURE;
+ goto error;
+ }
+
+ /* Allocate memory for member of adapter structure */
+ if (wlan_allocate_adapter(pmadapter)) {
+ ret = MLAN_STATUS_FAILURE;
+ goto error;
+ }
+
+ /* Initialize timers */
+ if (wlan_init_timer(pmadapter) != MLAN_STATUS_SUCCESS) {
+ ret = MLAN_STATUS_FAILURE;
+ goto error;
+ }
+ /* Return pointer of mlan_adapter to MOAL */
+ *ppmlan_adapter = pmadapter;
+
+ goto exit_register;
+
+ error:
+ PRINTM(MINFO, "Leave mlan_register with error\n");
+ /* Free timers */
+ wlan_free_timer(pmadapter);
+ /* Free adapter structure */
+ wlan_free_adapter(pmadapter);
+ /* Free lock variables */
+ wlan_free_lock_list(pmadapter);
+ for (i = 0; i < MLAN_MAX_BSS_NUM; i++) {
+ if (pmadapter->priv[i])
+ pcb->moal_mfree(pmadapter->pmoal_handle,
+ (t_u8 *) pmadapter->priv[i]);
+ }
+ pcb->moal_mfree(pmadapter->pmoal_handle, (t_u8 *) pmadapter);
+
+ exit_register:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function unregisters MOAL from MLAN module.
+ *
+ * @param pmlan_adapter A pointer to a mlan_device structure
+ * allocated in MOAL
+ *
+ * @return MLAN_STATUS_SUCCESS
+ * The deregistration succeeded.
+ */
+mlan_status
+mlan_unregister(IN t_void * pmlan_adapter)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_adapter *pmadapter = (mlan_adapter *) pmlan_adapter;
+ pmlan_callbacks pcb;
+ t_s32 i = 0;
+
+ MASSERT(pmlan_adapter);
+
+ ENTER();
+
+ pcb = &pmadapter->callbacks;
+
+ /* Free adapter structure */
+ wlan_free_adapter(pmadapter);
+
+ /* Free timers */
+ wlan_free_timer(pmadapter);
+
+ /* Free lock variables */
+ wlan_free_lock_list(pmadapter);
+
+ /* Free private structures */
+ for (i = 0; i < pmadapter->priv_num; i++) {
+ if (pmadapter->priv[i]) {
+ pcb->moal_mfree(pmadapter->pmoal_handle,
+ (t_u8 *) pmadapter->priv[i]);
+ }
+ }
+
+ /* Free mlan_adapter */
+ pcb->moal_mfree(pmadapter->pmoal_handle, (t_u8 *) pmadapter);
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function downloads the firmware
+ *
+ * @param pmlan_adapter A pointer to a t_void pointer to store
+ * mlan_adapter structure pointer
+ * @param pmfw A pointer to firmware image
+ *
+ * @return MLAN_STATUS_SUCCESS
+ * The firmware download succeeded.
+ * MLAN_STATUS_FAILURE
+ * The firmware download failed.
+ */
+mlan_status
+mlan_dnld_fw(IN t_void * pmlan_adapter, IN pmlan_fw_image pmfw)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_adapter *pmadapter = (mlan_adapter *) pmlan_adapter;
+ t_u32 poll_num = 1;
+ t_u32 winner = 0;
+
+ ENTER();
+ MASSERT(pmlan_adapter);
+
+ /* Card specific probing */
+ ret = wlan_sdio_probe(pmadapter);
+ if (ret == MLAN_STATUS_FAILURE) {
+ PRINTM(MERROR, "WLAN SDIO probe failed\n", ret);
+ LEAVE();
+ return ret;
+ }
+
+ /* Check if firmware is already running */
+ ret = wlan_check_fw_status(pmadapter, poll_num);
+ if (ret == MLAN_STATUS_SUCCESS) {
+ PRINTM(MMSG, "WLAN FW already running! Skip FW download\n");
+ goto done;
+ }
+ poll_num = MAX_FIRMWARE_POLL_TRIES;
+
+ /* Check if other interface is downloading */
+ ret = wlan_check_winner_status(pmadapter, &winner);
+ if (ret == MLAN_STATUS_FAILURE) {
+ PRINTM(MFATAL, "WLAN read winner status failed!\n");
+ goto done;
+ }
+ if (winner) {
+ PRINTM(MMSG, "WLAN is not the winner (0x%x). Skip FW download\n",
+ winner);
+ poll_num = MAX_MULTI_INTERFACE_POLL_TRIES;
+ goto poll_fw;
+ }
+
+ if (pmfw) {
+ /* Download helper/firmware */
+ ret = wlan_dnld_fw(pmadapter, pmfw);
+ if (ret != MLAN_STATUS_SUCCESS) {
+ PRINTM(MERROR, "wlan_dnld_fw fail ret=0x%x\n", ret);
+ LEAVE();
+ return ret;
+ }
+ }
+
+ poll_fw:
+ /* Check if the firmware is downloaded successfully or not */
+ ret = wlan_check_fw_status(pmadapter, poll_num);
+ if (ret != MLAN_STATUS_SUCCESS) {
+ PRINTM(MFATAL, "FW failed to be active in time!\n");
+ ret = MLAN_STATUS_FAILURE;
+ LEAVE();
+ return ret;
+ }
+ done:
+
+ /* re-enable host interrupt for mlan after fw dnld is successful */
+ wlan_enable_host_int(pmadapter);
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function pass init param to MLAN
+ *
+ * @param pmlan_adapter A pointer to a t_void pointer to store
+ * mlan_adapter structure pointer
+ * @param pparam A pointer to mlan_init_param structure
+ *
+ * @return MLAN_STATUS_SUCCESS
+ *
+ */
+mlan_status
+mlan_set_init_param(IN t_void * pmlan_adapter, IN pmlan_init_param pparam)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_adapter *pmadapter = (mlan_adapter *) pmlan_adapter;
+
+ ENTER();
+ MASSERT(pmlan_adapter);
+
+ /** Save cal data in MLAN */
+ if ((pparam->pcal_data_buf) && (pparam->cal_data_len > 0)) {
+ pmadapter->pcal_data = pparam->pcal_data_buf;
+ pmadapter->cal_data_len = pparam->cal_data_len;
+ }
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function initializes the firmware
+ *
+ * @param pmlan_adapter A pointer to a t_void pointer to store
+ * mlan_adapter structure pointer
+ *
+ * @return MLAN_STATUS_SUCCESS
+ * The firmware initialization succeeded.
+ * MLAN_STATUS_PENDING
+ * The firmware initialization is pending.
+ * MLAN_STATUS_FAILURE
+ * The firmware initialization failed.
+ */
+mlan_status
+mlan_init_fw(IN t_void * pmlan_adapter)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_adapter *pmadapter = (mlan_adapter *) pmlan_adapter;
+
+ ENTER();
+ MASSERT(pmlan_adapter);
+
+ pmadapter->hw_status = WlanHardwareStatusInitializing;
+
+ /* Initialize firmware, may return PENDING */
+ ret = wlan_init_fw(pmadapter);
+ PRINTM(MINFO, "wlan_init_fw returned ret=0x%x\n", ret);
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Shutdown firmware
+ *
+ * @param pmlan_adapter A pointer to mlan_adapter structure
+ *
+ * @return MLAN_STATUS_SUCCESS
+ * The firmware shutdown call succeeded.
+ * MLAN_STATUS_PENDING
+ * The firmware shutdown call is pending.
+ * MLAN_STATUS_FAILURE
+ * The firmware shutdown call failed.
+ */
+mlan_status
+mlan_shutdown_fw(IN t_void * pmlan_adapter)
+{
+ mlan_status ret = MLAN_STATUS_PENDING;
+ mlan_adapter *pmadapter = (mlan_adapter *) pmlan_adapter;
+ pmlan_callbacks pcb;
+ t_s32 i = 0;
+
+ ENTER();
+ MASSERT(pmlan_adapter);
+ /* mlan already shutdown */
+ if (pmadapter->hw_status == WlanHardwareStatusNotReady) {
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+ }
+
+ pmadapter->hw_status = WlanHardwareStatusClosing;
+ /* wait for mlan_process to complete */
+ if (pmadapter->mlan_processing) {
+ PRINTM(MWARN, "mlan main processing is still running\n");
+ LEAVE();
+ return ret;
+ }
+
+ /* shut down mlan */
+ PRINTM(MINFO, "Shutdown mlan...\n");
+
+ /* Clean up priv structures */
+ for (i = 0; i < pmadapter->priv_num; i++) {
+ if (pmadapter->priv[i]) {
+ wlan_free_priv(pmadapter->priv[i]);
+ }
+ }
+
+ pcb = &pmadapter->callbacks;
+
+ if (pcb->moal_spin_lock(pmadapter->pmoal_handle, pmadapter->pmlan_lock)
+ != MLAN_STATUS_SUCCESS) {
+ ret = MLAN_STATUS_FAILURE;
+ goto exit_shutdown_fw;
+ }
+
+ if (pcb->moal_spin_unlock(pmadapter->pmoal_handle, pmadapter->pmlan_lock)
+ != MLAN_STATUS_SUCCESS) {
+ ret = MLAN_STATUS_FAILURE;
+ goto exit_shutdown_fw;
+ }
+
+ /* Notify completion */
+ ret = wlan_shutdown_fw_complete(pmadapter);
+
+ exit_shutdown_fw:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief The main process
+ *
+ * @param pmlan_adapter A pointer to mlan_adapter structure
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status
+mlan_main_process(IN t_void * pmlan_adapter)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_adapter *pmadapter = (mlan_adapter *) pmlan_adapter;
+ pmlan_callbacks pcb;
+
+ ENTER();
+
+ MASSERT(pmlan_adapter);
+
+ pcb = &pmadapter->callbacks;
+
+ pcb->moal_spin_lock(pmadapter->pmoal_handle, pmadapter->pmain_proc_lock);
+
+ /* Check if already processing */
+ if (pmadapter->mlan_processing) {
+ pcb->moal_spin_unlock(pmadapter->pmoal_handle,
+ pmadapter->pmain_proc_lock);
+ goto exit_main_proc;
+ } else {
+ pmadapter->mlan_processing = MTRUE;
+ pcb->moal_spin_unlock(pmadapter->pmoal_handle,
+ pmadapter->pmain_proc_lock);
+ }
+ process_start:
+ do {
+ /* Is MLAN shutting down or not ready? */
+ if ((pmadapter->hw_status == WlanHardwareStatusClosing) ||
+ (pmadapter->hw_status == WlanHardwareStatusNotReady))
+ break;
+
+ /* Handle pending SDIO interrupts if any */
+ if (pmadapter->sdio_ireg) {
+ if (pmadapter->hs_activated == MTRUE)
+ wlan_process_hs_config(pmadapter);
+ wlan_process_int_status(pmadapter);
+ }
+
+ /* Need to wake up the card ? */
+ if ((pmadapter->ps_state == PS_STATE_SLEEP) &&
+ (pmadapter->pm_wakeup_card_req &&
+ !pmadapter->pm_wakeup_fw_try) &&
+ (util_peek_list
+ (pmadapter->pmoal_handle, &pmadapter->cmd_pending_q,
+ pcb->moal_spin_lock, pcb->moal_spin_unlock)
+ || !wlan_bypass_tx_list_empty(pmadapter)
+ || !wlan_wmm_lists_empty(pmadapter)
+ )) {
+ pmadapter->pm_wakeup_fw_try = MTRUE;
+ wlan_pm_wakeup_card(pmadapter);
+ continue;
+ }
+ if (IS_CARD_RX_RCVD(pmadapter)) {
+ pmadapter->data_received = MFALSE;
+ if (pmadapter->hs_activated == MTRUE) {
+ pmadapter->is_hs_configured = MFALSE;
+ wlan_host_sleep_activated_event(wlan_get_priv
+ (pmadapter, MLAN_BSS_ROLE_ANY),
+ MFALSE);
+ }
+ pmadapter->pm_wakeup_fw_try = MFALSE;
+ if (pmadapter->ps_state == PS_STATE_SLEEP)
+ pmadapter->ps_state = PS_STATE_AWAKE;
+ } else {
+ /* We have tried to wakeup the card already */
+ if (pmadapter->pm_wakeup_fw_try)
+ break;
+ if (pmadapter->ps_state != PS_STATE_AWAKE ||
+ (pmadapter->tx_lock_flag == MTRUE))
+ break;
+
+ if (pmadapter->scan_processing || pmadapter->data_sent
+ || (wlan_bypass_tx_list_empty(pmadapter) &&
+ wlan_wmm_lists_empty(pmadapter))
+ || wlan_11h_radar_detected_tx_blocked(pmadapter)
+ ) {
+ if (pmadapter->cmd_sent || pmadapter->curr_cmd ||
+ (!util_peek_list
+ (pmadapter->pmoal_handle, &pmadapter->cmd_pending_q,
+ pcb->moal_spin_lock, pcb->moal_spin_unlock))) {
+ break;
+ }
+ }
+ }
+
+ /* Check for Cmd Resp */
+ if (pmadapter->cmd_resp_received) {
+ pmadapter->cmd_resp_received = MFALSE;
+ wlan_process_cmdresp(pmadapter);
+
+ /* call moal back when init_fw is done */
+ if (pmadapter->hw_status == WlanHardwareStatusInitdone) {
+ pmadapter->hw_status = WlanHardwareStatusReady;
+ wlan_init_fw_complete(pmadapter);
+ }
+ }
+
+ /* Check for event */
+ if (pmadapter->event_received) {
+ pmadapter->event_received = MFALSE;
+ wlan_process_event(pmadapter);
+ }
+
+ /* Check if we need to confirm Sleep Request received previously */
+ if (pmadapter->ps_state == PS_STATE_PRE_SLEEP) {
+ if (!pmadapter->cmd_sent && !pmadapter->curr_cmd) {
+ wlan_check_ps_cond(pmadapter);
+ }
+ }
+
+ /*
+ * The ps_state may have been changed during processing of
+ * Sleep Request event.
+ */
+ if ((pmadapter->ps_state == PS_STATE_SLEEP)
+ || (pmadapter->ps_state == PS_STATE_PRE_SLEEP)
+ || (pmadapter->ps_state == PS_STATE_SLEEP_CFM)
+ || (pmadapter->tx_lock_flag == MTRUE)
+ )
+ continue;
+
+ if (!pmadapter->cmd_sent && !pmadapter->curr_cmd) {
+ if (wlan_exec_next_cmd(pmadapter) == MLAN_STATUS_FAILURE) {
+ ret = MLAN_STATUS_FAILURE;
+ break;
+ }
+ }
+
+ if (!pmadapter->scan_processing && !pmadapter->data_sent &&
+ !wlan_11h_radar_detected_tx_blocked(pmadapter) &&
+ !wlan_bypass_tx_list_empty(pmadapter)) {
+ PRINTM(MINFO, "mlan_send_pkt(): deq(bybass_txq)\n");
+ wlan_process_bypass_tx(pmadapter);
+ if (pmadapter->hs_activated == MTRUE) {
+ pmadapter->is_hs_configured = MFALSE;
+ wlan_host_sleep_activated_event(wlan_get_priv
+ (pmadapter, MLAN_BSS_ROLE_ANY),
+ MFALSE);
+ }
+ }
+
+ if (!pmadapter->scan_processing && !pmadapter->data_sent &&
+ !wlan_wmm_lists_empty(pmadapter)
+ && !wlan_11h_radar_detected_tx_blocked(pmadapter)
+ ) {
+ wlan_wmm_process_tx(pmadapter);
+ if (pmadapter->hs_activated == MTRUE) {
+ pmadapter->is_hs_configured = MFALSE;
+ wlan_host_sleep_activated_event(wlan_get_priv
+ (pmadapter, MLAN_BSS_ROLE_ANY),
+ MFALSE);
+ }
+ }
+
+#ifdef STA_SUPPORT
+ if (pmadapter->delay_null_pkt && !pmadapter->cmd_sent &&
+ !pmadapter->curr_cmd && !IS_COMMAND_PENDING(pmadapter) &&
+ wlan_bypass_tx_list_empty(pmadapter) &&
+ wlan_wmm_lists_empty(pmadapter)) {
+ if (wlan_send_null_packet
+ (wlan_get_priv(pmadapter, MLAN_BSS_ROLE_STA),
+ MRVDRV_TxPD_POWER_MGMT_NULL_PACKET |
+ MRVDRV_TxPD_POWER_MGMT_LAST_PACKET)
+ == MLAN_STATUS_SUCCESS) {
+ pmadapter->delay_null_pkt = MFALSE;
+ }
+ break;
+ }
+#endif
+
+ } while (MTRUE);
+
+ if ((pmadapter->sdio_ireg) || IS_CARD_RX_RCVD(pmadapter)) {
+ goto process_start;
+ }
+ pcb->moal_spin_lock(pmadapter->pmoal_handle, pmadapter->pmain_proc_lock);
+ pmadapter->mlan_processing = MFALSE;
+ pcb->moal_spin_unlock(pmadapter->pmoal_handle, pmadapter->pmain_proc_lock);
+
+ exit_main_proc:
+ if (pmadapter->hw_status == WlanHardwareStatusClosing)
+ mlan_shutdown_fw(pmadapter);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Function to send packet
+ *
+ * @param pmlan_adapter A pointer to mlan_adapter structure
+ * @param pmbuf A pointer to mlan_buffer structure
+ *
+ * @return MLAN_STATUS_PENDING
+ */
+mlan_status
+mlan_send_packet(IN t_void * pmlan_adapter, IN pmlan_buffer pmbuf)
+{
+ mlan_status ret = MLAN_STATUS_PENDING;
+ mlan_adapter *pmadapter = (mlan_adapter *) pmlan_adapter;
+
+ ENTER();
+ MASSERT(pmlan_adapter && pmbuf);
+
+ MASSERT(pmbuf->bss_index < pmadapter->priv_num);
+ pmbuf->flags = MLAN_BUF_FLAG_MOAL_TX_BUF;
+
+ if (((pmadapter->priv[pmbuf->bss_index]->port_ctrl_mode == MTRUE) &&
+ ((mlan_ntohs(*(t_u16 *) & pmbuf->pbuf[pmbuf->data_offset +
+ MLAN_ETHER_PKT_TYPE_OFFSET]) ==
+ MLAN_ETHER_PKT_TYPE_EAPOL)
+ ||
+ (mlan_ntohs
+ (*(t_u16 *) & pmbuf->
+ pbuf[pmbuf->data_offset + MLAN_ETHER_PKT_TYPE_OFFSET]) ==
+ MLAN_ETHER_PKT_TYPE_WAPI)
+ ))
+ || (pmbuf->buf_type == MLAN_BUF_TYPE_RAW_DATA)
+
+ ) {
+ PRINTM(MINFO, "mlan_send_pkt(): enq(bybass_txq)\n");
+ wlan_add_buf_bypass_txqueue(pmadapter, pmbuf);
+ } else {
+ /* Transmit the packet */
+ wlan_wmm_add_buf_txqueue(pmadapter, pmbuf);
+ }
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief MLAN ioctl handler
+ *
+ * @param adapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING --success, otherwise fail
+ */
+mlan_status
+mlan_ioctl(IN t_void * adapter, IN pmlan_ioctl_req pioctl_req)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ pmlan_adapter pmadapter = (pmlan_adapter) adapter;
+ pmlan_private pmpriv = MNULL;
+
+ ENTER();
+
+ if (pioctl_req == MNULL) {
+ PRINTM(MERROR, "MLAN IOCTL information buffer is NULL\n");
+ ret = MLAN_STATUS_FAILURE;
+ goto exit;
+ }
+ if (pioctl_req->action == MLAN_ACT_CANCEL) {
+ wlan_cancel_pending_ioctl(pmadapter, pioctl_req);
+ ret = MLAN_STATUS_SUCCESS;
+ goto exit;
+ }
+ pmpriv = pmadapter->priv[pioctl_req->bss_index];
+ ret = pmpriv->ops.ioctl(adapter, pioctl_req);
+ exit:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Packet receive completion callback handler
+ *
+ * @param pmlan_adapter A pointer to mlan_adapter structure
+ * @param pmbuf A pointer to mlan_buffer structure
+ * @param status Callback status
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+mlan_status
+mlan_recv_packet_complete(IN t_void * pmlan_adapter,
+ IN pmlan_buffer pmbuf, IN mlan_status status)
+{
+ mlan_adapter *pmadapter = (mlan_adapter *) pmlan_adapter;
+
+ ENTER();
+ wlan_recv_packet_complete(pmadapter, pmbuf, status);
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief select wmm queue
+ *
+ * @param pmlan_adapter A pointer to mlan_adapter structure
+ * @param bss_num BSS number
+ * @param tid TID
+ *
+ * @return wmm queue priority (0 - 3)
+ */
+t_u8
+mlan_select_wmm_queue(IN t_void * pmlan_adapter, IN t_u8 bss_num, IN t_u8 tid)
+{
+ mlan_adapter *pmadapter = (mlan_adapter *) pmlan_adapter;
+ pmlan_private pmpriv = pmadapter->priv[bss_num];
+ t_u8 ret;
+ ENTER();
+ ret = wlan_wmm_select_queue(pmpriv, tid);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function gets interrupt status.
+ *
+ * @param adapter A pointer to mlan_adapter structure
+ * @return N/A
+ */
+t_void
+mlan_interrupt(IN t_void * adapter)
+{
+ mlan_adapter *pmadapter = (mlan_adapter *) adapter;
+
+ ENTER();
+ if (!pmadapter->pps_uapsd_mode && pmadapter->ps_state == PS_STATE_SLEEP) {
+ pmadapter->pm_wakeup_fw_try = MFALSE;
+ pmadapter->ps_state = PS_STATE_AWAKE;
+ }
+ wlan_interrupt(pmadapter);
+ LEAVE();
+}
diff --git a/drivers/net/wireless/sd8797/mlan/mlan_sta_cmd.c b/drivers/net/wireless/sd8797/mlan/mlan_sta_cmd.c
new file mode 100644
index 000000000000..c3a3b956aa61
--- /dev/null
+++ b/drivers/net/wireless/sd8797/mlan/mlan_sta_cmd.c
@@ -0,0 +1,1888 @@
+/** @file mlan_sta_cmd.c
+ *
+ * @brief This file contains the handling of command.
+ * it prepares command and sends it to firmware when
+ * it is ready.
+ *
+ * Copyright (C) 2008-2011, Marvell International Ltd.
+ *
+ * This software file (the "File") is distributed by Marvell International
+ * Ltd. under the terms of the GNU General Public License Version 2, June 1991
+ * (the "License"). You may use, redistribute and/or modify this File in
+ * accordance with the terms and conditions of the License, a copy of which
+ * is available by writing to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
+ * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
+ *
+ * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
+ * ARE EXPRESSLY DISCLAIMED. The License provides additional details about
+ * this warranty disclaimer.
+ *
+ */
+
+/******************************************************
+Change log:
+ 10/21/2008: initial version
+******************************************************/
+
+#include "mlan.h"
+#include "mlan_join.h"
+#include "mlan_util.h"
+#include "mlan_fw.h"
+#include "mlan_main.h"
+#include "mlan_wmm.h"
+#include "mlan_11n.h"
+#include "mlan_11h.h"
+#include "mlan_sdio.h"
+#include "mlan_meas.h"
+
+/********************************************************
+ Local Variables
+********************************************************/
+
+/********************************************************
+ Global Variables
+********************************************************/
+
+/********************************************************
+ Local Functions
+********************************************************/
+
+/**
+ * @brief This function prepares command of RSSI info.
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param pcmd A pointer to HostCmd_DS_COMMAND structure
+ * @param cmd_action Command action
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+static mlan_status
+wlan_cmd_802_11_rssi_info(IN pmlan_private pmpriv,
+ IN HostCmd_DS_COMMAND * pcmd, IN t_u16 cmd_action)
+{
+ ENTER();
+
+ pcmd->command = wlan_cpu_to_le16(HostCmd_CMD_RSSI_INFO);
+ pcmd->size =
+ wlan_cpu_to_le16(sizeof(HostCmd_DS_802_11_RSSI_INFO) + S_DS_GEN);
+ pcmd->params.rssi_info.action = wlan_cpu_to_le16(cmd_action);
+ pcmd->params.rssi_info.ndata = wlan_cpu_to_le16(pmpriv->data_avg_factor);
+ pcmd->params.rssi_info.nbcn = wlan_cpu_to_le16(pmpriv->bcn_avg_factor);
+
+ /* Reset SNR/NF/RSSI values in private structure */
+ pmpriv->data_rssi_last = 0;
+ pmpriv->data_nf_last = 0;
+ pmpriv->data_rssi_avg = 0;
+ pmpriv->data_nf_avg = 0;
+ pmpriv->bcn_rssi_last = 0;
+ pmpriv->bcn_nf_last = 0;
+ pmpriv->bcn_rssi_avg = 0;
+ pmpriv->bcn_nf_avg = 0;
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function prepares command of mac_control.
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param pcmd A pointer to HostCmd_DS_COMMAND structure
+ * @param cmd_action Command action
+ * @param pdata_buf A pointer to command information buffer
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+static mlan_status
+wlan_cmd_mac_control(IN pmlan_private pmpriv,
+ IN HostCmd_DS_COMMAND * pcmd,
+ IN t_u16 cmd_action, IN t_void * pdata_buf)
+{
+ HostCmd_DS_MAC_CONTROL *pmac = &pcmd->params.mac_ctrl;
+ t_u16 action = *((t_u16 *) pdata_buf);
+
+ ENTER();
+
+ if (cmd_action != HostCmd_ACT_GEN_SET) {
+ PRINTM(MERROR, "wlan_cmd_mac_control(): support SET only.\n");
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+
+ pcmd->command = wlan_cpu_to_le16(HostCmd_CMD_MAC_CONTROL);
+ pcmd->size = wlan_cpu_to_le16(sizeof(HostCmd_DS_MAC_CONTROL) + S_DS_GEN);
+ pmac->action = wlan_cpu_to_le16(action);
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function prepares command of snmp_mib.
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param cmd A pointer to HostCmd_DS_COMMAND structure
+ * @param cmd_action The action: GET or SET
+ * @param cmd_oid OID: ENABLE or DISABLE
+ * @param pdata_buf A pointer to command information buffer
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+static mlan_status
+wlan_cmd_802_11_snmp_mib(IN pmlan_private pmpriv,
+ IN HostCmd_DS_COMMAND * cmd,
+ IN t_u16 cmd_action,
+ IN t_u32 cmd_oid, IN t_void * pdata_buf)
+{
+ HostCmd_DS_802_11_SNMP_MIB *psnmp_mib = &cmd->params.smib;
+ t_u32 ul_temp;
+
+ ENTER();
+ PRINTM(MINFO, "SNMP_CMD: cmd_oid = 0x%x\n", cmd_oid);
+ cmd->command = wlan_cpu_to_le16(HostCmd_CMD_802_11_SNMP_MIB);
+ cmd->size = sizeof(HostCmd_DS_802_11_SNMP_MIB) - 1 + S_DS_GEN;
+
+ if (cmd_action == HostCmd_ACT_GEN_GET) {
+ psnmp_mib->query_type = wlan_cpu_to_le16(HostCmd_ACT_GEN_GET);
+ psnmp_mib->buf_size = wlan_cpu_to_le16(MAX_SNMP_BUF_SIZE);
+ cmd->size += MAX_SNMP_BUF_SIZE;
+ }
+
+ switch (cmd_oid) {
+ case FragThresh_i:
+ psnmp_mib->oid = wlan_cpu_to_le16((t_u16) FragThresh_i);
+ if (cmd_action == HostCmd_ACT_GEN_SET) {
+ psnmp_mib->query_type = wlan_cpu_to_le16(HostCmd_ACT_GEN_SET);
+ psnmp_mib->buf_size = wlan_cpu_to_le16(sizeof(t_u16));
+ ul_temp = *((t_u32 *) pdata_buf);
+ *((t_u16 *) (psnmp_mib->value)) = wlan_cpu_to_le16((t_u16) ul_temp);
+ cmd->size += sizeof(t_u16);
+ }
+ break;
+ case RtsThresh_i:
+ psnmp_mib->oid = wlan_cpu_to_le16((t_u16) RtsThresh_i);
+ if (cmd_action == HostCmd_ACT_GEN_SET) {
+ psnmp_mib->query_type = wlan_cpu_to_le16(HostCmd_ACT_GEN_SET);
+ psnmp_mib->buf_size = wlan_cpu_to_le16(sizeof(t_u16));
+ ul_temp = *((t_u32 *) pdata_buf);
+ *(t_u16 *) (psnmp_mib->value) = wlan_cpu_to_le16((t_u16) ul_temp);
+ cmd->size += sizeof(t_u16);
+ }
+ break;
+
+ case ShortRetryLim_i:
+ psnmp_mib->oid = wlan_cpu_to_le16((t_u16) ShortRetryLim_i);
+ if (cmd_action == HostCmd_ACT_GEN_SET) {
+ psnmp_mib->query_type = wlan_cpu_to_le16(HostCmd_ACT_GEN_SET);
+ psnmp_mib->buf_size = wlan_cpu_to_le16(sizeof(t_u16));
+ ul_temp = (*(t_u32 *) pdata_buf);
+ *((t_u16 *) (psnmp_mib->value)) = wlan_cpu_to_le16((t_u16) ul_temp);
+ cmd->size += sizeof(t_u16);
+ }
+ break;
+ case Dot11D_i:
+ psnmp_mib->oid = wlan_cpu_to_le16((t_u16) Dot11D_i);
+ if (cmd_action == HostCmd_ACT_GEN_SET) {
+ psnmp_mib->query_type = wlan_cpu_to_le16(HostCmd_ACT_GEN_SET);
+ psnmp_mib->buf_size = wlan_cpu_to_le16(sizeof(t_u16));
+ ul_temp = *(t_u32 *) pdata_buf;
+ *((t_u16 *) (psnmp_mib->value)) = wlan_cpu_to_le16((t_u16) ul_temp);
+ cmd->size += sizeof(t_u16);
+ }
+ break;
+ case Dot11H_i:
+ psnmp_mib->oid = wlan_cpu_to_le16((t_u16) Dot11H_i);
+ if (cmd_action == HostCmd_ACT_GEN_SET) {
+ psnmp_mib->query_type = wlan_cpu_to_le16(HostCmd_ACT_GEN_SET);
+ psnmp_mib->buf_size = wlan_cpu_to_le16(sizeof(t_u16));
+ ul_temp = *(t_u32 *) pdata_buf;
+ *((t_u16 *) (psnmp_mib->value)) = wlan_cpu_to_le16((t_u16) ul_temp);
+ cmd->size += sizeof(t_u16);
+ }
+ break;
+ case WwsMode_i:
+ psnmp_mib->oid = wlan_cpu_to_le16((t_u16) WwsMode_i);
+ if (cmd_action == HostCmd_ACT_GEN_SET) {
+ psnmp_mib->query_type = wlan_cpu_to_le16(HostCmd_ACT_GEN_SET);
+ psnmp_mib->buf_size = wlan_cpu_to_le16(sizeof(t_u16));
+ ul_temp = *((t_u32 *) pdata_buf);
+ *((t_u16 *) (psnmp_mib->value)) = wlan_cpu_to_le16((t_u16) ul_temp);
+ cmd->size += sizeof(t_u16);
+ }
+ break;
+ case Thermal_i:
+ psnmp_mib->oid = wlan_cpu_to_le16((t_u16) Thermal_i);
+ break;
+ default:
+ break;
+ }
+ cmd->size = wlan_cpu_to_le16(cmd->size);
+ PRINTM(MINFO, "SNMP_CMD: Action=0x%x, OID=0x%x, OIDSize=0x%x, Value=0x%x\n",
+ cmd_action, cmd_oid, wlan_le16_to_cpu(psnmp_mib->buf_size),
+ wlan_le16_to_cpu(*(t_u16 *) psnmp_mib->value));
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function prepares command of get_log.
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param cmd A pointer to HostCmd_DS_COMMAND structure
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+static mlan_status
+wlan_cmd_802_11_get_log(IN pmlan_private pmpriv, IN HostCmd_DS_COMMAND * cmd)
+{
+ ENTER();
+ cmd->command = wlan_cpu_to_le16(HostCmd_CMD_802_11_GET_LOG);
+ cmd->size = wlan_cpu_to_le16(sizeof(HostCmd_DS_802_11_GET_LOG) + S_DS_GEN);
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function prepares command of tx_power_cfg.
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param cmd A pointer to HostCmd_DS_COMMAND structure
+ * @param cmd_action The action: GET or SET
+ * @param pdata_buf A pointer to data buffer
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+static mlan_status
+wlan_cmd_tx_power_cfg(IN pmlan_private pmpriv,
+ IN HostCmd_DS_COMMAND * cmd,
+ IN t_u16 cmd_action, IN t_void * pdata_buf)
+{
+ MrvlTypes_Power_Group_t *ppg_tlv = MNULL;
+ HostCmd_DS_TXPWR_CFG *ptxp = MNULL;
+ HostCmd_DS_TXPWR_CFG *ptxp_cfg = &cmd->params.txp_cfg;
+
+ ENTER();
+
+ cmd->command = wlan_cpu_to_le16(HostCmd_CMD_TXPWR_CFG);
+ cmd->size = wlan_cpu_to_le16(S_DS_GEN + sizeof(HostCmd_DS_TXPWR_CFG));
+ switch (cmd_action) {
+ case HostCmd_ACT_GEN_SET:
+ ptxp = (HostCmd_DS_TXPWR_CFG *) pdata_buf;
+ if (ptxp->mode) {
+ ppg_tlv =
+ (MrvlTypes_Power_Group_t *) ((t_u8 *) pdata_buf +
+ sizeof(HostCmd_DS_TXPWR_CFG));
+ memmove(pmpriv->adapter, ptxp_cfg, pdata_buf,
+ sizeof(HostCmd_DS_TXPWR_CFG) +
+ sizeof(MrvlTypes_Power_Group_t) + ppg_tlv->length);
+
+ ppg_tlv = (MrvlTypes_Power_Group_t *) ((t_u8 *) ptxp_cfg +
+ sizeof
+ (HostCmd_DS_TXPWR_CFG));
+ cmd->size +=
+ wlan_cpu_to_le16(sizeof(MrvlTypes_Power_Group_t) +
+ ppg_tlv->length);
+ ppg_tlv->type = wlan_cpu_to_le16(ppg_tlv->type);
+ ppg_tlv->length = wlan_cpu_to_le16(ppg_tlv->length);
+ } else {
+ memmove(pmpriv->adapter, ptxp_cfg, pdata_buf,
+ sizeof(HostCmd_DS_TXPWR_CFG));
+ }
+ ptxp_cfg->action = wlan_cpu_to_le16(cmd_action);
+ ptxp_cfg->cfg_index = wlan_cpu_to_le16(ptxp_cfg->cfg_index);
+ ptxp_cfg->mode = wlan_cpu_to_le32(ptxp_cfg->mode);
+ break;
+ case HostCmd_ACT_GEN_GET:
+ ptxp_cfg->action = wlan_cpu_to_le16(cmd_action);
+ break;
+ }
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function prepares command of rf_tx_power.
+ *
+ * @param pmpriv A pointer to wlan_private structure
+ * @param cmd A pointer to HostCmd_DS_COMMAND structure
+ * @param cmd_action the action: GET or SET
+ * @param pdata_buf A pointer to data buffer
+ * @return MLAN_STATUS_SUCCESS
+ */
+static mlan_status
+wlan_cmd_802_11_rf_tx_power(IN pmlan_private pmpriv,
+ IN HostCmd_DS_COMMAND * cmd,
+ IN t_u16 cmd_action, IN t_void * pdata_buf)
+{
+
+ HostCmd_DS_802_11_RF_TX_POWER *prtp = &cmd->params.txp;
+
+ ENTER();
+
+ cmd->size = wlan_cpu_to_le16((sizeof(HostCmd_DS_802_11_RF_TX_POWER))
+ + S_DS_GEN);
+ cmd->command = wlan_cpu_to_le16(HostCmd_CMD_802_11_RF_TX_POWER);
+ prtp->action = cmd_action;
+
+ PRINTM(MINFO, "RF_TX_POWER_CMD: Size:%d Cmd:0x%x Act:%d\n",
+ cmd->size, cmd->command, prtp->action);
+
+ switch (cmd_action) {
+ case HostCmd_ACT_GEN_GET:
+ prtp->action = wlan_cpu_to_le16(HostCmd_ACT_GEN_GET);
+ prtp->current_level = 0;
+ break;
+
+ case HostCmd_ACT_GEN_SET:
+ prtp->action = wlan_cpu_to_le16(HostCmd_ACT_GEN_SET);
+ prtp->current_level = wlan_cpu_to_le16(*((t_u16 *) pdata_buf));
+ break;
+ }
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function prepares command of hs_cfg.
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param cmd A pointer to HostCmd_DS_COMMAND structure
+ * @param cmd_action The action: GET or SET
+ * @param pdata_buf A pointer to data buffer
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+static mlan_status
+wlan_cmd_802_11_hs_cfg(IN pmlan_private pmpriv,
+ IN HostCmd_DS_COMMAND * cmd,
+ IN t_u16 cmd_action, IN hs_config_param * pdata_buf)
+{
+ pmlan_adapter pmadapter = pmpriv->adapter;
+ HostCmd_DS_802_11_HS_CFG_ENH *phs_cfg = &cmd->params.opt_hs_cfg;
+ t_u16 hs_activate = MFALSE;
+
+ ENTER();
+
+ if (pdata_buf == MNULL) {
+ /* New Activate command */
+ hs_activate = MTRUE;
+ }
+ cmd->command = wlan_cpu_to_le16(HostCmd_CMD_802_11_HS_CFG_ENH);
+
+ if (!hs_activate && (pdata_buf->conditions != HOST_SLEEP_CFG_CANCEL)
+ && ((pmadapter->arp_filter_size > 0)
+ && (pmadapter->arp_filter_size <= ARP_FILTER_MAX_BUF_SIZE))) {
+ PRINTM(MINFO, "Attach %d bytes ArpFilter to HSCfg cmd\n",
+ pmadapter->arp_filter_size);
+ memcpy(pmpriv->adapter,
+ ((t_u8 *) phs_cfg) + sizeof(HostCmd_DS_802_11_HS_CFG_ENH),
+ pmadapter->arp_filter, pmadapter->arp_filter_size);
+ cmd->size =
+ (t_u16) wlan_cpu_to_le16(pmadapter->arp_filter_size +
+ sizeof(HostCmd_DS_802_11_HS_CFG_ENH) +
+ S_DS_GEN);
+ } else
+ cmd->size =
+ wlan_cpu_to_le16(S_DS_GEN + sizeof(HostCmd_DS_802_11_HS_CFG_ENH));
+
+ if (hs_activate) {
+ phs_cfg->action = wlan_cpu_to_le16(HS_ACTIVATE);
+ phs_cfg->params.hs_activate.resp_ctrl = wlan_cpu_to_le16(RESP_NEEDED);
+ } else {
+ phs_cfg->action = wlan_cpu_to_le16(HS_CONFIGURE);
+ phs_cfg->params.hs_config.conditions =
+ wlan_cpu_to_le32(pdata_buf->conditions);
+ phs_cfg->params.hs_config.gpio = pdata_buf->gpio;
+ phs_cfg->params.hs_config.gap = pdata_buf->gap;
+ PRINTM(MCMND, "HS_CFG_CMD: condition:0x%x gpio:0x%x gap:0x%x\n",
+ phs_cfg->params.hs_config.conditions,
+ phs_cfg->params.hs_config.gpio, phs_cfg->params.hs_config.gap);
+ }
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function prepares command of mac_address.
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param cmd A pointer to HostCmd_DS_COMMAND structure
+ * @param cmd_action The action: GET or SET
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+static mlan_status
+wlan_cmd_802_11_mac_address(IN pmlan_private pmpriv,
+ IN HostCmd_DS_COMMAND * cmd, IN t_u16 cmd_action)
+{
+ ENTER();
+ cmd->command = wlan_cpu_to_le16(HostCmd_CMD_802_11_MAC_ADDRESS);
+ cmd->size = wlan_cpu_to_le16(sizeof(HostCmd_DS_802_11_MAC_ADDRESS) +
+ S_DS_GEN);
+ cmd->result = 0;
+
+ cmd->params.mac_addr.action = wlan_cpu_to_le16(cmd_action);
+
+ if (cmd_action == HostCmd_ACT_GEN_SET) {
+ memcpy(pmpriv->adapter, cmd->params.mac_addr.mac_addr,
+ pmpriv->curr_addr, MLAN_MAC_ADDR_LENGTH);
+ // HEXDUMP("SET_CMD: MAC ADDRESS-", priv->CurrentAddr, 6);
+ }
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function prepares command of sleep_period.
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param cmd A pointer to HostCmd_DS_COMMAND structure
+ * @param cmd_action The action: GET or SET
+ * @param pdata_buf A pointer to data buffer
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+static mlan_status
+wlan_cmd_802_11_sleep_period(IN pmlan_private pmpriv,
+ IN HostCmd_DS_COMMAND * cmd,
+ IN t_u16 cmd_action, IN t_u16 * pdata_buf)
+{
+ HostCmd_DS_802_11_SLEEP_PERIOD *pcmd_sleep_pd = &cmd->params.sleep_pd;
+
+ ENTER();
+
+ cmd->command = wlan_cpu_to_le16(HostCmd_CMD_802_11_SLEEP_PERIOD);
+ cmd->size =
+ wlan_cpu_to_le16(sizeof(HostCmd_DS_802_11_SLEEP_PERIOD) + S_DS_GEN);
+ if (cmd_action == HostCmd_ACT_GEN_SET) {
+ pcmd_sleep_pd->sleep_pd = wlan_cpu_to_le16(*(t_u16 *) pdata_buf);
+ }
+ pcmd_sleep_pd->action = wlan_cpu_to_le16(cmd_action);
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function prepares command of sleep_params.
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param cmd A pointer to HostCmd_DS_COMMAND structure
+ * @param cmd_action The action: GET or SET
+ * @param pdata_buf A pointer to data buffer
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+static mlan_status
+wlan_cmd_802_11_sleep_params(IN pmlan_private pmpriv,
+ IN HostCmd_DS_COMMAND * cmd,
+ IN t_u16 cmd_action, IN t_u16 * pdata_buf)
+{
+ HostCmd_DS_802_11_SLEEP_PARAMS *pcmd_sp = &cmd->params.sleep_param;
+ mlan_ds_sleep_params *psp = (mlan_ds_sleep_params *) pdata_buf;
+
+ ENTER();
+
+ cmd->command = wlan_cpu_to_le16(HostCmd_CMD_802_11_SLEEP_PARAMS);
+ cmd->size =
+ wlan_cpu_to_le16(sizeof(HostCmd_DS_802_11_SLEEP_PARAMS) + S_DS_GEN);
+ if (cmd_action == HostCmd_ACT_GEN_SET) {
+ pcmd_sp->reserved = (t_u16) psp->reserved;
+ pcmd_sp->error = (t_u16) psp->error;
+ pcmd_sp->offset = (t_u16) psp->offset;
+ pcmd_sp->stable_time = (t_u16) psp->stable_time;
+ pcmd_sp->cal_control = (t_u8) psp->cal_control;
+ pcmd_sp->external_sleep_clk = (t_u8) psp->ext_sleep_clk;
+
+ pcmd_sp->reserved = wlan_cpu_to_le16(pcmd_sp->reserved);
+ pcmd_sp->error = wlan_cpu_to_le16(pcmd_sp->error);
+ pcmd_sp->offset = wlan_cpu_to_le16(pcmd_sp->offset);
+ pcmd_sp->stable_time = wlan_cpu_to_le16(pcmd_sp->stable_time);
+ }
+ pcmd_sp->action = wlan_cpu_to_le16(cmd_action);
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function prepares command of mac_multicast_adr.
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param cmd A pointer to HostCmd_DS_COMMAND structure
+ * @param cmd_action The action: GET or SET
+ * @param pdata_buf A pointer to data buffer
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+static mlan_status
+wlan_cmd_mac_multicast_adr(IN pmlan_private pmpriv,
+ IN HostCmd_DS_COMMAND * cmd,
+ IN t_u16 cmd_action, IN t_void * pdata_buf)
+{
+ mlan_multicast_list *pmcast_list = (mlan_multicast_list *) pdata_buf;
+ HostCmd_DS_MAC_MULTICAST_ADR *pmc_addr = &cmd->params.mc_addr;
+
+ ENTER();
+ cmd->size =
+ wlan_cpu_to_le16(sizeof(HostCmd_DS_MAC_MULTICAST_ADR) + S_DS_GEN);
+ cmd->command = wlan_cpu_to_le16(HostCmd_CMD_MAC_MULTICAST_ADR);
+
+ pmc_addr->action = wlan_cpu_to_le16(cmd_action);
+ pmc_addr->num_of_adrs =
+ wlan_cpu_to_le16((t_u16) pmcast_list->num_multicast_addr);
+ memcpy(pmpriv->adapter, pmc_addr->mac_list, pmcast_list->mac_list,
+ pmcast_list->num_multicast_addr * MLAN_MAC_ADDR_LENGTH);
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function prepares command of deauthenticate.
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param cmd A pointer to HostCmd_DS_COMMAND structure
+ * @param pdata_buf A pointer to data buffer
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+static mlan_status
+wlan_cmd_802_11_deauthenticate(IN pmlan_private pmpriv,
+ IN HostCmd_DS_COMMAND * cmd,
+ IN t_void * pdata_buf)
+{
+ HostCmd_DS_802_11_DEAUTHENTICATE *pdeauth = &cmd->params.deauth;
+
+ ENTER();
+
+ cmd->command = wlan_cpu_to_le16(HostCmd_CMD_802_11_DEAUTHENTICATE);
+ cmd->size =
+ wlan_cpu_to_le16(sizeof(HostCmd_DS_802_11_DEAUTHENTICATE) + S_DS_GEN);
+
+ /* Set AP MAC address */
+ memcpy(pmpriv->adapter, pdeauth->mac_addr, (t_u8 *) pdata_buf,
+ MLAN_MAC_ADDR_LENGTH);
+
+ PRINTM(MCMND, "Deauth: %02x:%02x:%02x:%02x:%02x:%02x\n",
+ pdeauth->mac_addr[0], pdeauth->mac_addr[1], pdeauth->mac_addr[2],
+ pdeauth->mac_addr[3], pdeauth->mac_addr[4], pdeauth->mac_addr[5]);
+
+ if (pmpriv->adapter->state_11h.recvd_chanswann_event) {
+/** Reason code 36 = Requested from peer station as it is leaving the BSS */
+#define REASON_CODE_PEER_STA_LEAVING 36
+ pdeauth->reason_code = wlan_cpu_to_le16(REASON_CODE_PEER_STA_LEAVING);
+ } else {
+/** Reason code 3 = Station is leaving */
+#define REASON_CODE_STA_LEAVING 3
+ pdeauth->reason_code = wlan_cpu_to_le16(REASON_CODE_STA_LEAVING);
+ }
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function prepares command of ad_hoc_stop.
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param cmd A pointer to HostCmd_DS_COMMAND structure
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+static mlan_status
+wlan_cmd_802_11_ad_hoc_stop(IN pmlan_private pmpriv,
+ IN HostCmd_DS_COMMAND * cmd)
+{
+ ENTER();
+
+ cmd->command = wlan_cpu_to_le16(HostCmd_CMD_802_11_AD_HOC_STOP);
+ cmd->size = wlan_cpu_to_le16(S_DS_GEN);
+
+ if (wlan_11h_is_active(pmpriv))
+ wlan_11h_activate(pmpriv, MNULL, MFALSE);
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/** Length of WEP 40 bit key */
+#define WEP_40_BIT_LEN 5
+/** Length of WEP 104 bit key */
+#define WEP_104_BIT_LEN 13
+
+/**
+ * @brief This function sets WEP key(s) to key_param_set TLV(s).
+ *
+ * @param priv A pointer to mlan_private structure
+ * @param key_param_set A pointer to MrvlIEtype_KeyParamSet_t structure
+ * @param key_param_len A pointer to the length variable
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+static mlan_status
+wlan_set_keyparamset_wep(mlan_private * priv,
+ MrvlIEtype_KeyParamSet_t * key_param_set,
+ t_u16 * key_param_len)
+{
+ int cur_key_param_len = 0;
+ t_u8 i;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ /* Multi-key_param_set TLV is supported */
+ for (i = 0; i < MRVL_NUM_WEP_KEY; i++) {
+ if ((priv->wep_key[i].key_length == WEP_40_BIT_LEN) ||
+ (priv->wep_key[i].key_length == WEP_104_BIT_LEN)) {
+ key_param_set->type = wlan_cpu_to_le16(TLV_TYPE_KEY_MATERIAL);
+/** Key_param_set WEP fixed length */
+#define KEYPARAMSET_WEP_FIXED_LEN 8
+ key_param_set->length =
+ wlan_cpu_to_le16((t_u16)
+ (priv->wep_key[i].key_length +
+ KEYPARAMSET_WEP_FIXED_LEN));
+ key_param_set->key_type_id = wlan_cpu_to_le16(KEY_TYPE_ID_WEP);
+ key_param_set->key_info = wlan_cpu_to_le16
+ (KEY_INFO_WEP_ENABLED | KEY_INFO_WEP_UNICAST |
+ KEY_INFO_WEP_MCAST);
+ key_param_set->key_len =
+ (t_u16) wlan_cpu_to_le16(priv->wep_key[i].key_length);
+ /* Set WEP key index */
+ key_param_set->key[0] = i;
+ /* Set default Tx key flag */
+ if (i == (priv->wep_key_curr_index & HostCmd_WEP_KEY_INDEX_MASK))
+ key_param_set->key[1] = 1;
+ else
+ key_param_set->key[1] = 0;
+ memmove(priv->adapter, &key_param_set->key[2],
+ priv->wep_key[i].key_material, priv->wep_key[i].key_length);
+
+ cur_key_param_len = priv->wep_key[i].key_length +
+ KEYPARAMSET_WEP_FIXED_LEN + sizeof(MrvlIEtypesHeader_t);
+ *key_param_len += (t_u16) cur_key_param_len;
+ key_param_set =
+ (MrvlIEtype_KeyParamSet_t *) ((t_u8 *) key_param_set +
+ cur_key_param_len);
+ } else if (!priv->wep_key[i].key_length) {
+ continue;
+ } else {
+ PRINTM(MERROR, "key%d Length = %d is incorrect\n", (i + 1),
+ priv->wep_key[i].key_length);
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ }
+
+ done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function prepares command of key_material.
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param cmd A pointer to HostCmd_DS_COMMAND structure
+ * @param cmd_action The action: GET or SET
+ * @param cmd_oid OID: ENABLE or DISABLE
+ * @param pdata_buf A pointer to data buffer
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+static mlan_status
+wlan_cmd_802_11_key_material(IN pmlan_private pmpriv,
+ IN HostCmd_DS_COMMAND * cmd,
+ IN t_u16 cmd_action,
+ IN t_u32 cmd_oid, IN t_void * pdata_buf)
+{
+ HostCmd_DS_802_11_KEY_MATERIAL *pkey_material = &cmd->params.key_material;
+ mlan_ds_encrypt_key *pkey = (mlan_ds_encrypt_key *) pdata_buf;
+ t_u16 key_param_len = 0;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ const t_u8 bc_mac[] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
+
+ ENTER();
+
+ cmd->command = wlan_cpu_to_le16(HostCmd_CMD_802_11_KEY_MATERIAL);
+ pkey_material->action = wlan_cpu_to_le16(cmd_action);
+
+ if (cmd_action == HostCmd_ACT_GEN_GET) {
+ cmd->size = wlan_cpu_to_le16(sizeof(pkey_material->action) + S_DS_GEN);
+ goto done;
+ }
+
+ if (!pkey) {
+ memset(pmpriv->adapter, &pkey_material->key_param_set, 0,
+ (MRVL_NUM_WEP_KEY * sizeof(MrvlIEtype_KeyParamSet_t)));
+ ret =
+ wlan_set_keyparamset_wep(pmpriv, &pkey_material->key_param_set,
+ &key_param_len);
+ cmd->size =
+ wlan_cpu_to_le16(key_param_len + sizeof(pkey_material->action) +
+ S_DS_GEN);
+ goto done;
+ } else
+ memset(pmpriv->adapter, &pkey_material->key_param_set, 0,
+ sizeof(MrvlIEtype_KeyParamSet_t));
+ if (pkey->is_wapi_key) {
+ PRINTM(MINFO, "Set WAPI Key\n");
+ pkey_material->key_param_set.key_type_id =
+ wlan_cpu_to_le16(KEY_TYPE_ID_WAPI);
+ if (cmd_oid == KEY_INFO_ENABLED)
+ pkey_material->key_param_set.key_info =
+ wlan_cpu_to_le16(KEY_INFO_WAPI_ENABLED);
+ else
+ pkey_material->key_param_set.key_info =
+ !(wlan_cpu_to_le16(KEY_INFO_WAPI_ENABLED));
+
+ pkey_material->key_param_set.key[0] = (t_u8) pkey->key_index;
+ if (!pmpriv->sec_info.wapi_key_on)
+ pkey_material->key_param_set.key[1] = 1;
+ else
+ pkey_material->key_param_set.key[1] = 0; /* set 0 when re-key */
+
+ if (0 != memcmp(pmpriv->adapter, pkey->mac_addr, bc_mac, sizeof(bc_mac))) /* WAPI
+ pairwise
+ key:
+ unicast
+ */
+ pkey_material->key_param_set.key_info |=
+ wlan_cpu_to_le16(KEY_INFO_WAPI_UNICAST);
+ else { /* WAPI group key: multicast */
+ pkey_material->key_param_set.key_info |=
+ wlan_cpu_to_le16(KEY_INFO_WAPI_MCAST);
+ pmpriv->sec_info.wapi_key_on = MTRUE;
+ }
+
+ pkey_material->key_param_set.type =
+ wlan_cpu_to_le16(TLV_TYPE_KEY_MATERIAL);
+ pkey_material->key_param_set.key_len = wlan_cpu_to_le16(WAPI_KEY_LEN);
+ memcpy(pmpriv->adapter, &pkey_material->key_param_set.key[2],
+ pkey->key_material, pkey->key_len);
+ memcpy(pmpriv->adapter,
+ &pkey_material->key_param_set.key[2 + pkey->key_len], pkey->pn,
+ PN_SIZE);
+ pkey_material->key_param_set.length =
+ wlan_cpu_to_le16(WAPI_KEY_LEN + KEYPARAMSET_FIXED_LEN);
+
+ key_param_len =
+ (WAPI_KEY_LEN + KEYPARAMSET_FIXED_LEN) +
+ sizeof(MrvlIEtypesHeader_t);
+ cmd->size =
+ wlan_cpu_to_le16(key_param_len + sizeof(pkey_material->action) +
+ S_DS_GEN);
+ goto done;
+ }
+ if (pkey->key_len == WPA_AES_KEY_LEN) {
+ PRINTM(MCMND, "WPA_AES\n");
+ pkey_material->key_param_set.key_type_id =
+ wlan_cpu_to_le16(KEY_TYPE_ID_AES);
+ if (cmd_oid == KEY_INFO_ENABLED)
+ pkey_material->key_param_set.key_info =
+ wlan_cpu_to_le16(KEY_INFO_AES_ENABLED);
+ else
+ pkey_material->key_param_set.key_info =
+ !(wlan_cpu_to_le16(KEY_INFO_AES_ENABLED));
+
+ if (pkey->key_index & MLAN_KEY_INDEX_UNICAST) /* AES pairwise key:
+ unicast */
+ pkey_material->key_param_set.key_info |=
+ wlan_cpu_to_le16(KEY_INFO_AES_UNICAST);
+ else /* AES group key: multicast */
+ pkey_material->key_param_set.key_info |=
+ wlan_cpu_to_le16(KEY_INFO_AES_MCAST);
+ } else if (pkey->key_len == WPA_TKIP_KEY_LEN) {
+ PRINTM(MCMND, "WPA_TKIP\n");
+ pkey_material->key_param_set.key_type_id =
+ wlan_cpu_to_le16(KEY_TYPE_ID_TKIP);
+ pkey_material->key_param_set.key_info =
+ wlan_cpu_to_le16(KEY_INFO_TKIP_ENABLED);
+
+ if (pkey->key_index & MLAN_KEY_INDEX_UNICAST) /* TKIP pairwise key:
+ unicast */
+ pkey_material->key_param_set.key_info |=
+ wlan_cpu_to_le16(KEY_INFO_TKIP_UNICAST);
+ else /* TKIP group key: multicast */
+ pkey_material->key_param_set.key_info |=
+ wlan_cpu_to_le16(KEY_INFO_TKIP_MCAST);
+ }
+
+ if (pkey_material->key_param_set.key_type_id) {
+ pkey_material->key_param_set.type =
+ wlan_cpu_to_le16(TLV_TYPE_KEY_MATERIAL);
+ pkey_material->key_param_set.key_len =
+ wlan_cpu_to_le16((t_u16) pkey->key_len);
+ memcpy(pmpriv->adapter, pkey_material->key_param_set.key,
+ pkey->key_material, pkey->key_len);
+ pkey_material->key_param_set.length =
+ wlan_cpu_to_le16((t_u16) pkey->key_len + KEYPARAMSET_FIXED_LEN);
+
+ key_param_len =
+ (t_u16) (pkey->key_len + KEYPARAMSET_FIXED_LEN) +
+ sizeof(MrvlIEtypesHeader_t);
+
+ cmd->size =
+ wlan_cpu_to_le16(key_param_len + sizeof(pkey_material->action) +
+ S_DS_GEN);
+ }
+ done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function prepares command of supplicant pmk
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param cmd A pointer to HostCmd_DS_COMMAND structure
+ * @param cmd_action The action: GET or SET
+ * @param pdata_buf A pointer to data buffer
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+static mlan_status
+wlan_cmd_802_11_supplicant_pmk(IN pmlan_private pmpriv,
+ IN HostCmd_DS_COMMAND * cmd,
+ IN t_u16 cmd_action, IN t_void * pdata_buf)
+{
+ MrvlIEtypes_PMK_t *ppmk_tlv = MNULL;
+ MrvlIEtypes_Passphrase_t *ppassphrase_tlv = MNULL;
+ MrvlIEtypes_SsIdParamSet_t *pssid_tlv = MNULL;
+ MrvlIEtypes_Bssid_t *pbssid_tlv = MNULL;
+ HostCmd_DS_802_11_SUPPLICANT_PMK *pesupplicant_psk =
+ &cmd->params.esupplicant_psk;
+ t_u8 *ptlv_buffer = (t_u8 *) pesupplicant_psk->tlv_buffer;
+ mlan_ds_passphrase *psk = (mlan_ds_passphrase *) pdata_buf;
+ t_u8 zero_mac[] = { 0, 0, 0, 0, 0, 0 };
+
+ ENTER();
+ /*
+ * Parse the rest of the buf here
+ * 1) <ssid="valid ssid"> - This will get the passphrase, AKMP
+ * for specified ssid, if none specified then it will get all.
+ * Eg: iwpriv <mlanX> passphrase 0:ssid=marvell
+ * 2) <psk="psk">:<passphrase="passphare">:<bssid="00:50:43:ef:23:f3">
+ * <ssid="valid ssid"> - passphrase and psk cannot be provided to
+ * the same SSID, Takes one SSID at a time, If ssid= is present
+ * the it should contain a passphrase or psk. If no arguments are
+ * provided then AKMP=802.1x, and passphrase should be provided
+ * after association.
+ * End of each parameter should be followed by a ':'(except for the
+ * last parameter) as the delimiter. If ':' has to be used in
+ * an SSID then a '/' should be preceded to ':' as a escape.
+ * Eg:iwpriv <mlanX> passphrase
+ * "1:ssid=mrvl AP:psk=abcdefgh:bssid=00:50:43:ef:23:f3"
+ * iwpriv <mlanX> passphrase
+ * "1:ssid=mrvl/: AP:psk=abcdefgd:bssid=00:50:43:ef:23:f3"
+ * iwpriv <mlanX> passphrase "1:ssid=mrvlAP:psk=abcdefgd"
+ * 3) <ssid="valid ssid"> - This will clear the passphrase
+ * for specified ssid, if none specified then it will clear all.
+ * Eg: iwpriv <mlanX> passphrase 2:ssid=marvell
+ */
+
+ /* -1 is for t_u8 TlvBuffer[1] as this should not be included */
+ cmd->size = sizeof(HostCmd_DS_802_11_SUPPLICANT_PMK) + S_DS_GEN - 1;
+ if (psk->ssid.ssid_len) {
+ pssid_tlv = (MrvlIEtypes_SsIdParamSet_t *) ptlv_buffer;
+ pssid_tlv->header.type = wlan_cpu_to_le16(TLV_TYPE_SSID);
+ pssid_tlv->header.len =
+ (t_u16) MIN(MLAN_MAX_SSID_LENGTH, psk->ssid.ssid_len);
+ memcpy(pmpriv->adapter, (char *) pssid_tlv->ssid, psk->ssid.ssid,
+ MIN(MLAN_MAX_SSID_LENGTH, psk->ssid.ssid_len));
+ ptlv_buffer += (pssid_tlv->header.len + sizeof(MrvlIEtypesHeader_t));
+ cmd->size += (pssid_tlv->header.len + sizeof(MrvlIEtypesHeader_t));
+ pssid_tlv->header.len = wlan_cpu_to_le16(pssid_tlv->header.len);
+ }
+ if (memcmp
+ (pmpriv->adapter, (t_u8 *) & psk->bssid, zero_mac, sizeof(zero_mac))) {
+ pbssid_tlv = (MrvlIEtypes_Bssid_t *) ptlv_buffer;
+ pbssid_tlv->header.type = wlan_cpu_to_le16(TLV_TYPE_BSSID);
+ pbssid_tlv->header.len = MLAN_MAC_ADDR_LENGTH;
+ memcpy(pmpriv->adapter, pbssid_tlv->bssid, (t_u8 *) & psk->bssid,
+ MLAN_MAC_ADDR_LENGTH);
+ ptlv_buffer += (pbssid_tlv->header.len + sizeof(MrvlIEtypesHeader_t));
+ cmd->size += (pbssid_tlv->header.len + sizeof(MrvlIEtypesHeader_t));
+ pbssid_tlv->header.len = wlan_cpu_to_le16(pbssid_tlv->header.len);
+ }
+ if (psk->psk_type == MLAN_PSK_PASSPHRASE) {
+ ppassphrase_tlv = (MrvlIEtypes_Passphrase_t *) ptlv_buffer;
+ ppassphrase_tlv->header.type = wlan_cpu_to_le16(TLV_TYPE_PASSPHRASE);
+ ppassphrase_tlv->header.len =
+ (t_u16) MIN(MLAN_MAX_PASSPHRASE_LENGTH,
+ psk->psk.passphrase.passphrase_len);
+ memcpy(pmpriv->adapter, ppassphrase_tlv->passphrase,
+ psk->psk.passphrase.passphrase, MIN(MLAN_MAX_PASSPHRASE_LENGTH,
+ psk->psk.passphrase.
+ passphrase_len));
+ ptlv_buffer +=
+ (ppassphrase_tlv->header.len + sizeof(MrvlIEtypesHeader_t));
+ cmd->size +=
+ (ppassphrase_tlv->header.len + sizeof(MrvlIEtypesHeader_t));
+ ppassphrase_tlv->header.len =
+ wlan_cpu_to_le16(ppassphrase_tlv->header.len);
+ }
+ if (psk->psk_type == MLAN_PSK_PMK) {
+ ppmk_tlv = (MrvlIEtypes_PMK_t *) ptlv_buffer;
+ ppmk_tlv->header.type = wlan_cpu_to_le16(TLV_TYPE_PMK);
+ ppmk_tlv->header.len = MLAN_MAX_KEY_LENGTH;
+ memcpy(pmpriv->adapter, ppmk_tlv->pmk, psk->psk.pmk.pmk,
+ MLAN_MAX_KEY_LENGTH);
+ ptlv_buffer += (ppmk_tlv->header.len + sizeof(MrvlIEtypesHeader_t));
+ cmd->size += (ppmk_tlv->header.len + sizeof(MrvlIEtypesHeader_t));
+ ppmk_tlv->header.len = wlan_cpu_to_le16(ppmk_tlv->header.len);
+ }
+ if ((cmd_action == HostCmd_ACT_GEN_SET) &&
+ ((pssid_tlv || pbssid_tlv) && (!ppmk_tlv && !ppassphrase_tlv))) {
+ PRINTM(MERROR,
+ "Invalid case,ssid/bssid present without pmk or passphrase\n");
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+ cmd->command = wlan_cpu_to_le16(HostCmd_CMD_SUPPLICANT_PMK);
+ pesupplicant_psk->action = wlan_cpu_to_le16(cmd_action);
+ pesupplicant_psk->cache_result = 0;
+ cmd->size = wlan_cpu_to_le16(cmd->size);
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief Handle the supplicant profile command
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param cmd A pointer to HostCmd_DS_COMMAND structure
+ * @param cmd_action The action: GET or SET
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+static mlan_status
+wlan_cmd_802_11_supplicant_profile(IN pmlan_private pmpriv,
+ IN HostCmd_DS_COMMAND * cmd,
+ IN t_u16 cmd_action)
+{
+ HostCmd_DS_802_11_SUPPLICANT_PROFILE *sup_profile =
+ &cmd->params.esupplicant_profile;
+
+ ENTER();
+
+ cmd->size =
+ wlan_cpu_to_le16(sizeof(HostCmd_DS_802_11_SUPPLICANT_PROFILE) +
+ S_DS_GEN - 1);
+ cmd->command = wlan_cpu_to_le16(HostCmd_CMD_SUPPLICANT_PROFILE);
+ sup_profile->action = wlan_cpu_to_le16(cmd_action);
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function prepares command of rf_channel.
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param cmd A pointer to HostCmd_DS_COMMAND structure
+ * @param cmd_action The action: GET or SET
+ * @param pdata_buf A pointer to data buffer
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+static mlan_status
+wlan_cmd_802_11_rf_channel(IN pmlan_private pmpriv,
+ IN HostCmd_DS_COMMAND * cmd,
+ IN t_u16 cmd_action, IN t_void * pdata_buf)
+{
+ HostCmd_DS_802_11_RF_CHANNEL *prf_chan = &cmd->params.rf_channel;
+
+ ENTER();
+
+ cmd->command = wlan_cpu_to_le16(HostCmd_CMD_802_11_RF_CHANNEL);
+ cmd->size = wlan_cpu_to_le16(sizeof(HostCmd_DS_802_11_RF_CHANNEL)
+ + S_DS_GEN);
+
+ if (cmd_action == HostCmd_ACT_GEN_SET) {
+ if ((pmpriv->adapter->adhoc_start_band & BAND_A)
+ || (pmpriv->adapter->adhoc_start_band & BAND_AN)
+ )
+ prf_chan->rf_type = HostCmd_SCAN_RADIO_TYPE_A;
+ SET_SECONDARYCHAN(prf_chan->rf_type, pmpriv->adapter->chan_bandwidth);
+ prf_chan->rf_type = wlan_cpu_to_le16(prf_chan->rf_type);
+ prf_chan->current_channel = wlan_cpu_to_le16(*((t_u16 *) pdata_buf));
+ }
+ prf_chan->action = wlan_cpu_to_le16(cmd_action);
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function prepares command of ibss_coalescing_status.
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param cmd A pointer to HostCmd_DS_COMMAND structure
+ * @param cmd_action The action: GET or SET
+ * @param pdata_buf A pointer to data buffer or MNULL
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+static mlan_status
+wlan_cmd_ibss_coalescing_status(IN pmlan_private pmpriv,
+ IN HostCmd_DS_COMMAND * cmd,
+ IN t_u16 cmd_action, IN t_void * pdata_buf)
+{
+ HostCmd_DS_802_11_IBSS_STATUS *pibss_coal = &(cmd->params.ibss_coalescing);
+ t_u16 enable = 0;
+
+ ENTER();
+
+ cmd->command = wlan_cpu_to_le16(HostCmd_CMD_802_11_IBSS_COALESCING_STATUS);
+ cmd->size =
+ wlan_cpu_to_le16(sizeof(HostCmd_DS_802_11_IBSS_STATUS) + S_DS_GEN);
+ cmd->result = 0;
+ pibss_coal->action = wlan_cpu_to_le16(cmd_action);
+
+ switch (cmd_action) {
+ case HostCmd_ACT_GEN_SET:
+ if (pdata_buf != MNULL)
+ enable = *(t_u16 *) pdata_buf;
+ pibss_coal->enable = wlan_cpu_to_le16(enable);
+ break;
+
+ /* In other case.. Nothing to do */
+ case HostCmd_ACT_GEN_GET:
+ default:
+ break;
+ }
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function prepares command of mgmt IE list.
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param cmd A pointer to HostCmd_DS_COMMAND structure
+ * @param cmd_action The action: GET or SET
+ * @param pdata_buf A pointer to data buffer
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+static mlan_status
+wlan_cmd_mgmt_ie_list(IN pmlan_private pmpriv,
+ IN HostCmd_DS_COMMAND * cmd,
+ IN t_u16 cmd_action, IN t_void * pdata_buf)
+{
+ t_u16 req_len = 0, travel_len = 0;
+ custom_ie *cptr = MNULL;
+ mlan_ds_misc_custom_ie *cust_ie = MNULL;
+ HostCmd_DS_MGMT_IE_LIST_CFG *pmgmt_ie_list = &(cmd->params.mgmt_ie_list);
+
+ ENTER();
+
+ cmd->command = wlan_cpu_to_le16(HostCmd_CMD_MGMT_IE_LIST);
+ cmd->size = sizeof(HostCmd_DS_MGMT_IE_LIST_CFG) + S_DS_GEN;
+ cmd->result = 0;
+ pmgmt_ie_list->action = wlan_cpu_to_le16(cmd_action);
+
+ cust_ie = (mlan_ds_misc_custom_ie *) pdata_buf;
+ pmgmt_ie_list->ds_mgmt_ie.type = wlan_cpu_to_le16(cust_ie->type);
+ pmgmt_ie_list->ds_mgmt_ie.len = wlan_cpu_to_le16(cust_ie->len);
+
+ if (pmgmt_ie_list->ds_mgmt_ie.ie_data_list && cust_ie->ie_data_list) {
+ req_len = cust_ie->len;
+ travel_len = 0;
+ /* conversion for index, mask, len */
+ if (req_len == sizeof(t_u16))
+ cust_ie->ie_data_list[0].ie_index =
+ wlan_cpu_to_le16(cust_ie->ie_data_list[0].ie_index);
+
+ while (req_len > sizeof(t_u16)) {
+ cptr =
+ (custom_ie *) (((t_u8 *) cust_ie->ie_data_list) + travel_len);
+ travel_len += cptr->ie_length + sizeof(custom_ie) - MAX_IE_SIZE;
+ req_len -= cptr->ie_length + sizeof(custom_ie) - MAX_IE_SIZE;
+ cptr->ie_index = wlan_cpu_to_le16(cptr->ie_index);
+ cptr->mgmt_subtype_mask = wlan_cpu_to_le16(cptr->mgmt_subtype_mask);
+ cptr->ie_length = wlan_cpu_to_le16(cptr->ie_length);
+ }
+ if (cust_ie->len)
+ memcpy(pmpriv->adapter, pmgmt_ie_list->ds_mgmt_ie.ie_data_list,
+ cust_ie->ie_data_list, cust_ie->len);
+ }
+
+ cmd->size -=
+ (MAX_MGMT_IE_INDEX * sizeof(custom_ie)) + sizeof(tlvbuf_max_mgmt_ie);
+ cmd->size += cust_ie->len;
+ cmd->size = wlan_cpu_to_le16(cmd->size);
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function prepares system clock cfg command
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param cmd A pointer to HostCmd_DS_COMMAND structure
+ * @param cmd_action The action: GET or SET
+ * @param pdata_buf A pointer to data buffer
+ * @return MLAN_STATUS_SUCCESS
+ */
+static mlan_status
+wlan_cmd_sysclock_cfg(IN pmlan_private pmpriv,
+ IN HostCmd_DS_COMMAND * cmd,
+ IN t_u16 cmd_action, IN t_void * pdata_buf)
+{
+ HostCmd_DS_ECL_SYSTEM_CLOCK_CONFIG *cfg = &cmd->params.sys_clock_cfg;
+ mlan_ds_misc_sys_clock *clk_cfg = (mlan_ds_misc_sys_clock *) pdata_buf;
+ int i = 0;
+
+ ENTER();
+
+ cmd->command = wlan_cpu_to_le16(HostCmd_CMD_ECL_SYSTEM_CLOCK_CONFIG);
+ cmd->size =
+ wlan_cpu_to_le16(sizeof(HostCmd_DS_ECL_SYSTEM_CLOCK_CONFIG) + S_DS_GEN);
+
+ cfg->action = wlan_cpu_to_le16(cmd_action);
+ cfg->cur_sys_clk = wlan_cpu_to_le16(clk_cfg->cur_sys_clk);
+ cfg->sys_clk_type = wlan_cpu_to_le16(clk_cfg->sys_clk_type);
+ cfg->sys_clk_len = wlan_cpu_to_le16(clk_cfg->sys_clk_num) * sizeof(t_u16);
+ for (i = 0; i < clk_cfg->sys_clk_num; i++)
+ cfg->sys_clk[i] = wlan_cpu_to_le16(clk_cfg->sys_clk[i]);
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function prepares command of reg_access.
+ *
+ * @param cmd A pointer to HostCmd_DS_COMMAND structure
+ * @param cmd_action the action: GET or SET
+ * @param pdata_buf A pointer to data buffer
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+static mlan_status
+wlan_cmd_reg_access(IN HostCmd_DS_COMMAND * cmd,
+ IN t_u16 cmd_action, IN t_void * pdata_buf)
+{
+ mlan_ds_reg_rw *reg_rw;
+
+ ENTER();
+
+ reg_rw = (mlan_ds_reg_rw *) pdata_buf;
+ switch (cmd->command) {
+ case HostCmd_CMD_MAC_REG_ACCESS:
+ {
+ HostCmd_DS_MAC_REG_ACCESS *mac_reg;
+ cmd->size =
+ wlan_cpu_to_le16(sizeof(HostCmd_DS_MAC_REG_ACCESS) + S_DS_GEN);
+ mac_reg = (HostCmd_DS_MAC_REG_ACCESS *) & cmd->params.mac_reg;
+ mac_reg->action = wlan_cpu_to_le16(cmd_action);
+ mac_reg->offset = wlan_cpu_to_le16((t_u16) reg_rw->offset);
+ mac_reg->value = wlan_cpu_to_le32(reg_rw->value);
+ break;
+ }
+ case HostCmd_CMD_BBP_REG_ACCESS:
+ {
+ HostCmd_DS_BBP_REG_ACCESS *bbp_reg;
+ cmd->size =
+ wlan_cpu_to_le16(sizeof(HostCmd_DS_BBP_REG_ACCESS) + S_DS_GEN);
+ bbp_reg = (HostCmd_DS_BBP_REG_ACCESS *) & cmd->params.bbp_reg;
+ bbp_reg->action = wlan_cpu_to_le16(cmd_action);
+ bbp_reg->offset = wlan_cpu_to_le16((t_u16) reg_rw->offset);
+ bbp_reg->value = (t_u8) reg_rw->value;
+ break;
+ }
+ case HostCmd_CMD_RF_REG_ACCESS:
+ {
+ HostCmd_DS_RF_REG_ACCESS *rf_reg;
+ cmd->size =
+ wlan_cpu_to_le16(sizeof(HostCmd_DS_RF_REG_ACCESS) + S_DS_GEN);
+ rf_reg = (HostCmd_DS_RF_REG_ACCESS *) & cmd->params.rf_reg;
+ rf_reg->action = wlan_cpu_to_le16(cmd_action);
+ rf_reg->offset = wlan_cpu_to_le16((t_u16) reg_rw->offset);
+ rf_reg->value = (t_u8) reg_rw->value;
+ break;
+ }
+ case HostCmd_CMD_CAU_REG_ACCESS:
+ {
+ HostCmd_DS_RF_REG_ACCESS *cau_reg;
+ cmd->size =
+ wlan_cpu_to_le16(sizeof(HostCmd_DS_RF_REG_ACCESS) + S_DS_GEN);
+ cau_reg = (HostCmd_DS_RF_REG_ACCESS *) & cmd->params.rf_reg;
+ cau_reg->action = wlan_cpu_to_le16(cmd_action);
+ cau_reg->offset = wlan_cpu_to_le16((t_u16) reg_rw->offset);
+ cau_reg->value = (t_u8) reg_rw->value;
+ break;
+ }
+ case HostCmd_CMD_802_11_EEPROM_ACCESS:
+ {
+ mlan_ds_read_eeprom *rd_eeprom = (mlan_ds_read_eeprom *) pdata_buf;
+ HostCmd_DS_802_11_EEPROM_ACCESS *cmd_eeprom =
+ (HostCmd_DS_802_11_EEPROM_ACCESS *) & cmd->params.eeprom;
+ cmd->size =
+ wlan_cpu_to_le16(sizeof(HostCmd_DS_802_11_EEPROM_ACCESS) +
+ S_DS_GEN);
+ cmd_eeprom->action = wlan_cpu_to_le16(cmd_action);
+ cmd_eeprom->offset = wlan_cpu_to_le16(rd_eeprom->offset);
+ cmd_eeprom->byte_count = wlan_cpu_to_le16(rd_eeprom->byte_count);
+ cmd_eeprom->value = 0;
+ break;
+ }
+ default:
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+ cmd->command = wlan_cpu_to_le16(cmd->command);
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function prepares command of mem_access.
+ *
+ * @param cmd A pointer to HostCmd_DS_COMMAND structure
+ * @param cmd_action the action: GET or SET
+ * @param pdata_buf A pointer to data buffer
+ * @return MLAN_STATUS_SUCCESS
+ */
+static mlan_status
+wlan_cmd_mem_access(IN HostCmd_DS_COMMAND * cmd,
+ IN t_u16 cmd_action, IN t_void * pdata_buf)
+{
+ mlan_ds_mem_rw *mem_rw = (mlan_ds_mem_rw *) pdata_buf;
+ HostCmd_DS_MEM_ACCESS *mem_access =
+ (HostCmd_DS_MEM_ACCESS *) & cmd->params.mem;
+
+ ENTER();
+
+ cmd->command = wlan_cpu_to_le16(HostCmd_CMD_MEM_ACCESS);
+ cmd->size = wlan_cpu_to_le16(sizeof(HostCmd_DS_MEM_ACCESS) + S_DS_GEN);
+
+ mem_access->action = wlan_cpu_to_le16(cmd_action);
+ mem_access->addr = wlan_cpu_to_le32(mem_rw->addr);
+ mem_access->value = wlan_cpu_to_le32(mem_rw->value);
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function prepares command of subscribe event.
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param cmd A pointer to HostCmd_DS_COMMAND structure
+ * @param cmd_action the action: GET or SET
+ * @param pdata_buf A pointer to data buffer
+ * @return MLAN_STATUS_SUCCESS
+ */
+static mlan_status
+wlan_cmd_subscribe_event(IN pmlan_private pmpriv,
+ IN HostCmd_DS_COMMAND * cmd,
+ IN t_u16 cmd_action, IN t_void * pdata_buf)
+{
+ mlan_ds_subscribe_evt *sub_evt = (mlan_ds_subscribe_evt *) pdata_buf;
+ HostCmd_DS_SUBSCRIBE_EVENT *evt =
+ (HostCmd_DS_SUBSCRIBE_EVENT *) & cmd->params.subscribe_event;
+ t_u16 cmd_size = 0;
+ t_u8 *tlv = MNULL;
+ MrvlIEtypes_BeaconLowRssiThreshold_t *rssi_low = MNULL;
+ MrvlIEtypes_BeaconLowSnrThreshold_t *snr_low = MNULL;
+ MrvlIEtypes_FailureCount_t *fail_count = MNULL;
+ MrvlIEtypes_BeaconsMissed_t *beacon_missed = MNULL;
+ MrvlIEtypes_BeaconHighRssiThreshold_t *rssi_high = MNULL;
+ MrvlIEtypes_BeaconHighSnrThreshold_t *snr_high = MNULL;
+ MrvlIEtypes_DataLowRssiThreshold_t *data_rssi_low = MNULL;
+ MrvlIEtypes_DataLowSnrThreshold_t *data_snr_low = MNULL;
+ MrvlIEtypes_DataHighRssiThreshold_t *data_rssi_high = MNULL;
+ MrvlIEtypes_DataHighSnrThreshold_t *data_snr_high = MNULL;
+ MrvlIEtypes_LinkQualityThreshold_t *link_quality = MNULL;
+ MrvlIETypes_PreBeaconMissed_t *pre_bcn_missed = MNULL;
+
+ ENTER();
+
+ cmd->command = wlan_cpu_to_le16(HostCmd_CMD_802_11_SUBSCRIBE_EVENT);
+ evt->action = wlan_cpu_to_le16(cmd_action);
+ cmd_size = sizeof(HostCmd_DS_SUBSCRIBE_EVENT) + S_DS_GEN;
+ if (cmd_action == HostCmd_ACT_GEN_GET)
+ goto done;
+#define HostCmd_ACT_BITWISE_SET 0x02
+ evt->action = wlan_cpu_to_le16(HostCmd_ACT_BITWISE_SET);
+ evt->event_bitmap = wlan_cpu_to_le16(sub_evt->evt_bitmap);
+ tlv = (t_u8 *) cmd + cmd_size;
+ if (sub_evt->evt_bitmap & SUBSCRIBE_EVT_RSSI_LOW) {
+ rssi_low = (MrvlIEtypes_BeaconLowRssiThreshold_t *) tlv;
+ rssi_low->header.type = wlan_cpu_to_le16(TLV_TYPE_RSSI_LOW);
+ rssi_low->header.len =
+ wlan_cpu_to_le16(sizeof(MrvlIEtypes_BeaconLowRssiThreshold_t) -
+ sizeof(MrvlIEtypesHeader_t));
+ rssi_low->value = sub_evt->low_rssi;
+ rssi_low->frequency = sub_evt->low_rssi_freq;
+ tlv += sizeof(MrvlIEtypes_BeaconLowRssiThreshold_t);
+ cmd_size += sizeof(MrvlIEtypes_BeaconLowRssiThreshold_t);
+ }
+ if (sub_evt->evt_bitmap & SUBSCRIBE_EVT_SNR_LOW) {
+ snr_low = (MrvlIEtypes_BeaconLowSnrThreshold_t *) tlv;
+ snr_low->header.type = wlan_cpu_to_le16(TLV_TYPE_SNR_LOW);
+ snr_low->header.len =
+ wlan_cpu_to_le16(sizeof(MrvlIEtypes_BeaconLowSnrThreshold_t) -
+ sizeof(MrvlIEtypesHeader_t));
+ snr_low->value = sub_evt->low_snr;
+ snr_low->frequency = sub_evt->low_snr_freq;
+ tlv += sizeof(MrvlIEtypes_BeaconLowSnrThreshold_t);
+ cmd_size += sizeof(MrvlIEtypes_BeaconLowSnrThreshold_t);
+ }
+ if (sub_evt->evt_bitmap & SUBSCRIBE_EVT_MAX_FAIL) {
+ fail_count = (MrvlIEtypes_FailureCount_t *) tlv;
+ fail_count->header.type = wlan_cpu_to_le16(TLV_TYPE_FAILCOUNT);
+ fail_count->header.len =
+ wlan_cpu_to_le16(sizeof(MrvlIEtypes_FailureCount_t) -
+ sizeof(MrvlIEtypesHeader_t));
+ fail_count->value = sub_evt->failure_count;
+ fail_count->frequency = sub_evt->failure_count_freq;
+ tlv += sizeof(MrvlIEtypes_FailureCount_t);
+ cmd_size += sizeof(MrvlIEtypes_FailureCount_t);
+ }
+ if (sub_evt->evt_bitmap & SUBSCRIBE_EVT_BEACON_MISSED) {
+ beacon_missed = (MrvlIEtypes_BeaconsMissed_t *) tlv;
+ beacon_missed->header.type = wlan_cpu_to_le16(TLV_TYPE_BCNMISS);
+ beacon_missed->header.len =
+ wlan_cpu_to_le16(sizeof(MrvlIEtypes_BeaconsMissed_t) -
+ sizeof(MrvlIEtypesHeader_t));
+ beacon_missed->value = sub_evt->beacon_miss;
+ beacon_missed->frequency = sub_evt->beacon_miss_freq;
+ tlv += sizeof(MrvlIEtypes_BeaconsMissed_t);
+ cmd_size += sizeof(MrvlIEtypes_BeaconsMissed_t);
+ }
+ if (sub_evt->evt_bitmap & SUBSCRIBE_EVT_RSSI_HIGH) {
+ rssi_high = (MrvlIEtypes_BeaconHighRssiThreshold_t *) tlv;
+ rssi_high->header.type = wlan_cpu_to_le16(TLV_TYPE_RSSI_HIGH);
+ rssi_high->header.len =
+ wlan_cpu_to_le16(sizeof(MrvlIEtypes_BeaconHighRssiThreshold_t) -
+ sizeof(MrvlIEtypesHeader_t));
+ rssi_high->value = sub_evt->high_rssi;
+ rssi_high->frequency = sub_evt->high_rssi_freq;
+ tlv += sizeof(MrvlIEtypes_BeaconHighRssiThreshold_t);
+ cmd_size += sizeof(MrvlIEtypes_BeaconHighRssiThreshold_t);
+ }
+ if (sub_evt->evt_bitmap & SUBSCRIBE_EVT_SNR_HIGH) {
+ snr_high = (MrvlIEtypes_BeaconHighSnrThreshold_t *) tlv;
+ snr_high->header.type = wlan_cpu_to_le16(TLV_TYPE_SNR_HIGH);
+ snr_high->header.len =
+ wlan_cpu_to_le16(sizeof(MrvlIEtypes_BeaconHighSnrThreshold_t) -
+ sizeof(MrvlIEtypesHeader_t));
+ snr_high->value = sub_evt->high_snr;
+ snr_high->frequency = sub_evt->high_snr_freq;
+ tlv += sizeof(MrvlIEtypes_BeaconHighSnrThreshold_t);
+ cmd_size += sizeof(MrvlIEtypes_BeaconHighSnrThreshold_t);
+ }
+ if (sub_evt->evt_bitmap & SUBSCRIBE_EVT_DATA_RSSI_LOW) {
+ data_rssi_low = (MrvlIEtypes_DataLowRssiThreshold_t *) tlv;
+ data_rssi_low->header.type = wlan_cpu_to_le16(TLV_TYPE_RSSI_LOW_DATA);
+ data_rssi_low->header.len =
+ wlan_cpu_to_le16(sizeof(MrvlIEtypes_DataLowRssiThreshold_t) -
+ sizeof(MrvlIEtypesHeader_t));
+ data_rssi_low->value = sub_evt->data_low_rssi;
+ data_rssi_low->frequency = sub_evt->data_low_rssi_freq;
+ tlv += sizeof(MrvlIEtypes_DataLowRssiThreshold_t);
+ cmd_size += sizeof(MrvlIEtypes_DataLowRssiThreshold_t);
+ }
+ if (sub_evt->evt_bitmap & SUBSCRIBE_EVT_DATA_SNR_LOW) {
+ data_snr_low = (MrvlIEtypes_DataLowSnrThreshold_t *) tlv;
+ data_snr_low->header.type = wlan_cpu_to_le16(TLV_TYPE_SNR_LOW_DATA);
+ data_snr_low->header.len =
+ wlan_cpu_to_le16(sizeof(MrvlIEtypes_DataLowSnrThreshold_t) -
+ sizeof(MrvlIEtypesHeader_t));
+ data_snr_low->value = sub_evt->data_low_snr;
+ data_snr_low->frequency = sub_evt->data_low_snr_freq;
+ tlv += sizeof(MrvlIEtypes_DataLowSnrThreshold_t);
+ cmd_size += sizeof(MrvlIEtypes_DataLowSnrThreshold_t);
+ }
+ if (sub_evt->evt_bitmap & SUBSCRIBE_EVT_DATA_RSSI_HIGH) {
+ data_rssi_high = (MrvlIEtypes_DataHighRssiThreshold_t *) tlv;
+ data_rssi_high->header.type = wlan_cpu_to_le16(TLV_TYPE_RSSI_HIGH_DATA);
+ data_rssi_high->header.len =
+ wlan_cpu_to_le16(sizeof(MrvlIEtypes_DataHighRssiThreshold_t) -
+ sizeof(MrvlIEtypesHeader_t));
+ data_rssi_high->value = sub_evt->data_high_rssi;
+ data_rssi_high->frequency = sub_evt->data_high_rssi_freq;
+ tlv += sizeof(MrvlIEtypes_DataHighRssiThreshold_t);
+ cmd_size += sizeof(MrvlIEtypes_DataHighRssiThreshold_t);
+ }
+ if (sub_evt->evt_bitmap & SUBSCRIBE_EVT_DATA_SNR_HIGH) {
+ data_snr_high = (MrvlIEtypes_DataHighSnrThreshold_t *) tlv;
+ data_snr_high->header.type = wlan_cpu_to_le16(TLV_TYPE_SNR_HIGH_DATA);
+ data_snr_high->header.len =
+ wlan_cpu_to_le16(sizeof(MrvlIEtypes_DataHighSnrThreshold_t) -
+ sizeof(MrvlIEtypesHeader_t));
+ data_snr_high->value = sub_evt->data_high_snr;
+ data_snr_high->frequency = sub_evt->data_high_snr_freq;
+ tlv += sizeof(MrvlIEtypes_DataHighSnrThreshold_t);
+ cmd_size += sizeof(MrvlIEtypes_DataHighSnrThreshold_t);
+ }
+ if (sub_evt->evt_bitmap & SUBSCRIBE_EVT_LINK_QUALITY) {
+ link_quality = (MrvlIEtypes_LinkQualityThreshold_t *) tlv;
+ link_quality->header.type = wlan_cpu_to_le16(TLV_TYPE_LINK_QUALITY);
+ link_quality->header.len =
+ wlan_cpu_to_le16(sizeof(MrvlIEtypes_LinkQualityThreshold_t) -
+ sizeof(MrvlIEtypesHeader_t));
+ link_quality->link_snr = wlan_cpu_to_le16(sub_evt->link_snr);
+ link_quality->link_snr_freq = wlan_cpu_to_le16(sub_evt->link_snr_freq);
+ link_quality->link_rate = wlan_cpu_to_le16(sub_evt->link_rate);
+ link_quality->link_rate_freq =
+ wlan_cpu_to_le16(sub_evt->link_rate_freq);
+ link_quality->link_tx_latency =
+ wlan_cpu_to_le16(sub_evt->link_tx_latency);
+ link_quality->link_tx_lantency_freq =
+ wlan_cpu_to_le16(sub_evt->link_tx_lantency_freq);
+ tlv += sizeof(MrvlIEtypes_LinkQualityThreshold_t);
+ cmd_size += sizeof(MrvlIEtypes_LinkQualityThreshold_t);
+ }
+ if (sub_evt->evt_bitmap & SUBSCRIBE_EVT_PRE_BEACON_LOST) {
+ pre_bcn_missed = (MrvlIETypes_PreBeaconMissed_t *) tlv;
+ pre_bcn_missed->header.type = wlan_cpu_to_le16(TLV_TYPE_PRE_BCNMISS);
+ pre_bcn_missed->header.len =
+ wlan_cpu_to_le16(sizeof(MrvlIETypes_PreBeaconMissed_t) -
+ sizeof(MrvlIEtypesHeader_t));
+ pre_bcn_missed->value = sub_evt->pre_beacon_miss;
+ pre_bcn_missed->frequency = 0;
+ tlv += sizeof(MrvlIETypes_PreBeaconMissed_t);
+ cmd_size += sizeof(MrvlIETypes_PreBeaconMissed_t);
+ }
+ done:
+ cmd->size = wlan_cpu_to_le16(cmd_size);
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function prepares inactivity timeout command
+ *
+ * @param cmd A pointer to HostCmd_DS_COMMAND structure
+ * @param cmd_action the action: GET or SET
+ * @param pdata_buf A pointer to data buffer
+ * @return MLAN_STATUS_SUCCESS
+ */
+static mlan_status
+wlan_cmd_inactivity_timeout(IN HostCmd_DS_COMMAND * cmd,
+ IN t_u16 cmd_action, IN t_void * pdata_buf)
+{
+ pmlan_ds_inactivity_to inac_to;
+ HostCmd_DS_INACTIVITY_TIMEOUT_EXT *cmd_inac_to = &cmd->params.inactivity_to;
+
+ ENTER();
+
+ inac_to = (mlan_ds_inactivity_to *) pdata_buf;
+
+ cmd->size =
+ wlan_cpu_to_le16(sizeof(HostCmd_DS_INACTIVITY_TIMEOUT_EXT) + S_DS_GEN);
+ cmd->command = wlan_cpu_to_le16(cmd->command);
+ cmd_inac_to->action = wlan_cpu_to_le16(cmd_action);
+ if (cmd_action == HostCmd_ACT_GEN_SET) {
+ cmd_inac_to->timeout_unit =
+ wlan_cpu_to_le16((t_u16) inac_to->timeout_unit);
+ cmd_inac_to->unicast_timeout =
+ wlan_cpu_to_le16((t_u16) inac_to->unicast_timeout);
+ cmd_inac_to->mcast_timeout =
+ wlan_cpu_to_le16((t_u16) inac_to->mcast_timeout);
+ cmd_inac_to->ps_entry_timeout =
+ wlan_cpu_to_le16((t_u16) inac_to->ps_entry_timeout);
+ }
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/********************************************************
+ Global Functions
+********************************************************/
+
+/**
+ * @brief This function prepare the command before sending to firmware.
+ *
+ * @param priv A pointer to mlan_private structure
+ * @param cmd_no Command number
+ * @param cmd_action Command action: GET or SET
+ * @param cmd_oid Cmd oid: treated as sub command
+ * @param pioctl_buf A pointer to MLAN IOCTL Request buffer
+ * @param pdata_buf A pointer to information buffer
+ * @param pcmd_buf A pointer to cmd buf
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status
+wlan_ops_sta_prepare_cmd(IN t_void * priv,
+ IN t_u16 cmd_no,
+ IN t_u16 cmd_action,
+ IN t_u32 cmd_oid,
+ IN t_void * pioctl_buf,
+ IN t_void * pdata_buf, IN t_void * pcmd_buf)
+{
+ HostCmd_DS_COMMAND *cmd_ptr = (HostCmd_DS_COMMAND *) pcmd_buf;
+ mlan_private *pmpriv = (mlan_private *) priv;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ /* Prepare command */
+ switch (cmd_no) {
+ case HostCmd_CMD_GET_HW_SPEC:
+ ret = wlan_cmd_get_hw_spec(pmpriv, cmd_ptr);
+ break;
+ case HostCmd_CMD_CFG_DATA:
+ ret = wlan_cmd_cfg_data(pmpriv, cmd_ptr, cmd_action, pdata_buf);
+ break;
+ case HostCmd_CMD_MAC_CONTROL:
+ ret = wlan_cmd_mac_control(pmpriv, cmd_ptr, cmd_action, pdata_buf);
+ break;
+ case HostCmd_CMD_802_11_MAC_ADDRESS:
+ ret = wlan_cmd_802_11_mac_address(pmpriv, cmd_ptr, cmd_action);
+ break;
+ case HostCmd_CMD_MAC_MULTICAST_ADR:
+ ret =
+ wlan_cmd_mac_multicast_adr(pmpriv, cmd_ptr, cmd_action, pdata_buf);
+ break;
+ case HostCmd_CMD_TX_RATE_CFG:
+ ret = wlan_cmd_tx_rate_cfg(pmpriv, cmd_ptr, cmd_action, pdata_buf);
+ break;
+ case HostCmd_CMD_802_11_RF_ANTENNA:
+ ret =
+ wlan_cmd_802_11_rf_antenna(pmpriv, cmd_ptr, cmd_action, pdata_buf);
+ break;
+ case HostCmd_CMD_TXPWR_CFG:
+ ret = wlan_cmd_tx_power_cfg(pmpriv, cmd_ptr, cmd_action, pdata_buf);
+ break;
+ case HostCmd_CMD_802_11_RF_TX_POWER:
+ ret = wlan_cmd_802_11_rf_tx_power(pmpriv, cmd_ptr,
+ cmd_action, pdata_buf);
+ break;
+ case HostCmd_CMD_802_11_PS_MODE_ENH:
+ ret =
+ wlan_cmd_enh_power_mode(pmpriv, cmd_ptr, cmd_action,
+ (t_u16) cmd_oid, pdata_buf);
+ break;
+ case HostCmd_CMD_802_11_HS_CFG_ENH:
+ ret =
+ wlan_cmd_802_11_hs_cfg(pmpriv, cmd_ptr, cmd_action,
+ (hs_config_param *) pdata_buf);
+ break;
+ case HostCmd_CMD_802_11_SLEEP_PERIOD:
+ ret = wlan_cmd_802_11_sleep_period(pmpriv, cmd_ptr,
+ cmd_action, (t_u16 *) pdata_buf);
+ break;
+ case HostCmd_CMD_802_11_SLEEP_PARAMS:
+ ret = wlan_cmd_802_11_sleep_params(pmpriv, cmd_ptr,
+ cmd_action, (t_u16 *) pdata_buf);
+ break;
+ case HostCmd_CMD_802_11_SCAN:
+ ret = wlan_cmd_802_11_scan(pmpriv, cmd_ptr, pdata_buf);
+ break;
+ case HostCmd_CMD_802_11_BG_SCAN_CONFIG:
+ ret = wlan_cmd_bgscan_config(pmpriv, cmd_ptr, pdata_buf);
+ break;
+ case HostCmd_CMD_802_11_BG_SCAN_QUERY:
+ ret = wlan_cmd_802_11_bg_scan_query(pmpriv, cmd_ptr, pdata_buf);
+ break;
+ case HostCmd_CMD_802_11_ASSOCIATE:
+ ret = wlan_cmd_802_11_associate(pmpriv, cmd_ptr, pdata_buf);
+ break;
+ case HostCmd_CMD_802_11_DEAUTHENTICATE:
+ ret = wlan_cmd_802_11_deauthenticate(pmpriv, cmd_ptr, pdata_buf);
+ break;
+ case HostCmd_CMD_802_11_AD_HOC_START:
+ ret = wlan_cmd_802_11_ad_hoc_start(pmpriv, cmd_ptr, pdata_buf);
+ break;
+ case HostCmd_CMD_802_11_AD_HOC_JOIN:
+ ret = wlan_cmd_802_11_ad_hoc_join(pmpriv, cmd_ptr, pdata_buf);
+ break;
+ case HostCmd_CMD_802_11_AD_HOC_STOP:
+ ret = wlan_cmd_802_11_ad_hoc_stop(pmpriv, cmd_ptr);
+ break;
+ case HostCmd_CMD_802_11_GET_LOG:
+ ret = wlan_cmd_802_11_get_log(pmpriv, cmd_ptr);
+ break;
+ case HostCmd_CMD_RSSI_INFO:
+ ret = wlan_cmd_802_11_rssi_info(pmpriv, cmd_ptr, cmd_action);
+ break;
+ case HostCmd_CMD_802_11_SNMP_MIB:
+ ret =
+ wlan_cmd_802_11_snmp_mib(pmpriv, cmd_ptr, cmd_action, cmd_oid,
+ pdata_buf);
+ break;
+ case HostCmd_CMD_802_11_RADIO_CONTROL:
+ ret =
+ wlan_cmd_802_11_radio_control(pmpriv, cmd_ptr, cmd_action,
+ pdata_buf);
+ break;
+ case HostCmd_CMD_802_11_TX_RATE_QUERY:
+ cmd_ptr->command = wlan_cpu_to_le16(HostCmd_CMD_802_11_TX_RATE_QUERY);
+ cmd_ptr->size =
+ wlan_cpu_to_le16(sizeof(HostCmd_TX_RATE_QUERY) + S_DS_GEN);
+ pmpriv->tx_rate = 0;
+ ret = MLAN_STATUS_SUCCESS;
+ break;
+ case HostCmd_CMD_VERSION_EXT:
+ cmd_ptr->command = wlan_cpu_to_le16(cmd_no);
+ cmd_ptr->params.verext.version_str_sel =
+ (t_u8) (*((t_u32 *) pdata_buf));
+ cmd_ptr->size =
+ wlan_cpu_to_le16(sizeof(HostCmd_DS_VERSION_EXT) + S_DS_GEN);
+ ret = MLAN_STATUS_SUCCESS;
+ break;
+ case HostCmd_CMD_RX_MGMT_IND:
+ cmd_ptr->command = wlan_cpu_to_le16(cmd_no);
+ cmd_ptr->params.rx_mgmt_ind.action = wlan_cpu_to_le16(cmd_action);
+ cmd_ptr->params.rx_mgmt_ind.mgmt_subtype_mask =
+ wlan_cpu_to_le32((t_u32) (*((t_u32 *) pdata_buf)));
+ cmd_ptr->size = wlan_cpu_to_le16(sizeof(t_u32) + S_DS_GEN);
+ break;
+ case HostCmd_CMD_802_11_RF_CHANNEL:
+ ret =
+ wlan_cmd_802_11_rf_channel(pmpriv, cmd_ptr, cmd_action, pdata_buf);
+ break;
+ case HostCmd_CMD_FUNC_INIT:
+ if (pmpriv->adapter->hw_status == WlanHardwareStatusReset)
+ pmpriv->adapter->hw_status = WlanHardwareStatusInitializing;
+ cmd_ptr->command = wlan_cpu_to_le16(cmd_no);
+ cmd_ptr->size = wlan_cpu_to_le16(S_DS_GEN);
+ break;
+ case HostCmd_CMD_FUNC_SHUTDOWN:
+ pmpriv->adapter->hw_status = WlanHardwareStatusReset;
+ cmd_ptr->command = wlan_cpu_to_le16(cmd_no);
+ cmd_ptr->size = wlan_cpu_to_le16(S_DS_GEN);
+ break;
+ case HostCmd_CMD_SOFT_RESET:
+ cmd_ptr->command = wlan_cpu_to_le16(cmd_no);
+ cmd_ptr->size = wlan_cpu_to_le16(S_DS_GEN);
+ break;
+ case HostCmd_CMD_11N_ADDBA_REQ:
+ ret = wlan_cmd_11n_addba_req(pmpriv, cmd_ptr, pdata_buf);
+ break;
+ case HostCmd_CMD_11N_DELBA:
+ ret = wlan_cmd_11n_delba(pmpriv, cmd_ptr, pdata_buf);
+ break;
+ case HostCmd_CMD_11N_ADDBA_RSP:
+ ret = wlan_cmd_11n_addba_rspgen(pmpriv, cmd_ptr, pdata_buf);
+ break;
+ case HostCmd_CMD_802_11_KEY_MATERIAL:
+ ret =
+ wlan_cmd_802_11_key_material(pmpriv, cmd_ptr, cmd_action, cmd_oid,
+ pdata_buf);
+ break;
+
+ case HostCmd_CMD_SUPPLICANT_PMK:
+ ret = wlan_cmd_802_11_supplicant_pmk(pmpriv, cmd_ptr, cmd_action,
+ pdata_buf);
+ break;
+ case HostCmd_CMD_SUPPLICANT_PROFILE:
+ ret = wlan_cmd_802_11_supplicant_profile(pmpriv, cmd_ptr, cmd_action);
+ break;
+
+ case HostCmd_CMD_802_11D_DOMAIN_INFO:
+ ret = wlan_cmd_802_11d_domain_info(pmpriv, cmd_ptr, cmd_action);
+ break;
+ case HostCmd_CMD_802_11_TPC_ADAPT_REQ:
+ case HostCmd_CMD_802_11_TPC_INFO:
+ case HostCmd_CMD_802_11_CHAN_SW_ANN:
+ case HostCmd_CMD_CHAN_REPORT_REQUEST:
+ ret = wlan_11h_cmd_process(pmpriv, cmd_ptr, pdata_buf);
+ break;
+ case HostCmd_CMD_RECONFIGURE_TX_BUFF:
+ ret = wlan_cmd_recfg_tx_buf(pmpriv, cmd_ptr, cmd_action, pdata_buf);
+ break;
+ case HostCmd_CMD_AMSDU_AGGR_CTRL:
+ ret = wlan_cmd_amsdu_aggr_ctrl(pmpriv, cmd_ptr, cmd_action, pdata_buf);
+ break;
+ case HostCmd_CMD_11N_CFG:
+ ret = wlan_cmd_11n_cfg(pmpriv, cmd_ptr, cmd_action, pdata_buf);
+ break;
+ case HostCmd_CMD_TX_BF_CFG:
+ ret = wlan_cmd_tx_bf_cfg(pmpriv, cmd_ptr, cmd_action, pdata_buf);
+ break;
+ case HostCmd_CMD_WMM_GET_STATUS:
+ PRINTM(MINFO, "WMM: WMM_GET_STATUS cmd sent\n");
+ cmd_ptr->command = wlan_cpu_to_le16(HostCmd_CMD_WMM_GET_STATUS);
+ cmd_ptr->size =
+ wlan_cpu_to_le16(sizeof(HostCmd_DS_WMM_GET_STATUS) + S_DS_GEN);
+ ret = MLAN_STATUS_SUCCESS;
+ break;
+ case HostCmd_CMD_WMM_ADDTS_REQ:
+ ret = wlan_cmd_wmm_addts_req(pmpriv, cmd_ptr, pdata_buf);
+ break;
+ case HostCmd_CMD_WMM_DELTS_REQ:
+ ret = wlan_cmd_wmm_delts_req(pmpriv, cmd_ptr, pdata_buf);
+ break;
+ case HostCmd_CMD_WMM_QUEUE_CONFIG:
+ ret = wlan_cmd_wmm_queue_config(pmpriv, cmd_ptr, pdata_buf);
+ break;
+ case HostCmd_CMD_WMM_QUEUE_STATS:
+ ret = wlan_cmd_wmm_queue_stats(pmpriv, cmd_ptr, pdata_buf);
+ break;
+ case HostCmd_CMD_WMM_TS_STATUS:
+ ret = wlan_cmd_wmm_ts_status(pmpriv, cmd_ptr, pdata_buf);
+ break;
+ case HostCmd_CMD_802_11_IBSS_COALESCING_STATUS:
+ ret =
+ wlan_cmd_ibss_coalescing_status(pmpriv, cmd_ptr, cmd_action,
+ pdata_buf);
+ break;
+ case HostCmd_CMD_MGMT_IE_LIST:
+ ret = wlan_cmd_mgmt_ie_list(pmpriv, cmd_ptr, cmd_action, pdata_buf);
+ break;
+ case HostCmd_CMD_802_11_SCAN_EXT:
+ ret = wlan_cmd_802_11_scan_ext(pmpriv, cmd_ptr, pdata_buf);
+ break;
+ case HostCmd_CMD_ECL_SYSTEM_CLOCK_CONFIG:
+ ret = wlan_cmd_sysclock_cfg(pmpriv, cmd_ptr, cmd_action, pdata_buf);
+ break;
+ case HostCmd_CMD_MAC_REG_ACCESS:
+ case HostCmd_CMD_BBP_REG_ACCESS:
+ case HostCmd_CMD_RF_REG_ACCESS:
+ case HostCmd_CMD_CAU_REG_ACCESS:
+ case HostCmd_CMD_802_11_EEPROM_ACCESS:
+ ret = wlan_cmd_reg_access(cmd_ptr, cmd_action, pdata_buf);
+ break;
+ case HostCmd_CMD_MEM_ACCESS:
+ ret = wlan_cmd_mem_access(cmd_ptr, cmd_action, pdata_buf);
+ break;
+ case HostCmd_CMD_INACTIVITY_TIMEOUT_EXT:
+ ret = wlan_cmd_inactivity_timeout(cmd_ptr, cmd_action, pdata_buf);
+ break;
+ case HostCmd_CMD_SDIO_GPIO_INT_CONFIG:
+ ret = wlan_cmd_sdio_gpio_int(pmpriv, cmd_ptr, cmd_action, pdata_buf);
+ break;
+ case HostCmd_CMD_SET_BSS_MODE:
+ cmd_ptr->command = wlan_cpu_to_le16(cmd_no);
+#ifdef WIFI_DIRECT_SUPPORT
+ if (pdata_buf) {
+ cmd_ptr->params.bss_mode.con_type = *(t_u8 *) pdata_buf;
+ } else
+#endif
+ if (pmpriv->bss_mode == MLAN_BSS_MODE_IBSS)
+ cmd_ptr->params.bss_mode.con_type = CONNECTION_TYPE_ADHOC;
+ else if (pmpriv->bss_mode == MLAN_BSS_MODE_INFRA)
+ cmd_ptr->params.bss_mode.con_type = CONNECTION_TYPE_INFRA;
+ cmd_ptr->size =
+ wlan_cpu_to_le16(sizeof(HostCmd_DS_SET_BSS_MODE) + S_DS_GEN);
+ ret = MLAN_STATUS_SUCCESS;
+ break;
+ case HostCmd_CMD_MEASUREMENT_REQUEST:
+ case HostCmd_CMD_MEASUREMENT_REPORT:
+ ret = wlan_meas_cmd_process(pmpriv, cmd_ptr, pdata_buf);
+ break;
+#ifdef WIFI_DIRECT_SUPPORT
+ case HostCmd_CMD_802_11_REMAIN_ON_CHANNEL:
+ ret =
+ wlan_cmd_remain_on_channel(pmpriv, cmd_ptr, cmd_action, pdata_buf);
+ break;
+ case HOST_CMD_WIFI_DIRECT_MODE_CONFIG:
+ ret = wlan_cmd_wifi_direct_mode(pmpriv, cmd_ptr, cmd_action, pdata_buf);
+ break;
+#endif
+ case HostCmd_CMD_802_11_SUBSCRIBE_EVENT:
+ ret = wlan_cmd_subscribe_event(pmpriv, cmd_ptr, cmd_action, pdata_buf);
+ break;
+ default:
+ PRINTM(MERROR, "PREP_CMD: unknown command- %#x\n", cmd_no);
+ ret = MLAN_STATUS_FAILURE;
+ break;
+ }
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function issues commands to initialize firmware
+ *
+ * @param priv A pointer to mlan_private structure
+ * @param first_bss flag for first BSS
+ *
+ * @return MLAN_STATUS_PENDING or MLAN_STATUS_FAILURE
+ */
+mlan_status
+wlan_ops_sta_init_cmd(IN t_void * priv, IN t_u8 first_bss)
+{
+ pmlan_private pmpriv = (pmlan_private) priv;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ t_u16 enable = MTRUE;
+ mlan_ds_11n_amsdu_aggr_ctrl amsdu_aggr_ctrl;
+
+ ENTER();
+
+ if (first_bss == MTRUE) {
+ ret = wlan_adapter_init_cmd(pmpriv->adapter);
+ if (ret == MLAN_STATUS_FAILURE)
+ goto done;
+ }
+
+ /* get tx rate */
+ ret = wlan_prepare_cmd(pmpriv,
+ HostCmd_CMD_TX_RATE_CFG,
+ HostCmd_ACT_GEN_GET, 0, MNULL, MNULL);
+ if (ret) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ pmpriv->data_rate = 0;
+
+ /* get tx power */
+ ret = wlan_prepare_cmd(pmpriv,
+ HostCmd_CMD_802_11_RF_TX_POWER,
+ HostCmd_ACT_GEN_GET, 0, MNULL, MNULL);
+ if (ret) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ /* set ibss coalescing_status */
+ ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_802_11_IBSS_COALESCING_STATUS,
+ HostCmd_ACT_GEN_SET, 0, MNULL, &enable);
+ if (ret) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ memset(pmpriv->adapter, &amsdu_aggr_ctrl, 0, sizeof(amsdu_aggr_ctrl));
+ amsdu_aggr_ctrl.enable = MLAN_ACT_ENABLE;
+ /* Send request to firmware */
+ ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_AMSDU_AGGR_CTRL,
+ HostCmd_ACT_GEN_SET, 0, MNULL,
+ (t_void *) & amsdu_aggr_ctrl);
+ if (ret) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ /* MAC Control must be the last command in init_fw */
+ /* set MAC Control */
+ ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_MAC_CONTROL,
+ HostCmd_ACT_GEN_SET, 0, MNULL,
+ &pmpriv->curr_pkt_filter);
+ if (ret) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ /** set last_init_cmd */
+ pmpriv->adapter->last_init_cmd = HostCmd_CMD_MAC_CONTROL;
+
+ if (first_bss == MFALSE) {
+ /* Get MAC address */
+ ret = wlan_prepare_cmd(pmpriv,
+ HostCmd_CMD_802_11_MAC_ADDRESS,
+ HostCmd_ACT_GEN_GET, 0, MNULL, MNULL);
+ if (ret) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ pmpriv->adapter->last_init_cmd = HostCmd_CMD_802_11_MAC_ADDRESS;
+ }
+
+ ret = MLAN_STATUS_PENDING;
+ done:
+ LEAVE();
+ return ret;
+}
diff --git a/drivers/net/wireless/sd8797/mlan/mlan_sta_cmdresp.c b/drivers/net/wireless/sd8797/mlan/mlan_sta_cmdresp.c
new file mode 100644
index 000000000000..19ff2ef7fdf2
--- /dev/null
+++ b/drivers/net/wireless/sd8797/mlan/mlan_sta_cmdresp.c
@@ -0,0 +1,1640 @@
+/** @file mlan_sta_cmdresp.c
+ *
+ * @brief This file contains the handling of command
+ * responses generated by firmware.
+ *
+ * Copyright (C) 2008-2011, Marvell International Ltd.
+ *
+ * This software file (the "File") is distributed by Marvell International
+ * Ltd. under the terms of the GNU General Public License Version 2, June 1991
+ * (the "License"). You may use, redistribute and/or modify this File in
+ * accordance with the terms and conditions of the License, a copy of which
+ * is available by writing to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
+ * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
+ *
+ * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
+ * ARE EXPRESSLY DISCLAIMED. The License provides additional details about
+ * this warranty disclaimer.
+ */
+
+/******************************************************
+Change log:
+ 10/21/2008: initial version
+******************************************************/
+
+#include "mlan.h"
+#include "mlan_join.h"
+#include "mlan_util.h"
+#include "mlan_fw.h"
+#include "mlan_main.h"
+#include "mlan_wmm.h"
+#include "mlan_11n.h"
+#include "mlan_11h.h"
+
+#include "mlan_sdio.h"
+#include "mlan_meas.h"
+
+/********************************************************
+ Local Variables
+********************************************************/
+
+/********************************************************
+ Global Variables
+********************************************************/
+
+/********************************************************
+ Local Functions
+********************************************************/
+/**
+ * @brief This function handles the command response error
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param resp A pointer to HostCmd_DS_COMMAND
+ * @param pioctl_buf A pointer to command buffer
+ *
+ * @return N/A
+ */
+static void
+wlan_process_cmdresp_error(mlan_private * pmpriv, HostCmd_DS_COMMAND * resp,
+ mlan_ioctl_req * pioctl_buf)
+{
+ mlan_adapter *pmadapter = pmpriv->adapter;
+
+ ENTER();
+
+ PRINTM(MERROR, "CMD_RESP: cmd %#x error, result=%#x\n",
+ resp->command, resp->result);
+ if (pioctl_buf)
+ pioctl_buf->status_code = MLAN_ERROR_FW_CMDRESP;
+
+ switch (resp->command) {
+ case HostCmd_CMD_802_11_PS_MODE_ENH:
+ {
+ HostCmd_DS_802_11_PS_MODE_ENH *pm = &resp->params.psmode_enh;
+ PRINTM(MERROR,
+ "PS_MODE_ENH command failed: result=0x%x action=0x%X\n",
+ resp->result, wlan_le16_to_cpu(pm->action));
+ /*
+ * We do not re-try enter-ps command in ad-hoc mode.
+ */
+ if (wlan_le16_to_cpu(pm->action) == EN_AUTO_PS &&
+ (wlan_le16_to_cpu(pm->params.auto_ps.ps_bitmap) & BITMAP_STA_PS)
+ && pmpriv->bss_mode == MLAN_BSS_MODE_IBSS)
+ pmadapter->ps_mode = Wlan802_11PowerModeCAM;
+ }
+ break;
+ case HostCmd_CMD_802_11_SCAN_EXT:
+ case HostCmd_CMD_802_11_SCAN:
+ /* Cancel all pending scan command */
+ wlan_flush_scan_queue(pmadapter);
+ wlan_recv_event(pmpriv, MLAN_EVENT_ID_DRV_SCAN_REPORT, MNULL);
+ break;
+
+ case HostCmd_CMD_MAC_CONTROL:
+ break;
+
+ default:
+ break;
+ }
+ /*
+ * Handling errors here
+ */
+ wlan_insert_cmd_to_free_q(pmadapter, pmadapter->curr_cmd);
+
+ wlan_request_cmd_lock(pmadapter);
+ pmadapter->curr_cmd = MNULL;
+ wlan_release_cmd_lock(pmadapter);
+
+ LEAVE();
+ return;
+}
+
+/**
+ * @brief This function handles the command response of RSSI info
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param resp A pointer to HostCmd_DS_COMMAND
+ * @param pioctl_buf A pointer to mlan_ioctl_req structure
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+static mlan_status
+wlan_ret_802_11_rssi_info(IN pmlan_private pmpriv,
+ IN HostCmd_DS_COMMAND * resp,
+ IN mlan_ioctl_req * pioctl_buf)
+{
+ HostCmd_DS_802_11_RSSI_INFO_RSP *prssi_info_rsp =
+ &resp->params.rssi_info_rsp;
+ mlan_ds_get_info *pget_info = MNULL;
+
+ ENTER();
+
+ pmpriv->data_rssi_last = wlan_le16_to_cpu(prssi_info_rsp->data_rssi_last);
+ pmpriv->data_nf_last = wlan_le16_to_cpu(prssi_info_rsp->data_nf_last);
+
+ pmpriv->data_rssi_avg = wlan_le16_to_cpu(prssi_info_rsp->data_rssi_avg);
+ pmpriv->data_nf_avg = wlan_le16_to_cpu(prssi_info_rsp->data_nf_avg);
+
+ pmpriv->bcn_rssi_last = wlan_le16_to_cpu(prssi_info_rsp->bcn_rssi_last);
+ pmpriv->bcn_nf_last = wlan_le16_to_cpu(prssi_info_rsp->bcn_nf_last);
+
+ pmpriv->bcn_rssi_avg = wlan_le16_to_cpu(prssi_info_rsp->bcn_rssi_avg);
+ pmpriv->bcn_nf_avg = wlan_le16_to_cpu(prssi_info_rsp->bcn_nf_avg);
+
+ /* Need to indicate IOCTL complete */
+ if (pioctl_buf != MNULL) {
+ pget_info = (mlan_ds_get_info *) pioctl_buf->pbuf;
+
+ memset(pmpriv->adapter, &pget_info->param.signal, 0,
+ sizeof(mlan_ds_get_signal));
+
+ pget_info->param.signal.selector = ALL_RSSI_INFO_MASK;
+
+ /* RSSI */
+ pget_info->param.signal.bcn_rssi_last = pmpriv->bcn_rssi_last;
+ pget_info->param.signal.bcn_rssi_avg = pmpriv->bcn_rssi_avg;
+ pget_info->param.signal.data_rssi_last = pmpriv->data_rssi_last;
+ pget_info->param.signal.data_rssi_avg = pmpriv->data_rssi_avg;
+
+ /* SNR */
+ pget_info->param.signal.bcn_snr_last =
+ CAL_SNR(pmpriv->bcn_rssi_last, pmpriv->bcn_nf_last);
+ pget_info->param.signal.bcn_snr_avg =
+ CAL_SNR(pmpriv->bcn_rssi_avg, pmpriv->bcn_nf_avg);
+ pget_info->param.signal.data_snr_last =
+ CAL_SNR(pmpriv->data_rssi_last, pmpriv->data_nf_last);
+ pget_info->param.signal.data_snr_avg =
+ CAL_SNR(pmpriv->data_rssi_avg, pmpriv->data_nf_avg);
+
+ /* NF */
+ pget_info->param.signal.bcn_nf_last = pmpriv->bcn_nf_last;
+ pget_info->param.signal.bcn_nf_avg = pmpriv->bcn_nf_avg;
+ pget_info->param.signal.data_nf_last = pmpriv->data_nf_last;
+ pget_info->param.signal.data_nf_avg = pmpriv->data_nf_avg;
+
+ pioctl_buf->data_read_written = sizeof(mlan_ds_get_info);
+ }
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function handles the command response of mac_control
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param resp A pointer to HostCmd_DS_COMMAND
+ * @param pioctl_buf A pointer to mlan_ioctl_req structure
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+static mlan_status
+wlan_ret_mac_control(IN pmlan_private pmpriv,
+ IN HostCmd_DS_COMMAND * resp,
+ IN mlan_ioctl_req * pioctl_buf)
+{
+ ENTER();
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function handles the command response of snmp_mib
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param resp A pointer to HostCmd_DS_COMMAND
+ * @param pioctl_buf A pointer to mlan_ioctl_req structure
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+static mlan_status
+wlan_ret_802_11_snmp_mib(IN pmlan_private pmpriv,
+ IN HostCmd_DS_COMMAND * resp,
+ IN mlan_ioctl_req * pioctl_buf)
+{
+ HostCmd_DS_802_11_SNMP_MIB *psmib = &resp->params.smib;
+ t_u16 oid = wlan_le16_to_cpu(psmib->oid);
+ t_u16 query_type = wlan_le16_to_cpu(psmib->query_type);
+ t_u32 ul_temp;
+ mlan_ds_snmp_mib *mib = MNULL;
+
+ ENTER();
+
+ if (pioctl_buf)
+ mib = (mlan_ds_snmp_mib *) pioctl_buf->pbuf;
+
+ PRINTM(MINFO, "SNMP_RESP: value of the oid = 0x%x, query_type=0x%x\n", oid,
+ query_type);
+ PRINTM(MINFO, "SNMP_RESP: Buf size = 0x%x\n",
+ wlan_le16_to_cpu(psmib->buf_size));
+ if (query_type == HostCmd_ACT_GEN_GET) {
+ switch (oid) {
+ case FragThresh_i:
+ ul_temp = wlan_le16_to_cpu(*((t_u16 *) (psmib->value)));
+ PRINTM(MINFO, "SNMP_RESP: FragThsd =%u\n", ul_temp);
+ if (mib)
+ mib->param.frag_threshold = ul_temp;
+ break;
+
+ case RtsThresh_i:
+ ul_temp = wlan_le16_to_cpu(*((t_u16 *) (psmib->value)));
+ PRINTM(MINFO, "SNMP_RESP: RTSThsd =%u\n", ul_temp);
+ if (mib)
+ mib->param.rts_threshold = ul_temp;
+ break;
+
+ case ShortRetryLim_i:
+ ul_temp = wlan_le16_to_cpu(*((t_u16 *) (psmib->value)));
+ PRINTM(MINFO, "SNMP_RESP: TxRetryCount=%u\n", ul_temp);
+ if (mib)
+ mib->param.retry_count = ul_temp;
+ break;
+ case WwsMode_i:
+ ul_temp = wlan_le16_to_cpu(*((t_u16 *) (psmib->value)));
+ PRINTM(MINFO, "SNMP_RESP: WWSCfg =%u\n", ul_temp);
+ if (pioctl_buf)
+ ((mlan_ds_misc_cfg *) pioctl_buf->pbuf)->param.wws_cfg =
+ ul_temp;
+ break;
+ case Thermal_i:
+ ul_temp = wlan_le32_to_cpu(*((t_u32 *) (psmib->value)));
+ PRINTM(MINFO, "SNMP_RESP: Thermal =%u\n", ul_temp);
+ if (pioctl_buf)
+ ((mlan_ds_misc_cfg *) pioctl_buf->pbuf)->param.thermal =
+ ul_temp;
+ break;
+
+ default:
+ break;
+ }
+ } else { /* (query_type == HostCmd_ACT_GEN_SET) */
+ /* Update state for 11d */
+ if (oid == Dot11D_i) {
+ ul_temp = wlan_le16_to_cpu(*((t_u16 *) (psmib->value)));
+ /* Set 11d state to private */
+ pmpriv->state_11d.enable_11d = ul_temp;
+ /* Set user enable flag if called from ioctl */
+ if (pioctl_buf)
+ pmpriv->state_11d.user_enable_11d = ul_temp;
+ }
+ /* Update state for 11h */
+ if (oid == Dot11H_i) {
+ ul_temp = wlan_le16_to_cpu(*((t_u16 *) (psmib->value)));
+ /* Set 11h state to priv */
+ pmpriv->intf_state_11h.is_11h_active = (ul_temp & ENABLE_11H_MASK);
+ /* Set radar_det state to adapter */
+ pmpriv->adapter->state_11h.is_master_radar_det_active
+ = (ul_temp & MASTER_RADAR_DET_MASK) ? MTRUE : MFALSE;
+ pmpriv->adapter->state_11h.is_slave_radar_det_active
+ = (ul_temp & SLAVE_RADAR_DET_MASK) ? MTRUE : MFALSE;
+ }
+ }
+
+ if (pioctl_buf) {
+ /* Indicate ioctl complete */
+ pioctl_buf->data_read_written = sizeof(mlan_ds_snmp_mib);
+ }
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function handles the command response of get_log
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param resp A pointer to HostCmd_DS_COMMAND
+ * @param pioctl_buf A pointer to mlan_ioctl_req structure
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+static mlan_status
+wlan_ret_get_log(IN pmlan_private pmpriv,
+ IN HostCmd_DS_COMMAND * resp, IN mlan_ioctl_req * pioctl_buf)
+{
+ HostCmd_DS_802_11_GET_LOG *pget_log =
+ (HostCmd_DS_802_11_GET_LOG *) & resp->params.get_log;
+ mlan_ds_get_info *pget_info = MNULL;
+
+ ENTER();
+ if (pioctl_buf) {
+ pget_info = (mlan_ds_get_info *) pioctl_buf->pbuf;
+ pget_info->param.stats.mcast_tx_frame =
+ wlan_le32_to_cpu(pget_log->mcast_tx_frame);
+ pget_info->param.stats.failed = wlan_le32_to_cpu(pget_log->failed);
+ pget_info->param.stats.retry = wlan_le32_to_cpu(pget_log->retry);
+ pget_info->param.stats.multi_retry =
+ wlan_le32_to_cpu(pget_log->multiretry);
+ pget_info->param.stats.frame_dup =
+ wlan_le32_to_cpu(pget_log->frame_dup);
+ pget_info->param.stats.rts_success =
+ wlan_le32_to_cpu(pget_log->rts_success);
+ pget_info->param.stats.rts_failure =
+ wlan_le32_to_cpu(pget_log->rts_failure);
+ pget_info->param.stats.ack_failure =
+ wlan_le32_to_cpu(pget_log->ack_failure);
+ pget_info->param.stats.rx_frag = wlan_le32_to_cpu(pget_log->rx_frag);
+ pget_info->param.stats.mcast_rx_frame =
+ wlan_le32_to_cpu(pget_log->mcast_rx_frame);
+ pget_info->param.stats.fcs_error =
+ wlan_le32_to_cpu(pget_log->fcs_error);
+ pget_info->param.stats.tx_frame = wlan_le32_to_cpu(pget_log->tx_frame);
+ pget_info->param.stats.wep_icv_error[0] =
+ wlan_le32_to_cpu(pget_log->wep_icv_err_cnt[0]);
+ pget_info->param.stats.wep_icv_error[1] =
+ wlan_le32_to_cpu(pget_log->wep_icv_err_cnt[1]);
+ pget_info->param.stats.wep_icv_error[2] =
+ wlan_le32_to_cpu(pget_log->wep_icv_err_cnt[2]);
+ pget_info->param.stats.wep_icv_error[3] =
+ wlan_le32_to_cpu(pget_log->wep_icv_err_cnt[3]);
+ /* Indicate ioctl complete */
+ pioctl_buf->data_read_written = sizeof(mlan_ds_get_info);
+ }
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief Get power level and rate index
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param pdata_buf Pointer to the data buffer
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+static mlan_status
+wlan_get_power_level(pmlan_private pmpriv, void *pdata_buf)
+{
+ int length = -1, max_power = -1, min_power = -1;
+ MrvlTypes_Power_Group_t *ppg_tlv = MNULL;
+ Power_Group_t *pg = MNULL;
+
+ ENTER();
+
+ if (pdata_buf) {
+ ppg_tlv =
+ (MrvlTypes_Power_Group_t *) ((t_u8 *) pdata_buf +
+ sizeof(HostCmd_DS_TXPWR_CFG));
+ pg = (Power_Group_t *) ((t_u8 *) ppg_tlv +
+ sizeof(MrvlTypes_Power_Group_t));
+ length = ppg_tlv->length;
+ if (length > 0) {
+ max_power = pg->power_max;
+ min_power = pg->power_min;
+ length -= sizeof(Power_Group_t);
+ }
+ while (length) {
+ pg++;
+ if (max_power < pg->power_max) {
+ max_power = pg->power_max;
+ }
+ if (min_power > pg->power_min) {
+ min_power = pg->power_min;
+ }
+ length -= sizeof(Power_Group_t);
+ }
+ if (ppg_tlv->length > 0) {
+ pmpriv->min_tx_power_level = (t_u8) min_power;
+ pmpriv->max_tx_power_level = (t_u8) max_power;
+ }
+ } else {
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function handles the command response of tx_power_cfg
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param resp A pointer to HostCmd_DS_COMMAND
+ * @param pioctl_buf A pointer to mlan_ioctl_req structure
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+static mlan_status
+wlan_ret_tx_power_cfg(IN pmlan_private pmpriv,
+ IN HostCmd_DS_COMMAND * resp,
+ IN mlan_ioctl_req * pioctl_buf)
+{
+ HostCmd_DS_TXPWR_CFG *ptxp_cfg = &resp->params.txp_cfg;
+ MrvlTypes_Power_Group_t *ppg_tlv = MNULL;
+ Power_Group_t *pg = MNULL;
+ t_u16 action = wlan_le16_to_cpu(ptxp_cfg->action);
+ mlan_ds_power_cfg *power = MNULL;
+ t_u32 data[5];
+
+ ENTER();
+
+ ppg_tlv = (MrvlTypes_Power_Group_t *) ((t_u8 *) ptxp_cfg
+ + sizeof(HostCmd_DS_TXPWR_CFG));
+ pg = (Power_Group_t *) ((t_u8 *) ppg_tlv + sizeof(MrvlTypes_Power_Group_t));
+
+ switch (action) {
+ case HostCmd_ACT_GEN_GET:
+ ppg_tlv->length = wlan_le16_to_cpu(ppg_tlv->length);
+ if (pmpriv->adapter->hw_status == WlanHardwareStatusInitializing)
+ wlan_get_power_level(pmpriv, ptxp_cfg);
+ pmpriv->tx_power_level = (t_u16) pg->power_min;
+ break;
+
+ case HostCmd_ACT_GEN_SET:
+ if (wlan_le32_to_cpu(ptxp_cfg->mode)) {
+ if (pg->power_max == pg->power_min)
+ pmpriv->tx_power_level = (t_u16) pg->power_min;
+ }
+ break;
+
+ default:
+ PRINTM(MERROR, "CMD_RESP: unknown command action %d\n", action);
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+ }
+
+ PRINTM(MINFO, "Current TxPower Level = %d,Max Power=%d, Min Power=%d\n",
+ pmpriv->tx_power_level,
+ pmpriv->max_tx_power_level, pmpriv->min_tx_power_level);
+
+ if (pioctl_buf) {
+ power = (mlan_ds_power_cfg *) pioctl_buf->pbuf;
+ if (action == HostCmd_ACT_GEN_GET) {
+ if (power->sub_command == MLAN_OID_POWER_CFG) {
+ pioctl_buf->data_read_written
+ = sizeof(mlan_power_cfg_t) + MLAN_SUB_COMMAND_SIZE;
+ power->param.power_cfg.power_level = pmpriv->tx_power_level;
+ if (wlan_le32_to_cpu(ptxp_cfg->mode))
+ power->param.power_cfg.is_power_auto = 0;
+ else
+ power->param.power_cfg.is_power_auto = 1;
+ } else {
+ power->param.power_ext.len = 0;
+ while (ppg_tlv->length) {
+ data[0] = pg->first_rate_code;
+ data[1] = pg->last_rate_code;
+ if (pg->modulation_class == MOD_CLASS_OFDM) {
+ data[0] += MLAN_RATE_INDEX_OFDM0;
+ data[1] += MLAN_RATE_INDEX_OFDM0;
+ } else if (pg->modulation_class == MOD_CLASS_HT) {
+ data[0] += MLAN_RATE_INDEX_MCS0;
+ data[1] += MLAN_RATE_INDEX_MCS0;
+ if (pg->ht_bandwidth == HT_BW_40) {
+ data[0] |= TX_RATE_HT_BW40_BIT;
+ data[1] |= TX_RATE_HT_BW40_BIT;
+ }
+ }
+ data[2] = pg->power_min;
+ data[3] = pg->power_max;
+ data[4] = pg->power_step;
+ memcpy(pmpriv->adapter,
+ (t_u8 *) (&power->param.power_ext.
+ power_data[power->param.power_ext.len]),
+ (t_u8 *) data, sizeof(data));
+ power->param.power_ext.len += 5;
+ pg++;
+ ppg_tlv->length -= sizeof(Power_Group_t);
+ }
+ pioctl_buf->data_read_written
+ = sizeof(mlan_power_cfg_ext) + MLAN_SUB_COMMAND_SIZE;
+ }
+ }
+ }
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function handles the command response of rf_tx_power
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param resp A pointer to HostCmd_DS_COMMAND
+ * @param pioctl_buf A pointer to mlan_ioctl_req structure
+ * @return MLAN_STATUS_SUCCESS
+ */
+static mlan_status
+wlan_ret_802_11_rf_tx_power(IN pmlan_private pmpriv,
+ IN HostCmd_DS_COMMAND * resp,
+ IN mlan_ioctl_req * pioctl_buf)
+{
+ HostCmd_DS_802_11_RF_TX_POWER *rtp = &resp->params.txp;
+ t_u16 action = wlan_le16_to_cpu(rtp->action);
+ mlan_ds_power_cfg *power = MNULL;
+
+ ENTER();
+
+ pmpriv->tx_power_level = wlan_le16_to_cpu(rtp->current_level);
+
+ if (action == HostCmd_ACT_GEN_GET) {
+ pmpriv->max_tx_power_level = rtp->max_power;
+ pmpriv->min_tx_power_level = rtp->min_power;
+ if (pioctl_buf) {
+ power = (mlan_ds_power_cfg *) pioctl_buf->pbuf;
+ if (power->sub_command == MLAN_OID_POWER_CFG) {
+ pioctl_buf->data_read_written
+ = sizeof(mlan_power_cfg_t) + MLAN_SUB_COMMAND_SIZE;
+ power->param.power_cfg.power_level = pmpriv->tx_power_level;
+ }
+ }
+ }
+
+ PRINTM(MINFO, "Current TxPower Level = %d,Max Power=%d, Min Power=%d\n",
+ pmpriv->tx_power_level,
+ pmpriv->max_tx_power_level, pmpriv->min_tx_power_level);
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function handles the command response of sleep_period
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param resp A pointer to HostCmd_DS_COMMAND
+ * @param pioctl_buf A pointer to mlan_ioctl_req structure
+ * @return MLAN_STATUS_SUCCESS
+ */
+static mlan_status
+wlan_ret_802_11_sleep_period(IN pmlan_private pmpriv,
+ IN HostCmd_DS_COMMAND * resp,
+ IN mlan_ioctl_req * pioctl_buf)
+{
+ HostCmd_DS_802_11_SLEEP_PERIOD *pcmd_sleep_pd = &resp->params.sleep_pd;
+ mlan_ds_pm_cfg *pm_cfg = MNULL;
+ t_u16 sleep_pd = 0;
+
+ ENTER();
+
+ sleep_pd = wlan_le16_to_cpu(pcmd_sleep_pd->sleep_pd);
+ if (pioctl_buf) {
+ pm_cfg = (mlan_ds_pm_cfg *) pioctl_buf->pbuf;
+ pm_cfg->param.sleep_period = (t_u32) sleep_pd;
+ pioctl_buf->data_read_written = sizeof(pm_cfg->param.sleep_period)
+ + MLAN_SUB_COMMAND_SIZE;
+ }
+ pmpriv->adapter->sleep_period.period = sleep_pd;
+
+ pmpriv->adapter->pps_uapsd_mode = MFALSE;
+ if ((pmpriv->adapter->sleep_period.period != 0) &&
+ (pmpriv->adapter->sleep_period.period != SLEEP_PERIOD_RESERVED_FF)) {
+ pmpriv->adapter->gen_null_pkt = MTRUE;
+ } else {
+ pmpriv->adapter->delay_null_pkt = MFALSE;
+ pmpriv->adapter->gen_null_pkt = MFALSE;
+ }
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function handles the command response of sleep_params
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param resp A pointer to HostCmd_DS_COMMAND
+ * @param pioctl_buf A pointer to mlan_ioctl_req structure
+ * @return MLAN_STATUS_SUCCESS
+ */
+static mlan_status
+wlan_ret_802_11_sleep_params(IN pmlan_private pmpriv,
+ IN HostCmd_DS_COMMAND * resp,
+ IN mlan_ioctl_req * pioctl_buf)
+{
+ HostCmd_DS_802_11_SLEEP_PARAMS *presp_sp = &resp->params.sleep_param;
+ mlan_ds_pm_cfg *pm_cfg = MNULL;
+ mlan_ds_sleep_params *psp = MNULL;
+ sleep_params_t *psleep_params = &pmpriv->adapter->sleep_params;
+
+ ENTER();
+
+ psleep_params->sp_reserved = wlan_le16_to_cpu(presp_sp->reserved);
+ psleep_params->sp_error = wlan_le16_to_cpu(presp_sp->error);
+ psleep_params->sp_offset = wlan_le16_to_cpu(presp_sp->offset);
+ psleep_params->sp_stable_time = wlan_le16_to_cpu(presp_sp->stable_time);
+ psleep_params->sp_cal_control = presp_sp->cal_control;
+ psleep_params->sp_ext_sleep_clk = presp_sp->external_sleep_clk;
+
+ if (pioctl_buf) {
+ pm_cfg = (mlan_ds_pm_cfg *) pioctl_buf->pbuf;
+ psp = (mlan_ds_sleep_params *) & pm_cfg->param.sleep_params;
+
+ psp->error = (t_u32) psleep_params->sp_error;
+ psp->offset = (t_u32) psleep_params->sp_offset;
+ psp->stable_time = (t_u32) psleep_params->sp_stable_time;
+ psp->cal_control = (t_u32) psleep_params->sp_cal_control;
+ psp->ext_sleep_clk = (t_u32) psleep_params->sp_ext_sleep_clk;
+ psp->reserved = (t_u32) psleep_params->sp_reserved;
+
+ pioctl_buf->data_read_written = sizeof(pm_cfg->param.sleep_params)
+ + MLAN_SUB_COMMAND_SIZE;
+ }
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function handles the command response of mac_address
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param resp A pointer to HostCmd_DS_COMMAND
+ * @param pioctl_buf A pointer to mlan_ioctl_req structure
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+static mlan_status
+wlan_ret_802_11_mac_address(IN pmlan_private pmpriv,
+ IN HostCmd_DS_COMMAND * resp,
+ IN mlan_ioctl_req * pioctl_buf)
+{
+ HostCmd_DS_802_11_MAC_ADDRESS *pmac_addr = &resp->params.mac_addr;
+ mlan_ds_bss *bss = MNULL;
+
+ ENTER();
+
+ memcpy(pmpriv->adapter, pmpriv->curr_addr, pmac_addr->mac_addr,
+ MLAN_MAC_ADDR_LENGTH);
+
+ PRINTM(MINFO, "MAC address: %02x:%02x:%02x:%02x:%02x:%02x\n",
+ pmpriv->curr_addr[0], pmpriv->curr_addr[1], pmpriv->curr_addr[2],
+ pmpriv->curr_addr[3], pmpriv->curr_addr[4], pmpriv->curr_addr[5]);
+ if (pioctl_buf) {
+ bss = (mlan_ds_bss *) pioctl_buf->pbuf;
+ memcpy(pmpriv->adapter, &bss->param.mac_addr, pmpriv->curr_addr,
+ MLAN_MAC_ADDR_LENGTH);
+ pioctl_buf->data_read_written =
+ MLAN_MAC_ADDR_LENGTH + MLAN_SUB_COMMAND_SIZE;
+ }
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function handles the command response of multicast_address
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param resp A pointer to HostCmd_DS_COMMAND
+ * @param pioctl_buf A pointer to mlan_ioctl_req structure
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+static mlan_status
+wlan_ret_mac_multicast_adr(IN pmlan_private pmpriv,
+ IN HostCmd_DS_COMMAND * resp,
+ IN mlan_ioctl_req * pioctl_buf)
+{
+ ENTER();
+ if (pioctl_buf) {
+ pioctl_buf->data_read_written =
+ sizeof(mlan_multicast_list) + MLAN_SUB_COMMAND_SIZE;
+ }
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function handles the command response of deauthenticate
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param resp A pointer to HostCmd_DS_COMMAND
+ * @param pioctl_buf A pointer to mlan_ioctl_req structure
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+static mlan_status
+wlan_ret_802_11_deauthenticate(IN pmlan_private pmpriv,
+ IN HostCmd_DS_COMMAND * resp,
+ IN mlan_ioctl_req * pioctl_buf)
+{
+ mlan_adapter *pmadapter = pmpriv->adapter;
+ ENTER();
+
+ pmadapter->dbg.num_cmd_deauth++;
+
+ if (!memcmp(pmadapter, resp->params.deauth.mac_addr,
+ &pmpriv->curr_bss_params.bss_descriptor.mac_address,
+ sizeof(resp->params.deauth.mac_addr))) {
+ wlan_reset_connect_state(pmpriv, MTRUE);
+
+ }
+ if (pmpriv->adapter->state_rdh.stage == RDH_STOP_INTFS)
+ wlan_11h_radar_detected_callback((t_void *) pmpriv);
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function handles the command response of ad_hoc_stop
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param resp A pointer to HostCmd_DS_COMMAND
+ * @param pioctl_buf A pointer to mlan_ioctl_req structure
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+static mlan_status
+wlan_ret_802_11_ad_hoc_stop(IN pmlan_private pmpriv,
+ IN HostCmd_DS_COMMAND * resp,
+ IN mlan_ioctl_req * pioctl_buf)
+{
+ ENTER();
+
+ wlan_reset_connect_state(pmpriv, MTRUE);
+ if (pmpriv->adapter->state_rdh.stage == RDH_STOP_INTFS)
+ wlan_11h_radar_detected_callback((t_void *) pmpriv);
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function handles the command response of key_material
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param resp A pointer to HostCmd_DS_COMMAND
+ * @param pioctl_buf A pointer to mlan_ioctl_req structure
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+static mlan_status
+wlan_ret_802_11_key_material(IN pmlan_private pmpriv,
+ IN HostCmd_DS_COMMAND * resp,
+ IN mlan_ioctl_req * pioctl_buf)
+{
+ HostCmd_DS_802_11_KEY_MATERIAL *pkey = &resp->params.key_material;
+
+ ENTER();
+
+ if (wlan_le16_to_cpu(pkey->action) == HostCmd_ACT_GEN_SET) {
+ if ((wlan_le16_to_cpu(pkey->key_param_set.key_info) &
+ KEY_INFO_TKIP_MCAST)) {
+ PRINTM(MINFO, "key: GTK is set\n");
+ pmpriv->wpa_is_gtk_set = MTRUE;
+ if (pmpriv->port_ctrl_mode == MTRUE) {
+ /* GTK is set, open the port */
+ PRINTM(MINFO, "GTK_SET: Open port for WPA/WPA2 h-supp mode\n");
+ pmpriv->port_open = MTRUE;
+ }
+ pmpriv->scan_block = MFALSE;
+ }
+ }
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief Handle the supplicant pmk response
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param resp A pointer to HostCmd_DS_COMMAND
+ * @param pioctl_buf A pointer to mlan_ioctl_req structure
+ *
+ * @return MLAN_STATUS_SUCCESS MLAN_STATUS_FAILURE
+ */
+static mlan_status
+wlan_ret_802_11_supplicant_pmk(IN pmlan_private pmpriv,
+ IN HostCmd_DS_COMMAND * resp,
+ IN mlan_ioctl_req * pioctl_buf)
+{
+ HostCmd_DS_802_11_SUPPLICANT_PMK *supplicant_pmk_resp =
+ &resp->params.esupplicant_psk;
+ mlan_ds_sec_cfg sec_buf;
+ mlan_ds_sec_cfg *sec = MNULL;
+ MrvlIEtypes_PMK_t *ppmk_tlv = MNULL;
+ MrvlIEtypes_Passphrase_t *passphrase_tlv = MNULL;
+ MrvlIEtypes_SsIdParamSet_t *pssid_tlv = MNULL;
+ MrvlIEtypes_Bssid_t *pbssid_tlv = MNULL;
+ t_u8 *tlv_buf = (t_u8 *) supplicant_pmk_resp->tlv_buffer;
+ t_u16 action = wlan_le16_to_cpu(supplicant_pmk_resp->action);
+ int tlv_buf_len = 0;
+ t_u16 tlv;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+ tlv_buf_len = resp->size - (sizeof(HostCmd_DS_802_11_SUPPLICANT_PMK) +
+ S_DS_GEN - 1);
+ if (pioctl_buf) {
+ if (((mlan_ds_bss *) pioctl_buf->pbuf)->sub_command ==
+ MLAN_OID_BSS_FIND_BSS)
+ sec = &sec_buf;
+ else
+ sec = (mlan_ds_sec_cfg *) pioctl_buf->pbuf;
+ if (action == HostCmd_ACT_GEN_GET) {
+ while (tlv_buf_len > 0) {
+ tlv = (*tlv_buf) | (*(tlv_buf + 1) << 8);
+ if ((tlv != TLV_TYPE_SSID) && (tlv != TLV_TYPE_BSSID) &&
+ (tlv != TLV_TYPE_PASSPHRASE)
+ && (tlv != TLV_TYPE_PMK))
+ break;
+ switch (tlv) {
+ case TLV_TYPE_SSID:
+ pssid_tlv = (MrvlIEtypes_SsIdParamSet_t *) tlv_buf;
+ pssid_tlv->header.len =
+ wlan_le16_to_cpu(pssid_tlv->header.len);
+ memcpy(pmpriv->adapter, sec->param.passphrase.ssid.ssid,
+ pssid_tlv->ssid, MIN(MLAN_MAX_SSID_LENGTH,
+ pssid_tlv->header.len));
+ sec->param.passphrase.ssid.ssid_len =
+ MIN(MLAN_MAX_SSID_LENGTH, pssid_tlv->header.len);
+ tlv_buf +=
+ pssid_tlv->header.len + sizeof(MrvlIEtypesHeader_t);
+ tlv_buf_len -=
+ (pssid_tlv->header.len + sizeof(MrvlIEtypesHeader_t));
+ break;
+ case TLV_TYPE_BSSID:
+ pbssid_tlv = (MrvlIEtypes_Bssid_t *) tlv_buf;
+ pbssid_tlv->header.len =
+ wlan_le16_to_cpu(pbssid_tlv->header.len);
+ memcpy(pmpriv->adapter, &sec->param.passphrase.bssid,
+ pbssid_tlv->bssid, MLAN_MAC_ADDR_LENGTH);
+ tlv_buf +=
+ pbssid_tlv->header.len + sizeof(MrvlIEtypesHeader_t);
+ tlv_buf_len -=
+ (pbssid_tlv->header.len + sizeof(MrvlIEtypesHeader_t));
+ break;
+ case TLV_TYPE_PASSPHRASE:
+ passphrase_tlv = (MrvlIEtypes_Passphrase_t *) tlv_buf;
+ passphrase_tlv->header.len =
+ wlan_le16_to_cpu(passphrase_tlv->header.len);
+ sec->param.passphrase.psk_type = MLAN_PSK_PASSPHRASE;
+ sec->param.passphrase.psk.passphrase.passphrase_len =
+ passphrase_tlv->header.len;
+ memcpy(pmpriv->adapter,
+ sec->param.passphrase.psk.passphrase.passphrase,
+ passphrase_tlv->passphrase,
+ MIN(MLAN_MAX_PASSPHRASE_LENGTH,
+ passphrase_tlv->header.len));
+ tlv_buf +=
+ passphrase_tlv->header.len +
+ sizeof(MrvlIEtypesHeader_t);
+ tlv_buf_len -=
+ (passphrase_tlv->header.len +
+ sizeof(MrvlIEtypesHeader_t));
+ break;
+ case TLV_TYPE_PMK:
+ ppmk_tlv = (MrvlIEtypes_PMK_t *) tlv_buf;
+ ppmk_tlv->header.len =
+ wlan_le16_to_cpu(ppmk_tlv->header.len);
+ sec->param.passphrase.psk_type = MLAN_PSK_PMK;
+ memcpy(pmpriv->adapter, sec->param.passphrase.psk.pmk.pmk,
+ ppmk_tlv->pmk, MIN(MLAN_MAX_KEY_LENGTH,
+ ppmk_tlv->header.len));
+ tlv_buf +=
+ ppmk_tlv->header.len + sizeof(MrvlIEtypesHeader_t);
+ tlv_buf_len -=
+ (ppmk_tlv->header.len + sizeof(MrvlIEtypesHeader_t));
+ break;
+
+ }
+ }
+ if (((mlan_ds_bss *) pioctl_buf->pbuf)->sub_command ==
+ MLAN_OID_BSS_FIND_BSS) {
+ wlan_set_ewpa_mode(pmpriv, &sec->param.passphrase);
+ ret = wlan_find_bss(pmpriv, pioctl_buf);
+ }
+ } else if (action == HostCmd_ACT_GEN_SET) {
+ PRINTM(MINFO, "Esupp PMK set: enable ewpa query\n");
+ pmpriv->ewpa_query = MTRUE;
+ }
+ }
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Handle the supplicant profile response
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param resp A pointer to HostCmd_DS_COMMAND
+ * @param pioctl_buf A pointer to mlan_ioctl_req structure
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+static mlan_status
+wlan_ret_802_11_supplicant_profile(IN pmlan_private pmpriv,
+ IN HostCmd_DS_COMMAND * resp,
+ IN mlan_ioctl_req * pioctl_buf)
+{
+ HostCmd_DS_802_11_SUPPLICANT_PROFILE *psup_profile =
+ &resp->params.esupplicant_profile;
+ MrvlIEtypesHeader_t *head;
+ MrvlIEtypes_EncrProto_t *encr_proto_tlv = MNULL;
+ MrvlIEtypes_Cipher_t *pcipher_tlv = MNULL;
+ mlan_ds_sec_cfg *sec = MNULL;
+ t_u8 *tlv;
+ int len;
+
+ ENTER();
+
+ len = resp->size - S_DS_GEN - sizeof(t_u16);
+ tlv = psup_profile->tlv_buf;
+ if (pioctl_buf) {
+ sec = (mlan_ds_sec_cfg *) pioctl_buf->pbuf;
+ while (len > 0) {
+ head = (MrvlIEtypesHeader_t *) tlv;
+ head->type = wlan_le16_to_cpu(head->type);
+ head->len = wlan_le16_to_cpu(head->len);
+ switch (head->type) {
+ case TLV_TYPE_ENCRYPTION_PROTO:
+ encr_proto_tlv = (MrvlIEtypes_EncrProto_t *) head;
+ sec->param.esupp_mode.rsn_mode =
+ wlan_le16_to_cpu(encr_proto_tlv->rsn_mode);
+ PRINTM(MINFO, "rsn_mode=0x%x\n",
+ sec->param.esupp_mode.rsn_mode);
+ break;
+ case TLV_TYPE_CIPHER:
+ pcipher_tlv = (MrvlIEtypes_Cipher_t *) head;
+ sec->param.esupp_mode.act_paircipher = pcipher_tlv->pair_cipher;
+ sec->param.esupp_mode.act_groupcipher =
+ pcipher_tlv->group_cipher;
+ PRINTM(MINFO, "paircipher=0x%x, groupcipher=0x%x\n",
+ sec->param.esupp_mode.act_paircipher,
+ sec->param.esupp_mode.act_groupcipher);
+ break;
+ }
+ len -= (head->len - sizeof(MrvlIEtypesHeader_t));
+ tlv = tlv + (head->len + sizeof(MrvlIEtypesHeader_t));
+ }
+ }
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function handles the command response of rf_channel
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param resp A pointer to HostCmd_DS_COMMAND
+ * @param pioctl_buf A pointer to mlan_ioctl_req structure
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+static mlan_status
+wlan_ret_802_11_rf_channel(IN pmlan_private pmpriv,
+ IN HostCmd_DS_COMMAND * resp,
+ IN mlan_ioctl_req * pioctl_buf)
+{
+ HostCmd_DS_802_11_RF_CHANNEL *prf_channel = &resp->params.rf_channel;
+ t_u16 new_channel = wlan_le16_to_cpu(prf_channel->current_channel);
+ mlan_ds_bss *bss = MNULL;
+ ENTER();
+ if (pmpriv->curr_bss_params.bss_descriptor.channel != new_channel) {
+ PRINTM(MINFO, "Channel Switch: %d to %d\n",
+ pmpriv->curr_bss_params.bss_descriptor.channel, new_channel);
+ /* Update the channel again */
+ pmpriv->curr_bss_params.bss_descriptor.channel = new_channel;
+ }
+ if (pioctl_buf) {
+ bss = (mlan_ds_bss *) pioctl_buf->pbuf;
+ bss->param.bss_chan.channel = new_channel;
+ }
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief Handle the ibss_coalescing_status resp
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param resp A pointer to HostCmd_DS_COMMAND
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+static mlan_status
+wlan_ret_ibss_coalescing_status(IN pmlan_private pmpriv,
+ IN HostCmd_DS_COMMAND * resp)
+{
+ HostCmd_DS_802_11_IBSS_STATUS *pibss_coal_resp =
+ &(resp->params.ibss_coalescing);
+ t_u8 zero_mac[MLAN_MAC_ADDR_LENGTH] = { 0, 0, 0, 0, 0, 0 };
+
+ ENTER();
+
+ if (wlan_le16_to_cpu(pibss_coal_resp->action) == HostCmd_ACT_GEN_SET) {
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+ }
+
+ PRINTM(MINFO, "New BSSID %02x:%02x:%02x:%02x:%02x:%02x\n",
+ pibss_coal_resp->bssid[0], pibss_coal_resp->bssid[1],
+ pibss_coal_resp->bssid[2], pibss_coal_resp->bssid[3],
+ pibss_coal_resp->bssid[4], pibss_coal_resp->bssid[5]);
+
+ /* If rsp has MNULL BSSID, Just return..... No Action */
+ if (!memcmp
+ (pmpriv->adapter, pibss_coal_resp->bssid, zero_mac,
+ MLAN_MAC_ADDR_LENGTH)) {
+ PRINTM(MMSG, "New BSSID is MNULL\n");
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+ }
+
+ /* If BSSID is diff, modify current BSS parameters */
+ if (memcmp
+ (pmpriv->adapter, pmpriv->curr_bss_params.bss_descriptor.mac_address,
+ pibss_coal_resp->bssid, MLAN_MAC_ADDR_LENGTH)) {
+ /* BSSID */
+ memcpy(pmpriv->adapter,
+ pmpriv->curr_bss_params.bss_descriptor.mac_address,
+ pibss_coal_resp->bssid, MLAN_MAC_ADDR_LENGTH);
+
+ /* Beacon Interval and ATIM window */
+ pmpriv->curr_bss_params.bss_descriptor.beacon_period
+ = wlan_le16_to_cpu(pibss_coal_resp->beacon_interval);
+ pmpriv->curr_bss_params.bss_descriptor.atim_window
+ = wlan_le16_to_cpu(pibss_coal_resp->atim_window);
+
+ /* ERP Information */
+ pmpriv->curr_bss_params.bss_descriptor.erp_flags
+ = (t_u8) wlan_le16_to_cpu(pibss_coal_resp->use_g_rate_protect);
+
+ pmpriv->adhoc_state = ADHOC_COALESCED;
+ }
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function handles the command response of MGMT_IE_LIST
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param resp A pointer to HostCmd_DS_COMMAND
+ * @param pioctl_buf A pointer to mlan_ioctl_req structure
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+static mlan_status
+wlan_ret_mgmt_ie_list(IN pmlan_private pmpriv,
+ IN HostCmd_DS_COMMAND * resp,
+ OUT mlan_ioctl_req * pioctl_buf)
+{
+ t_u16 resp_len = 0, travel_len = 0;
+ int i = 0;
+ mlan_ds_misc_cfg *misc = MNULL;
+ mlan_ds_misc_custom_ie *cust_ie = MNULL;
+ custom_ie *cptr;
+ tlvbuf_max_mgmt_ie *max_mgmt_ie = MNULL;
+ HostCmd_DS_MGMT_IE_LIST_CFG *pmgmt_ie_list = &(resp->params.mgmt_ie_list);
+
+ ENTER();
+
+ if (wlan_le16_to_cpu(pmgmt_ie_list->action) == HostCmd_ACT_GEN_SET) {
+ if ((pmpriv->adapter->state_rdh.stage == RDH_SET_CUSTOM_IE) ||
+ (pmpriv->adapter->state_rdh.stage == RDH_REM_CUSTOM_IE))
+ wlan_11h_radar_detected_callback((t_void *) pmpriv);
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+ }
+
+ misc = (mlan_ds_misc_cfg *) pioctl_buf->pbuf;
+ cust_ie = (mlan_ds_misc_custom_ie *) & pmgmt_ie_list->ds_mgmt_ie;
+ max_mgmt_ie =
+ (tlvbuf_max_mgmt_ie *) ((t_u8 *) cust_ie + cust_ie->len +
+ sizeof(MrvlIEtypesHeader_t));
+ if (cust_ie) {
+ cust_ie->type = wlan_le16_to_cpu(cust_ie->type);
+ resp_len = cust_ie->len = wlan_le16_to_cpu(cust_ie->len);
+ travel_len = 0;
+ /* conversion for index, mask, len */
+ if (resp_len == sizeof(t_u16))
+ cust_ie->ie_data_list[0].ie_index =
+ wlan_cpu_to_le16(cust_ie->ie_data_list[0].ie_index);
+
+ while (resp_len > sizeof(t_u16)) {
+ cptr =
+ (custom_ie *) (((t_u8 *) cust_ie->ie_data_list) + travel_len);
+ cptr->ie_index = wlan_le16_to_cpu(cptr->ie_index);
+ cptr->mgmt_subtype_mask = wlan_le16_to_cpu(cptr->mgmt_subtype_mask);
+ cptr->ie_length = wlan_le16_to_cpu(cptr->ie_length);
+ travel_len += cptr->ie_length + sizeof(custom_ie) - MAX_IE_SIZE;
+ resp_len -= cptr->ie_length + sizeof(custom_ie) - MAX_IE_SIZE;
+ }
+ memcpy(pmpriv->adapter, &misc->param.cust_ie, cust_ie,
+ (cust_ie->len + sizeof(MrvlIEtypesHeader_t)));
+ if (max_mgmt_ie) {
+ max_mgmt_ie->type = wlan_le16_to_cpu(max_mgmt_ie->type);
+ if (max_mgmt_ie->type == TLV_TYPE_MAX_MGMT_IE) {
+ max_mgmt_ie->len = wlan_le16_to_cpu(max_mgmt_ie->len);
+ max_mgmt_ie->count = wlan_le16_to_cpu(max_mgmt_ie->count);
+ for (i = 0; i < max_mgmt_ie->count; i++) {
+ max_mgmt_ie->info[i].buf_size =
+ wlan_le16_to_cpu(max_mgmt_ie->info[i].buf_size);
+ max_mgmt_ie->info[i].buf_count =
+ wlan_le16_to_cpu(max_mgmt_ie->info[i].buf_count);
+ }
+ /* Append max_mgmt_ie TLV after custom_ie */
+ memcpy(pmpriv->adapter,
+ (t_u8 *) & misc->param.cust_ie + (cust_ie->len +
+ sizeof
+ (MrvlIEtypesHeader_t)),
+ max_mgmt_ie,
+ max_mgmt_ie->len + sizeof(MrvlIEtypesHeader_t));
+ }
+ }
+ }
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function handles the command response of sysclock
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param resp A pointer to HostCmd_DS_COMMAND
+ * @param pioctl_buf A pointer to mlan_ioctl_req structure
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+static mlan_status
+wlan_ret_sysclock_cfg(IN pmlan_private pmpriv,
+ IN HostCmd_DS_COMMAND * resp,
+ IN mlan_ioctl_req * pioctl_buf)
+{
+ mlan_ds_misc_cfg *mis_ccfg = MNULL;
+ HostCmd_DS_ECL_SYSTEM_CLOCK_CONFIG *clk_cfg = &resp->params.sys_clock_cfg;
+ int i = 0;
+
+ ENTER();
+
+ if (pioctl_buf) {
+ mis_ccfg = (mlan_ds_misc_cfg *) pioctl_buf->pbuf;
+ mis_ccfg->param.sys_clock.cur_sys_clk =
+ wlan_le16_to_cpu(clk_cfg->cur_sys_clk);
+ mis_ccfg->param.sys_clock.sys_clk_type =
+ wlan_le16_to_cpu(clk_cfg->sys_clk_type);
+ mis_ccfg->param.sys_clock.sys_clk_num =
+ wlan_le16_to_cpu(clk_cfg->sys_clk_len) / sizeof(t_u16);
+ for (i = 0; i < mis_ccfg->param.sys_clock.sys_clk_num; i++)
+ mis_ccfg->param.sys_clock.sys_clk[i] =
+ wlan_le16_to_cpu(clk_cfg->sys_clk[i]);
+ }
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function handles the command response of reg_access
+ *
+ * @param type The type of reg access (MAC, BBP or RF)
+ * @param resp A pointer to HostCmd_DS_COMMAND
+ * @param pioctl_buf A pointer to command buffer
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+static mlan_status
+wlan_ret_reg_access(mlan_adapter * pmadapter,
+ t_u16 type,
+ IN HostCmd_DS_COMMAND * resp,
+ IN mlan_ioctl_req * pioctl_buf)
+{
+ mlan_ds_reg_mem *reg_mem = MNULL;
+ mlan_ds_reg_rw *reg_rw = MNULL;
+
+ ENTER();
+
+ if (pioctl_buf) {
+ reg_mem = (mlan_ds_reg_mem *) pioctl_buf->pbuf;
+ reg_rw = &reg_mem->param.reg_rw;
+ switch (type) {
+ case HostCmd_CMD_MAC_REG_ACCESS:
+ {
+ HostCmd_DS_MAC_REG_ACCESS *reg;
+ reg = (HostCmd_DS_MAC_REG_ACCESS *) & resp->params.mac_reg;
+ reg_rw->offset = (t_u32) wlan_le16_to_cpu(reg->offset);
+ reg_rw->value = wlan_le32_to_cpu(reg->value);
+ break;
+ }
+ case HostCmd_CMD_BBP_REG_ACCESS:
+ {
+ HostCmd_DS_BBP_REG_ACCESS *reg;
+ reg = (HostCmd_DS_BBP_REG_ACCESS *) & resp->params.bbp_reg;
+ reg_rw->offset = (t_u32) wlan_le16_to_cpu(reg->offset);
+ reg_rw->value = (t_u32) reg->value;
+ break;
+ }
+
+ case HostCmd_CMD_RF_REG_ACCESS:
+ {
+ HostCmd_DS_RF_REG_ACCESS *reg;
+ reg = (HostCmd_DS_RF_REG_ACCESS *) & resp->params.rf_reg;
+ reg_rw->offset = (t_u32) wlan_le16_to_cpu(reg->offset);
+ reg_rw->value = (t_u32) reg->value;
+ break;
+ }
+ case HostCmd_CMD_CAU_REG_ACCESS:
+ {
+ HostCmd_DS_RF_REG_ACCESS *reg;
+ reg = (HostCmd_DS_RF_REG_ACCESS *) & resp->params.rf_reg;
+ reg_rw->offset = (t_u32) wlan_le16_to_cpu(reg->offset);
+ reg_rw->value = (t_u32) reg->value;
+ break;
+ }
+ case HostCmd_CMD_802_11_EEPROM_ACCESS:
+ {
+ mlan_ds_read_eeprom *eeprom = &reg_mem->param.rd_eeprom;
+ HostCmd_DS_802_11_EEPROM_ACCESS *cmd_eeprom =
+ (HostCmd_DS_802_11_EEPROM_ACCESS *) & resp->params.eeprom;
+ cmd_eeprom->byte_count =
+ wlan_le16_to_cpu(cmd_eeprom->byte_count);
+ PRINTM(MINFO, "EEPROM read len=%x\n", cmd_eeprom->byte_count);
+ if (eeprom->byte_count < cmd_eeprom->byte_count) {
+ eeprom->byte_count = 0;
+ PRINTM(MINFO, "EEPROM read return length is too big\n");
+ pioctl_buf->status_code = MLAN_ERROR_CMD_RESP_FAIL;
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+ eeprom->offset = wlan_le16_to_cpu(cmd_eeprom->offset);
+ eeprom->byte_count = cmd_eeprom->byte_count;
+ if (eeprom->byte_count > 0) {
+ memcpy(pmadapter, &eeprom->value, &cmd_eeprom->value,
+ MIN(MAX_EEPROM_DATA, eeprom->byte_count));
+ HEXDUMP("EEPROM", (char *) &eeprom->value,
+ MIN(MAX_EEPROM_DATA, eeprom->byte_count));
+ }
+ break;
+ }
+ default:
+ pioctl_buf->status_code = MLAN_ERROR_CMD_RESP_FAIL;
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+ }
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function handles the command response of mem_access
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param resp A pointer to HostCmd_DS_COMMAND
+ * @param pioctl_buf A pointer to command buffer
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+static mlan_status
+wlan_ret_mem_access(IN pmlan_private pmpriv,
+ IN HostCmd_DS_COMMAND * resp,
+ IN mlan_ioctl_req * pioctl_buf)
+{
+ mlan_ds_reg_mem *reg_mem = MNULL;
+ mlan_ds_mem_rw *mem_rw = MNULL;
+ HostCmd_DS_MEM_ACCESS *mem = (HostCmd_DS_MEM_ACCESS *) & resp->params.mem;
+
+ ENTER();
+
+ if (pioctl_buf) {
+ reg_mem = (mlan_ds_reg_mem *) pioctl_buf->pbuf;
+ mem_rw = &reg_mem->param.mem_rw;
+
+ mem_rw->addr = wlan_le32_to_cpu(mem->addr);
+ mem_rw->value = wlan_le32_to_cpu(mem->value);
+ }
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function handles the command response of inactivity timeout
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param resp A pointer to HostCmd_DS_COMMAND
+ * @param pioctl_buf A pointer to command buffer
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+static mlan_status
+wlan_ret_inactivity_timeout(IN pmlan_private pmpriv,
+ IN HostCmd_DS_COMMAND * resp,
+ IN mlan_ioctl_req * pioctl_buf)
+{
+ mlan_ds_pm_cfg *pmcfg = MNULL;
+ mlan_ds_inactivity_to *inac_to = MNULL;
+ HostCmd_DS_INACTIVITY_TIMEOUT_EXT *cmd_inac_to =
+ (HostCmd_DS_INACTIVITY_TIMEOUT_EXT *) & resp->params.inactivity_to;
+
+ ENTER();
+
+ if (pioctl_buf) {
+ pmcfg = (mlan_ds_pm_cfg *) pioctl_buf->pbuf;
+ inac_to = &pmcfg->param.inactivity_to;
+ inac_to->timeout_unit = wlan_le16_to_cpu(cmd_inac_to->timeout_unit);
+ inac_to->unicast_timeout =
+ wlan_le16_to_cpu(cmd_inac_to->unicast_timeout);
+ inac_to->mcast_timeout = wlan_le16_to_cpu(cmd_inac_to->mcast_timeout);
+ inac_to->ps_entry_timeout =
+ wlan_le16_to_cpu(cmd_inac_to->ps_entry_timeout);
+ }
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function handles the command response of
+ * subscribe event
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param resp A pointer to HostCmd_DS_COMMAND
+ * @param pioctl_buf A pointer to command buffer
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+static mlan_status
+wlan_ret_subscribe_event(IN pmlan_private pmpriv,
+ IN HostCmd_DS_COMMAND * resp,
+ IN mlan_ioctl_req * pioctl_buf)
+{
+
+ HostCmd_DS_SUBSCRIBE_EVENT *evt =
+ (HostCmd_DS_SUBSCRIBE_EVENT *) & resp->params.subscribe_event;
+ mlan_ds_subscribe_evt *sub_evt = MNULL;
+ mlan_ds_misc_cfg *misc = MNULL;
+
+ ENTER();
+ if (pioctl_buf && (pioctl_buf->action == MLAN_ACT_GET)) {
+ misc = (mlan_ds_misc_cfg *) pioctl_buf->pbuf;
+ sub_evt = &misc->param.subscribe_event;
+ sub_evt->evt_bitmap = wlan_le16_to_cpu(evt->event_bitmap);
+ pioctl_buf->data_read_written = sizeof(mlan_ds_misc_cfg);
+ }
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/********************************************************
+ Global Functions
+********************************************************/
+/**
+ * @brief This function handles the station command response
+ *
+ * @param priv A pointer to mlan_private structure
+ * @param cmdresp_no cmd no
+ * @param pcmd_buf cmdresp buf
+ * @param pioctl A pointer to ioctl buf
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status
+wlan_ops_sta_process_cmdresp(IN t_void * priv,
+ IN t_u16 cmdresp_no,
+ IN t_void * pcmd_buf, IN t_void * pioctl)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_private *pmpriv = (mlan_private *) priv;
+ HostCmd_DS_COMMAND *resp = (HostCmd_DS_COMMAND *) pcmd_buf;
+ mlan_ioctl_req *pioctl_buf = (mlan_ioctl_req *) pioctl;
+ mlan_adapter *pmadapter = pmpriv->adapter;
+ int ctr;
+
+ ENTER();
+
+ /* If the command is not successful, cleanup and return failure */
+ if ((resp->result != HostCmd_RESULT_OK)
+ ) {
+ wlan_process_cmdresp_error(pmpriv, resp, pioctl_buf);
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+ /* Command successful, handle response */
+ switch (cmdresp_no) {
+ case HostCmd_CMD_GET_HW_SPEC:
+ ret = wlan_ret_get_hw_spec(pmpriv, resp, pioctl_buf);
+ break;
+ case HostCmd_CMD_CFG_DATA:
+ ret = wlan_ret_cfg_data(pmpriv, resp, pioctl_buf);
+ break;
+ case HostCmd_CMD_MAC_CONTROL:
+ ret = wlan_ret_mac_control(pmpriv, resp, pioctl_buf);
+ break;
+ case HostCmd_CMD_802_11_MAC_ADDRESS:
+ ret = wlan_ret_802_11_mac_address(pmpriv, resp, pioctl_buf);
+ break;
+ case HostCmd_CMD_MAC_MULTICAST_ADR:
+ ret = wlan_ret_mac_multicast_adr(pmpriv, resp, pioctl_buf);
+ break;
+ case HostCmd_CMD_TX_RATE_CFG:
+ ret = wlan_ret_tx_rate_cfg(pmpriv, resp, pioctl_buf);
+ break;
+ case HostCmd_CMD_802_11_SCAN:
+ ret = wlan_ret_802_11_scan(pmpriv, resp, pioctl_buf);
+ pioctl_buf = MNULL;
+ pmadapter->curr_cmd->pioctl_buf = MNULL;
+ break;
+ case HostCmd_CMD_802_11_SCAN_EXT:
+ ret = wlan_ret_802_11_scan_ext(pmpriv, resp, pioctl_buf);
+ pioctl_buf = MNULL;
+ pmadapter->curr_cmd->pioctl_buf = MNULL;
+ break;
+ case HostCmd_CMD_802_11_BG_SCAN_CONFIG:
+ ret = wlan_ret_bgscan_config(pmpriv, resp, pioctl_buf);
+ break;
+ case HostCmd_CMD_802_11_BG_SCAN_QUERY:
+ ret = wlan_ret_802_11_scan(pmpriv, resp, pioctl_buf);
+ wlan_recv_event(pmpriv, MLAN_EVENT_ID_FW_BG_SCAN, MNULL);
+ PRINTM(MINFO, "CMD_RESP: BG_SCAN result is ready!\n");
+ break;
+ case HostCmd_CMD_TXPWR_CFG:
+ ret = wlan_ret_tx_power_cfg(pmpriv, resp, pioctl_buf);
+ break;
+
+ case HostCmd_CMD_802_11_RF_TX_POWER:
+ ret = wlan_ret_802_11_rf_tx_power(pmpriv, resp, pioctl_buf);
+ break;
+
+ case HostCmd_CMD_802_11_PS_MODE_ENH:
+ ret = wlan_ret_enh_power_mode(pmpriv, resp, pioctl_buf);
+ break;
+ case HostCmd_CMD_802_11_HS_CFG_ENH:
+ ret = wlan_ret_802_11_hs_cfg(pmpriv, resp, pioctl_buf);
+ break;
+ case HostCmd_CMD_802_11_SLEEP_PERIOD:
+ ret = wlan_ret_802_11_sleep_period(pmpriv, resp, pioctl_buf);
+ break;
+ case HostCmd_CMD_802_11_SLEEP_PARAMS:
+ ret = wlan_ret_802_11_sleep_params(pmpriv, resp, pioctl_buf);
+ break;
+ case HostCmd_CMD_802_11_ASSOCIATE:
+ ret = wlan_ret_802_11_associate(pmpriv, resp, pioctl_buf);
+ break;
+ case HostCmd_CMD_802_11_DEAUTHENTICATE:
+ ret = wlan_ret_802_11_deauthenticate(pmpriv, resp, pioctl_buf);
+ break;
+ case HostCmd_CMD_802_11_AD_HOC_START:
+ case HostCmd_CMD_802_11_AD_HOC_JOIN:
+ ret = wlan_ret_802_11_ad_hoc(pmpriv, resp, pioctl_buf);
+ break;
+ case HostCmd_CMD_802_11_AD_HOC_STOP:
+ ret = wlan_ret_802_11_ad_hoc_stop(pmpriv, resp, pioctl_buf);
+ break;
+ case HostCmd_CMD_802_11_GET_LOG:
+ ret = wlan_ret_get_log(pmpriv, resp, pioctl_buf);
+ break;
+ case HostCmd_CMD_RSSI_INFO:
+ ret = wlan_ret_802_11_rssi_info(pmpriv, resp, pioctl_buf);
+ break;
+ case HostCmd_CMD_802_11_SNMP_MIB:
+ ret = wlan_ret_802_11_snmp_mib(pmpriv, resp, pioctl_buf);
+ break;
+ case HostCmd_CMD_802_11_RADIO_CONTROL:
+ ret = wlan_ret_802_11_radio_control(pmpriv, resp, pioctl_buf);
+ break;
+ case HostCmd_CMD_802_11_TX_RATE_QUERY:
+ ret = wlan_ret_802_11_tx_rate_query(pmpriv, resp, pioctl_buf);
+ break;
+ case HostCmd_CMD_802_11_RF_CHANNEL:
+ ret = wlan_ret_802_11_rf_channel(pmpriv, resp, pioctl_buf);
+ break;
+ case HostCmd_CMD_802_11_RF_ANTENNA:
+ ret = wlan_ret_802_11_rf_antenna(pmpriv, resp, pioctl_buf);
+ break;
+ case HostCmd_CMD_VERSION_EXT:
+ ret = wlan_ret_ver_ext(pmpriv, resp, pioctl_buf);
+ break;
+ case HostCmd_CMD_RX_MGMT_IND:
+ ret = wlan_ret_rx_mgmt_ind(pmpriv, resp, pioctl_buf);
+ break;
+ case HostCmd_CMD_FUNC_INIT:
+ case HostCmd_CMD_FUNC_SHUTDOWN:
+ break;
+ case HostCmd_CMD_802_11_KEY_MATERIAL:
+ ret = wlan_ret_802_11_key_material(pmpriv, resp, pioctl_buf);
+ break;
+ case HostCmd_CMD_SUPPLICANT_PMK:
+ ret = wlan_ret_802_11_supplicant_pmk(pmpriv, resp, pioctl_buf);
+ break;
+ case HostCmd_CMD_SUPPLICANT_PROFILE:
+ ret = wlan_ret_802_11_supplicant_profile(pmpriv, resp, pioctl_buf);
+ break;
+ case HostCmd_CMD_802_11D_DOMAIN_INFO:
+ ret = wlan_ret_802_11d_domain_info(pmpriv, resp);
+ break;
+ case HostCmd_CMD_802_11_TPC_ADAPT_REQ:
+ case HostCmd_CMD_802_11_TPC_INFO:
+ case HostCmd_CMD_802_11_CHAN_SW_ANN:
+ case HostCmd_CMD_CHAN_REPORT_REQUEST:
+ ret = wlan_11h_cmdresp_process(pmpriv, resp);
+ break;
+ case HostCmd_CMD_11N_ADDBA_REQ:
+ ret = wlan_ret_11n_addba_req(pmpriv, resp);
+ break;
+ case HostCmd_CMD_11N_DELBA:
+ ret = wlan_ret_11n_delba(pmpriv, resp);
+ break;
+ case HostCmd_CMD_11N_ADDBA_RSP:
+ ret = wlan_ret_11n_addba_resp(pmpriv, resp);
+ break;
+ case HostCmd_CMD_RECONFIGURE_TX_BUFF:
+ pmadapter->tx_buf_size =
+ (t_u16) wlan_le16_to_cpu(resp->params.tx_buf.buff_size);
+ pmadapter->tx_buf_size =
+ (pmadapter->tx_buf_size / MLAN_SDIO_BLOCK_SIZE) *
+ MLAN_SDIO_BLOCK_SIZE;
+ pmadapter->curr_tx_buf_size = pmadapter->tx_buf_size;
+ pmadapter->mp_end_port =
+ wlan_le16_to_cpu(resp->params.tx_buf.mp_end_port);
+ pmadapter->mp_data_port_mask = DATA_PORT_MASK;
+
+ for (ctr = 1; ctr <= MAX_PORT - pmadapter->mp_end_port; ctr++) {
+ pmadapter->mp_data_port_mask &= ~(1 << (MAX_PORT - ctr));
+ }
+
+ pmadapter->curr_wr_port = 1;
+ PRINTM(MCMND, "end port %d, data port mask %x\n",
+ wlan_le16_to_cpu(resp->params.tx_buf.mp_end_port),
+ pmadapter->mp_data_port_mask);
+ PRINTM(MCMND, "max_tx_buf_size=%d, tx_buf_size=%d\n",
+ pmadapter->max_tx_buf_size, pmadapter->tx_buf_size);
+ break;
+ case HostCmd_CMD_AMSDU_AGGR_CTRL:
+ ret = wlan_ret_amsdu_aggr_ctrl(pmpriv, resp, pioctl_buf);
+ break;
+ case HostCmd_CMD_WMM_GET_STATUS:
+ ret = wlan_ret_wmm_get_status(pmpriv,
+ resp->params.get_wmm_status.
+ queue_status_tlv, resp->size - S_DS_GEN);
+ break;
+ case HostCmd_CMD_WMM_ADDTS_REQ:
+ ret = wlan_ret_wmm_addts_req(pmpriv, resp, pioctl_buf);
+ break;
+ case HostCmd_CMD_WMM_DELTS_REQ:
+ ret = wlan_ret_wmm_delts_req(pmpriv, resp, pioctl_buf);
+ break;
+ case HostCmd_CMD_WMM_QUEUE_CONFIG:
+ ret = wlan_ret_wmm_queue_config(pmpriv, resp, pioctl_buf);
+ break;
+ case HostCmd_CMD_WMM_QUEUE_STATS:
+ ret = wlan_ret_wmm_queue_stats(pmpriv, resp, pioctl_buf);
+ break;
+ case HostCmd_CMD_WMM_TS_STATUS:
+ ret = wlan_ret_wmm_ts_status(pmpriv, resp, pioctl_buf);
+ break;
+ case HostCmd_CMD_802_11_IBSS_COALESCING_STATUS:
+ ret = wlan_ret_ibss_coalescing_status(pmpriv, resp);
+ break;
+ case HostCmd_CMD_MGMT_IE_LIST:
+ ret = wlan_ret_mgmt_ie_list(pmpriv, resp, pioctl_buf);
+ break;
+ case HostCmd_CMD_11N_CFG:
+ ret = wlan_ret_11n_cfg(pmpriv, resp, pioctl_buf);
+ break;
+ case HostCmd_CMD_TX_BF_CFG:
+ ret = wlan_ret_tx_bf_cfg(pmpriv, resp, pioctl_buf);
+ break;
+ case HostCmd_CMD_ECL_SYSTEM_CLOCK_CONFIG:
+ ret = wlan_ret_sysclock_cfg(pmpriv, resp, pioctl_buf);
+ break;
+ case HostCmd_CMD_MAC_REG_ACCESS:
+ case HostCmd_CMD_BBP_REG_ACCESS:
+ case HostCmd_CMD_RF_REG_ACCESS:
+ case HostCmd_CMD_CAU_REG_ACCESS:
+ case HostCmd_CMD_802_11_EEPROM_ACCESS:
+ ret =
+ wlan_ret_reg_access(pmpriv->adapter, cmdresp_no, resp, pioctl_buf);
+ break;
+ case HostCmd_CMD_MEM_ACCESS:
+ ret = wlan_ret_mem_access(pmpriv, resp, pioctl_buf);
+ break;
+ case HostCmd_CMD_INACTIVITY_TIMEOUT_EXT:
+ ret = wlan_ret_inactivity_timeout(pmpriv, resp, pioctl_buf);
+ break;
+ case HostCmd_CMD_SDIO_GPIO_INT_CONFIG:
+ break;
+ case HostCmd_CMD_SET_BSS_MODE:
+ break;
+ case HostCmd_CMD_MEASUREMENT_REQUEST:
+ case HostCmd_CMD_MEASUREMENT_REPORT:
+ ret = wlan_meas_cmdresp_process(pmpriv, resp);
+ break;
+#ifdef WIFI_DIRECT_SUPPORT
+ case HostCmd_CMD_802_11_REMAIN_ON_CHANNEL:
+ ret = wlan_ret_remain_on_channel(pmpriv, resp, pioctl_buf);
+ break;
+ case HOST_CMD_WIFI_DIRECT_MODE_CONFIG:
+ ret = wlan_ret_wifi_direct_mode(pmpriv, resp, pioctl_buf);
+ break;
+#endif
+ case HostCmd_CMD_802_11_SUBSCRIBE_EVENT:
+ ret = wlan_ret_subscribe_event(pmpriv, resp, pioctl_buf);
+ break;
+ default:
+ PRINTM(MERROR, "CMD_RESP: Unknown command response %#x\n",
+ resp->command);
+ break;
+ }
+
+ LEAVE();
+ return ret;
+}
diff --git a/drivers/net/wireless/sd8797/mlan/mlan_sta_event.c b/drivers/net/wireless/sd8797/mlan/mlan_sta_event.c
new file mode 100644
index 000000000000..232496681dae
--- /dev/null
+++ b/drivers/net/wireless/sd8797/mlan/mlan_sta_event.c
@@ -0,0 +1,595 @@
+/** @file mlan_sta_event.c
+ *
+ * @brief This file contains MLAN event handling.
+ *
+ * Copyright (C) 2008-2011, Marvell International Ltd.
+ *
+ * This software file (the "File") is distributed by Marvell International
+ * Ltd. under the terms of the GNU General Public License Version 2, June 1991
+ * (the "License"). You may use, redistribute and/or modify this File in
+ * accordance with the terms and conditions of the License, a copy of which
+ * is available by writing to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
+ * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
+ *
+ * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
+ * ARE EXPRESSLY DISCLAIMED. The License provides additional details about
+ * this warranty disclaimer.
+ */
+
+/********************************************************
+Change log:
+ 10/13/2008: initial version
+********************************************************/
+
+#include "mlan.h"
+#include "mlan_join.h"
+#include "mlan_util.h"
+#include "mlan_fw.h"
+#include "mlan_main.h"
+#include "mlan_wmm.h"
+#include "mlan_11n.h"
+#include "mlan_11h.h"
+
+/********************************************************
+ Global Variables
+********************************************************/
+
+/********************************************************
+ Local Functions
+********************************************************/
+
+/**
+ * @brief This function handles link lost, deauth and
+ * disassoc events.
+ *
+ * @param priv A pointer to mlan_private structure
+ * @return N/A
+ */
+static t_void
+wlan_handle_disconnect_event(pmlan_private pmpriv)
+{
+ ENTER();
+
+ if (pmpriv->media_connected == MTRUE) {
+ wlan_reset_connect_state(pmpriv, MTRUE);
+ }
+
+ LEAVE();
+}
+
+/********************************************************
+ Global Functions
+********************************************************/
+/**
+ * @brief This function handles disconnect event, reports disconnect
+ * to upper layer, cleans tx/rx packets,
+ * resets link state etc.
+ *
+ * @param priv A pointer to mlan_private structure
+ * @param drv_disconnect Flag indicating the driver should disconnect
+ * and flush pending packets.
+ *
+ * @return N/A
+ */
+t_void
+wlan_reset_connect_state(pmlan_private priv, t_u8 drv_disconnect)
+{
+ mlan_adapter *pmadapter = priv->adapter;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ state_11d_t enable;
+
+ ENTER();
+
+ if (priv->media_connected != MTRUE) {
+ LEAVE();
+ return;
+ }
+
+ PRINTM(MINFO, "Handles disconnect event.\n");
+
+ if (drv_disconnect) {
+ priv->media_connected = MFALSE;
+ wlan_11h_check_update_radar_det_state(priv);
+ }
+
+ if (priv->port_ctrl_mode == MTRUE) {
+ /* Close the port on Disconnect */
+ PRINTM(MINFO, "DISC: port_status = CLOSED\n");
+ priv->port_open = MFALSE;
+ }
+ priv->scan_block = MFALSE;
+
+ /* Reset SNR/NF/RSSI values */
+ priv->data_rssi_last = 0;
+ priv->data_nf_last = 0;
+ priv->data_rssi_avg = 0;
+ priv->data_nf_avg = 0;
+ priv->bcn_rssi_last = 0;
+ priv->bcn_nf_last = 0;
+ priv->bcn_rssi_avg = 0;
+ priv->bcn_nf_avg = 0;
+ priv->rxpd_rate = 0;
+ priv->rxpd_htinfo = 0;
+ priv->max_amsdu = 0;
+
+ priv->sec_info.ewpa_enabled = MFALSE;
+ priv->sec_info.wpa_enabled = MFALSE;
+ priv->sec_info.wpa2_enabled = MFALSE;
+ priv->wpa_ie_len = 0;
+
+ priv->sec_info.wapi_enabled = MFALSE;
+ priv->wapi_ie_len = 0;
+ priv->sec_info.wapi_key_on = MFALSE;
+
+ priv->wps.session_enable = MFALSE;
+ memset(priv->adapter, (t_u8 *) & priv->wps.wps_ie, 0x00,
+ sizeof(priv->wps.wps_ie));
+
+ priv->sec_info.encryption_mode = MLAN_ENCRYPTION_MODE_NONE;
+
+ /* Enable auto data rate */
+ priv->is_data_rate_auto = MTRUE;
+ priv->data_rate = 0;
+
+ if (priv->bss_mode == MLAN_BSS_MODE_IBSS) {
+ priv->adhoc_state = ADHOC_IDLE;
+ priv->adhoc_is_link_sensed = MFALSE;
+ priv->intf_state_11h.adhoc_auto_sel_chan = MTRUE;
+ }
+
+ if (drv_disconnect) {
+ /* Free Tx and Rx packets, report disconnect to upper layer */
+ wlan_clean_txrx(priv);
+
+ /* Need to erase the current SSID and BSSID info */
+ memset(pmadapter,
+ &priv->curr_bss_params, 0x00, sizeof(priv->curr_bss_params));
+ }
+ pmadapter->tx_lock_flag = MFALSE;
+ pmadapter->pps_uapsd_mode = MFALSE;
+ pmadapter->delay_null_pkt = MFALSE;
+
+ if ((wlan_11d_is_enabled(priv)) &&
+ (priv->state_11d.user_enable_11d == DISABLE_11D)) {
+
+ priv->state_11d.enable_11d = DISABLE_11D;
+ enable = DISABLE_11D;
+
+ /* Send cmd to FW to enable/disable 11D function */
+ ret = wlan_prepare_cmd(priv,
+ HostCmd_CMD_802_11_SNMP_MIB,
+ HostCmd_ACT_GEN_SET, Dot11D_i, MNULL, &enable);
+ if (ret)
+ PRINTM(MERROR, "11D: Failed to enable 11D\n");
+ }
+ if (pmadapter->num_cmd_timeout && pmadapter->curr_cmd &&
+ (pmadapter->cmd_timer_is_set == MFALSE)) {
+ LEAVE();
+ return;
+ }
+
+ wlan_recv_event(priv, MLAN_EVENT_ID_FW_DISCONNECTED, MNULL);
+
+ LEAVE();
+}
+
+/**
+ * @brief This function sends the OBSS scan parameters to the application
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ *
+ * @return N/A
+ */
+t_void
+wlan_2040_coex_event(pmlan_private pmpriv)
+{
+ t_u8 event_buf[100];
+ mlan_event *pevent = (mlan_event *) event_buf;
+ t_u8 ele_len;
+
+ ENTER();
+
+ if (pmpriv->curr_bss_params.bss_descriptor.poverlap_bss_scan_param &&
+ pmpriv->curr_bss_params.bss_descriptor.poverlap_bss_scan_param->
+ ieee_hdr.element_id == OVERLAPBSSSCANPARAM) {
+ ele_len =
+ pmpriv->curr_bss_params.bss_descriptor.poverlap_bss_scan_param->
+ ieee_hdr.len;
+ pevent->bss_index = pmpriv->bss_index;
+ pevent->event_id = MLAN_EVENT_ID_DRV_OBSS_SCAN_PARAM;
+ /* Copy OBSS scan parameters */
+ memcpy(pmpriv->adapter, (t_u8 *) pevent->event_buf,
+ (t_u8 *) & pmpriv->curr_bss_params.bss_descriptor.
+ poverlap_bss_scan_param->obss_scan_param, ele_len);
+ pevent->event_len = ele_len;
+ wlan_recv_event(pmpriv, MLAN_EVENT_ID_DRV_OBSS_SCAN_PARAM, pevent);
+ }
+
+ LEAVE();
+}
+
+/**
+ * @brief This function handles events generated by firmware
+ *
+ * @param priv A pointer to mlan_private structure
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status
+wlan_ops_sta_process_event(IN t_void * priv)
+{
+ pmlan_private pmpriv = (pmlan_private) priv;
+ pmlan_adapter pmadapter = pmpriv->adapter;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ t_u32 eventcause = pmadapter->event_cause;
+ t_u8 event_buf[100];
+ t_u8 *evt_buf = MNULL;
+ pmlan_buffer pmbuf = pmadapter->pmlan_buffer_event;
+ pmlan_callbacks pcb = &pmadapter->callbacks;
+ mlan_event *pevent = (mlan_event *) event_buf;
+
+ ENTER();
+
+ if (eventcause != EVENT_PS_SLEEP && eventcause != EVENT_PS_AWAKE &&
+ pmbuf->data_len > sizeof(eventcause))
+ DBG_HEXDUMP(MEVT_D, "EVENT", pmbuf->pbuf + pmbuf->data_offset,
+ pmbuf->data_len);
+
+ switch (eventcause) {
+ case EVENT_DUMMY_HOST_WAKEUP_SIGNAL:
+ PRINTM(MERROR,
+ "Invalid EVENT: DUMMY_HOST_WAKEUP_SIGNAL, ignoring it\n");
+ break;
+ case EVENT_LINK_SENSED:
+ PRINTM(MEVENT, "EVENT: LINK_SENSED\n");
+ pmpriv->adhoc_is_link_sensed = MTRUE;
+ wlan_recv_event(pmpriv, MLAN_EVENT_ID_FW_ADHOC_LINK_SENSED, MNULL);
+ break;
+
+ case EVENT_DEAUTHENTICATED:
+ PRINTM(MEVENT, "EVENT: Deauthenticated\n");
+ pmadapter->dbg.num_event_deauth++;
+ wlan_handle_disconnect_event(pmpriv);
+
+ break;
+
+ case EVENT_DISASSOCIATED:
+ PRINTM(MEVENT, "EVENT: Disassociated\n");
+ pmadapter->dbg.num_event_disassoc++;
+ wlan_handle_disconnect_event(pmpriv);
+ break;
+
+ case EVENT_LINK_LOST:
+ PRINTM(MEVENT, "EVENT: Link lost\n");
+ pmadapter->dbg.num_event_link_lost++;
+ wlan_handle_disconnect_event(pmpriv);
+ break;
+
+ case EVENT_PS_SLEEP:
+ PRINTM(MINFO, "EVENT: SLEEP\n");
+ PRINTM(MEVENT, "_");
+
+ /* Handle unexpected PS SLEEP event */
+ if (pmadapter->ps_state == PS_STATE_SLEEP_CFM)
+ break;
+ pmadapter->ps_state = PS_STATE_PRE_SLEEP;
+
+ wlan_check_ps_cond(pmadapter);
+ break;
+
+ case EVENT_PS_AWAKE:
+ PRINTM(MINFO, "EVENT: AWAKE \n");
+ PRINTM(MEVENT, "|");
+ if (!pmadapter->pps_uapsd_mode &&
+ pmpriv->media_connected &&
+ (pmpriv->port_open || !pmpriv->port_ctrl_mode) &&
+ pmadapter->sleep_period.period) {
+ pmadapter->pps_uapsd_mode = MTRUE;
+ PRINTM(MEVENT, "PPS/UAPSD mode activated\n");
+ }
+ /* Handle unexpected PS AWAKE event */
+ if (pmadapter->ps_state == PS_STATE_SLEEP_CFM)
+ break;
+ pmadapter->tx_lock_flag = MFALSE;
+ if (pmadapter->pps_uapsd_mode && pmadapter->gen_null_pkt) {
+ if (MTRUE == wlan_check_last_packet_indication(pmpriv)) {
+ if (!pmadapter->data_sent) {
+ if (wlan_send_null_packet(pmpriv,
+ MRVDRV_TxPD_POWER_MGMT_NULL_PACKET
+ |
+ MRVDRV_TxPD_POWER_MGMT_LAST_PACKET)
+ == MLAN_STATUS_SUCCESS) {
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+ }
+ }
+ }
+ }
+ pmadapter->ps_state = PS_STATE_AWAKE;
+ pmadapter->pm_wakeup_card_req = MFALSE;
+ pmadapter->pm_wakeup_fw_try = MFALSE;
+ break;
+
+ case EVENT_HS_ACT_REQ:
+ PRINTM(MEVENT, "EVENT: HS_ACT_REQ\n");
+ ret = wlan_prepare_cmd(priv,
+ HostCmd_CMD_802_11_HS_CFG_ENH,
+ 0, 0, MNULL, MNULL);
+ break;
+
+ case EVENT_MIC_ERR_UNICAST:
+ PRINTM(MEVENT, "EVENT: UNICAST MIC ERROR\n");
+ wlan_recv_event(pmpriv, MLAN_EVENT_ID_FW_MIC_ERR_UNI, MNULL);
+ break;
+
+ case EVENT_MIC_ERR_MULTICAST:
+ PRINTM(MEVENT, "EVENT: MULTICAST MIC ERROR\n");
+ wlan_recv_event(pmpriv, MLAN_EVENT_ID_FW_MIC_ERR_MUL, MNULL);
+ break;
+ case EVENT_MIB_CHANGED:
+ case EVENT_INIT_DONE:
+ break;
+
+ case EVENT_ADHOC_BCN_LOST:
+ PRINTM(MEVENT, "EVENT: ADHOC_BCN_LOST\n");
+ pmpriv->adhoc_is_link_sensed = MFALSE;
+ wlan_clean_txrx(pmpriv);
+ wlan_recv_event(pmpriv, MLAN_EVENT_ID_FW_ADHOC_LINK_LOST, MNULL);
+ break;
+
+ case EVENT_BG_SCAN_REPORT:
+ PRINTM(MEVENT, "EVENT: BGS_REPORT\n");
+ /* Clear the previous scan result */
+ memset(pmadapter, pmadapter->pscan_table, 0x00,
+ sizeof(BSSDescriptor_t) * MRVDRV_MAX_BSSID_LIST);
+ pmadapter->num_in_scan_table = 0;
+ pmadapter->pbcn_buf_end = pmadapter->bcn_buf;
+ ret = wlan_prepare_cmd(pmpriv,
+ HostCmd_CMD_802_11_BG_SCAN_QUERY,
+ HostCmd_ACT_GEN_GET, 0, MNULL, MNULL);
+ break;
+
+ case EVENT_PORT_RELEASE:
+ PRINTM(MEVENT, "EVENT: PORT RELEASE\n");
+ /* Open the port for e-supp mode */
+ if (pmpriv->port_ctrl_mode == MTRUE) {
+ PRINTM(MINFO, "PORT_REL: port_status = OPEN\n");
+ pmpriv->port_open = MTRUE;
+ }
+ pmpriv->scan_block = MFALSE;
+ wlan_recv_event(pmpriv, MLAN_EVENT_ID_FW_PORT_RELEASE, MNULL);
+ break;
+
+ case EVENT_STOP_TX:
+ PRINTM(MEVENT, "EVENT: Stop Tx (%#x)\n", eventcause);
+ wlan_11h_tx_disable(pmpriv); // this fn will send event up to MOAL
+ break;
+ case EVENT_START_TX:
+ PRINTM(MEVENT, "EVENT: Start Tx (%#x)\n", eventcause);
+ wlan_11h_tx_enable(pmpriv); // this fn will send event up to MOAL
+ break;
+ case EVENT_CHANNEL_SWITCH:
+ PRINTM(MEVENT, "EVENT: Channel Switch (%#x)\n", eventcause);
+ /* To be handled for 'chanswann' private command */
+ break;
+ case EVENT_CHANNEL_SWITCH_ANN:
+ PRINTM(MEVENT, "EVENT: Channel Switch Announcement\n");
+ /* Here, pass up event first, as handling will send deauth */
+ wlan_recv_event(pmpriv, MLAN_EVENT_ID_FW_CHANNEL_SWITCH_ANN, MNULL);
+ wlan_11h_handle_event_chanswann(pmpriv);
+ break;
+ case EVENT_RADAR_DETECTED:
+ PRINTM(MEVENT, "EVENT: Radar Detected\n");
+
+ /* Send as passthru first, this event can cause other events */
+ memset(pmadapter, pevent, 0x00, sizeof(event_buf));
+ pevent->bss_index = pmpriv->bss_index;
+ pevent->event_id = MLAN_EVENT_ID_DRV_PASSTHRU;
+ pevent->event_len = pmbuf->data_len;
+ memcpy(pmadapter, (t_u8 *) pevent->event_buf,
+ pmbuf->pbuf + pmbuf->data_offset, pevent->event_len);
+ wlan_recv_event(pmpriv, pevent->event_id, pevent);
+
+ if (pmadapter->state_rdh.stage == RDH_OFF) {
+ pmadapter->state_rdh.stage = RDH_CHK_INTFS;
+ wlan_11h_radar_detected_handling(pmadapter);
+ } else {
+ PRINTM(MEVENT, "Ignore Event Radar Detected - handling"
+ " already in progress.\n");
+ }
+
+ break;
+
+ case EVENT_CHANNEL_REPORT_RDY:
+ PRINTM(MEVENT, "EVENT: Channel Report Ready\n");
+ /* Allocate memory for event buffer */
+ ret = pcb->moal_malloc(pmadapter->pmoal_handle,
+ MAX_EVENT_SIZE, MLAN_MEM_DEF, &evt_buf);
+ if ((ret == MLAN_STATUS_SUCCESS) && evt_buf) {
+ memset(pmadapter, evt_buf, 0x00, MAX_EVENT_SIZE);
+ /* Setup event buffer */
+ pevent = (pmlan_event) evt_buf;
+ pevent->bss_index = pmpriv->bss_index;
+ pevent->event_id = MLAN_EVENT_ID_FW_CHANNEL_REPORT_RDY;
+ pevent->event_len = pmbuf->data_len - sizeof(eventcause);
+ /* Copy event data */
+ memcpy(pmadapter, (t_u8 *) pevent->event_buf,
+ pmbuf->pbuf + pmbuf->data_offset + sizeof(eventcause),
+ pevent->event_len);
+ /* Handle / pass event data */
+ ret = wlan_11h_handle_event_chanrpt_ready(pmpriv, pevent);
+
+ /* Also send this event as passthru */
+ pevent->event_id = MLAN_EVENT_ID_DRV_PASSTHRU;
+ pevent->event_len = pmbuf->data_len;
+ memcpy(pmadapter, (t_u8 *) pevent->event_buf,
+ pmbuf->pbuf + pmbuf->data_offset, pevent->event_len);
+ wlan_recv_event(pmpriv, pevent->event_id, pevent);
+ /* Now done with buffer */
+ pcb->moal_mfree(pmadapter->pmoal_handle, evt_buf);
+ }
+ /* Send up this Event to unblock MOAL waitqueue */
+ wlan_recv_event(pmpriv, MLAN_EVENT_ID_DRV_MEAS_REPORT, MNULL);
+ break;
+ case EVENT_EXT_SCAN_REPORT:
+ PRINTM(MEVENT, "EVENT: EXT_SCAN Report (%#x)\n", eventcause);
+ ret = wlan_handle_event_ext_scan_report(priv, pmbuf);
+ break;
+ case EVENT_MEAS_REPORT_RDY:
+ PRINTM(MEVENT, "EVENT: Measurement Report Ready (%#x)\n", eventcause);
+ wlan_prepare_cmd(priv, HostCmd_CMD_MEASUREMENT_REPORT,
+ HostCmd_ACT_GEN_SET, 0, 0, MNULL);
+ break;
+ case EVENT_WMM_STATUS_CHANGE:
+ if (pmbuf && pmbuf->data_len
+ > sizeof(eventcause) + sizeof(MrvlIEtypesHeader_t)) {
+ PRINTM(MEVENT, "EVENT: WMM status changed: %d\n", pmbuf->data_len);
+
+ evt_buf = (pmbuf->pbuf + pmbuf->data_offset + sizeof(eventcause));
+
+ wlan_ret_wmm_get_status(pmpriv,
+ evt_buf,
+ pmbuf->data_len - sizeof(eventcause));
+ } else {
+ PRINTM(MEVENT, "EVENT: WMM status changed\n");
+ ret = wlan_cmd_wmm_status_change(pmpriv);
+ }
+ break;
+
+ case EVENT_RSSI_LOW:
+ PRINTM(MEVENT, "EVENT: Beacon RSSI_LOW\n");
+ wlan_recv_event(pmpriv, MLAN_EVENT_ID_FW_BCN_RSSI_LOW, MNULL);
+ break;
+ case EVENT_SNR_LOW:
+ PRINTM(MEVENT, "EVENT: Beacon SNR_LOW\n");
+ wlan_recv_event(pmpriv, MLAN_EVENT_ID_FW_BCN_SNR_LOW, MNULL);
+ break;
+ case EVENT_MAX_FAIL:
+ PRINTM(MEVENT, "EVENT: MAX_FAIL\n");
+ wlan_recv_event(pmpriv, MLAN_EVENT_ID_FW_MAX_FAIL, MNULL);
+ break;
+ case EVENT_RSSI_HIGH:
+ PRINTM(MEVENT, "EVENT: Beacon RSSI_HIGH\n");
+ wlan_recv_event(pmpriv, MLAN_EVENT_ID_FW_BCN_RSSI_HIGH, MNULL);
+ break;
+ case EVENT_SNR_HIGH:
+ PRINTM(MEVENT, "EVENT: Beacon SNR_HIGH\n");
+ wlan_recv_event(pmpriv, MLAN_EVENT_ID_FW_BCN_SNR_HIGH, MNULL);
+ break;
+ case EVENT_DATA_RSSI_LOW:
+ PRINTM(MEVENT, "EVENT: Data RSSI_LOW\n");
+ wlan_recv_event(pmpriv, MLAN_EVENT_ID_FW_DATA_RSSI_LOW, MNULL);
+ break;
+ case EVENT_DATA_SNR_LOW:
+ PRINTM(MEVENT, "EVENT: Data SNR_LOW\n");
+ wlan_recv_event(pmpriv, MLAN_EVENT_ID_FW_DATA_SNR_LOW, MNULL);
+ break;
+ case EVENT_DATA_RSSI_HIGH:
+ PRINTM(MEVENT, "EVENT: Data RSSI_HIGH\n");
+ wlan_recv_event(pmpriv, MLAN_EVENT_ID_FW_DATA_RSSI_HIGH, MNULL);
+ break;
+ case EVENT_DATA_SNR_HIGH:
+ PRINTM(MEVENT, "EVENT: Data SNR_HIGH\n");
+ wlan_recv_event(pmpriv, MLAN_EVENT_ID_FW_DATA_SNR_HIGH, MNULL);
+ break;
+ case EVENT_LINK_QUALITY:
+ PRINTM(MEVENT, "EVENT: Link Quality\n");
+ wlan_recv_event(pmpriv, MLAN_EVENT_ID_FW_LINK_QUALITY, MNULL);
+ break;
+ case EVENT_PRE_BEACON_LOST:
+ PRINTM(MEVENT, "EVENT: Pre-Beacon Lost\n");
+ wlan_recv_event(pmpriv, MLAN_EVENT_ID_FW_PRE_BCN_LOST, MNULL);
+ break;
+ case EVENT_IBSS_COALESCED:
+ PRINTM(MEVENT, "EVENT: IBSS_COALESCED\n");
+ ret = wlan_prepare_cmd(pmpriv,
+ HostCmd_CMD_802_11_IBSS_COALESCING_STATUS,
+ HostCmd_ACT_GEN_GET, 0, MNULL, MNULL);
+ break;
+ case EVENT_ADDBA:
+ PRINTM(MEVENT, "EVENT: ADDBA Request\n");
+ wlan_prepare_cmd(pmpriv, HostCmd_CMD_11N_ADDBA_RSP,
+ HostCmd_ACT_GEN_SET, 0, MNULL, pmadapter->event_body);
+ break;
+ case EVENT_DELBA:
+ PRINTM(MEVENT, "EVENT: DELBA Request\n");
+ wlan_11n_delete_bastream(pmpriv, pmadapter->event_body);
+ break;
+ case EVENT_BA_STREAM_TIMEOUT:
+ PRINTM(MEVENT, "EVENT: BA Stream timeout\n");
+ wlan_11n_ba_stream_timeout(pmpriv,
+ (HostCmd_DS_11N_BATIMEOUT *) pmadapter->
+ event_body);
+ break;
+ case EVENT_RXBA_SYNC:
+ PRINTM(MEVENT, "EVENT: RXBA_SYNC\n");
+ wlan_11n_rxba_sync_event(pmpriv, pmadapter->event_body,
+ pmbuf->data_len - sizeof(eventcause));
+ break;
+ case EVENT_AMSDU_AGGR_CTRL:
+ PRINTM(MEVENT, "EVENT: AMSDU_AGGR_CTRL %d\n",
+ *(t_u16 *) pmadapter->event_body);
+ pmadapter->tx_buf_size =
+ MIN(pmadapter->curr_tx_buf_size,
+ wlan_le16_to_cpu(*(t_u16 *) pmadapter->event_body));
+ PRINTM(MEVENT, "tx_buf_size %d\n", pmadapter->tx_buf_size);
+ break;
+
+ case EVENT_WEP_ICV_ERR:
+ PRINTM(MEVENT, "EVENT: WEP ICV error\n");
+ pevent->bss_index = pmpriv->bss_index;
+ pevent->event_id = MLAN_EVENT_ID_FW_WEP_ICV_ERR;
+ pevent->event_len = sizeof(Event_WEP_ICV_ERR);
+ memcpy(pmadapter, (t_u8 *) pevent->event_buf, pmadapter->event_body,
+ pevent->event_len);
+ wlan_recv_event(pmpriv, MLAN_EVENT_ID_FW_WEP_ICV_ERR, pevent);
+ break;
+
+ case EVENT_BW_CHANGE:
+ PRINTM(MEVENT, "EVENT: BW Change\n");
+ pevent->bss_index = pmpriv->bss_index;
+ pevent->event_id = MLAN_EVENT_ID_FW_BW_CHANGED;
+ pevent->event_len = sizeof(t_u8);
+ /* Copy event body from the event buffer */
+ memcpy(pmadapter, (t_u8 *) pevent->event_buf, pmadapter->event_body,
+ pevent->event_len);
+ wlan_recv_event(pmpriv, MLAN_EVENT_ID_FW_BW_CHANGED, pevent);
+ break;
+
+#ifdef WIFI_DIRECT_SUPPORT
+ case EVENT_WIFIDIRECT_GENERIC_EVENT:
+ case EVENT_WIFIDIRECT_SERVICE_DISCOVERY:
+ PRINTM(MEVENT, "EVENT: WIFIDIRECT event %d\n", eventcause);
+ /* Allocate memory for event buffer */
+ ret =
+ pcb->moal_malloc(pmadapter->pmoal_handle, MAX_EVENT_SIZE,
+ MLAN_MEM_DEF, &evt_buf);
+ if ((ret == MLAN_STATUS_SUCCESS) && evt_buf) {
+ pevent = (pmlan_event) evt_buf;
+ pevent->bss_index = pmpriv->bss_index;
+ pevent->event_id = MLAN_EVENT_ID_DRV_PASSTHRU;
+ pevent->event_len = pmbuf->data_len;
+ memcpy(pmadapter, (t_u8 *) pevent->event_buf,
+ pmbuf->pbuf + pmbuf->data_offset, pevent->event_len);
+ wlan_recv_event(pmpriv, pevent->event_id, pevent);
+ pcb->moal_mfree(pmadapter->pmoal_handle, evt_buf);
+ }
+ break;
+ case EVENT_REMAIN_ON_CHANNEL_EXPIRED:
+ PRINTM(MEVENT, "EVENT: REMAIN_ON_CHANNEL_EXPIRED reason=%d\n",
+ *(t_u16 *) pmadapter->event_body);
+ wlan_recv_event(pmpriv, MLAN_EVENT_ID_FW_REMAIN_ON_CHAN_EXPIRED, MNULL);
+ break;
+#endif /* WIFI_DIRECT_SUPPORT */
+
+ default:
+ PRINTM(MEVENT, "EVENT: unknown event id: %#x\n", eventcause);
+ wlan_recv_event(pmpriv, MLAN_EVENT_ID_FW_UNKNOWN, MNULL);
+ break;
+ }
+
+ LEAVE();
+ return ret;
+}
diff --git a/drivers/net/wireless/sd8797/mlan/mlan_sta_ioctl.c b/drivers/net/wireless/sd8797/mlan/mlan_sta_ioctl.c
new file mode 100644
index 000000000000..f5e2edc56b09
--- /dev/null
+++ b/drivers/net/wireless/sd8797/mlan/mlan_sta_ioctl.c
@@ -0,0 +1,5257 @@
+/** @file mlan_sta_ioctl.c
+ *
+ * @brief This file contains the functions for station ioctl.
+ *
+ * Copyright (C) 2008-2011, Marvell International Ltd.
+ *
+ * This software file (the "File") is distributed by Marvell International
+ * Ltd. under the terms of the GNU General Public License Version 2, June 1991
+ * (the "License"). You may use, redistribute and/or modify this File in
+ * accordance with the terms and conditions of the License, a copy of which
+ * is available by writing to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
+ * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
+ *
+ * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
+ * ARE EXPRESSLY DISCLAIMED. The License provides additional details about
+ * this warranty disclaimer.
+ */
+
+/******************************************************
+Change log:
+ 10/21/2008: initial version
+******************************************************/
+
+#include "mlan.h"
+#include "mlan_join.h"
+#include "mlan_util.h"
+#include "mlan_fw.h"
+#include "mlan_main.h"
+#include "mlan_wmm.h"
+#include "mlan_11n.h"
+#include "mlan_sdio.h"
+#include "mlan_11h.h"
+
+/********************************************************
+ Local Variables
+********************************************************/
+
+/********************************************************
+ Global Variables
+********************************************************/
+
+/********************************************************
+ Local Functions
+********************************************************/
+/**
+ * @brief enable adhoc aes key
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ *
+ * @return N/A
+ */
+static void
+wlan_enable_aes_key(pmlan_private pmpriv)
+{
+ mlan_ds_encrypt_key encrypt_key;
+
+ ENTER();
+
+ if (pmpriv->aes_key.key_param_set.key_len != WPA_AES_KEY_LEN) {
+ LEAVE();
+ return;
+ }
+
+ memset(pmpriv->adapter, &encrypt_key, 0, sizeof(mlan_ds_encrypt_key));
+ encrypt_key.key_len = WPA_AES_KEY_LEN;
+ encrypt_key.key_index = MLAN_KEY_INDEX_UNICAST;
+ memcpy(pmpriv->adapter, encrypt_key.key_material,
+ pmpriv->aes_key.key_param_set.key, encrypt_key.key_len);
+ wlan_prepare_cmd(pmpriv, HostCmd_CMD_802_11_KEY_MATERIAL,
+ HostCmd_ACT_GEN_SET, KEY_INFO_ENABLED, MNULL,
+ &encrypt_key);
+ encrypt_key.key_index &= ~MLAN_KEY_INDEX_UNICAST;
+ wlan_prepare_cmd(pmpriv, HostCmd_CMD_802_11_KEY_MATERIAL,
+ HostCmd_ACT_GEN_SET,
+ KEY_INFO_ENABLED, MNULL, &encrypt_key);
+
+ LEAVE();
+ return;
+}
+
+/**
+ * @brief Get signal information
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_PENDING --success, otherwise fail
+ */
+static mlan_status
+wlan_get_info_signal(IN pmlan_adapter pmadapter, IN pmlan_ioctl_req pioctl_req)
+{
+ pmlan_private pmpriv = MNULL;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ if (pioctl_req != MNULL) {
+ pmpriv = pmadapter->priv[pioctl_req->bss_index];
+ } else {
+ PRINTM(MERROR, "MLAN IOCTL information is not present\n");
+ ret = MLAN_STATUS_FAILURE;
+ goto exit;
+ }
+
+ /* Check information buffer length of MLAN IOCTL */
+ if (pioctl_req->buf_len < sizeof(mlan_ds_get_signal)) {
+ PRINTM(MWARN, "MLAN IOCTL information buffer length is too short.\n");
+ pioctl_req->data_read_written = 0;
+ pioctl_req->buf_len_needed = sizeof(mlan_ds_get_signal);
+ pioctl_req->status_code = MLAN_ERROR_INVALID_PARAMETER;
+ ret = MLAN_STATUS_RESOURCE;
+ goto exit;
+ }
+
+ /* Signal info can be obtained only if connected */
+ if (pmpriv->media_connected == MFALSE) {
+ PRINTM(MINFO, "Can not get signal in disconnected state\n");
+ pioctl_req->status_code = MLAN_ERROR_IOCTL_INVALID;
+ ret = MLAN_STATUS_FAILURE;
+ goto exit;
+ }
+
+ /* Send request to firmware */
+ ret = wlan_prepare_cmd(pmpriv,
+ HostCmd_CMD_RSSI_INFO,
+ HostCmd_ACT_GEN_GET,
+ 0, (t_void *) pioctl_req, MNULL);
+
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+
+ exit:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Get statistics information
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_PENDING --success, otherwise fail
+ */
+static mlan_status
+wlan_get_info_stats(IN pmlan_adapter pmadapter, IN pmlan_ioctl_req pioctl_req)
+{
+ pmlan_private pmpriv = MNULL;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ if (pioctl_req != MNULL) {
+ pmpriv = pmadapter->priv[pioctl_req->bss_index];
+ } else {
+ PRINTM(MERROR, "MLAN IOCTL information is not present\n");
+ ret = MLAN_STATUS_FAILURE;
+ goto exit;
+ }
+
+ /* Check information buffer length of MLAN IOCTL */
+ if (pioctl_req->buf_len < sizeof(mlan_ds_get_stats)) {
+ PRINTM(MWARN, "MLAN IOCTL information buffer length is too short.\n");
+ pioctl_req->data_read_written = 0;
+ pioctl_req->buf_len_needed = sizeof(mlan_ds_get_stats);
+ pioctl_req->status_code = MLAN_ERROR_INVALID_PARAMETER;
+ ret = MLAN_STATUS_RESOURCE;
+ goto exit;
+ }
+
+ /* Send request to firmware */
+ ret = wlan_prepare_cmd(pmpriv,
+ HostCmd_CMD_802_11_GET_LOG,
+ HostCmd_ACT_GEN_GET,
+ 0, (t_void *) pioctl_req, MNULL);
+
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+
+ exit:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Get BSS information
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_SUCCESS --success
+ */
+static mlan_status
+wlan_get_info_bss_info(IN pmlan_adapter pmadapter,
+ IN pmlan_ioctl_req pioctl_req)
+{
+ pmlan_private pmpriv = pmadapter->priv[pioctl_req->bss_index];
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_ds_get_info *info;
+ BSSDescriptor_t *pbss_desc;
+ t_s32 tbl_idx = 0;
+
+ ENTER();
+
+ /* Get current BSS info */
+ pbss_desc = &pmpriv->curr_bss_params.bss_descriptor;
+ info = (mlan_ds_get_info *) pioctl_req->pbuf;
+
+ /* BSS mode */
+ info->param.bss_info.bss_mode = pmpriv->bss_mode;
+
+ /* SSID */
+ memcpy(pmadapter, &info->param.bss_info.ssid, &pbss_desc->ssid,
+ sizeof(mlan_802_11_ssid));
+
+ /* BSSID */
+ memcpy(pmadapter, &info->param.bss_info.bssid, &pbss_desc->mac_address,
+ MLAN_MAC_ADDR_LENGTH);
+
+ /* Channel */
+ info->param.bss_info.bss_chan = pbss_desc->channel;
+
+ /* Band */
+ info->param.bss_info.bss_band = (t_u8) pbss_desc->bss_band;
+
+ /* Region code */
+ info->param.bss_info.region_code = pmadapter->region_code;
+
+ /* Scan table index if connected */
+ info->param.bss_info.scan_table_idx = 0;
+ if (pmpriv->media_connected == MTRUE) {
+ tbl_idx =
+ wlan_find_ssid_in_list(pmpriv, &pbss_desc->ssid,
+ pbss_desc->mac_address, pmpriv->bss_mode);
+ if (tbl_idx >= 0)
+ info->param.bss_info.scan_table_idx = tbl_idx;
+ }
+
+ /* Connection status */
+ info->param.bss_info.media_connected = pmpriv->media_connected;
+
+ /* Radio status */
+ info->param.bss_info.radio_on = pmadapter->radio_on;
+
+ /* Tx power information */
+ info->param.bss_info.max_power_level = pmpriv->max_tx_power_level;
+ info->param.bss_info.min_power_level = pmpriv->min_tx_power_level;
+
+ /* AdHoc state */
+ info->param.bss_info.adhoc_state = pmpriv->adhoc_state;
+
+ /* Last beacon NF */
+ info->param.bss_info.bcn_nf_last = pmpriv->bcn_nf_last;
+
+ /* wep status */
+ if (pmpriv->sec_info.wep_status == Wlan802_11WEPEnabled)
+ info->param.bss_info.wep_status = MTRUE;
+ else
+ info->param.bss_info.wep_status = MFALSE;
+
+ info->param.bss_info.is_hs_configured = pmadapter->is_hs_configured;
+ info->param.bss_info.is_deep_sleep = pmadapter->is_deep_sleep;
+
+ /* Capability Info */
+ info->param.bss_info.capability_info = 0;
+ memcpy(pmadapter, &info->param.bss_info.capability_info,
+ &pbss_desc->cap_info, sizeof(info->param.bss_info.capability_info));
+
+ /* Listen Interval */
+ info->param.bss_info.listen_interval = pmpriv->listen_interval;
+
+ /* Association ID */
+ if (pmpriv->assoc_rsp_buf)
+ info->param.bss_info.assoc_id =
+ (t_u16) ((IEEEtypes_AssocRsp_t *) pmpriv->assoc_rsp_buf)->a_id;
+ else
+ info->param.bss_info.assoc_id = 0;
+
+ /* AP/Peer supported rates */
+ memset(pmadapter, info->param.bss_info.peer_supp_rates, 0,
+ sizeof(info->param.bss_info.peer_supp_rates));
+ memcpy(pmadapter, info->param.bss_info.peer_supp_rates,
+ pbss_desc->supported_rates,
+ MIN(sizeof(info->param.bss_info.peer_supp_rates),
+ sizeof(pbss_desc->supported_rates)));
+
+ pioctl_req->data_read_written =
+ sizeof(mlan_bss_info) + MLAN_SUB_COMMAND_SIZE;
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Get information handler
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static mlan_status
+wlan_get_info_ioctl(IN pmlan_adapter pmadapter, IN pmlan_ioctl_req pioctl_req)
+{
+ mlan_status status = MLAN_STATUS_SUCCESS;
+ mlan_ds_get_info *pget_info = MNULL;
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
+
+ ENTER();
+
+ pget_info = (mlan_ds_get_info *) pioctl_req->pbuf;
+
+ switch (pget_info->sub_command) {
+ case MLAN_OID_GET_STATS:
+ status = wlan_get_info_stats(pmadapter, pioctl_req);
+ break;
+ case MLAN_OID_GET_SIGNAL:
+ status = wlan_get_info_signal(pmadapter, pioctl_req);
+ break;
+ case MLAN_OID_GET_FW_INFO:
+ pioctl_req->data_read_written =
+ sizeof(mlan_fw_info) + MLAN_SUB_COMMAND_SIZE;
+ pget_info->param.fw_info.fw_ver = pmadapter->fw_release_number;
+ memcpy(pmadapter, &pget_info->param.fw_info.mac_addr, pmpriv->curr_addr,
+ MLAN_MAC_ADDR_LENGTH);
+ pget_info->param.fw_info.fw_bands = pmadapter->fw_bands;
+ pget_info->param.fw_info.hw_dev_mcs_support =
+ pmadapter->hw_dev_mcs_support;
+ break;
+ case MLAN_OID_GET_BSS_INFO:
+ status = wlan_get_info_bss_info(pmadapter, pioctl_req);
+ break;
+ case MLAN_OID_GET_DEBUG_INFO:
+ status = wlan_get_info_debug_info(pmadapter, pioctl_req);
+ break;
+ case MLAN_OID_GET_VER_EXT:
+ status = wlan_get_info_ver_ext(pmadapter, pioctl_req);
+ break;
+ default:
+ pioctl_req->status_code = MLAN_ERROR_IOCTL_INVALID;
+ status = MLAN_STATUS_FAILURE;
+ break;
+ }
+
+ LEAVE();
+ return status;
+}
+
+/**
+ * @brief Set/Get SNMP MIB handler
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_PENDING --success, otherwise fail
+ */
+static mlan_status
+wlan_snmp_mib_ioctl(IN pmlan_adapter pmadapter, IN pmlan_ioctl_req pioctl_req)
+{
+ pmlan_private pmpriv = pmadapter->priv[pioctl_req->bss_index];
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ t_u16 cmd_action = 0;
+ t_u16 cmd_oid = 0;
+ mlan_ds_snmp_mib *mib = MNULL;
+ t_u32 value = 0;
+
+ ENTER();
+
+ if (pioctl_req->buf_len < sizeof(mlan_ds_snmp_mib)) {
+ PRINTM(MWARN, "MLAN IOCTL information buffer length is too short.\n");
+ pioctl_req->data_read_written = 0;
+ pioctl_req->buf_len_needed = sizeof(mlan_ds_snmp_mib);
+ pioctl_req->status_code = MLAN_ERROR_INVALID_PARAMETER;
+ ret = MLAN_STATUS_RESOURCE;
+ goto exit;
+ }
+
+ mib = (mlan_ds_snmp_mib *) pioctl_req->pbuf;
+ if (pioctl_req->action == MLAN_ACT_SET)
+ cmd_action = HostCmd_ACT_GEN_SET;
+ else
+ cmd_action = HostCmd_ACT_GEN_GET;
+
+ switch (mib->sub_command) {
+ case MLAN_OID_SNMP_MIB_RTS_THRESHOLD:
+ value = mib->param.rts_threshold;
+ cmd_oid = RtsThresh_i;
+ break;
+ case MLAN_OID_SNMP_MIB_FRAG_THRESHOLD:
+ value = mib->param.frag_threshold;
+ cmd_oid = FragThresh_i;
+ break;
+ case MLAN_OID_SNMP_MIB_RETRY_COUNT:
+ value = mib->param.retry_count;
+ cmd_oid = ShortRetryLim_i;
+ break;
+ }
+
+ /* Send request to firmware */
+ ret = wlan_prepare_cmd(pmpriv,
+ HostCmd_CMD_802_11_SNMP_MIB,
+ cmd_action, cmd_oid, (t_void *) pioctl_req, &value);
+
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+
+ exit:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set/Get Infra/Ad-hoc band configuration
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static mlan_status
+wlan_radio_ioctl_band_cfg(IN pmlan_adapter pmadapter,
+ IN pmlan_ioctl_req pioctl_req)
+{
+ t_u8 i, global_band = 0;
+ t_u8 infra_band = 0;
+ t_u8 adhoc_band = 0;
+ t_u32 adhoc_channel = 0;
+ mlan_ds_radio_cfg *radio_cfg = MNULL;
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
+
+ ENTER();
+
+ radio_cfg = (mlan_ds_radio_cfg *) pioctl_req->pbuf;
+ if (pioctl_req->action == MLAN_ACT_SET) {
+ infra_band = (t_u8) radio_cfg->param.band_cfg.config_bands;
+ adhoc_band = (t_u8) radio_cfg->param.band_cfg.adhoc_start_band;
+ adhoc_channel = radio_cfg->param.band_cfg.adhoc_channel;
+
+ /* SET Infra band */
+ if ((infra_band | pmadapter->fw_bands) & ~pmadapter->fw_bands) {
+ pioctl_req->status_code = MLAN_ERROR_INVALID_PARAMETER;
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+
+ /* SET Ad-hoc Band */
+ if ((adhoc_band | pmadapter->fw_bands) & ~pmadapter->fw_bands) {
+ pioctl_req->status_code = MLAN_ERROR_INVALID_PARAMETER;
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+ if (!adhoc_band)
+ adhoc_band = pmadapter->adhoc_start_band;
+
+ for (i = 0; i < pmadapter->priv_num; i++) {
+ if (pmadapter->priv[i] && pmadapter->priv[i] != pmpriv &&
+ GET_BSS_ROLE(pmadapter->priv[i]) == MLAN_BSS_ROLE_STA)
+ global_band |= pmadapter->priv[i]->config_bands;
+ }
+ global_band |= infra_band;
+
+ if (wlan_set_regiontable
+ (pmpriv, (t_u8) pmadapter->region_code, global_band | adhoc_band)) {
+ pioctl_req->status_code = MLAN_ERROR_IOCTL_FAIL;
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+
+ if (wlan_11d_set_universaltable(pmpriv, global_band | adhoc_band)) {
+ pioctl_req->status_code = MLAN_ERROR_IOCTL_FAIL;
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+ pmpriv->config_bands = infra_band;
+ pmadapter->config_bands = global_band;
+
+ pmadapter->adhoc_start_band = adhoc_band;
+ pmpriv->intf_state_11h.adhoc_auto_sel_chan = MFALSE;
+ pmadapter->chan_bandwidth =
+ (t_u8) radio_cfg->param.band_cfg.sec_chan_offset;
+ /*
+ * If no adhoc_channel is supplied verify if the existing adhoc channel
+ * compiles with new adhoc_band
+ */
+ if (!adhoc_channel) {
+ if (!wlan_find_cfp_by_band_and_channel
+ (pmadapter, pmadapter->adhoc_start_band,
+ pmpriv->adhoc_channel)) {
+ /* Pass back the default channel */
+ radio_cfg->param.band_cfg.adhoc_channel =
+ DEFAULT_AD_HOC_CHANNEL;
+ if ((pmadapter->adhoc_start_band & BAND_A)
+ || (pmadapter->adhoc_start_band & BAND_AN)
+ ) {
+ radio_cfg->param.band_cfg.adhoc_channel =
+ DEFAULT_AD_HOC_CHANNEL_A;
+ }
+ }
+ } else { /* Return error if adhoc_band and adhoc_channel
+ combination is invalid */
+ if (!wlan_find_cfp_by_band_and_channel
+ (pmadapter, pmadapter->adhoc_start_band,
+ (t_u16) adhoc_channel)) {
+ pioctl_req->status_code = MLAN_ERROR_INVALID_PARAMETER;
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+ pmpriv->adhoc_channel = (t_u8) adhoc_channel;
+ }
+ if ((adhoc_band & BAND_GN)
+ || (adhoc_band & BAND_AN)
+ ) {
+ pmadapter->adhoc_11n_enabled = MTRUE;
+ } else {
+ pmadapter->adhoc_11n_enabled = MFALSE;
+ }
+ } else {
+ radio_cfg->param.band_cfg.config_bands = pmpriv->config_bands; /* Infra
+ Bands
+ */
+ radio_cfg->param.band_cfg.adhoc_start_band = pmadapter->adhoc_start_band; /* Adhoc
+ Band
+ */
+ radio_cfg->param.band_cfg.adhoc_channel = pmpriv->adhoc_channel; /* Adhoc
+ Channel
+ */
+ radio_cfg->param.band_cfg.fw_bands = pmadapter->fw_bands; /* FW
+ support
+ Bands
+ */
+ PRINTM(MINFO, "Global config band = %d\n", pmadapter->config_bands);
+ radio_cfg->param.band_cfg.sec_chan_offset = pmadapter->chan_bandwidth; /* adhoc
+ channel
+ bandwidth
+ */
+
+ }
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief Radio command handler
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static mlan_status
+wlan_radio_ioctl(IN pmlan_adapter pmadapter, IN pmlan_ioctl_req pioctl_req)
+{
+ mlan_status status = MLAN_STATUS_SUCCESS;
+ mlan_ds_radio_cfg *radio_cfg = MNULL;
+
+ ENTER();
+
+ if (pioctl_req->buf_len < sizeof(mlan_ds_radio_cfg)) {
+ PRINTM(MWARN, "MLAN IOCTL information buffer length is too short.\n");
+ pioctl_req->data_read_written = 0;
+ pioctl_req->buf_len_needed = sizeof(mlan_ds_radio_cfg);
+ pioctl_req->status_code = MLAN_ERROR_INVALID_PARAMETER;
+ LEAVE();
+ return MLAN_STATUS_RESOURCE;
+ }
+ radio_cfg = (mlan_ds_radio_cfg *) pioctl_req->pbuf;
+ switch (radio_cfg->sub_command) {
+ case MLAN_OID_RADIO_CTRL:
+ status = wlan_radio_ioctl_radio_ctl(pmadapter, pioctl_req);
+ break;
+ case MLAN_OID_BAND_CFG:
+ status = wlan_radio_ioctl_band_cfg(pmadapter, pioctl_req);
+ break;
+ case MLAN_OID_ANT_CFG:
+ status = wlan_radio_ioctl_ant_cfg(pmadapter, pioctl_req);
+ break;
+#ifdef WIFI_DIRECT_SUPPORT
+ case MLAN_OID_REMAIN_CHAN_CFG:
+ status = wlan_radio_ioctl_remain_chan_cfg(pmadapter, pioctl_req);
+ break;
+#endif
+ default:
+ pioctl_req->status_code = MLAN_ERROR_IOCTL_INVALID;
+ status = MLAN_STATUS_FAILURE;
+ break;
+ }
+
+ LEAVE();
+ return status;
+}
+
+/**
+ * @brief Set/Get MAC address
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_PENDING --success, otherwise fail
+ */
+static mlan_status
+wlan_bss_ioctl_mac_address(IN pmlan_adapter pmadapter,
+ IN pmlan_ioctl_req pioctl_req)
+{
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
+ mlan_ds_bss *bss = MNULL;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ ENTER();
+ bss = (mlan_ds_bss *) pioctl_req->pbuf;
+ if (pioctl_req->action == MLAN_ACT_GET) {
+ pioctl_req->data_read_written =
+ MLAN_MAC_ADDR_LENGTH + MLAN_SUB_COMMAND_SIZE;
+ memcpy(pmadapter, &bss->param.mac_addr, pmpriv->curr_addr,
+ MLAN_MAC_ADDR_LENGTH);
+ ret = MLAN_STATUS_SUCCESS;
+ goto exit;
+ }
+
+ memcpy(pmadapter, pmpriv->curr_addr, &bss->param.mac_addr,
+ MLAN_MAC_ADDR_LENGTH);
+
+ /* Send request to firmware */
+ ret = wlan_prepare_cmd(pmpriv,
+ HostCmd_CMD_802_11_MAC_ADDRESS,
+ HostCmd_ACT_GEN_SET,
+ 0, (t_void *) pioctl_req, MNULL);
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+ exit:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set multicast list
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING --success, otherwise fail
+ */
+static mlan_status
+wlan_bss_ioctl_set_multicast_list(IN pmlan_adapter pmadapter,
+ IN pmlan_ioctl_req pioctl_req)
+{
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
+ mlan_ds_bss *bss = MNULL;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ t_u16 old_pkt_filter;
+
+ ENTER();
+
+ old_pkt_filter = pmpriv->curr_pkt_filter;
+ bss = (mlan_ds_bss *) pioctl_req->pbuf;
+ if (pioctl_req->action == MLAN_ACT_GET) {
+ pioctl_req->status_code = MLAN_ERROR_IOCTL_INVALID;
+ ret = MLAN_STATUS_FAILURE;
+ goto exit;
+ }
+ pioctl_req->data_read_written =
+ sizeof(mlan_multicast_list) + MLAN_SUB_COMMAND_SIZE;
+ if (bss->param.multicast_list.mode == MLAN_PROMISC_MODE) {
+ PRINTM(MINFO, "Enable Promiscuous mode\n");
+ pmpriv->curr_pkt_filter |= HostCmd_ACT_MAC_PROMISCUOUS_ENABLE;
+ pmpriv->curr_pkt_filter &= ~HostCmd_ACT_MAC_ALL_MULTICAST_ENABLE;
+ } else {
+ /* Multicast */
+ pmpriv->curr_pkt_filter &= ~HostCmd_ACT_MAC_PROMISCUOUS_ENABLE;
+ if (bss->param.multicast_list.mode == MLAN_ALL_MULTI_MODE) {
+ PRINTM(MINFO, "Enabling All Multicast!\n");
+ pmpriv->curr_pkt_filter |= HostCmd_ACT_MAC_ALL_MULTICAST_ENABLE;
+ } else {
+ pmpriv->curr_pkt_filter &= ~HostCmd_ACT_MAC_ALL_MULTICAST_ENABLE;
+ if (bss->param.multicast_list.num_multicast_addr) {
+ PRINTM(MINFO, "Set multicast list=%d\n",
+ bss->param.multicast_list.num_multicast_addr);
+ /* Set multicast addresses to firmware */
+ if (old_pkt_filter == pmpriv->curr_pkt_filter) {
+ /* Send request to firmware */
+ ret =
+ wlan_prepare_cmd(pmpriv, HostCmd_CMD_MAC_MULTICAST_ADR,
+ HostCmd_ACT_GEN_SET, 0,
+ (t_void *) pioctl_req,
+ &bss->param.multicast_list);
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+ } else {
+ /* Send request to firmware */
+ ret =
+ wlan_prepare_cmd(pmpriv, HostCmd_CMD_MAC_MULTICAST_ADR,
+ HostCmd_ACT_GEN_SET, 0, MNULL,
+ &bss->param.multicast_list);
+ }
+ }
+ }
+ }
+ PRINTM(MINFO, "old_pkt_filter=0x%x, curr_pkt_filter=0x%x\n", old_pkt_filter,
+ pmpriv->curr_pkt_filter);
+ if (old_pkt_filter != pmpriv->curr_pkt_filter) {
+ ret = wlan_prepare_cmd(pmpriv,
+ HostCmd_CMD_MAC_CONTROL,
+ HostCmd_ACT_GEN_SET,
+ 0,
+ (t_void *) pioctl_req, &pmpriv->curr_pkt_filter);
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+ }
+
+ exit:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Get channel list
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static mlan_status
+wlan_bss_ioctl_get_channel_list(IN pmlan_adapter pmadapter,
+ IN pmlan_ioctl_req pioctl_req)
+{
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
+ mlan_ds_bss *bss = MNULL;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ chan_freq_power_t *cfp;
+ t_u32 i, j;
+
+ ENTER();
+
+ bss = (mlan_ds_bss *) pioctl_req->pbuf;
+ if (pioctl_req->action != MLAN_ACT_GET) {
+ pioctl_req->status_code = MLAN_ERROR_IOCTL_INVALID;
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+ if ((wlan_11d_is_enabled(pmpriv) &&
+ pmpriv->media_connected == MTRUE) &&
+ ((pmpriv->bss_mode == MLAN_BSS_MODE_INFRA) ||
+ (pmpriv->bss_mode == MLAN_BSS_MODE_IBSS &&
+ pmpriv->adhoc_state != ADHOC_STARTED))
+ ) {
+ t_u8 chan_no;
+ t_u8 band;
+
+ parsed_region_chan_11d_t *parsed_region_chan = MNULL;
+ parsed_region_chan_11d_t region_chan;
+
+ BSSDescriptor_t *pbss_desc = &pmpriv->curr_bss_params.bss_descriptor;
+
+ memset(pmadapter, &region_chan, 0, sizeof(parsed_region_chan_11d_t));
+
+ /* If country IE is present in the associated AP then return the
+ channel list from country IE else return it from the learning table */
+
+ if (wlan_11d_parse_domain_info(pmadapter, &pbss_desc->country_info,
+ (t_u8) pbss_desc->bss_band,
+ &region_chan) == MLAN_STATUS_SUCCESS) {
+
+ parsed_region_chan = &region_chan;
+ } else {
+ parsed_region_chan = &pmadapter->parsed_region_chan;
+ }
+
+ PRINTM(MINFO, "no_of_chan=%d\n", parsed_region_chan->no_of_chan);
+
+ for (i = 0; (bss->param.chanlist.num_of_chan < MLAN_MAX_CHANNEL_NUM)
+ && (i < parsed_region_chan->no_of_chan); i++) {
+ chan_no = parsed_region_chan->chan_pwr[i].chan;
+ band = parsed_region_chan->chan_pwr[i].band;
+ PRINTM(MINFO, "band=%d, chan_no=%d\n", band, chan_no);
+ bss->param.chanlist.cf[bss->param.chanlist.num_of_chan].channel =
+ (t_u32) chan_no;
+ bss->param.chanlist.cf[bss->param.chanlist.num_of_chan].freq =
+ (t_u32) wlan_11d_chan_2_freq(pmadapter, chan_no, band);
+ bss->param.chanlist.num_of_chan++;
+ }
+ } else {
+ for (j = 0; (bss->param.chanlist.num_of_chan < MLAN_MAX_CHANNEL_NUM)
+ && (j < MAX_REGION_CHANNEL_NUM); j++) {
+ cfp = pmadapter->region_channel[j].pcfp;
+ for (i = 0; (bss->param.chanlist.num_of_chan < MLAN_MAX_CHANNEL_NUM)
+ && pmadapter->region_channel[j].valid
+ && cfp && (i < pmadapter->region_channel[j].num_cfp); i++) {
+ bss->param.chanlist.cf[bss->param.chanlist.num_of_chan].
+ channel = (t_u32) cfp->channel;
+ bss->param.chanlist.cf[bss->param.chanlist.num_of_chan].freq =
+ (t_u32) cfp->freq;
+ bss->param.chanlist.num_of_chan++;
+ cfp++;
+ }
+ }
+ }
+
+ PRINTM(MINFO, "num of channel=%d\n", bss->param.chanlist.num_of_chan);
+
+ LEAVE();
+ return ret;
+}
+
+/** Highest channel used in 2.4GHz band */
+#define MAX_CHANNEL_BAND_B (14)
+
+/** Highest frequency used in 2.4GHz band */
+#define MAX_FREQUENCY_BAND_B (2484)
+
+/**
+ * @brief Set/Get BSS channel
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static mlan_status
+wlan_bss_ioctl_channel(IN pmlan_adapter pmadapter,
+ IN pmlan_ioctl_req pioctl_req)
+{
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
+ mlan_ds_bss *bss = MNULL;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ chan_freq_power_t *cfp = MNULL;
+ ENTER();
+
+ if ((pioctl_req == MNULL) || (pioctl_req->pbuf == MNULL)) {
+ PRINTM(MERROR, "Request buffer not found!\n");
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+ bss = (mlan_ds_bss *) pioctl_req->pbuf;
+ if (pioctl_req->action == MLAN_ACT_GET) {
+ cfp = wlan_find_cfp_by_band_and_channel(pmadapter,
+ pmpriv->curr_bss_params.band,
+ (t_u16) pmpriv->curr_bss_params.
+ bss_descriptor.channel);
+ if (cfp) {
+ bss->param.bss_chan.channel = cfp->channel;
+ bss->param.bss_chan.freq = cfp->freq;
+ } else {
+ pioctl_req->status_code = MLAN_ERROR_INVALID_PARAMETER;
+ ret = MLAN_STATUS_FAILURE;
+ }
+ pioctl_req->data_read_written =
+ sizeof(chan_freq) + MLAN_SUB_COMMAND_SIZE;
+ LEAVE();
+ return ret;
+ }
+ if (!bss->param.bss_chan.channel && !bss->param.bss_chan.freq) {
+ pioctl_req->status_code = MLAN_ERROR_INVALID_PARAMETER;
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+ if (pmadapter->adhoc_start_band & BAND_AN)
+ pmadapter->adhoc_start_band = BAND_G | BAND_B | BAND_GN;
+ else if (pmadapter->adhoc_start_band & BAND_A)
+ pmadapter->adhoc_start_band = BAND_G | BAND_B;
+ if (bss->param.bss_chan.channel) {
+ if (bss->param.bss_chan.channel <= MAX_CHANNEL_BAND_B)
+ cfp =
+ wlan_find_cfp_by_band_and_channel(pmadapter, BAND_B,
+ (t_u16) bss->param.bss_chan.
+ channel);
+ if (!cfp) {
+ cfp =
+ wlan_find_cfp_by_band_and_channel(pmadapter, BAND_A,
+ (t_u16) bss->param.bss_chan.
+ channel);
+ if (cfp) {
+ if (pmadapter->adhoc_11n_enabled)
+ pmadapter->adhoc_start_band = BAND_A | BAND_AN;
+ else
+ pmadapter->adhoc_start_band = BAND_A;
+ }
+ }
+ } else {
+ if (bss->param.bss_chan.freq <= MAX_FREQUENCY_BAND_B)
+ cfp =
+ wlan_find_cfp_by_band_and_freq(pmadapter, BAND_B,
+ bss->param.bss_chan.freq);
+ if (!cfp) {
+ cfp =
+ wlan_find_cfp_by_band_and_freq(pmadapter, BAND_A,
+ bss->param.bss_chan.freq);
+ if (cfp) {
+ if (pmadapter->adhoc_11n_enabled)
+ pmadapter->adhoc_start_band = BAND_A | BAND_AN;
+ else
+ pmadapter->adhoc_start_band = BAND_A;
+ }
+ }
+ }
+ if (!cfp || !cfp->channel) {
+ PRINTM(MERROR, "Invalid channel/freq\n");
+ if (pioctl_req)
+ pioctl_req->status_code = MLAN_ERROR_INVALID_PARAMETER;
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+
+ }
+ pmpriv->adhoc_channel = (t_u8) cfp->channel;
+ pmpriv->intf_state_11h.adhoc_auto_sel_chan = MFALSE;
+ bss->param.bss_chan.channel = cfp->channel;
+ bss->param.bss_chan.freq = cfp->freq;
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set/Get BSS mode
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING --success, otherwise fail
+ */
+static mlan_status
+wlan_bss_ioctl_mode(IN pmlan_adapter pmadapter, IN pmlan_ioctl_req pioctl_req)
+{
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
+ mlan_ds_bss *bss = MNULL;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ bss = (mlan_ds_bss *) pioctl_req->pbuf;
+
+ ENTER();
+
+ if (pioctl_req->action == MLAN_ACT_GET) {
+ bss->param.bss_mode = pmpriv->bss_mode;
+ pioctl_req->data_read_written = sizeof(t_u32) + MLAN_SUB_COMMAND_SIZE;
+ goto exit;
+ }
+
+ if ((pmpriv->bss_mode == bss->param.bss_mode) ||
+ (bss->param.bss_mode == MLAN_BSS_MODE_AUTO)) {
+ PRINTM(MINFO, "Already set to required mode! No change!\n");
+ pmpriv->bss_mode = bss->param.bss_mode;
+ goto exit;
+ }
+
+ if (pmpriv->bss_mode != MLAN_BSS_MODE_AUTO)
+ ret = wlan_disconnect(pmpriv, MNULL, MNULL);
+ else
+ ret = wlan_disconnect(pmpriv, pioctl_req, MNULL);
+
+ if (pmpriv->sec_info.authentication_mode != MLAN_AUTH_MODE_AUTO)
+ pmpriv->sec_info.authentication_mode = MLAN_AUTH_MODE_OPEN;
+ pmpriv->bss_mode = bss->param.bss_mode;
+
+ if (pmpriv->bss_mode == MLAN_BSS_MODE_INFRA)
+ pmpriv->port_ctrl_mode = MTRUE;
+ else
+ pmpriv->port_ctrl_mode = MFALSE;
+
+ if ((pmpriv->bss_mode != MLAN_BSS_MODE_AUTO)
+ ) {
+ ret = wlan_prepare_cmd(pmpriv,
+ HostCmd_CMD_SET_BSS_MODE,
+ HostCmd_ACT_GEN_SET,
+ 0, (t_void *) pioctl_req, MNULL);
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+ }
+ exit:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Start BSS
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_PENDING --success, otherwise fail
+ */
+static mlan_status
+wlan_bss_ioctl_start(IN pmlan_adapter pmadapter, IN pmlan_ioctl_req pioctl_req)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
+ mlan_ds_bss *bss = (mlan_ds_bss *) pioctl_req->pbuf;
+ t_s32 i = -1;
+ t_u8 zero_mac[] = { 0, 0, 0, 0, 0, 0 };
+
+ ENTER();
+
+ /* Before ASSOC REQ, If "port ctrl" mode is enabled, move the port to
+ CLOSED state */
+ if (pmpriv->port_ctrl_mode == MTRUE) {
+ PRINTM(MINFO, "bss_ioctl_start(): port_state=CLOSED\n");
+ pmpriv->port_open = MFALSE;
+ }
+ pmpriv->scan_block = MFALSE;
+
+ if (pmpriv->bss_mode == MLAN_BSS_MODE_INFRA) {
+ if (!bss->param.ssid_bssid.idx ||
+ bss->param.ssid_bssid.idx > pmadapter->num_in_scan_table) {
+ /* Search for the requested SSID in the scan table */
+ if (bss->param.ssid_bssid.ssid.ssid_len) {
+ if (memcmp
+ (pmadapter, &bss->param.ssid_bssid.bssid, zero_mac,
+ sizeof(zero_mac)))
+ i = wlan_find_ssid_in_list(pmpriv,
+ &bss->param.ssid_bssid.ssid,
+ (t_u8 *) & bss->param.ssid_bssid.
+ bssid, MLAN_BSS_MODE_INFRA);
+ else
+ i = wlan_find_ssid_in_list(pmpriv,
+ &bss->param.ssid_bssid.ssid,
+ MNULL, MLAN_BSS_MODE_INFRA);
+ } else {
+ i = wlan_find_bssid_in_list(pmpriv,
+ (t_u8 *) & bss->param.ssid_bssid.
+ bssid, MLAN_BSS_MODE_INFRA);
+ }
+ } else {
+ /* use bsslist index number to assoicate */
+ i = wlan_is_network_compatible(pmpriv,
+ bss->param.ssid_bssid.idx - 1,
+ pmpriv->bss_mode);
+ }
+ if (i >= 0) {
+ PRINTM(MINFO, "SSID found in scan list ... associating...\n");
+
+ /* Clear any past association response stored for application
+ retrieval */
+ pmpriv->assoc_rsp_size = 0;
+ ret = wlan_associate(pmpriv, pioctl_req,
+ &pmadapter->pscan_table[i]);
+ if (ret)
+ goto start_ssid_done;
+ } else { /* i >= 0 */
+ PRINTM(MERROR,
+ "SSID not found in scan list: ssid=%s, %02x:%02x:%02x:%02x:%02x:%02x, idx=%d\n",
+ bss->param.ssid_bssid.ssid.ssid,
+ bss->param.ssid_bssid.bssid[0],
+ bss->param.ssid_bssid.bssid[1],
+ bss->param.ssid_bssid.bssid[2],
+ bss->param.ssid_bssid.bssid[3],
+ bss->param.ssid_bssid.bssid[4],
+ bss->param.ssid_bssid.bssid[5],
+ (int) bss->param.ssid_bssid.idx);
+ pioctl_req->status_code = MLAN_ERROR_INVALID_PARAMETER;
+ ret = MLAN_STATUS_FAILURE;
+ goto start_ssid_done;
+ }
+ } else {
+ /* Adhoc mode */
+ /* If the requested SSID matches current SSID, return */
+ if (bss->param.ssid_bssid.ssid.ssid_len &&
+ (!wlan_ssid_cmp
+ (pmadapter, &pmpriv->curr_bss_params.bss_descriptor.ssid,
+ &bss->param.ssid_bssid.ssid))) {
+ ret = MLAN_STATUS_SUCCESS;
+ goto start_ssid_done;
+ }
+
+ /* Exit Adhoc mode first */
+ PRINTM(MINFO, "Sending Adhoc Stop\n");
+ ret = wlan_disconnect(pmpriv, MNULL, MNULL);
+ if (ret)
+ goto start_ssid_done;
+
+ pmpriv->adhoc_is_link_sensed = MFALSE;
+
+ if (!bss->param.ssid_bssid.idx ||
+ bss->param.ssid_bssid.idx > pmadapter->num_in_scan_table) {
+ /* Search for the requested network in the scan table */
+ if (bss->param.ssid_bssid.ssid.ssid_len) {
+ i = wlan_find_ssid_in_list(pmpriv,
+ &bss->param.ssid_bssid.ssid,
+ MNULL, MLAN_BSS_MODE_IBSS);
+ } else {
+ i = wlan_find_bssid_in_list(pmpriv,
+ (t_u8 *) & bss->param.ssid_bssid.
+ bssid, MLAN_BSS_MODE_IBSS);
+ }
+ } else {
+ /* use bsslist index number to assoicate */
+ i = wlan_is_network_compatible(pmpriv,
+ bss->param.ssid_bssid.idx - 1,
+ pmpriv->bss_mode);
+ }
+
+ if (i >= 0) {
+ PRINTM(MINFO, "Network found in scan list ... joining ...\n");
+ ret =
+ wlan_adhoc_join(pmpriv, pioctl_req, &pmadapter->pscan_table[i]);
+ if (ret)
+ goto start_ssid_done;
+ if (pmpriv->adhoc_aes_enabled)
+ wlan_enable_aes_key(pmpriv);
+ } else { /* i >= 0 */
+ PRINTM(MINFO, "Network not found in the list, "
+ "creating adhoc with ssid = %s\n",
+ bss->param.ssid_bssid.ssid.ssid);
+ ret =
+ wlan_adhoc_start(pmpriv, pioctl_req,
+ &bss->param.ssid_bssid.ssid);
+ if (ret)
+ goto start_ssid_done;
+ if (pmpriv->adhoc_aes_enabled)
+ wlan_enable_aes_key(pmpriv);
+ }
+ }
+
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+
+ start_ssid_done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Stop BSS
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING --success, otherwise fail
+ */
+static mlan_status
+wlan_bss_ioctl_stop(IN pmlan_adapter pmadapter, IN pmlan_ioctl_req pioctl_req)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ pmlan_private pmpriv = pmadapter->priv[pioctl_req->bss_index];
+ mlan_ds_bss *bss = (mlan_ds_bss *) pioctl_req->pbuf;
+
+ ENTER();
+
+ ret = wlan_disconnect(pmpriv, pioctl_req, &bss->param.bssid);
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set/Get IBSS channel
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING --success, otherwise fail
+ */
+static mlan_status
+wlan_bss_ioctl_ibss_channel(IN pmlan_adapter pmadapter,
+ IN pmlan_ioctl_req pioctl_req)
+{
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
+ mlan_ds_bss *bss = MNULL;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ t_u16 cmd_action;
+
+ ENTER();
+
+ bss = (mlan_ds_bss *) pioctl_req->pbuf;
+ if (pioctl_req->action == MLAN_ACT_GET) {
+ if (pmpriv->media_connected == MFALSE) {
+ bss->param.bss_chan.channel = pmpriv->adhoc_channel;
+ goto exit;
+ }
+ cmd_action = HostCmd_ACT_GEN_GET;
+ } else {
+ cmd_action = HostCmd_ACT_GEN_SET;
+ pmpriv->adhoc_channel = (t_u8) bss->param.bss_chan.channel;
+ pmpriv->intf_state_11h.adhoc_auto_sel_chan = MFALSE;
+ }
+
+ /* Send request to firmware */
+ ret = wlan_prepare_cmd(pmpriv,
+ HostCmd_CMD_802_11_RF_CHANNEL,
+ cmd_action,
+ 0,
+ (t_void *) pioctl_req, &bss->param.bss_chan.channel);
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+
+ exit:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set/Get beacon interval
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_SUCCESS --success
+ */
+static mlan_status
+wlan_bss_ioctl_beacon_interval(IN pmlan_adapter pmadapter,
+ IN pmlan_ioctl_req pioctl_req)
+{
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
+ mlan_ds_bss *bss = MNULL;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ ENTER();
+ bss = (mlan_ds_bss *) pioctl_req->pbuf;
+ if (pioctl_req->action == MLAN_ACT_GET) {
+ bss->param.bcn_interval = pmpriv->beacon_period;
+ if (pmpriv->media_connected == MTRUE)
+ bss->param.bcn_interval =
+ pmpriv->curr_bss_params.bss_descriptor.beacon_period;
+ } else
+ pmpriv->beacon_period = (t_u16) bss->param.bcn_interval;
+ pioctl_req->data_read_written = sizeof(t_u32) + MLAN_SUB_COMMAND_SIZE;
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set/Get ATIM window
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_SUCCESS --success
+ */
+static mlan_status
+wlan_bss_ioctl_atim_window(IN pmlan_adapter pmadapter,
+ IN pmlan_ioctl_req pioctl_req)
+{
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
+ mlan_ds_bss *bss = MNULL;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ ENTER();
+ bss = (mlan_ds_bss *) pioctl_req->pbuf;
+ if (pioctl_req->action == MLAN_ACT_GET) {
+ bss->param.atim_window = pmpriv->atim_window;
+ if (pmpriv->media_connected == MTRUE)
+ bss->param.atim_window =
+ pmpriv->curr_bss_params.bss_descriptor.atim_window;
+ } else
+ pmpriv->atim_window = (t_u16) bss->param.atim_window;
+
+ pioctl_req->data_read_written = sizeof(t_u32) + MLAN_SUB_COMMAND_SIZE;
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Query embe
+ *
+ * @param priv A pointer to mlan_private structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_SUCCESS -- success, otherwise fail
+ */
+static mlan_status
+wlan_query_passphrase(mlan_private * priv, pmlan_ioctl_req pioctl_req)
+{
+ mlan_adapter *pmadapter = priv->adapter;
+ mlan_ds_bss *bss = MNULL;
+ mlan_ssid_bssid *ssid_bssid = MNULL;
+ mlan_ds_passphrase sec_pp;
+ int i = 0;
+ BSSDescriptor_t *pbss_desc;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ bss = (mlan_ds_bss *) pioctl_req->pbuf;
+ ssid_bssid = &bss->param.ssid_bssid;
+
+ memset(pmadapter, &sec_pp, 0, sizeof(mlan_ds_passphrase));
+ sec_pp.psk_type = MLAN_PSK_QUERY;
+ if (ssid_bssid->ssid.ssid_len == 0) {
+ i = wlan_find_bssid_in_list(priv, (t_u8 *) & ssid_bssid->bssid,
+ MLAN_BSS_MODE_AUTO);
+ if (i >= 0) {
+ pbss_desc = &pmadapter->pscan_table[i];
+ memcpy(pmadapter, &sec_pp.ssid, &pbss_desc->ssid,
+ sizeof(mlan_802_11_ssid));
+ } else
+ memcpy(pmadapter, &sec_pp.bssid, &ssid_bssid->bssid,
+ MLAN_MAC_ADDR_LENGTH);
+ } else {
+ memcpy(pmadapter, &sec_pp.ssid, &ssid_bssid->ssid,
+ sizeof(mlan_802_11_ssid));
+ }
+
+ /* Send request to firmware */
+ ret = wlan_prepare_cmd(priv,
+ HostCmd_CMD_SUPPLICANT_PMK,
+ HostCmd_ACT_GEN_GET,
+ 0, (t_void *) pioctl_req, &sec_pp);
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Search for a BSS
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING --success, otherwise fail
+ */
+mlan_status
+wlan_bss_ioctl_find_bss(IN pmlan_adapter pmadapter,
+ IN pmlan_ioctl_req pioctl_req)
+{
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ if (pmpriv->ewpa_query) {
+ if (wlan_query_passphrase(pmpriv, pioctl_req) == MLAN_STATUS_SUCCESS) {
+ PRINTM(MINFO, "Find BSS ioctl: query passphrase\n");
+ LEAVE();
+ return MLAN_STATUS_PENDING;
+ }
+ }
+ ret = wlan_find_bss(pmpriv, pioctl_req);
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief BSS command handler
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static mlan_status
+wlan_bss_ioctl(IN pmlan_adapter pmadapter, IN pmlan_ioctl_req pioctl_req)
+{
+ mlan_status status = MLAN_STATUS_SUCCESS;
+ mlan_ds_bss *bss = MNULL;
+
+ ENTER();
+
+ if (pioctl_req->buf_len < sizeof(mlan_ds_bss)) {
+ PRINTM(MWARN, "MLAN bss IOCTL length is too short.\n");
+ pioctl_req->data_read_written = 0;
+ pioctl_req->buf_len_needed = sizeof(mlan_ds_bss);
+ pioctl_req->status_code = MLAN_ERROR_INVALID_PARAMETER;
+ LEAVE();
+ return MLAN_STATUS_RESOURCE;
+ }
+
+ bss = (mlan_ds_bss *) pioctl_req->pbuf;
+
+ switch (bss->sub_command) {
+ case MLAN_OID_BSS_START:
+ status = wlan_bss_ioctl_start(pmadapter, pioctl_req);
+ break;
+ case MLAN_OID_BSS_STOP:
+ status = wlan_bss_ioctl_stop(pmadapter, pioctl_req);
+ break;
+ case MLAN_OID_BSS_MODE:
+ status = wlan_bss_ioctl_mode(pmadapter, pioctl_req);
+ break;
+ case MLAN_OID_BSS_CHANNEL:
+ status = wlan_bss_ioctl_channel(pmadapter, pioctl_req);
+ break;
+ case MLAN_OID_BSS_CHANNEL_LIST:
+ status = wlan_bss_ioctl_get_channel_list(pmadapter, pioctl_req);
+ break;
+ case MLAN_OID_BSS_MAC_ADDR:
+ status = wlan_bss_ioctl_mac_address(pmadapter, pioctl_req);
+ break;
+ case MLAN_OID_BSS_MULTICAST_LIST:
+ status = wlan_bss_ioctl_set_multicast_list(pmadapter, pioctl_req);
+ break;
+ case MLAN_OID_BSS_FIND_BSS:
+ status = wlan_bss_ioctl_find_bss(pmadapter, pioctl_req);
+ break;
+ case MLAN_OID_IBSS_BCN_INTERVAL:
+ status = wlan_bss_ioctl_beacon_interval(pmadapter, pioctl_req);
+ break;
+ case MLAN_OID_IBSS_ATIM_WINDOW:
+ status = wlan_bss_ioctl_atim_window(pmadapter, pioctl_req);
+ break;
+ case MLAN_OID_IBSS_CHANNEL:
+ status = wlan_bss_ioctl_ibss_channel(pmadapter, pioctl_req);
+ break;
+#if defined(STA_SUPPORT) && defined(UAP_SUPPORT)
+ case MLAN_OID_BSS_ROLE:
+ status = wlan_bss_ioctl_bss_role(pmadapter, pioctl_req);
+ break;
+#endif
+#ifdef WIFI_DIRECT_SUPPORT
+ case MLAN_OID_WIFI_DIRECT_MODE:
+ status = wlan_bss_ioctl_wifi_direct_mode(pmadapter, pioctl_req);
+ break;
+#endif
+ default:
+ status = MLAN_STATUS_FAILURE;
+ break;
+ }
+
+ LEAVE();
+ return status;
+}
+
+/**
+ * @brief Get supported rates
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static mlan_status
+wlan_rate_ioctl_get_supported_rate(IN pmlan_adapter pmadapter,
+ IN pmlan_ioctl_req pioctl_req)
+{
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
+ mlan_ds_rate *rate = MNULL;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+ if (pioctl_req->action != MLAN_ACT_GET) {
+ pioctl_req->status_code = MLAN_ERROR_IOCTL_INVALID;
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+ rate = (mlan_ds_rate *) pioctl_req->pbuf;
+ if (rate->param.rate_band_cfg.config_bands &&
+ rate->param.rate_band_cfg.bss_mode)
+ wlan_get_active_data_rates(pmpriv, rate->param.rate_band_cfg.bss_mode,
+ rate->param.rate_band_cfg.config_bands,
+ rate->param.rates);
+ else
+ wlan_get_active_data_rates(pmpriv, pmpriv->bss_mode,
+ (pmpriv->bss_mode == MLAN_BSS_MODE_INFRA) ?
+ pmadapter->config_bands : pmadapter->
+ adhoc_start_band, rate->param.rates);
+ pioctl_req->data_read_written =
+ MLAN_SUPPORTED_RATES + MLAN_SUB_COMMAND_SIZE;
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Get data rates
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_PENDING --success, otherwise fail
+ */
+static mlan_status
+wlan_rate_ioctl_get_data_rate(IN pmlan_adapter pmadapter,
+ IN pmlan_ioctl_req pioctl_req)
+{
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ if (pioctl_req->action != MLAN_ACT_GET) {
+ ret = MLAN_STATUS_FAILURE;
+ goto exit;
+ }
+
+ /* Send request to firmware */
+ ret = wlan_prepare_cmd(pmpriv,
+ HostCmd_CMD_802_11_TX_RATE_QUERY,
+ HostCmd_ACT_GEN_GET,
+ 0, (t_void *) pioctl_req, MNULL);
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+
+ exit:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Rate command handler
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING --success, otherwise fail
+ */
+static mlan_status
+wlan_rate_ioctl(IN pmlan_adapter pmadapter, IN pmlan_ioctl_req pioctl_req)
+{
+ mlan_status status = MLAN_STATUS_SUCCESS;
+ mlan_ds_rate *rate = MNULL;
+
+ ENTER();
+
+ if (pioctl_req->buf_len < sizeof(mlan_ds_rate)) {
+ PRINTM(MWARN, "MLAN bss IOCTL length is too short.\n");
+ pioctl_req->data_read_written = 0;
+ pioctl_req->buf_len_needed = sizeof(mlan_ds_rate);
+ pioctl_req->status_code = MLAN_ERROR_INVALID_PARAMETER;
+ LEAVE();
+ return MLAN_STATUS_RESOURCE;
+ }
+ rate = (mlan_ds_rate *) pioctl_req->pbuf;
+ switch (rate->sub_command) {
+ case MLAN_OID_RATE_CFG:
+ status = wlan_rate_ioctl_cfg(pmadapter, pioctl_req);
+ break;
+ case MLAN_OID_GET_DATA_RATE:
+ status = wlan_rate_ioctl_get_data_rate(pmadapter, pioctl_req);
+ break;
+ case MLAN_OID_SUPPORTED_RATES:
+ status = wlan_rate_ioctl_get_supported_rate(pmadapter, pioctl_req);
+ break;
+ default:
+ pioctl_req->status_code = MLAN_ERROR_IOCTL_INVALID;
+ status = MLAN_STATUS_FAILURE;
+ break;
+ }
+ LEAVE();
+ return status;
+}
+
+/**
+ * @brief Get Tx power configuration
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param cmd_no Firmware command number used to retrieve power values
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_PENDING --success, otherwise fail
+ */
+static mlan_status
+wlan_power_ioctl_get_power(IN pmlan_adapter pmadapter,
+ IN t_u16 cmd_no, IN pmlan_ioctl_req pioctl_req)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
+
+ ENTER();
+
+ /* Send request to firmware */
+ ret = wlan_prepare_cmd(pmpriv,
+ cmd_no,
+ HostCmd_ACT_GEN_GET,
+ 0, (t_void *) pioctl_req, MNULL);
+
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set Tx power configuration
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_PENDING --success, otherwise fail
+ */
+static mlan_status
+wlan_power_ioctl_set_power(IN pmlan_adapter pmadapter,
+ IN pmlan_ioctl_req pioctl_req)
+{
+ mlan_ds_power_cfg *power = MNULL;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+
+ HostCmd_DS_TXPWR_CFG *txp_cfg = MNULL;
+ MrvlTypes_Power_Group_t *pg_tlv = MNULL;
+ Power_Group_t *pg = MNULL;
+ pmlan_callbacks pcb = &pmadapter->callbacks;
+ t_u8 *buf = MNULL;
+ t_u16 dbm = 0;
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
+
+ ENTER();
+
+ power = (mlan_ds_power_cfg *) pioctl_req->pbuf;
+ if (!power->param.power_cfg.is_power_auto) {
+ dbm = (t_u16) power->param.power_cfg.power_level;
+ if ((dbm < pmpriv->min_tx_power_level) ||
+ (dbm > pmpriv->max_tx_power_level)) {
+ PRINTM(MERROR,
+ "The set txpower value %d dBm is out of range (%d dBm-%d dBm)!\n",
+ dbm, pmpriv->min_tx_power_level, pmpriv->max_tx_power_level);
+ pioctl_req->status_code = MLAN_ERROR_INVALID_PARAMETER;
+ ret = MLAN_STATUS_FAILURE;
+ goto exit;
+ }
+ }
+
+ ret = pcb->moal_malloc(pmadapter->pmoal_handle,
+ MRVDRV_SIZE_OF_CMD_BUFFER, MLAN_MEM_DEF, &buf);
+ if (ret != MLAN_STATUS_SUCCESS || buf == MNULL) {
+ PRINTM(MERROR, "ALLOC_CMD_BUF: Failed to allocate command buffer\n");
+ pioctl_req->status_code = MLAN_ERROR_NO_MEM;
+ ret = MLAN_STATUS_FAILURE;
+ goto exit;
+ }
+ memset(pmadapter, buf, 0, MRVDRV_SIZE_OF_CMD_BUFFER);
+ txp_cfg = (HostCmd_DS_TXPWR_CFG *) buf;
+ txp_cfg->action = HostCmd_ACT_GEN_SET;
+ if (!power->param.power_cfg.is_power_auto) {
+ txp_cfg->mode = 1;
+ pg_tlv = (MrvlTypes_Power_Group_t *) (buf +
+ sizeof(HostCmd_DS_TXPWR_CFG));
+ pg_tlv->type = TLV_TYPE_POWER_GROUP;
+ pg_tlv->length = 4 * sizeof(Power_Group_t);
+ pg = (Power_Group_t *) (buf + sizeof(HostCmd_DS_TXPWR_CFG) +
+ sizeof(MrvlTypes_Power_Group_t));
+ /* Power group for modulation class HR/DSSS */
+ pg->first_rate_code = 0x00;
+ pg->last_rate_code = 0x03;
+ pg->modulation_class = MOD_CLASS_HR_DSSS;
+ pg->power_step = 0;
+ pg->power_min = (t_s8) dbm;
+ pg->power_max = (t_s8) dbm;
+ pg++;
+ /* Power group for modulation class OFDM */
+ pg->first_rate_code = 0x00;
+ pg->last_rate_code = 0x07;
+ pg->modulation_class = MOD_CLASS_OFDM;
+ pg->power_step = 0;
+ pg->power_min = (t_s8) dbm;
+ pg->power_max = (t_s8) dbm;
+ pg++;
+ /* Power group for modulation class HTBW20 */
+ pg->first_rate_code = 0x00;
+ pg->last_rate_code = 0x20;
+ pg->modulation_class = MOD_CLASS_HT;
+ pg->power_step = 0;
+ pg->power_min = (t_s8) dbm;
+ pg->power_max = (t_s8) dbm;
+ pg->ht_bandwidth = HT_BW_20;
+ pg++;
+ /* Power group for modulation class HTBW40 */
+ pg->first_rate_code = 0x00;
+ pg->last_rate_code = 0x20;
+ pg->modulation_class = MOD_CLASS_HT;
+ pg->power_step = 0;
+ pg->power_min = (t_s8) dbm;
+ pg->power_max = (t_s8) dbm;
+ pg->ht_bandwidth = HT_BW_40;
+ }
+
+ /* Send request to firmware */
+ ret = wlan_prepare_cmd(pmpriv,
+ HostCmd_CMD_TXPWR_CFG,
+ HostCmd_ACT_GEN_SET, 0, (t_void *) pioctl_req, buf);
+
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+
+ if (buf)
+ pcb->moal_mfree(pmadapter->pmoal_handle, buf);
+
+ exit:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Get modulation class from rate index
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param rate_index Rate index
+ *
+ * @return 0 fail, otherwise return modulation class
+ */
+static int
+wlan_get_modulation_class(pmlan_adapter pmadapter, int rate_index)
+{
+ int tx_mcs_supp = GET_TXMCSSUPP(pmadapter->usr_dev_mcs_support);
+ ENTER();
+ if (rate_index >= MLAN_RATE_INDEX_HRDSSS0 &&
+ rate_index <= MLAN_RATE_INDEX_HRDSSS3) {
+ LEAVE();
+ return MOD_CLASS_HR_DSSS;
+ } else if (rate_index >= MLAN_RATE_INDEX_OFDM0 &&
+ rate_index <= MLAN_RATE_INDEX_OFDM7) {
+ LEAVE();
+ return MOD_CLASS_OFDM;
+ } else if (rate_index >= MLAN_RATE_INDEX_MCS0 &&
+ rate_index <= MLAN_RATE_INDEX_MCS127) {
+ if ((rate_index > MLAN_RATE_INDEX_MCS7 &&
+ rate_index <= MLAN_RATE_INDEX_MCS15) && (tx_mcs_supp < 2)) {
+ PRINTM(MERROR,
+ "HW don't support 2x2, rate_index=%d hw_mcs_supp=0x%x\n",
+ rate_index, pmadapter->usr_dev_mcs_support);
+ LEAVE();
+ return 0;
+ }
+ LEAVE();
+ return MOD_CLASS_HT;
+ }
+ PRINTM(MERROR, "Invalid rate index = %d supplied!\n", rate_index);
+
+ LEAVE();
+ return 0;
+}
+
+/**
+ * @brief Set extended power configuration
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_PENDING --success, otherwise fail
+ */
+static mlan_status
+wlan_power_ioctl_set_power_ext(IN pmlan_adapter pmadapter,
+ IN pmlan_ioctl_req pioctl_req)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
+ mlan_ds_power_cfg *power = MNULL;
+ pmlan_callbacks pcb = &pmadapter->callbacks;
+ t_u8 *buf = MNULL;
+ HostCmd_DS_TXPWR_CFG *txp_cfg = MNULL;
+ MrvlTypes_Power_Group_t *pg_tlv = MNULL;
+ Power_Group_t *pg = MNULL;
+ int mod_class;
+ t_u32 data[4];
+ t_u8 ht_bw;
+
+ ENTER();
+
+ power = (mlan_ds_power_cfg *) pioctl_req->pbuf;
+ ret =
+ pcb->moal_malloc(pmadapter->pmoal_handle, MRVDRV_SIZE_OF_CMD_BUFFER,
+ MLAN_MEM_DEF, &buf);
+ if (ret != MLAN_STATUS_SUCCESS || buf == MNULL) {
+ PRINTM(MERROR, "ALLOC_CMD_BUF: Failed to allocate command buffer\n");
+ pioctl_req->status_code = MLAN_ERROR_NO_MEM;
+ ret = MLAN_STATUS_FAILURE;
+ goto exit;
+ }
+ memset(pmadapter, buf, 0, MRVDRV_SIZE_OF_CMD_BUFFER);
+ txp_cfg = (HostCmd_DS_TXPWR_CFG *) buf;
+ txp_cfg->action = HostCmd_ACT_GEN_SET;
+ memcpy(pmadapter, (t_u8 *) & data,
+ (t_u8 *) power->param.power_ext.power_data, sizeof(data));
+ switch (power->param.power_ext.len) {
+ case 1:
+ if (data[0] == 0xFF)
+ txp_cfg->mode = 0;
+ else {
+ pioctl_req->status_code = MLAN_ERROR_INVALID_PARAMETER;
+ ret = MLAN_STATUS_FAILURE;
+ }
+ break;
+ case 2:
+ case 4:
+ ht_bw = (data[0] & TX_RATE_HT_BW40_BIT) ? HT_BW_40 : HT_BW_20;
+ data[0] &= ~TX_RATE_HT_BW40_BIT;
+ if (!(mod_class = wlan_get_modulation_class(pmadapter, data[0]))) {
+ pioctl_req->status_code = MLAN_ERROR_CMD_RESP_FAIL;
+ ret = MLAN_STATUS_FAILURE;
+ break;
+ }
+ if (ht_bw && mod_class != MOD_CLASS_HT) {
+ pioctl_req->status_code = MLAN_ERROR_CMD_RESP_FAIL;
+ ret = MLAN_STATUS_FAILURE;
+ break;
+ }
+ txp_cfg->mode = 1;
+ pg_tlv =
+ (MrvlTypes_Power_Group_t *) (buf + sizeof(HostCmd_DS_TXPWR_CFG));
+ pg_tlv->type = TLV_TYPE_POWER_GROUP;
+ pg_tlv->length = sizeof(Power_Group_t);
+ pg = (Power_Group_t *) (buf + sizeof(HostCmd_DS_TXPWR_CFG) +
+ sizeof(MrvlTypes_Power_Group_t));
+ pg->modulation_class = (t_u8) mod_class;
+ pg->first_rate_code = (t_u8) data[0];
+ pg->last_rate_code = (t_u8) data[0];
+ if (mod_class == MOD_CLASS_OFDM) {
+ pg->first_rate_code = (t_u8) (data[0] - MLAN_RATE_INDEX_OFDM0);
+ pg->last_rate_code = (t_u8) (data[0] - MLAN_RATE_INDEX_OFDM0);
+ } else if (mod_class == MOD_CLASS_HT) {
+ pg->first_rate_code = (t_u8) (data[0] - MLAN_RATE_INDEX_MCS0);
+ pg->last_rate_code = (t_u8) (data[0] - MLAN_RATE_INDEX_MCS0);
+ pg->ht_bandwidth = ht_bw;
+ }
+ pg->power_min = (t_s8) data[1];
+ pg->power_max = (t_s8) data[1];
+ if (power->param.power_ext.len == 4) {
+ pg->power_max = (t_s8) data[2];
+ pg->power_step = (t_s8) data[3];
+ }
+ break;
+ default:
+ pioctl_req->status_code = MLAN_ERROR_INVALID_PARAMETER;
+ ret = MLAN_STATUS_FAILURE;
+ break;
+ }
+ if (ret == MLAN_STATUS_FAILURE) {
+ if (buf)
+ pcb->moal_mfree(pmadapter->pmoal_handle, buf);
+ goto exit;
+ }
+
+ /* Send request to firmware */
+ ret = wlan_prepare_cmd(pmpriv,
+ HostCmd_CMD_TXPWR_CFG,
+ HostCmd_ACT_GEN_SET, 0, (t_void *) pioctl_req, buf);
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+ if (buf)
+ pcb->moal_mfree(pmadapter->pmoal_handle, buf);
+
+ exit:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Power configuration command handler
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static mlan_status
+wlan_power_ioctl(IN pmlan_adapter pmadapter, IN pmlan_ioctl_req pioctl_req)
+{
+ mlan_status status = MLAN_STATUS_SUCCESS;
+ mlan_ds_power_cfg *power = MNULL;
+
+ ENTER();
+
+ if (pioctl_req->buf_len < sizeof(mlan_ds_power_cfg)) {
+ PRINTM(MWARN, "MLAN bss IOCTL length is too short.\n");
+ pioctl_req->data_read_written = 0;
+ pioctl_req->buf_len_needed = sizeof(mlan_ds_power_cfg);
+ pioctl_req->status_code = MLAN_ERROR_INVALID_PARAMETER;
+ LEAVE();
+ return MLAN_STATUS_RESOURCE;
+ }
+ power = (mlan_ds_power_cfg *) pioctl_req->pbuf;
+ switch (power->sub_command) {
+ case MLAN_OID_POWER_CFG:
+ if (pioctl_req->action == MLAN_ACT_GET)
+ status = wlan_power_ioctl_get_power(pmadapter,
+ HostCmd_CMD_TXPWR_CFG,
+ pioctl_req);
+ else
+ status = wlan_power_ioctl_set_power(pmadapter, pioctl_req);
+ break;
+
+ case MLAN_OID_POWER_CFG_EXT:
+ if (pioctl_req->action == MLAN_ACT_GET)
+ status = wlan_power_ioctl_get_power(pmadapter,
+ HostCmd_CMD_TXPWR_CFG,
+ pioctl_req);
+ else
+ status = wlan_power_ioctl_set_power_ext(pmadapter, pioctl_req);
+ break;
+ default:
+ pioctl_req->status_code = MLAN_ERROR_IOCTL_INVALID;
+ status = MLAN_STATUS_FAILURE;
+ break;
+ }
+ LEAVE();
+ return status;
+}
+
+/**
+ * @brief Set power save configurations
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ * @param ps_mode Power save mode
+ *
+ * @return MLAN_STATUS_PENDING --success, otherwise fail
+ */
+static mlan_status
+wlan_pm_ioctl_ps_mode(IN pmlan_adapter pmadapter,
+ IN pmlan_ioctl_req pioctl_req, IN t_u16 ps_mode)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
+ t_u16 sub_cmd;
+
+ ENTER();
+
+ if (pioctl_req->action == MLAN_ACT_SET) {
+ sub_cmd = (pmadapter->ps_mode == Wlan802_11PowerModePSP) ?
+ EN_AUTO_PS : DIS_AUTO_PS;
+ ret = wlan_prepare_cmd(pmpriv,
+ HostCmd_CMD_802_11_PS_MODE_ENH, sub_cmd,
+ BITMAP_STA_PS, (t_void *) pioctl_req, MNULL);
+ if ((ret == MLAN_STATUS_SUCCESS) && (sub_cmd == DIS_AUTO_PS)) {
+ ret = wlan_prepare_cmd(pmpriv,
+ HostCmd_CMD_802_11_PS_MODE_ENH, GET_PS,
+ 0, MNULL, MNULL);
+ }
+ } else {
+ ret = wlan_prepare_cmd(pmpriv,
+ HostCmd_CMD_802_11_PS_MODE_ENH, GET_PS,
+ 0, (t_void *) pioctl_req, MNULL);
+ }
+
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set/Get Inactivity timeout extend
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_PENDING --success, otherwise fail
+ */
+static mlan_status
+wlan_pm_ioctl_inactivity_timeout(IN pmlan_adapter pmadapter,
+ IN pmlan_ioctl_req pioctl_req)
+{
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
+ mlan_ds_pm_cfg *pmcfg = MNULL;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ t_u16 cmd_action = 0;
+
+ ENTER();
+
+ pmcfg = (mlan_ds_pm_cfg *) pioctl_req->pbuf;
+ cmd_action = HostCmd_ACT_GEN_GET;
+ if (pioctl_req->action == MLAN_ACT_SET) {
+ cmd_action = HostCmd_ACT_GEN_SET;
+ }
+
+ /* Send request to firmware */
+ ret = wlan_prepare_cmd(pmpriv,
+ HostCmd_CMD_INACTIVITY_TIMEOUT_EXT,
+ cmd_action, 0, (t_void *) pioctl_req,
+ (t_void *) & pmcfg->param.inactivity_to);
+
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Enable/Disable Auto Deep Sleep
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_PENDING --success, otherwise fail
+ */
+static mlan_status
+wlan_set_auto_deep_sleep(IN pmlan_adapter pmadapter,
+ IN pmlan_ioctl_req pioctl_req)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ pmlan_private pmpriv =
+ (pmlan_private) pmadapter->priv[pioctl_req->bss_index];
+ mlan_ds_auto_ds auto_ds;
+ t_u32 mode;
+
+ ENTER();
+
+ if (((mlan_ds_pm_cfg *) pioctl_req->pbuf)->param.auto_deep_sleep.auto_ds ==
+ DEEP_SLEEP_ON) {
+ auto_ds.auto_ds = DEEP_SLEEP_ON;
+ PRINTM(MINFO, "Auto Deep Sleep: on\n");
+ mode = EN_AUTO_PS;
+ } else {
+ auto_ds.auto_ds = DEEP_SLEEP_OFF;
+ PRINTM(MINFO, "Auto Deep Sleep: off\n");
+ mode = DIS_AUTO_PS;
+ }
+ if (((mlan_ds_pm_cfg *) pioctl_req->pbuf)->param.auto_deep_sleep.idletime)
+ auto_ds.idletime =
+ ((mlan_ds_pm_cfg *) pioctl_req->pbuf)->param.auto_deep_sleep.
+ idletime;
+ else
+ auto_ds.idletime = pmadapter->idle_time;
+ /* note: the command could be queued and executed later if there is
+ command in progress. */
+ ret = wlan_prepare_cmd(pmpriv,
+ HostCmd_CMD_802_11_PS_MODE_ENH,
+ (t_u16) mode,
+ BITMAP_AUTO_DS, (t_void *) pioctl_req, &auto_ds);
+ if (ret) {
+ LEAVE();
+ return ret;
+ }
+ ret = MLAN_STATUS_PENDING;
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set/Get sleep period
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_PENDING --success, otherwise fail
+ */
+static mlan_status
+wlan_set_get_sleep_pd(IN pmlan_adapter pmadapter, IN pmlan_ioctl_req pioctl_req)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ pmlan_private pmpriv = pmadapter->priv[pioctl_req->bss_index];
+ mlan_ds_pm_cfg *pm_cfg = MNULL;
+ t_u16 cmd_action = 0, sleep_pd = 0;
+
+ ENTER();
+
+ pm_cfg = (mlan_ds_pm_cfg *) pioctl_req->pbuf;
+ cmd_action = HostCmd_ACT_GEN_GET;
+ if (pioctl_req->action == MLAN_ACT_SET) {
+ cmd_action = HostCmd_ACT_GEN_SET;
+ sleep_pd = (t_u16) pm_cfg->param.sleep_period;
+ }
+
+ ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_802_11_SLEEP_PERIOD,
+ cmd_action, 0, (t_void *) pioctl_req, &sleep_pd);
+
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set/Get PS configuration parameter
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_SUCCESS --success
+ */
+static mlan_status
+wlan_set_get_ps_cfg(IN pmlan_adapter pmadapter, IN pmlan_ioctl_req pioctl_req)
+{
+ mlan_ds_pm_cfg *pm_cfg = MNULL;
+
+ ENTER();
+
+ pm_cfg = (mlan_ds_pm_cfg *) pioctl_req->pbuf;
+ if (pioctl_req->action == MLAN_ACT_GET) {
+ pm_cfg->param.ps_cfg.ps_null_interval =
+ (t_u32) pmadapter->null_pkt_interval;
+ pm_cfg->param.ps_cfg.multiple_dtim_interval =
+ (t_u32) pmadapter->multiple_dtim;
+ pm_cfg->param.ps_cfg.listen_interval =
+ (t_u32) pmadapter->local_listen_interval;
+ pm_cfg->param.ps_cfg.adhoc_awake_period =
+ (t_u32) pmadapter->adhoc_awake_period;
+ pm_cfg->param.ps_cfg.bcn_miss_timeout =
+ (t_u32) pmadapter->bcn_miss_time_out;
+ pm_cfg->param.ps_cfg.delay_to_ps = (t_u32) pmadapter->delay_to_ps;
+ pm_cfg->param.ps_cfg.ps_mode = (t_u32) pmadapter->enhanced_ps_mode;
+ } else {
+ if (pm_cfg->param.ps_cfg.ps_null_interval)
+ pmadapter->null_pkt_interval =
+ (t_u16) pm_cfg->param.ps_cfg.ps_null_interval;
+ else
+ pm_cfg->param.ps_cfg.ps_null_interval =
+ (t_u32) pmadapter->null_pkt_interval;
+ if (pm_cfg->param.ps_cfg.multiple_dtim_interval)
+ pmadapter->multiple_dtim =
+ (t_u16) pm_cfg->param.ps_cfg.multiple_dtim_interval;
+ else
+ pm_cfg->param.ps_cfg.multiple_dtim_interval =
+ (t_u32) pmadapter->multiple_dtim;
+ if (((t_s32) pm_cfg->param.ps_cfg.listen_interval) ==
+ MRVDRV_LISTEN_INTERVAL_DISABLE)
+ pmadapter->local_listen_interval = 0;
+ else if (pm_cfg->param.ps_cfg.listen_interval)
+ pmadapter->local_listen_interval =
+ (t_u16) pm_cfg->param.ps_cfg.listen_interval;
+ else
+ pm_cfg->param.ps_cfg.listen_interval =
+ (t_u32) pmadapter->local_listen_interval;
+ if (pm_cfg->param.ps_cfg.adhoc_awake_period)
+ pmadapter->adhoc_awake_period =
+ (t_u16) pm_cfg->param.ps_cfg.adhoc_awake_period;
+ else
+ pm_cfg->param.ps_cfg.adhoc_awake_period =
+ (t_u32) pmadapter->adhoc_awake_period;
+ if (pm_cfg->param.ps_cfg.bcn_miss_timeout)
+ pmadapter->bcn_miss_time_out =
+ (t_u16) pm_cfg->param.ps_cfg.bcn_miss_timeout;
+ else
+ pm_cfg->param.ps_cfg.bcn_miss_timeout =
+ (t_u32) pmadapter->bcn_miss_time_out;
+ if (pm_cfg->param.ps_cfg.delay_to_ps != DELAY_TO_PS_UNCHANGED)
+ pmadapter->delay_to_ps = (t_u16) pm_cfg->param.ps_cfg.delay_to_ps;
+ else
+ pm_cfg->param.ps_cfg.delay_to_ps = (t_u32) pmadapter->delay_to_ps;
+ if (pm_cfg->param.ps_cfg.ps_mode)
+ pmadapter->enhanced_ps_mode = (t_u16) pm_cfg->param.ps_cfg.ps_mode;
+ else
+ pm_cfg->param.ps_cfg.ps_mode = (t_u32) pmadapter->enhanced_ps_mode;
+ }
+ pioctl_req->data_read_written = sizeof(t_u32) + MLAN_SUB_COMMAND_SIZE;
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief Get/Set the sleep parameters
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_PENDING --success, otherwise fail
+ */
+static mlan_status
+wlan_set_get_sleep_params(IN pmlan_adapter pmadapter,
+ IN pmlan_ioctl_req pioctl_req)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
+ mlan_ds_pm_cfg *pm_cfg = MNULL;
+ t_u16 cmd_action = 0;
+
+ ENTER();
+
+ pm_cfg = (mlan_ds_pm_cfg *) pioctl_req->pbuf;
+ cmd_action = HostCmd_ACT_GEN_GET;
+ if (pioctl_req->action == MLAN_ACT_SET) {
+ cmd_action = HostCmd_ACT_GEN_SET;
+ }
+
+ /* Send command to firmware */
+ ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_802_11_SLEEP_PARAMS,
+ cmd_action, 0, (t_void *) pioctl_req,
+ &pm_cfg->param.sleep_params);
+
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Power save command handler
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static mlan_status
+wlan_pm_ioctl(IN pmlan_adapter pmadapter, IN pmlan_ioctl_req pioctl_req)
+{
+ mlan_status status = MLAN_STATUS_SUCCESS;
+ mlan_ds_pm_cfg *pm = MNULL;
+
+ ENTER();
+
+ if (pioctl_req->buf_len < sizeof(mlan_ds_pm_cfg)) {
+ PRINTM(MWARN, "MLAN bss IOCTL length is too short.\n");
+ pioctl_req->data_read_written = 0;
+ pioctl_req->buf_len_needed = sizeof(mlan_ds_pm_cfg);
+ LEAVE();
+ return MLAN_STATUS_RESOURCE;
+ }
+ pm = (mlan_ds_pm_cfg *) pioctl_req->pbuf;
+ switch (pm->sub_command) {
+ case MLAN_OID_PM_CFG_IEEE_PS:
+ switch (pioctl_req->action) {
+ case MLAN_ACT_SET:
+ if (pm->param.ps_mode)
+ pmadapter->ps_mode = Wlan802_11PowerModePSP;
+ else
+ pmadapter->ps_mode = Wlan802_11PowerModeCAM;
+ status =
+ wlan_pm_ioctl_ps_mode(pmadapter, pioctl_req,
+ pmadapter->ps_mode);
+ break;
+ case MLAN_ACT_GET:
+ status =
+ wlan_pm_ioctl_ps_mode(pmadapter, pioctl_req,
+ pmadapter->ps_mode);
+ break;
+ default:
+ pioctl_req->status_code = MLAN_ERROR_IOCTL_INVALID;
+ status = MLAN_STATUS_FAILURE;
+ break;
+ }
+ break;
+ case MLAN_OID_PM_CFG_HS_CFG:
+ status = wlan_pm_ioctl_hscfg(pmadapter, pioctl_req);
+ break;
+ case MLAN_OID_PM_CFG_INACTIVITY_TO:
+ status = wlan_pm_ioctl_inactivity_timeout(pmadapter, pioctl_req);
+ break;
+ case MLAN_OID_PM_CFG_DEEP_SLEEP:
+ switch (pioctl_req->action) {
+ case MLAN_ACT_SET:
+ if (pmadapter->is_deep_sleep &&
+ pm->param.auto_deep_sleep.auto_ds == DEEP_SLEEP_ON) {
+ PRINTM(MMSG, "Station already in enhanced deep sleep mode\n");
+ status = MLAN_STATUS_FAILURE;
+ break;
+ } else if (!pmadapter->is_deep_sleep &&
+ pm->param.auto_deep_sleep.auto_ds == DEEP_SLEEP_OFF) {
+ PRINTM(MMSG,
+ "Station already not in enhanced deep sleep mode\n");
+ status = MLAN_STATUS_FAILURE;
+ break;
+ }
+ status = wlan_set_auto_deep_sleep(pmadapter, pioctl_req);
+ break;
+ case MLAN_ACT_GET:
+ if (pmadapter->is_deep_sleep) {
+ pm->param.auto_deep_sleep.auto_ds = DEEP_SLEEP_ON;
+ pm->param.auto_deep_sleep.idletime = pmadapter->idle_time;
+ } else
+ pm->param.auto_deep_sleep.auto_ds = DEEP_SLEEP_OFF;
+ break;
+ default:
+ pioctl_req->status_code = MLAN_ERROR_IOCTL_INVALID;
+ status = MLAN_STATUS_FAILURE;
+ break;
+ }
+ break;
+ case MLAN_OID_PM_CFG_PS_CFG:
+ status = wlan_set_get_ps_cfg(pmadapter, pioctl_req);
+ break;
+ case MLAN_OID_PM_CFG_SLEEP_PD:
+ status = wlan_set_get_sleep_pd(pmadapter, pioctl_req);
+ break;
+ case MLAN_OID_PM_CFG_SLEEP_PARAMS:
+ status = wlan_set_get_sleep_params(pmadapter, pioctl_req);
+ break;
+ case MLAN_OID_PM_INFO:
+ status = wlan_get_pm_info(pmadapter, pioctl_req);
+ break;
+ default:
+ pioctl_req->status_code = MLAN_ERROR_IOCTL_INVALID;
+ status = MLAN_STATUS_FAILURE;
+ break;
+ }
+ LEAVE();
+ return status;
+}
+
+/**
+ * @brief Set/Get WMM status
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_SUCCESS --success
+ */
+static mlan_status
+wlan_wmm_ioctl_enable(IN pmlan_adapter pmadapter, IN pmlan_ioctl_req pioctl_req)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
+ mlan_ds_wmm_cfg *wmm = MNULL;
+ ENTER();
+ wmm = (mlan_ds_wmm_cfg *) pioctl_req->pbuf;
+ if (pioctl_req->action == MLAN_ACT_GET)
+ wmm->param.wmm_enable = (t_u32) pmpriv->wmm_required;
+ else
+ pmpriv->wmm_required = (t_u8) wmm->param.wmm_enable;
+ pioctl_req->data_read_written = sizeof(t_u32) + MLAN_SUB_COMMAND_SIZE;
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set/Get WMM QoS configuration
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_SUCCESS --success
+ */
+static mlan_status
+wlan_wmm_ioctl_qos(IN pmlan_adapter pmadapter, IN pmlan_ioctl_req pioctl_req)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
+ mlan_ds_wmm_cfg *wmm = MNULL;
+
+ ENTER();
+
+ wmm = (mlan_ds_wmm_cfg *) pioctl_req->pbuf;
+
+ if (pioctl_req->action == MLAN_ACT_GET)
+ wmm->param.qos_cfg = pmpriv->wmm_qosinfo;
+ else {
+ pmpriv->wmm_qosinfo = wmm->param.qos_cfg;
+ }
+
+ pioctl_req->data_read_written = sizeof(t_u8) + MLAN_SUB_COMMAND_SIZE;
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Request for add a TSPEC
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_PENDING --success, otherwise fail
+ */
+static mlan_status
+wlan_wmm_ioctl_addts_req(IN pmlan_adapter pmadapter,
+ IN pmlan_ioctl_req pioctl_req)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ pmlan_private pmpriv = pmadapter->priv[pioctl_req->bss_index];
+ mlan_ds_wmm_cfg *cfg = MNULL;
+
+ ENTER();
+ cfg = (mlan_ds_wmm_cfg *) pioctl_req->pbuf;
+
+ /* Send request to firmware */
+ ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_WMM_ADDTS_REQ,
+ 0, 0, (t_void *) pioctl_req,
+ (t_void *) & cfg->param.addts);
+
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Request for delete a TSPEC
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_PENDING --success, otherwise fail
+ */
+static mlan_status
+wlan_wmm_ioctl_delts_req(IN pmlan_adapter pmadapter,
+ IN pmlan_ioctl_req pioctl_req)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ pmlan_private pmpriv = pmadapter->priv[pioctl_req->bss_index];
+ mlan_ds_wmm_cfg *cfg = MNULL;
+
+ ENTER();
+ cfg = (mlan_ds_wmm_cfg *) pioctl_req->pbuf;
+
+ /* Send request to firmware */
+ ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_WMM_DELTS_REQ,
+ 0, 0, (t_void *) pioctl_req,
+ (t_void *) & cfg->param.delts);
+
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set/Get a specified AC Queue's parameters
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_PENDING --success, otherwise fail
+ */
+static mlan_status
+wlan_wmm_ioctl_queue_config(IN pmlan_adapter pmadapter,
+ IN pmlan_ioctl_req pioctl_req)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ pmlan_private pmpriv = pmadapter->priv[pioctl_req->bss_index];
+ mlan_ds_wmm_cfg *cfg = MNULL;
+
+ ENTER();
+ cfg = (mlan_ds_wmm_cfg *) pioctl_req->pbuf;
+
+ /* Send request to firmware */
+ ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_WMM_QUEUE_CONFIG,
+ 0, 0, (t_void *) pioctl_req,
+ (t_void *) & cfg->param.q_cfg);
+
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief To get and start/stop queue stats on a WMM AC
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_PENDING --success, otherwise fail
+ */
+static mlan_status
+wlan_wmm_ioctl_queue_stats(IN pmlan_adapter pmadapter,
+ IN pmlan_ioctl_req pioctl_req)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ pmlan_private pmpriv = pmadapter->priv[pioctl_req->bss_index];
+ mlan_ds_wmm_cfg *cfg = MNULL;
+
+ ENTER();
+ cfg = (mlan_ds_wmm_cfg *) pioctl_req->pbuf;
+
+ /* Send request to firmware */
+ ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_WMM_QUEUE_STATS,
+ 0, 0, (t_void *) pioctl_req,
+ (t_void *) & cfg->param.q_stats);
+
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Get the status of the WMM AC queues
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_SUCCESS --success
+ */
+static mlan_status
+wlan_wmm_ioctl_queue_status(IN pmlan_adapter pmadapter,
+ IN pmlan_ioctl_req pioctl_req)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ pmlan_private pmpriv = pmadapter->priv[pioctl_req->bss_index];
+ mlan_ds_wmm_cfg *cfg = MNULL;
+ mlan_ds_wmm_queue_status *pqstatus = MNULL;
+ WmmAcStatus_t *pac_status = MNULL;
+ mlan_wmm_ac_e ac_idx;
+
+ ENTER();
+
+ cfg = (mlan_ds_wmm_cfg *) pioctl_req->pbuf;
+ pqstatus = (mlan_ds_wmm_queue_status *) & cfg->param.q_status;
+
+ for (ac_idx = WMM_AC_BK; ac_idx <= WMM_AC_VO; ac_idx++) {
+ pac_status = &pmpriv->wmm.ac_status[ac_idx];
+
+ /* Firmware status */
+ pqstatus->ac_status[ac_idx].flow_required = pac_status->flow_required;
+ pqstatus->ac_status[ac_idx].flow_created = pac_status->flow_created;
+ pqstatus->ac_status[ac_idx].disabled = pac_status->disabled;
+
+ /* ACM bit reflected in firmware status (redundant) */
+ pqstatus->ac_status[ac_idx].wmm_acm = pac_status->flow_required;
+ }
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Get the status of the WMM Traffic Streams
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_PENDING --success, otherwise fail
+ */
+static mlan_status
+wlan_wmm_ioctl_ts_status(IN pmlan_adapter pmadapter,
+ IN pmlan_ioctl_req pioctl_req)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ pmlan_private pmpriv = pmadapter->priv[pioctl_req->bss_index];
+ mlan_ds_wmm_cfg *cfg = MNULL;
+
+ ENTER();
+
+ cfg = (mlan_ds_wmm_cfg *) pioctl_req->pbuf;
+
+ /* Send request to firmware */
+ ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_WMM_TS_STATUS,
+ 0, 0, (t_void *) pioctl_req,
+ (t_void *) & cfg->param.ts_status);
+
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief WMM configuration handler
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static mlan_status
+wlan_wmm_cfg_ioctl(IN pmlan_adapter pmadapter, IN pmlan_ioctl_req pioctl_req)
+{
+ mlan_status status = MLAN_STATUS_SUCCESS;
+ mlan_ds_wmm_cfg *wmm = MNULL;
+
+ ENTER();
+
+ if (pioctl_req->buf_len < sizeof(mlan_ds_wmm_cfg)) {
+ PRINTM(MWARN, "MLAN bss IOCTL length is too short.\n");
+ pioctl_req->data_read_written = 0;
+ pioctl_req->buf_len_needed = sizeof(mlan_ds_wmm_cfg);
+ pioctl_req->status_code = MLAN_ERROR_INVALID_PARAMETER;
+ LEAVE();
+ return MLAN_STATUS_RESOURCE;
+ }
+ wmm = (mlan_ds_wmm_cfg *) pioctl_req->pbuf;
+ switch (wmm->sub_command) {
+ case MLAN_OID_WMM_CFG_ENABLE:
+ status = wlan_wmm_ioctl_enable(pmadapter, pioctl_req);
+ break;
+ case MLAN_OID_WMM_CFG_QOS:
+ status = wlan_wmm_ioctl_qos(pmadapter, pioctl_req);
+ break;
+ case MLAN_OID_WMM_CFG_ADDTS:
+ status = wlan_wmm_ioctl_addts_req(pmadapter, pioctl_req);
+ break;
+ case MLAN_OID_WMM_CFG_DELTS:
+ status = wlan_wmm_ioctl_delts_req(pmadapter, pioctl_req);
+ break;
+ case MLAN_OID_WMM_CFG_QUEUE_CONFIG:
+ status = wlan_wmm_ioctl_queue_config(pmadapter, pioctl_req);
+ break;
+ case MLAN_OID_WMM_CFG_QUEUE_STATS:
+ status = wlan_wmm_ioctl_queue_stats(pmadapter, pioctl_req);
+ break;
+ case MLAN_OID_WMM_CFG_QUEUE_STATUS:
+ status = wlan_wmm_ioctl_queue_status(pmadapter, pioctl_req);
+ break;
+ case MLAN_OID_WMM_CFG_TS_STATUS:
+ status = wlan_wmm_ioctl_ts_status(pmadapter, pioctl_req);
+ break;
+ default:
+ pioctl_req->status_code = MLAN_ERROR_IOCTL_INVALID;
+ status = MLAN_STATUS_FAILURE;
+ break;
+ }
+ LEAVE();
+ return status;
+}
+
+/**
+ * @brief Set/Get WPA IE
+ *
+ * @param priv A pointer to mlan_private structure
+ * @param ie_data_ptr A pointer to IE
+ * @param ie_len Length of the IE
+ *
+ * @return MLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static mlan_status
+wlan_set_wpa_ie_helper(mlan_private * priv, t_u8 * ie_data_ptr, t_u16 ie_len)
+{
+ ENTER();
+
+ if (ie_len) {
+ if (ie_len > sizeof(priv->wpa_ie)) {
+ PRINTM(MERROR, "failed to copy, WPA IE is too big \n");
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+ memcpy(priv->adapter, priv->wpa_ie, ie_data_ptr, ie_len);
+ priv->wpa_ie_len = (t_u8) ie_len;
+ PRINTM(MIOCTL, "Set Wpa_ie_len=%d IE=%#x\n", priv->wpa_ie_len,
+ priv->wpa_ie[0]);
+ DBG_HEXDUMP(MCMD_D, "Wpa_ie", priv->wpa_ie, priv->wpa_ie_len);
+ if (priv->wpa_ie[0] == WPA_IE) {
+ priv->sec_info.wpa_enabled = MTRUE;
+ } else if (priv->wpa_ie[0] == RSN_IE) {
+ priv->sec_info.wpa2_enabled = MTRUE;
+ } else {
+ priv->sec_info.wpa_enabled = MFALSE;
+ priv->sec_info.wpa2_enabled = MFALSE;
+ }
+ } else {
+ memset(priv->adapter, priv->wpa_ie, 0, sizeof(priv->wpa_ie));
+ priv->wpa_ie_len = 0;
+ PRINTM(MINFO, "Reset Wpa_ie_len=%d IE=%#x\n", priv->wpa_ie_len,
+ priv->wpa_ie[0]);
+ priv->sec_info.wpa_enabled = MFALSE;
+ priv->sec_info.wpa2_enabled = MFALSE;
+ }
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief Set WAPI IE
+ *
+ * @param priv A pointer to mlan_private structure
+ * @param ie_data_ptr A pointer to IE
+ * @param ie_len Length of the IE
+ *
+ * @return MLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static mlan_status
+wlan_set_wapi_ie(mlan_private * priv, t_u8 * ie_data_ptr, t_u16 ie_len)
+{
+ ENTER();
+ if (ie_len) {
+ if (ie_len > sizeof(priv->wapi_ie)) {
+ PRINTM(MWARN, "failed to copy, WAPI IE is too big \n");
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+ memcpy(priv->adapter, priv->wapi_ie, ie_data_ptr, ie_len);
+ priv->wapi_ie_len = (t_u8) ie_len;
+ PRINTM(MIOCTL, "Set wapi_ie_len=%d IE=%#x\n", priv->wapi_ie_len,
+ priv->wapi_ie[0]);
+ DBG_HEXDUMP(MCMD_D, "wapi_ie", priv->wapi_ie, priv->wapi_ie_len);
+ if (priv->wapi_ie[0] == WAPI_IE)
+ priv->sec_info.wapi_enabled = MTRUE;
+ } else {
+ memset(priv->adapter, priv->wapi_ie, 0, sizeof(priv->wapi_ie));
+ priv->wapi_ie_len = (t_u8) ie_len;
+ PRINTM(MINFO, "Reset wapi_ie_len=%d IE=%#x\n", priv->wapi_ie_len,
+ priv->wapi_ie[0]);
+ priv->sec_info.wapi_enabled = MFALSE;
+ }
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief Set/Get WAPI status
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_SUCCESS --success
+ */
+static mlan_status
+wlan_sec_ioctl_wapi_enable(IN pmlan_adapter pmadapter,
+ IN pmlan_ioctl_req pioctl_req)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
+ mlan_ds_sec_cfg *sec = MNULL;
+ ENTER();
+ sec = (mlan_ds_sec_cfg *) pioctl_req->pbuf;
+ if (pioctl_req->action == MLAN_ACT_GET) {
+ if (pmpriv->wapi_ie_len)
+ sec->param.wapi_enabled = MTRUE;
+ else
+ sec->param.wapi_enabled = MFALSE;
+ } else {
+ if (sec->param.wapi_enabled == MFALSE) {
+ wlan_set_wapi_ie(pmpriv, MNULL, 0);
+ }
+ }
+ pioctl_req->data_read_written = sizeof(t_u32) + MLAN_SUB_COMMAND_SIZE;
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set WAPI key
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_PENDING --success, otherwise fail
+ */
+static mlan_status
+wlan_sec_ioctl_set_wapi_key(IN pmlan_adapter pmadapter,
+ IN pmlan_ioctl_req pioctl_req)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
+ mlan_ds_sec_cfg *sec = MNULL;
+ ENTER();
+
+ sec = (mlan_ds_sec_cfg *) pioctl_req->pbuf;
+ ret = wlan_prepare_cmd(pmpriv,
+ HostCmd_CMD_802_11_KEY_MATERIAL,
+ HostCmd_ACT_GEN_SET,
+ KEY_INFO_ENABLED,
+ (t_void *) pioctl_req, &sec->param.encrypt_key);
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set/Get Port Control status
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static mlan_status
+wlan_sec_ioctl_port_ctrl_enable(IN pmlan_adapter pmadapter,
+ IN pmlan_ioctl_req pioctl_req)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_ds_sec_cfg *sec = MNULL;
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
+
+ ENTER();
+
+ sec = (mlan_ds_sec_cfg *) pioctl_req->pbuf;
+ if (pioctl_req->action == MLAN_ACT_GET) {
+ if (pmpriv->port_ctrl_mode)
+ sec->param.port_ctrl_enabled = MTRUE;
+ else
+ sec->param.port_ctrl_enabled = MFALSE;
+ } else {
+ if (sec->param.port_ctrl_enabled) {
+ pmpriv->port_ctrl_mode = MTRUE;
+ pmpriv->port_open = MFALSE;
+ } else {
+ if (pmpriv->port_ctrl_mode == MTRUE) {
+ pmpriv->port_ctrl_mode = MFALSE;
+ /* Cleanup the bypass TX queue */
+ wlan_cleanup_bypass_txq(pmadapter);
+ }
+ }
+ }
+ PRINTM(MINFO, "port_ctrl: port_ctrl_mode=%d port_open=%d\n",
+ pmpriv->port_ctrl_mode, pmpriv->port_open);
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set/Get authentication mode
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_SUCCESS --success
+ */
+static mlan_status
+wlan_sec_ioctl_auth_mode(IN pmlan_adapter pmadapter,
+ IN pmlan_ioctl_req pioctl_req)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
+ mlan_ds_sec_cfg *sec = MNULL;
+ ENTER();
+ sec = (mlan_ds_sec_cfg *) pioctl_req->pbuf;
+ if (pioctl_req->action == MLAN_ACT_GET)
+ sec->param.auth_mode = pmpriv->sec_info.authentication_mode;
+ else {
+ pmpriv->sec_info.authentication_mode = sec->param.auth_mode;
+ if (pmpriv->sec_info.authentication_mode == MLAN_AUTH_MODE_NETWORKEAP)
+ wlan_set_wpa_ie_helper(pmpriv, MNULL, 0);
+ }
+ pioctl_req->data_read_written = sizeof(t_u32) + MLAN_SUB_COMMAND_SIZE;
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set/Get encryption mode
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_SUCCESS --success
+ */
+static mlan_status
+wlan_sec_ioctl_encrypt_mode(IN pmlan_adapter pmadapter,
+ IN pmlan_ioctl_req pioctl_req)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
+ mlan_ds_sec_cfg *sec = MNULL;
+ ENTER();
+ sec = (mlan_ds_sec_cfg *) pioctl_req->pbuf;
+ if (pioctl_req->action == MLAN_ACT_GET)
+ sec->param.encrypt_mode = pmpriv->sec_info.encryption_mode;
+ else {
+ pmpriv->sec_info.encryption_mode = sec->param.encrypt_mode;
+ }
+ pioctl_req->data_read_written = sizeof(t_u32) + MLAN_SUB_COMMAND_SIZE;
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set/Get WPA status
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_SUCCESS --success
+ */
+static mlan_status
+wlan_sec_ioctl_wpa_enable(IN pmlan_adapter pmadapter,
+ IN pmlan_ioctl_req pioctl_req)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
+ mlan_ds_sec_cfg *sec = MNULL;
+ ENTER();
+ sec = (mlan_ds_sec_cfg *) pioctl_req->pbuf;
+ if (pioctl_req->action == MLAN_ACT_GET) {
+ if (pmpriv->wpa_ie_len)
+ sec->param.wpa_enabled = MTRUE;
+ else
+ sec->param.wpa_enabled = MFALSE;
+ } else {
+ if (sec->param.wpa_enabled == MFALSE) {
+ wlan_set_wpa_ie_helper(pmpriv, MNULL, 0);
+ }
+ /** clear adhoc aes flag, when WPA enabled */
+ pmpriv->adhoc_aes_enabled = MFALSE;
+ pmpriv->aes_key.key_param_set.key_len = 0;
+ }
+ pioctl_req->data_read_written = sizeof(t_u32) + MLAN_SUB_COMMAND_SIZE;
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set WEP keys
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_PENDING --success, otherwise fail
+ */
+static mlan_status
+wlan_sec_ioctl_set_wep_key(IN pmlan_adapter pmadapter,
+ IN pmlan_ioctl_req pioctl_req)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
+ mlan_ds_sec_cfg *sec = MNULL;
+ mrvl_wep_key_t *pwep_key = MNULL;
+ int index;
+
+ ENTER();
+
+ if (pmpriv->wep_key_curr_index >= MRVL_NUM_WEP_KEY)
+ pmpriv->wep_key_curr_index = 0;
+ pwep_key = &pmpriv->wep_key[pmpriv->wep_key_curr_index];
+ sec = (mlan_ds_sec_cfg *) pioctl_req->pbuf;
+ if (sec->param.encrypt_key.key_index == MLAN_KEY_INDEX_DEFAULT) {
+ index = pmpriv->wep_key_curr_index;
+ } else
+ index = sec->param.encrypt_key.key_index;
+ if ((sec->param.encrypt_key.key_disable == MTRUE) ||
+ (sec->param.encrypt_key.key_remove == MTRUE)) {
+ pmpriv->sec_info.wep_status = Wlan802_11WEPDisabled;
+ /* remove key */
+ if (sec->param.encrypt_key.key_remove == MTRUE) {
+ memset(pmadapter, &pmpriv->wep_key[index], 0,
+ sizeof(mrvl_wep_key_t));
+ }
+ } else {
+ if (sec->param.encrypt_key.key_len) {
+ pwep_key = &pmpriv->wep_key[index];
+ /* Cleanup */
+ memset(pmadapter, pwep_key, 0, sizeof(mrvl_wep_key_t));
+ /* Copy the key in the driver */
+
+ memcpy(pmadapter, pwep_key->key_material,
+ sec->param.encrypt_key.key_material,
+ sec->param.encrypt_key.key_len);
+ pwep_key->key_index = index;
+ pwep_key->key_length = sec->param.encrypt_key.key_len;
+ if (pmpriv->sec_info.wep_status != Wlan802_11WEPEnabled) {
+ /*
+ * The status is set as Key Absent
+ * so as to make sure we display the
+ * keys when iwlist mlanX key is used
+ */
+ pmpriv->sec_info.wep_status = Wlan802_11WEPKeyAbsent;
+ }
+ }
+ if (sec->param.encrypt_key.is_current_wep_key == MTRUE) {
+ /* Copy the required key as the current key */
+ pwep_key = &pmpriv->wep_key[index];
+ if (!pwep_key->key_length) {
+ PRINTM(MERROR, "Key %d not set,so cannot enable it\n", index);
+ pioctl_req->status_code = MLAN_ERROR_CMD_RESP_FAIL;
+ ret = MLAN_STATUS_FAILURE;
+ goto exit;
+ }
+ pmpriv->wep_key_curr_index = (t_u16) index;
+ pmpriv->sec_info.wep_status = Wlan802_11WEPEnabled;
+ }
+ }
+ if (pmpriv->sec_info.wep_status == Wlan802_11WEPEnabled)
+ pmpriv->curr_pkt_filter |= HostCmd_ACT_MAC_WEP_ENABLE;
+ else
+ pmpriv->curr_pkt_filter &= ~HostCmd_ACT_MAC_WEP_ENABLE;
+
+ /* Send request to firmware */
+ if (pmpriv->sec_info.wep_status == Wlan802_11WEPEnabled
+ && pwep_key->key_length) {
+ ret = wlan_prepare_cmd(pmpriv,
+ HostCmd_CMD_MAC_CONTROL,
+ HostCmd_ACT_GEN_SET,
+ 0, MNULL, &pmpriv->curr_pkt_filter);
+ if (ret)
+ goto exit;
+ ret = wlan_prepare_cmd(pmpriv,
+ HostCmd_CMD_802_11_KEY_MATERIAL,
+ HostCmd_ACT_GEN_SET,
+ 0, (t_void *) pioctl_req, MNULL);
+ } else {
+ if (pwep_key->key_length) {
+ ret = wlan_prepare_cmd(pmpriv,
+ HostCmd_CMD_802_11_KEY_MATERIAL,
+ HostCmd_ACT_GEN_SET, 0, MNULL, MNULL);
+ if (ret)
+ goto exit;
+ }
+ ret = wlan_prepare_cmd(pmpriv,
+ HostCmd_CMD_MAC_CONTROL,
+ HostCmd_ACT_GEN_SET,
+ 0,
+ (t_void *) pioctl_req, &pmpriv->curr_pkt_filter);
+ }
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+
+ exit:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set WPA key
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_PENDING --success, otherwise fail
+ */
+static mlan_status
+wlan_sec_ioctl_set_wpa_key(IN pmlan_adapter pmadapter,
+ IN pmlan_ioctl_req pioctl_req)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
+ mlan_ds_sec_cfg *sec = MNULL;
+ t_u8 broadcast_mac_addr[] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
+ t_u8 remove_key = MFALSE;
+
+ ENTER();
+
+ sec = (mlan_ds_sec_cfg *) pioctl_req->pbuf;
+ /* Current driver only supports key length of up to 32 bytes */
+ if (sec->param.encrypt_key.key_len > MLAN_MAX_KEY_LENGTH) {
+ PRINTM(MERROR, "Key length is incorrect\n");
+ pioctl_req->status_code = MLAN_ERROR_INVALID_PARAMETER;
+ ret = MLAN_STATUS_FAILURE;
+ goto exit;
+ }
+ if ((pmpriv->bss_mode == MLAN_BSS_MODE_IBSS) &&
+ pmpriv->sec_info.wpa_enabled) {
+ /*
+ * IBSS/WPA-None uses only one key (Group) for both receiving and
+ * sending unicast and multicast packets.
+ */
+ /* Send the key as PTK to firmware */
+ sec->param.encrypt_key.key_index = MLAN_KEY_INDEX_UNICAST;
+ ret = wlan_prepare_cmd(pmpriv,
+ HostCmd_CMD_802_11_KEY_MATERIAL,
+ HostCmd_ACT_GEN_SET,
+ KEY_INFO_ENABLED,
+ MNULL, &sec->param.encrypt_key);
+ if (ret)
+ goto exit;
+
+ /* Send the key as GTK to firmware */
+ sec->param.encrypt_key.key_index = ~MLAN_KEY_INDEX_UNICAST;
+ }
+
+ if (sec->param.encrypt_key.key_len == WPA_AES_KEY_LEN) {
+ /** back up adhoc AES key */
+ memset(pmpriv->adapter, pmpriv->aes_key.key_param_set.key, 0,
+ sizeof(pmpriv->aes_key.key_param_set.key));
+ pmpriv->aes_key.key_param_set.key_len = sec->param.encrypt_key.key_len;
+ memcpy(pmpriv->adapter, pmpriv->aes_key.key_param_set.key,
+ sec->param.encrypt_key.key_material,
+ pmpriv->aes_key.key_param_set.key_len);
+ }
+
+ /** only adhoc aes key_index = MLAN_KEY_INDEX_UNICAST */
+ if (pmpriv->bss_mode == MLAN_BSS_MODE_IBSS &&
+ sec->param.encrypt_key.key_len == WPA_AES_KEY_LEN
+ && sec->param.encrypt_key.key_index & MLAN_KEY_INDEX_UNICAST) {
+ t_u8 zero_key_material[WPA_AES_KEY_LEN];
+ memset(pmadapter, zero_key_material, 0, sizeof(zero_key_material));
+ if (memcmp
+ (pmadapter, sec->param.encrypt_key.key_material, zero_key_material,
+ WPA_AES_KEY_LEN)) {
+ PRINTM(MINFO, "Adhoc AES Enabled.\n");
+ pmpriv->adhoc_aes_enabled = MTRUE;
+ remove_key = MFALSE;
+ } else {
+ PRINTM(MINFO, "Adhoc AES Disabled.\n");
+ pmpriv->adhoc_aes_enabled = MFALSE;
+ /** clear adhoc AES key */
+ remove_key = MTRUE;
+ pmpriv->aes_key.key_param_set.key_len = 0;
+ }
+ }
+
+ if (memcmp
+ (pmadapter, sec->param.encrypt_key.mac_addr, broadcast_mac_addr,
+ MLAN_MAC_ADDR_LENGTH))
+ sec->param.encrypt_key.key_index = MLAN_KEY_INDEX_UNICAST;
+
+ if (remove_key == MTRUE) {
+ /* Send request to firmware */
+ ret = wlan_prepare_cmd(pmpriv,
+ HostCmd_CMD_802_11_KEY_MATERIAL,
+ HostCmd_ACT_GEN_SET,
+ !(KEY_INFO_ENABLED),
+ (t_void *) pioctl_req, &sec->param.encrypt_key);
+ } else {
+ /* Send request to firmware */
+ ret = wlan_prepare_cmd(pmpriv,
+ HostCmd_CMD_802_11_KEY_MATERIAL,
+ HostCmd_ACT_GEN_SET,
+ KEY_INFO_ENABLED,
+ (t_void *) pioctl_req, &sec->param.encrypt_key);
+ }
+
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+
+ exit:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Get security keys
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static mlan_status
+wlan_sec_ioctl_get_key(IN pmlan_adapter pmadapter,
+ IN pmlan_ioctl_req pioctl_req)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
+ mlan_ds_sec_cfg *sec = MNULL;
+ int index;
+ ENTER();
+
+ sec = (mlan_ds_sec_cfg *) pioctl_req->pbuf;
+
+ if ((sec->param.encrypt_key.key_index == MLAN_KEY_INDEX_UNICAST) &&
+ (sec->param.encrypt_key.key_len == WPA_AES_KEY_LEN)) {
+ if (pmpriv->adhoc_aes_enabled == MTRUE &&
+ (pmpriv->aes_key.key_param_set.key_len == WPA_AES_KEY_LEN)) {
+ HEXDUMP("Get ADHOCAES Key", pmpriv->aes_key.key_param_set.key,
+ WPA_AES_KEY_LEN);
+ memcpy(pmadapter, sec->param.encrypt_key.key_material,
+ pmpriv->aes_key.key_param_set.key, WPA_AES_KEY_LEN);
+ LEAVE();
+ return ret;
+ } else {
+ PRINTM(MERROR, " ADHOCAES key is not set yet!\n");
+ pioctl_req->status_code = MLAN_ERROR_INVALID_PARAMETER;
+ ret = MLAN_STATUS_FAILURE;
+ LEAVE();
+ return ret;
+ }
+ }
+ if (pmpriv->wep_key_curr_index >= MRVL_NUM_WEP_KEY)
+ pmpriv->wep_key_curr_index = 0;
+
+ if ((pmpriv->sec_info.wep_status == Wlan802_11WEPEnabled)
+ || (pmpriv->sec_info.wep_status == Wlan802_11WEPKeyAbsent)
+ || pmpriv->sec_info.ewpa_enabled
+ || pmpriv->sec_info.wpa_enabled
+ || pmpriv->sec_info.wpa2_enabled || pmpriv->adhoc_aes_enabled) {
+ sec->param.encrypt_key.key_disable = MFALSE;
+ } else {
+ sec->param.encrypt_key.key_disable = MTRUE;
+ }
+ if (sec->param.encrypt_key.key_index == MLAN_KEY_INDEX_DEFAULT) {
+ if ((pmpriv->wep_key[pmpriv->wep_key_curr_index].key_length) &&
+ (pmpriv->sec_info.wep_status == Wlan802_11WEPEnabled)) {
+ index = pmpriv->wep_key_curr_index;
+ sec->param.encrypt_key.key_index = pmpriv->wep_key[index].key_index;
+ memcpy(pmadapter, sec->param.encrypt_key.key_material,
+ pmpriv->wep_key[index].key_material, MIN(MLAN_MAX_KEY_LENGTH,
+ pmpriv->
+ wep_key[index].
+ key_length));
+ sec->param.encrypt_key.key_len =
+ MIN(MLAN_MAX_KEY_LENGTH, pmpriv->wep_key[index].key_length);
+ } else if ((pmpriv->sec_info.wpa_enabled)
+ || (pmpriv->sec_info.ewpa_enabled)
+ || (pmpriv->sec_info.wpa2_enabled)
+ || (pmpriv->sec_info.wapi_enabled)
+ || (pmpriv->adhoc_aes_enabled)
+ ) {
+ /* Return WPA enabled */
+ sec->param.encrypt_key.key_disable = MFALSE;
+ memcpy(pmadapter, sec->param.encrypt_key.key_material,
+ pmpriv->aes_key.key_param_set.key, MIN(MLAN_MAX_KEY_LENGTH,
+ pmpriv->aes_key.
+ key_param_set.
+ key_len));
+ sec->param.encrypt_key.key_len =
+ MIN(MLAN_MAX_KEY_LENGTH, pmpriv->aes_key.key_param_set.key_len);
+ } else {
+ sec->param.encrypt_key.key_disable = MTRUE;
+ }
+ } else {
+ index = sec->param.encrypt_key.key_index;
+ if (pmpriv->wep_key[index].key_length) {
+ sec->param.encrypt_key.key_index = pmpriv->wep_key[index].key_index;
+ memcpy(pmadapter, sec->param.encrypt_key.key_material,
+ pmpriv->wep_key[index].key_material, MIN(MLAN_MAX_KEY_LENGTH,
+ pmpriv->
+ wep_key[index].
+ key_length));
+ sec->param.encrypt_key.key_len =
+ MIN(MLAN_MAX_KEY_LENGTH, pmpriv->wep_key[index].key_length);
+ } else if ((pmpriv->sec_info.wpa_enabled)
+ || (pmpriv->sec_info.ewpa_enabled)
+ || (pmpriv->sec_info.wpa2_enabled)
+ || (pmpriv->sec_info.wapi_enabled)
+ || (pmpriv->adhoc_aes_enabled)
+ ) {
+ /* Return WPA enabled */
+ sec->param.encrypt_key.key_disable = MFALSE;
+ } else {
+ sec->param.encrypt_key.key_disable = MTRUE;
+ }
+ }
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set security key(s)
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING --success, otherwise fail
+ */
+static mlan_status
+wlan_sec_ioctl_encrypt_key(IN pmlan_adapter pmadapter,
+ IN pmlan_ioctl_req pioctl_req)
+{
+ mlan_status status = MLAN_STATUS_SUCCESS;
+ mlan_ds_sec_cfg *sec = MNULL;
+ ENTER();
+ sec = (mlan_ds_sec_cfg *) pioctl_req->pbuf;
+ if (pioctl_req->action == MLAN_ACT_SET) {
+ if (sec->param.encrypt_key.is_wapi_key)
+ status = wlan_sec_ioctl_set_wapi_key(pmadapter, pioctl_req);
+ else if (sec->param.encrypt_key.key_len > MAX_WEP_KEY_SIZE)
+ status = wlan_sec_ioctl_set_wpa_key(pmadapter, pioctl_req);
+ else
+ status = wlan_sec_ioctl_set_wep_key(pmadapter, pioctl_req);
+ } else {
+ status = wlan_sec_ioctl_get_key(pmadapter, pioctl_req);
+ }
+ LEAVE();
+ return status;
+}
+
+/**
+ * @brief Set/Get WPA passphrase for esupplicant
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_PENDING --success, otherwise fail
+ */
+static mlan_status
+wlan_sec_ioctl_passphrase(IN pmlan_adapter pmadapter,
+ IN pmlan_ioctl_req pioctl_req)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
+ mlan_ds_sec_cfg *sec = MNULL;
+ t_u16 cmd_action = 0;
+ BSSDescriptor_t *pbss_desc;
+ int i = 0;
+
+ ENTER();
+
+ sec = (mlan_ds_sec_cfg *) pioctl_req->pbuf;
+ if (pioctl_req->action == MLAN_ACT_SET) {
+ if (sec->param.passphrase.psk_type == MLAN_PSK_CLEAR)
+ cmd_action = HostCmd_ACT_GEN_REMOVE;
+ else
+ cmd_action = HostCmd_ACT_GEN_SET;
+ } else {
+ if (sec->param.passphrase.psk_type == MLAN_PSK_QUERY) {
+ if (sec->param.passphrase.ssid.ssid_len == 0) {
+ i = wlan_find_bssid_in_list(pmpriv,
+ (t_u8 *) & sec->param.passphrase.
+ bssid, MLAN_BSS_MODE_AUTO);
+ if (i >= 0) {
+ pbss_desc = &pmadapter->pscan_table[i];
+ memcpy(pmadapter, &sec->param.passphrase.ssid,
+ &pbss_desc->ssid, sizeof(mlan_802_11_ssid));
+ memset(pmadapter, &sec->param.passphrase.bssid, 0,
+ MLAN_MAC_ADDR_LENGTH);
+ PRINTM(MINFO, "PSK_QUERY: found ssid=%s\n",
+ sec->param.passphrase.ssid.ssid);
+ }
+ } else
+ memset(pmadapter, &sec->param.passphrase.bssid, 0,
+ MLAN_MAC_ADDR_LENGTH);
+ }
+ cmd_action = HostCmd_ACT_GEN_GET;
+ }
+
+ /* Send request to firmware */
+ ret = wlan_prepare_cmd(pmpriv,
+ HostCmd_CMD_SUPPLICANT_PMK,
+ cmd_action,
+ 0, (t_void *) pioctl_req, &sec->param.passphrase);
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set/Get esupplicant status
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_SUCCESS --success
+ */
+static mlan_status
+wlan_sec_ioctl_ewpa_enable(IN pmlan_adapter pmadapter,
+ IN pmlan_ioctl_req pioctl_req)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
+ mlan_ds_sec_cfg *sec = MNULL;
+ ENTER();
+ sec = (mlan_ds_sec_cfg *) pioctl_req->pbuf;
+ if (pioctl_req->action == MLAN_ACT_GET) {
+ sec->param.ewpa_enabled = pmpriv->sec_info.ewpa_enabled;
+ } else {
+ pmpriv->sec_info.ewpa_enabled = (t_u8) sec->param.ewpa_enabled;
+ PRINTM(MINFO, "Set: ewpa_enabled = %d\n",
+ (int) pmpriv->sec_info.ewpa_enabled);
+ }
+ pioctl_req->data_read_written = sizeof(t_u32) + MLAN_SUB_COMMAND_SIZE;
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Get esupplicant mode
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_PENDING --success, otherwise fail
+ */
+static mlan_status
+wlan_sec_ioctl_esupp_mode(IN pmlan_adapter pmadapter,
+ IN pmlan_ioctl_req pioctl_req)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
+
+ ENTER();
+
+ if (pmpriv->media_connected != MTRUE) {
+ pioctl_req->status_code = MLAN_ERROR_IOCTL_INVALID;
+ ret = MLAN_STATUS_FAILURE;
+ goto exit;
+ }
+
+ /* Send request to firmware */
+ ret = wlan_prepare_cmd(pmpriv,
+ HostCmd_CMD_SUPPLICANT_PROFILE,
+ HostCmd_ACT_GEN_GET_CURRENT,
+ 0, (t_void *) pioctl_req, MNULL);
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+
+ exit:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Security configuration handler
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING --success, otherwise fail
+ */
+static mlan_status
+wlan_sec_cfg_ioctl(IN pmlan_adapter pmadapter, IN pmlan_ioctl_req pioctl_req)
+{
+ mlan_status status = MLAN_STATUS_SUCCESS;
+ mlan_ds_sec_cfg *sec = MNULL;
+
+ ENTER();
+
+ if (pioctl_req->buf_len < sizeof(mlan_ds_sec_cfg)) {
+ PRINTM(MWARN, "MLAN bss IOCTL length is too short.\n");
+ pioctl_req->data_read_written = 0;
+ pioctl_req->buf_len_needed = sizeof(mlan_ds_sec_cfg);
+ pioctl_req->status_code = MLAN_ERROR_INVALID_PARAMETER;
+ LEAVE();
+ return MLAN_STATUS_RESOURCE;
+ }
+ sec = (mlan_ds_sec_cfg *) pioctl_req->pbuf;
+ switch (sec->sub_command) {
+ case MLAN_OID_SEC_CFG_AUTH_MODE:
+ status = wlan_sec_ioctl_auth_mode(pmadapter, pioctl_req);
+ break;
+ case MLAN_OID_SEC_CFG_ENCRYPT_MODE:
+ status = wlan_sec_ioctl_encrypt_mode(pmadapter, pioctl_req);
+ break;
+ case MLAN_OID_SEC_CFG_WPA_ENABLED:
+ status = wlan_sec_ioctl_wpa_enable(pmadapter, pioctl_req);
+ break;
+ case MLAN_OID_SEC_CFG_WAPI_ENABLED:
+ status = wlan_sec_ioctl_wapi_enable(pmadapter, pioctl_req);
+ break;
+ case MLAN_OID_SEC_CFG_PORT_CTRL_ENABLED:
+ status = wlan_sec_ioctl_port_ctrl_enable(pmadapter, pioctl_req);
+ break;
+ case MLAN_OID_SEC_CFG_ENCRYPT_KEY:
+ status = wlan_sec_ioctl_encrypt_key(pmadapter, pioctl_req);
+ break;
+ case MLAN_OID_SEC_CFG_PASSPHRASE:
+ status = wlan_sec_ioctl_passphrase(pmadapter, pioctl_req);
+ break;
+ case MLAN_OID_SEC_CFG_EWPA_ENABLED:
+ status = wlan_sec_ioctl_ewpa_enable(pmadapter, pioctl_req);
+ break;
+ case MLAN_OID_SEC_CFG_ESUPP_MODE:
+ status = wlan_sec_ioctl_esupp_mode(pmadapter, pioctl_req);
+ break;
+
+ default:
+ pioctl_req->status_code = MLAN_ERROR_IOCTL_INVALID;
+ status = MLAN_STATUS_FAILURE;
+ break;
+ }
+ LEAVE();
+ return status;
+}
+
+/**
+ * @brief Append/Reset IE buffer.
+ *
+ * Pass an opaque block of data, expected to be IEEE IEs, to the driver
+ * for eventual passthrough to the firmware in an associate/join
+ * (and potentially start) command. This function is the main body
+ * for both wlan_set_gen_ie_ioctl and wlan_set_gen_ie
+ *
+ * Data is appended to an existing buffer and then wrapped in a passthrough
+ * TLV in the command API to the firmware. The firmware treats the data
+ * as a transparent passthrough to the transmitted management frame.
+ *
+ * @param priv A pointer to mlan_private structure
+ * @param ie_data_ptr A pointer to iwreq structure
+ * @param ie_len Length of the IE or IE block passed in ie_data_ptr
+ *
+ * @return MLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static int
+wlan_set_gen_ie_helper(mlan_private * priv, t_u8 * ie_data_ptr, t_u16 ie_len)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ IEEEtypes_VendorHeader_t *pvendor_ie;
+ const t_u8 wpa_oui[] = { 0x00, 0x50, 0xf2, 0x01 };
+ const t_u8 wps_oui[] = { 0x00, 0x50, 0xf2, 0x04 };
+
+ ENTER();
+
+ /* If the passed length is zero, reset the buffer */
+ if (!ie_len) {
+ priv->gen_ie_buf_len = 0;
+ priv->wps.session_enable = MFALSE;
+ wlan_set_wpa_ie_helper(priv, MNULL, 0);
+ } else if (!ie_data_ptr) {
+ /* MNULL check */
+ ret = MLAN_STATUS_FAILURE;
+ } else {
+
+ pvendor_ie = (IEEEtypes_VendorHeader_t *) ie_data_ptr;
+ /* Test to see if it is a WPA IE, if not, then it is a gen IE */
+ if (((pvendor_ie->element_id == WPA_IE)
+ &&
+ (!memcmp
+ (priv->adapter, pvendor_ie->oui, wpa_oui, sizeof(wpa_oui))))
+ || (pvendor_ie->element_id == RSN_IE)
+ ) {
+
+ /* IE is a WPA/WPA2 IE so call set_wpa function */
+ ret = wlan_set_wpa_ie_helper(priv, ie_data_ptr, ie_len);
+ priv->wps.session_enable = MFALSE;
+ } else if (pvendor_ie->element_id == WAPI_IE) {
+ /* IE is a WAPI IE so call set_wapi function */
+ ret = wlan_set_wapi_ie(priv, ie_data_ptr, ie_len);
+ } else
+ if ((pvendor_ie->element_id == WPS_IE) &&
+ (priv->wps.session_enable == MFALSE) &&
+ (!memcmp
+ (priv->adapter, pvendor_ie->oui, wps_oui, sizeof(wps_oui)))) {
+ /*
+ * Discard first two byte (Element ID and Length)
+ * because they are not needed in the case of setting WPS_IE
+ */
+ if (pvendor_ie->len > 4) {
+ memcpy(priv->adapter, (t_u8 *) & priv->wps.wps_ie, ie_data_ptr,
+ ie_len);
+ HEXDUMP("wps_ie", (t_u8 *) & priv->wps.wps_ie,
+ priv->wps.wps_ie.vend_hdr.len + 2);
+ } else {
+ /* Only wps oui exist, reset driver wps buffer */
+ memset(priv->adapter, (t_u8 *) & priv->wps.wps_ie, 0x00,
+ sizeof(priv->wps.wps_ie));
+ PRINTM(MINFO, "wps_ie cleared\n");
+ }
+ } else {
+ /*
+ * Verify that the passed length is not larger than the available
+ * space remaining in the buffer
+ */
+ if (ie_len < (sizeof(priv->gen_ie_buf) - priv->gen_ie_buf_len)) {
+
+ /* Test to see if it is a WPS IE, if so, enable wps session
+ flag */
+ pvendor_ie = (IEEEtypes_VendorHeader_t *) ie_data_ptr;
+ if ((pvendor_ie->element_id == WPS_IE)
+ &&
+ (!memcmp
+ (priv->adapter, pvendor_ie->oui, wps_oui,
+ sizeof(wps_oui)))) {
+ priv->wps.session_enable = MTRUE;
+ PRINTM(MINFO, "WPS Session Enabled.\n");
+ }
+
+ /* Append the passed data to the end of the genIeBuffer */
+ memcpy(priv->adapter, priv->gen_ie_buf + priv->gen_ie_buf_len,
+ ie_data_ptr, ie_len);
+ /* Increment the stored buffer length by the size passed */
+ priv->gen_ie_buf_len += ie_len;
+ } else {
+ /* Passed data does not fit in the remaining buffer space */
+ ret = MLAN_STATUS_FAILURE;
+ }
+ }
+ }
+
+ /* Return MLAN_STATUS_SUCCESS, or MLAN_STATUS_FAILURE for error case */
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set/Get WWS mode
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_PENDING --success, otherwise fail
+ */
+static mlan_status
+wlan_misc_ioctl_wws_cfg(IN pmlan_adapter pmadapter,
+ IN pmlan_ioctl_req pioctl_req)
+{
+ pmlan_private pmpriv = pmadapter->priv[pioctl_req->bss_index];
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_ds_misc_cfg *misc_cfg = MNULL;
+ t_u16 cmd_action = 0;
+ t_u32 enable = 0;
+
+ ENTER();
+
+ if (pioctl_req->buf_len < sizeof(mlan_ds_misc_cfg)) {
+ PRINTM(MWARN, "MLAN IOCTL information buffer length is too short.\n");
+ pioctl_req->data_read_written = 0;
+ pioctl_req->buf_len_needed = sizeof(mlan_ds_misc_cfg);
+ pioctl_req->status_code = MLAN_ERROR_INVALID_PARAMETER;
+ ret = MLAN_STATUS_RESOURCE;
+ goto exit;
+ }
+
+ misc_cfg = (mlan_ds_misc_cfg *) pioctl_req->pbuf;
+ if (pioctl_req->action == MLAN_ACT_SET)
+ cmd_action = HostCmd_ACT_GEN_SET;
+ else
+ cmd_action = HostCmd_ACT_GEN_GET;
+
+ enable = misc_cfg->param.wws_cfg;
+
+ /* Send request to firmware */
+ ret = wlan_prepare_cmd(pmpriv,
+ HostCmd_CMD_802_11_SNMP_MIB,
+ cmd_action,
+ WwsMode_i, (t_void *) pioctl_req, &enable);
+
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+
+ exit:
+ LEAVE();
+ return ret;
+
+}
+
+/**
+ * @brief Set/Get 11D status
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING --success, otherwise fail
+ */
+static mlan_status
+wlan_11d_cfg_ioctl_enable(IN pmlan_adapter pmadapter,
+ IN pmlan_ioctl_req pioctl_req)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
+ mlan_ds_11d_cfg *pcfg_11d = MNULL;
+
+ ENTER();
+
+ pcfg_11d = (mlan_ds_11d_cfg *) pioctl_req->pbuf;
+
+ if (pioctl_req->action == MLAN_ACT_SET) {
+ if (pmpriv->media_connected == MTRUE) {
+ PRINTM(MIOCTL,
+ "11D setting cannot be changed while interface is active.\n");
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ PRINTM(MINFO, "11D: 11dcfg SET=%d\n", pcfg_11d->param.enable_11d);
+
+ /* Compare with current settings */
+ if (pmpriv->state_11d.user_enable_11d != pcfg_11d->param.enable_11d) {
+ ret =
+ wlan_11d_enable(pmpriv, pioctl_req,
+ (state_11d_t) pcfg_11d->param.enable_11d);
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+ } else {
+ PRINTM(MINFO, "11D: same as current setting, do nothing\n");
+ }
+ } else {
+ pcfg_11d->param.enable_11d = (t_u32) pmpriv->state_11d.user_enable_11d;
+ pioctl_req->data_read_written = sizeof(t_u32) + MLAN_SUB_COMMAND_SIZE;
+ PRINTM(MINFO, "11D: 11dcfg GET=%d\n", pcfg_11d->param.enable_11d);
+ }
+
+ done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Clear 11D chan table
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_SUCCESS --success
+ */
+static mlan_status
+wlan_11d_clr_chan_table(IN pmlan_adapter pmadapter,
+ IN pmlan_ioctl_req pioctl_req)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
+
+ ENTER();
+
+ if (pioctl_req->action == MLAN_ACT_SET) {
+ PRINTM(MINFO, "11D: 11dclrtbl SET\n");
+
+ if (wlan_11d_clear_parsedtable(pmpriv) == MLAN_STATUS_SUCCESS)
+ PRINTM(MINFO,
+ "11D: cleared parsed_region_chan (now no_of_chan=%d)\n",
+ pmadapter->parsed_region_chan.no_of_chan);
+ }
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief 11D configuration handler
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING --success, otherwise fail
+ */
+static mlan_status
+wlan_11d_cfg_ioctl(IN pmlan_adapter pmadapter, IN pmlan_ioctl_req pioctl_req)
+{
+ mlan_status status = MLAN_STATUS_SUCCESS;
+ mlan_ds_11d_cfg *pcfg_11d = MNULL;
+
+ ENTER();
+
+ if (pioctl_req->buf_len < sizeof(mlan_ds_11d_cfg)) {
+ PRINTM(MWARN, "MLAN bss IOCTL length is too short.\n");
+ pioctl_req->data_read_written = 0;
+ pioctl_req->buf_len_needed = sizeof(mlan_ds_11d_cfg);
+ pioctl_req->status_code = MLAN_ERROR_INVALID_PARAMETER;
+ status = MLAN_STATUS_RESOURCE;
+ goto exit;
+ }
+
+ pcfg_11d = (mlan_ds_11d_cfg *) pioctl_req->pbuf;
+ switch (pcfg_11d->sub_command) {
+ case MLAN_OID_11D_CFG_ENABLE:
+ status = wlan_11d_cfg_ioctl_enable(pmadapter, pioctl_req);
+ break;
+ case MLAN_OID_11D_CLR_CHAN_TABLE:
+ status = wlan_11d_clr_chan_table(pmadapter, pioctl_req);
+ break;
+ case MLAN_OID_11D_DOMAIN_INFO:
+ status = wlan_11d_cfg_domain_info(pmadapter, pioctl_req);
+ break;
+ default:
+ pioctl_req->status_code = MLAN_ERROR_IOCTL_INVALID;
+ status = MLAN_STATUS_FAILURE;
+ break;
+ }
+
+ exit:
+ LEAVE();
+ return status;
+}
+
+/**
+ * @brief WPS configuration handler
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static mlan_status
+wlan_wps_cfg_ioctl(IN pmlan_adapter pmadapter, IN pmlan_ioctl_req pioctl_req)
+{
+ mlan_status status = MLAN_STATUS_SUCCESS;
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
+ mlan_ds_wps_cfg *pwps = MNULL;
+
+ ENTER();
+
+ if (pioctl_req->buf_len < sizeof(mlan_ds_wps_cfg)) {
+ PRINTM(MWARN, "MLAN bss IOCTL length is too short.\n");
+ pioctl_req->data_read_written = 0;
+ pioctl_req->buf_len_needed = sizeof(mlan_ds_wps_cfg);
+ pioctl_req->status_code = MLAN_ERROR_INVALID_PARAMETER;
+ LEAVE();
+ return MLAN_STATUS_RESOURCE;
+ }
+
+ pwps = (mlan_ds_wps_cfg *) pioctl_req->pbuf;
+ switch (pwps->sub_command) {
+ case MLAN_OID_WPS_CFG_SESSION:
+ if (pioctl_req->action == MLAN_ACT_SET) {
+ if (pwps->param.wps_session == MLAN_WPS_CFG_SESSION_START)
+ pmpriv->wps.session_enable = MTRUE;
+ } else {
+ pwps->param.wps_session = (t_u32) pmpriv->wps.session_enable;
+ pioctl_req->data_read_written = sizeof(t_u32);
+ PRINTM(MINFO, "wpscfg GET=%d\n", pwps->param.wps_session);
+ }
+ break;
+ default:
+ pioctl_req->status_code = MLAN_ERROR_IOCTL_INVALID;
+ status = MLAN_STATUS_FAILURE;
+ break;
+ }
+
+ LEAVE();
+ return status;
+}
+
+/**
+ * @brief Read/write adapter register
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_PENDING --success, otherwise fail
+ */
+static mlan_status
+wlan_reg_mem_ioctl_reg_rw(IN pmlan_adapter pmadapter,
+ IN pmlan_ioctl_req pioctl_req)
+{
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
+ mlan_ds_reg_mem *reg_mem = MNULL;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ t_u16 cmd_action = 0, cmd_no;
+
+ ENTER();
+
+ reg_mem = (mlan_ds_reg_mem *) pioctl_req->pbuf;
+ if (pioctl_req->action == MLAN_ACT_GET)
+ cmd_action = HostCmd_ACT_GEN_GET;
+ else
+ cmd_action = HostCmd_ACT_GEN_SET;
+
+ switch (reg_mem->param.reg_rw.type) {
+ case MLAN_REG_MAC:
+ cmd_no = HostCmd_CMD_MAC_REG_ACCESS;
+ break;
+ case MLAN_REG_BBP:
+ cmd_no = HostCmd_CMD_BBP_REG_ACCESS;
+ break;
+ case MLAN_REG_RF:
+ cmd_no = HostCmd_CMD_RF_REG_ACCESS;
+ break;
+ case MLAN_REG_CAU:
+ cmd_no = HostCmd_CMD_CAU_REG_ACCESS;
+ break;
+ default:
+ pioctl_req->status_code = MLAN_ERROR_IOCTL_INVALID;
+ ret = MLAN_STATUS_FAILURE;
+ goto exit;
+ }
+
+ /* Send request to firmware */
+ ret = wlan_prepare_cmd(pmpriv, cmd_no, cmd_action,
+ 0, (t_void *) pioctl_req,
+ (t_void *) & reg_mem->param.reg_rw);
+
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+
+ exit:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Read the EEPROM contents of the card
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_PENDING --success, otherwise fail
+ */
+static mlan_status
+wlan_reg_mem_ioctl_read_eeprom(IN pmlan_adapter pmadapter,
+ IN pmlan_ioctl_req pioctl_req)
+{
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
+ mlan_ds_reg_mem *reg_mem = MNULL;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ t_u16 cmd_action = 0;
+
+ ENTER();
+
+ reg_mem = (mlan_ds_reg_mem *) pioctl_req->pbuf;
+ if (pioctl_req->action == MLAN_ACT_GET)
+ cmd_action = HostCmd_ACT_GEN_GET;
+
+ /* Send request to firmware */
+ ret = wlan_prepare_cmd(pmpriv,
+ HostCmd_CMD_802_11_EEPROM_ACCESS,
+ cmd_action, 0, (t_void *) pioctl_req,
+ (t_void *) & reg_mem->param.rd_eeprom);
+
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Read/write memory of device
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_PENDING --success, otherwise fail
+ */
+static mlan_status
+wlan_reg_mem_ioctl_mem_rw(IN pmlan_adapter pmadapter,
+ IN pmlan_ioctl_req pioctl_req)
+{
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
+ mlan_ds_reg_mem *reg_mem = MNULL;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ t_u16 cmd_action = 0;
+
+ ENTER();
+
+ reg_mem = (mlan_ds_reg_mem *) pioctl_req->pbuf;
+ if (pioctl_req->action == MLAN_ACT_GET)
+ cmd_action = HostCmd_ACT_GEN_GET;
+ else
+ cmd_action = HostCmd_ACT_GEN_SET;
+
+ /* Send request to firmware */
+ ret = wlan_prepare_cmd(pmpriv,
+ HostCmd_CMD_MEM_ACCESS,
+ cmd_action, 0,
+ (t_void *) pioctl_req,
+ (t_void *) & reg_mem->param.mem_rw);
+
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief register memory access handler
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_PENDING --success, otherwise fail
+ */
+static mlan_status
+wlan_reg_mem_ioctl(IN pmlan_adapter pmadapter, IN pmlan_ioctl_req pioctl_req)
+{
+ mlan_status status = MLAN_STATUS_SUCCESS;
+ mlan_ds_reg_mem *reg_mem = MNULL;
+
+ ENTER();
+
+ if (pioctl_req->buf_len < sizeof(mlan_ds_reg_mem)) {
+ PRINTM(MWARN, "MLAN REG_MEM IOCTL length is too short\n");
+ pioctl_req->data_read_written = 0;
+ pioctl_req->buf_len_needed = sizeof(mlan_ds_reg_mem);
+ pioctl_req->status_code = MLAN_ERROR_INVALID_PARAMETER;
+ LEAVE();
+ return MLAN_STATUS_RESOURCE;
+ }
+ reg_mem = (mlan_ds_reg_mem *) pioctl_req->pbuf;
+ switch (reg_mem->sub_command) {
+ case MLAN_OID_REG_RW:
+ status = wlan_reg_mem_ioctl_reg_rw(pmadapter, pioctl_req);
+ break;
+ case MLAN_OID_EEPROM_RD:
+ status = wlan_reg_mem_ioctl_read_eeprom(pmadapter, pioctl_req);
+ break;
+ case MLAN_OID_MEM_RW:
+ status = wlan_reg_mem_ioctl_mem_rw(pmadapter, pioctl_req);
+ break;
+ default:
+ pioctl_req->status_code = MLAN_ERROR_IOCTL_INVALID;
+ status = MLAN_STATUS_FAILURE;
+ break;
+ }
+ LEAVE();
+ return status;
+}
+
+/**
+ * @brief 802.11h ad-hoc start channel check
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_PENDING --success, otherwise fail
+ */
+static mlan_status
+wlan_11h_channel_check_req(IN pmlan_adapter pmadapter,
+ IN pmlan_ioctl_req pioctl_req)
+{
+ pmlan_private pmpriv = MNULL;
+ mlan_status ret = MLAN_STATUS_FAILURE;
+
+ ENTER();
+
+ if (pioctl_req != MNULL) {
+ pmpriv = pmadapter->priv[pioctl_req->bss_index];
+ } else {
+ PRINTM(MERROR, "MLAN IOCTL information is not present\n");
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+
+ pmpriv->adhoc_state = ADHOC_STARTING;
+
+ if ((pmadapter->adhoc_start_band & BAND_A)
+ || (pmadapter->adhoc_start_band & BAND_AN)
+ ) {
+ if (pmpriv->intf_state_11h.adhoc_auto_sel_chan)
+ pmpriv->adhoc_channel = wlan_11h_get_adhoc_start_channel(pmpriv);
+
+ /*
+ * Check if the region and channel requires a channel availability
+ * check.
+ */
+ if (wlan_11h_radar_detect_required(pmpriv, pmpriv->adhoc_channel)
+ && !wlan_11h_is_channel_under_nop(pmadapter, pmpriv->adhoc_channel)
+ ) {
+ /*
+ * Radar detection is required for this channel, make sure
+ * 11h is activated in the firmware
+ */
+ ret = wlan_11h_activate(pmpriv, MNULL, MTRUE);
+ ret = wlan_11h_config_master_radar_det(pmpriv, MTRUE);
+ ret = wlan_11h_check_update_radar_det_state(pmpriv);
+
+ /* Check for radar on the channel */
+ ret = wlan_11h_issue_radar_detect(pmpriv, pioctl_req,
+ pmpriv->adhoc_channel);
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+ }
+ }
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief 802.11h set/get local power constraint
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+static mlan_status
+wlan_11h_ioctl_local_power_constraint(IN pmlan_adapter pmadapter,
+ IN pmlan_ioctl_req pioctl_req)
+{
+ mlan_ds_11h_cfg *ds_11hcfg = MNULL;
+ t_s8 *plocalpower = &pmadapter->state_11h.usr_def_power_constraint;
+
+ ENTER();
+
+ ds_11hcfg = (mlan_ds_11h_cfg *) pioctl_req->pbuf;
+
+ if (pioctl_req->action == MLAN_ACT_GET)
+ ds_11hcfg->param.usr_local_power_constraint = *plocalpower;
+ else
+ *plocalpower = ds_11hcfg->param.usr_local_power_constraint;
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief 11h configuration handler
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING --success, otherwise fail
+ */
+static mlan_status
+wlan_11h_cfg_ioctl(IN pmlan_adapter pmadapter, IN pmlan_ioctl_req pioctl_req)
+{
+ mlan_status status = MLAN_STATUS_SUCCESS;
+ mlan_ds_11h_cfg *ds_11hcfg = MNULL;
+
+ ENTER();
+
+ if (pioctl_req->buf_len < sizeof(mlan_ds_11h_cfg)) {
+ PRINTM(MWARN, "MLAN 11H IOCTL length is too short.\n");
+ pioctl_req->data_read_written = 0;
+ pioctl_req->buf_len_needed = sizeof(mlan_ds_11h_cfg);
+ pioctl_req->status_code = MLAN_ERROR_INVALID_PARAMETER;
+ LEAVE();
+ return MLAN_STATUS_RESOURCE;
+ }
+ ds_11hcfg = (mlan_ds_11h_cfg *) pioctl_req->pbuf;
+
+ switch (ds_11hcfg->sub_command) {
+ case MLAN_OID_11H_CHANNEL_CHECK:
+ status = wlan_11h_channel_check_req(pmadapter, pioctl_req);
+ break;
+ case MLAN_OID_11H_LOCAL_POWER_CONSTRAINT:
+ status = wlan_11h_ioctl_local_power_constraint(pmadapter, pioctl_req);
+ break;
+#if defined(DFS_TESTING_SUPPORT)
+ case MLAN_OID_11H_DFS_TESTING:
+ status = wlan_11h_ioctl_dfs_testing(pmadapter, pioctl_req);
+ break;
+#endif
+ default:
+ pioctl_req->status_code = MLAN_ERROR_IOCTL_INVALID;
+ status = MLAN_STATUS_FAILURE;
+ break;
+ }
+
+ LEAVE();
+ return status;
+}
+
+/**
+ * @brief Set/Get generic IE
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static mlan_status
+wlan_misc_ioctl_gen_ie(IN pmlan_adapter pmadapter,
+ IN pmlan_ioctl_req pioctl_req)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
+ mlan_ds_misc_cfg *misc = MNULL;
+
+ ENTER();
+
+ misc = (mlan_ds_misc_cfg *) pioctl_req->pbuf;
+ switch (misc->param.gen_ie.type) {
+ case MLAN_IE_TYPE_GEN_IE:
+ if (pioctl_req->action == MLAN_ACT_GET) {
+ misc->param.gen_ie.len = pmpriv->wpa_ie_len;
+ memcpy(pmadapter, misc->param.gen_ie.ie_data, pmpriv->wpa_ie,
+ misc->param.gen_ie.len);
+ } else {
+ wlan_set_gen_ie_helper(pmpriv, misc->param.gen_ie.ie_data,
+ (t_u16) misc->param.gen_ie.len);
+ }
+ break;
+ case MLAN_IE_TYPE_ARP_FILTER:
+ memset(pmadapter, pmadapter->arp_filter, 0,
+ sizeof(pmadapter->arp_filter));
+ if (misc->param.gen_ie.len > ARP_FILTER_MAX_BUF_SIZE) {
+ pmadapter->arp_filter_size = 0;
+ PRINTM(MERROR, "Invalid ARP Filter Size\n");
+ pioctl_req->status_code = MLAN_ERROR_INVALID_PARAMETER;
+ ret = MLAN_STATUS_FAILURE;
+ } else if (misc->param.gen_ie.len <= sizeof(MrvlIEtypesHeader_t)) {
+ pmadapter->arp_filter_size = 0;
+ PRINTM(MINFO, "Clear ARP filter\n");
+ } else {
+ memcpy(pmadapter, pmadapter->arp_filter, misc->param.gen_ie.ie_data,
+ misc->param.gen_ie.len);
+ pmadapter->arp_filter_size = misc->param.gen_ie.len;
+ HEXDUMP("ArpFilter", pmadapter->arp_filter,
+ pmadapter->arp_filter_size);
+ }
+ break;
+ default:
+ PRINTM(MERROR, "Invalid IE type\n");
+ pioctl_req->status_code = MLAN_ERROR_INVALID_PARAMETER;
+ ret = MLAN_STATUS_FAILURE;
+ }
+ pioctl_req->data_read_written =
+ sizeof(mlan_ds_misc_gen_ie) + MLAN_SUB_COMMAND_SIZE;
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set/Get region code
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static mlan_status
+wlan_misc_ioctl_region(IN pmlan_adapter pmadapter,
+ IN pmlan_ioctl_req pioctl_req)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
+ mlan_ds_misc_cfg *misc = MNULL;
+ int i;
+
+ ENTER();
+
+ misc = (mlan_ds_misc_cfg *) pioctl_req->pbuf;
+ if (pioctl_req->action == MLAN_ACT_GET) {
+ misc->param.region_code = pmadapter->region_code;
+ } else {
+ for (i = 0; i < MRVDRV_MAX_REGION_CODE; i++) {
+ /* Use the region code to search for the index */
+ if (misc->param.region_code == region_code_index[i]) {
+ pmadapter->region_code = (t_u16) misc->param.region_code;
+ break;
+ }
+ }
+ /* It's unidentified region code */
+ if (i >= MRVDRV_MAX_REGION_CODE) {
+ PRINTM(MERROR, "Region Code not identified\n");
+ pioctl_req->status_code = MLAN_ERROR_INVALID_PARAMETER;
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+ if (wlan_set_regiontable(pmpriv, (t_u8) pmadapter->region_code,
+ pmadapter->config_bands | pmadapter->
+ adhoc_start_band)) {
+ pioctl_req->status_code = MLAN_ERROR_IOCTL_FAIL;
+ ret = MLAN_STATUS_FAILURE;
+ }
+ }
+ pioctl_req->data_read_written = sizeof(t_u32) + MLAN_SUB_COMMAND_SIZE;
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Perform warm reset
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_PENDING
+ */
+static mlan_status
+wlan_misc_ioctl_warm_reset(IN pmlan_adapter pmadapter,
+ IN pmlan_ioctl_req pioctl_req)
+{
+ pmlan_private pmpriv = pmadapter->priv[pioctl_req->bss_index];
+ t_s32 i = 0;
+
+ ENTER();
+
+ /** Init all the head nodes and free all the locks here */
+ for (i = 0; i < pmadapter->priv_num; i++) {
+ wlan_free_priv(pmadapter->priv[i]);
+ }
+
+ /* Initialize adapter structure */
+ wlan_init_adapter(pmadapter);
+
+ /* Initialize private structures */
+ for (i = 0; i < pmadapter->priv_num; i++) {
+ if (pmadapter->priv[i]) {
+ wlan_init_priv(pmadapter->priv[i]);
+ }
+ }
+
+ /* Restart the firmware */
+ wlan_prepare_cmd(pmpriv, HostCmd_CMD_FUNC_SHUTDOWN,
+ HostCmd_ACT_GEN_SET, 0, MNULL, MNULL);
+
+ /* Issue firmware initialize commands for first BSS, for other interfaces
+ it will be called after getting the last init command response of
+ previous interface */
+ pmpriv = wlan_get_priv(pmadapter, MLAN_BSS_ROLE_ANY);
+ pmadapter->pwarm_reset_ioctl_req = pioctl_req;
+ pmpriv->ops.init_cmd(pmpriv, MTRUE);
+
+ LEAVE();
+ return MLAN_STATUS_PENDING;
+}
+
+#if defined(SDIO_MULTI_PORT_TX_AGGR) || defined(SDIO_MULTI_PORT_RX_AGGR)
+/**
+ * @brief Reconfigure SDIO multiport aggregation parameters
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static mlan_status
+wlan_misc_ioctl_sdio_mpa_ctrl(IN pmlan_adapter pmadapter,
+ IN pmlan_ioctl_req pioctl_req)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ pmlan_private pmpriv = pmadapter->priv[pioctl_req->bss_index];
+ mlan_ds_misc_cfg *misc = (mlan_ds_misc_cfg *) pioctl_req->pbuf;
+ mlan_ds_misc_sdio_mpa_ctrl *mpa_ctrl = MNULL;
+
+ ENTER();
+
+ mpa_ctrl = &misc->param.mpa_ctrl;
+
+ if (pioctl_req->action == MLAN_ACT_SET) {
+
+ if (pmpriv->media_connected == MTRUE) {
+ PRINTM(MMSG, "SDIO MPA CTRL: not allowed in connected state\n");
+ pioctl_req->status_code = MLAN_ERROR_IOCTL_INVALID;
+ ret = MLAN_STATUS_FAILURE;
+ goto exit;
+ }
+
+ if (mpa_ctrl->tx_enable > 1) {
+ pioctl_req->status_code = MLAN_ERROR_INVALID_PARAMETER;
+ ret = MLAN_STATUS_FAILURE;
+ goto exit;
+ }
+
+ if (mpa_ctrl->rx_enable > 1) {
+ pioctl_req->status_code = MLAN_ERROR_INVALID_PARAMETER;
+ ret = MLAN_STATUS_FAILURE;
+ goto exit;
+ }
+
+ if (mpa_ctrl->tx_max_ports > SDIO_MP_AGGR_DEF_PKT_LIMIT) {
+ pioctl_req->status_code = MLAN_ERROR_INVALID_PARAMETER;
+ ret = MLAN_STATUS_FAILURE;
+ goto exit;
+ }
+
+ if (mpa_ctrl->rx_max_ports > SDIO_MP_AGGR_DEF_PKT_LIMIT) {
+ pioctl_req->status_code = MLAN_ERROR_INVALID_PARAMETER;
+ ret = MLAN_STATUS_FAILURE;
+ goto exit;
+ }
+
+ if (mpa_ctrl->tx_buf_size || mpa_ctrl->rx_buf_size) {
+
+ wlan_free_sdio_mpa_buffers(pmadapter);
+
+ if (mpa_ctrl->tx_buf_size > 0)
+ pmadapter->mpa_tx.buf_size = mpa_ctrl->tx_buf_size;
+
+ if (mpa_ctrl->rx_buf_size > 0)
+ pmadapter->mpa_rx.buf_size = mpa_ctrl->rx_buf_size;
+
+ if (wlan_alloc_sdio_mpa_buffers(pmadapter,
+ pmadapter->mpa_tx.buf_size,
+ pmadapter->mpa_rx.buf_size) !=
+ MLAN_STATUS_SUCCESS) {
+ PRINTM(MERROR, "Failed to allocate sdio mp-a buffers\n");
+ pioctl_req->status_code = MLAN_ERROR_NO_MEM;
+ ret = MLAN_STATUS_FAILURE;
+ goto exit;
+ }
+ }
+
+ if (mpa_ctrl->tx_max_ports > 0)
+ pmadapter->mpa_tx.pkt_aggr_limit = mpa_ctrl->tx_max_ports;
+ if (mpa_ctrl->rx_max_ports > 0)
+ pmadapter->mpa_rx.pkt_aggr_limit = mpa_ctrl->rx_max_ports;
+
+ pmadapter->mpa_tx.enabled = (t_u8) mpa_ctrl->tx_enable;
+ pmadapter->mpa_rx.enabled = (t_u8) mpa_ctrl->rx_enable;
+
+ } else {
+ mpa_ctrl->tx_enable = (t_u16) pmadapter->mpa_tx.enabled;
+ mpa_ctrl->rx_enable = (t_u16) pmadapter->mpa_rx.enabled;
+ mpa_ctrl->tx_buf_size = (t_u16) pmadapter->mpa_tx.buf_size;
+ mpa_ctrl->rx_buf_size = (t_u16) pmadapter->mpa_rx.buf_size;
+ mpa_ctrl->tx_max_ports = (t_u16) pmadapter->mpa_tx.pkt_aggr_limit;
+ mpa_ctrl->rx_max_ports = (t_u16) pmadapter->mpa_rx.pkt_aggr_limit;
+ }
+
+ exit:
+ LEAVE();
+ return ret;
+}
+#endif /* SDIO_MULTI_PORT_TX_AGGR || SDIO_MULTI_PORT_RX_AGGR */
+
+/**
+ * @brief Set/Get system clock configuration
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_PENDING --success, otherwise fail
+ */
+static mlan_status
+wlan_misc_ioctl_sysclock(IN pmlan_adapter pmadapter,
+ IN pmlan_ioctl_req pioctl_req)
+{
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
+ mlan_ds_misc_cfg *misc = MNULL;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ t_u16 cmd_action = 0;
+
+ ENTER();
+
+ misc = (mlan_ds_misc_cfg *) pioctl_req->pbuf;
+ if (pioctl_req->action == MLAN_ACT_GET)
+ cmd_action = HostCmd_ACT_GEN_GET;
+ else
+ cmd_action = HostCmd_ACT_GEN_SET;
+
+ /* Send request to firmware */
+ ret = wlan_prepare_cmd(pmpriv,
+ HostCmd_CMD_ECL_SYSTEM_CLOCK_CONFIG,
+ cmd_action,
+ 0,
+ (t_void *) pioctl_req,
+ (t_void *) & misc->param.sys_clock);
+
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Send function softreset command to firmware
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_PENDING --success, otherwise fail
+ */
+static mlan_status
+wlan_misc_ioctl_soft_reset(IN pmlan_adapter pmadapter,
+ IN pmlan_ioctl_req pioctl_req)
+{
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+ /* Send command to firmware */
+ ret = wlan_prepare_cmd(pmpriv,
+ HostCmd_CMD_SOFT_RESET,
+ HostCmd_ACT_GEN_SET,
+ 0, (t_void *) pioctl_req, MNULL);
+
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set/Get the MAC control configuration.
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_PENDING -- success, otherwise fail
+ */
+mlan_status
+wlan_misc_ioctl_mac_control(IN pmlan_adapter pmadapter,
+ IN pmlan_ioctl_req pioctl_req)
+{
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
+ mlan_ds_misc_cfg *misc = (mlan_ds_misc_cfg *) pioctl_req->pbuf;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ t_u16 cmd_action = 0;
+
+ ENTER();
+
+ misc = (mlan_ds_misc_cfg *) pioctl_req->pbuf;
+
+ if (pioctl_req->action == MLAN_ACT_GET) {
+ misc->param.mac_ctrl = pmpriv->curr_pkt_filter;
+ } else {
+ pmpriv->curr_pkt_filter = misc->param.mac_ctrl;
+ cmd_action = HostCmd_ACT_GEN_SET;
+
+ /* Send command to firmware */
+ ret = wlan_prepare_cmd(pmpriv,
+ HostCmd_CMD_MAC_CONTROL,
+ cmd_action, 0,
+ (t_void *) pioctl_req, &misc->param.mac_ctrl);
+
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+ }
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Get the thermal reading
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_PENDING -- success, otherwise fail
+ */
+mlan_status
+wlan_misc_ioctl_thermal(IN pmlan_adapter pmadapter,
+ IN pmlan_ioctl_req pioctl_req)
+{
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_ds_misc_cfg *misc = MNULL;
+ t_u16 cmd_action = 0;
+
+ ENTER();
+
+ if (pioctl_req->buf_len < sizeof(mlan_ds_misc_cfg)) {
+ PRINTM(MWARN, "MLAN IOCTL information buffer length is too short.\n");
+ pioctl_req->data_read_written = 0;
+ pioctl_req->buf_len_needed = sizeof(mlan_ds_misc_cfg);
+ pioctl_req->status_code = MLAN_ERROR_INVALID_PARAMETER;
+ LEAVE();
+ return MLAN_STATUS_RESOURCE;
+ }
+
+ misc = (mlan_ds_misc_cfg *) pioctl_req->pbuf;
+ if (pioctl_req->action == MLAN_ACT_SET) {
+ PRINTM(MERROR, "Thermal reading setting is not allowed!\n");
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ } else {
+ cmd_action = HostCmd_ACT_GEN_GET;
+ }
+
+ /* Send command to firmware */
+ ret = wlan_prepare_cmd(pmpriv,
+ HostCmd_CMD_802_11_SNMP_MIB,
+ cmd_action, Thermal_i, (t_void *) pioctl_req, MNULL);
+
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Get/Set subscribe event
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_PENDING -- success, otherwise fail
+ */
+mlan_status
+wlan_misc_ioctl_subscribe_evt(IN pmlan_adapter pmadapter,
+ IN pmlan_ioctl_req pioctl_req)
+{
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_ds_misc_cfg *misc = MNULL;
+ t_u16 cmd_action = 0;
+
+ ENTER();
+
+ misc = (mlan_ds_misc_cfg *) pioctl_req->pbuf;
+ if (pioctl_req->action == MLAN_ACT_SET) {
+ cmd_action = HostCmd_ACT_GEN_SET;
+ } else {
+ cmd_action = HostCmd_ACT_GEN_GET;
+ }
+
+ /* Send command to firmware */
+ ret = wlan_prepare_cmd(pmpriv,
+ HostCmd_CMD_802_11_SUBSCRIBE_EVENT,
+ cmd_action,
+ 0,
+ (t_void *) pioctl_req, &misc->param.subscribe_event);
+
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set ARP filter based on IP address
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ * @param ipv4_addr ipv4 Address
+ *
+ * @return MLAN_STATUS_PENDING --success, otherwise fail
+ */
+mlan_status
+wlan_ipaddr_arp_filter(IN pmlan_adapter pmadapter,
+ IN pmlan_ioctl_req pioctl_req, IN t_u32 ipv4_addr)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ pmlan_callbacks pcb = &pmadapter->callbacks;
+ t_u8 *buf;
+ arpfilter_header *arpfilter = MNULL;
+ filter_entry *entry = MNULL;
+ t_u32 len;
+
+ ENTER();
+
+ pcb->moal_malloc(pmadapter->pmoal_handle, MRVDRV_SIZE_OF_CMD_BUFFER,
+ MLAN_MEM_DEF, &buf);
+ if (!buf) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ /* Construct the ARP filter TLV */
+ arpfilter = (arpfilter_header *) buf;
+ arpfilter->type = wlan_cpu_to_le16(TLV_TYPE_ARP_FILTER);
+
+ if (ipv4_addr) {
+ arpfilter->len = wlan_cpu_to_le16(sizeof(filter_entry) * 3);
+ entry = (filter_entry *) (buf + sizeof(arpfilter_header));
+ entry->addr_type = wlan_cpu_to_le16(ADDR_TYPE_BROADCAST);
+ entry->eth_type = wlan_cpu_to_le16(ETHER_TYPE_ARP);
+ entry->ipv4_addr = wlan_cpu_to_le32(ipv4_addr);
+ entry++;
+ entry->addr_type = wlan_cpu_to_le16(ADDR_TYPE_UNICAST);
+ entry->eth_type = wlan_cpu_to_le16(ETHER_TYPE_ANY);
+ entry->ipv4_addr = wlan_cpu_to_le32(IPV4_ADDR_ANY);
+ entry++;
+ entry->addr_type = wlan_cpu_to_le16(ADDR_TYPE_MULTICAST);
+ entry->eth_type = wlan_cpu_to_le16(ETHER_TYPE_ANY);
+ entry->ipv4_addr = wlan_cpu_to_le32(IPV4_ADDR_ANY);
+ } else
+ arpfilter->len = 0;
+
+ /* Update the total length */
+ len = sizeof(arpfilter_header) + wlan_le16_to_cpu(arpfilter->len);
+
+ memset(pmadapter, pmadapter->arp_filter, 0, sizeof(pmadapter->arp_filter));
+ if (len > ARP_FILTER_MAX_BUF_SIZE) {
+ pmadapter->arp_filter_size = 0;
+ PRINTM(MERROR, "Invalid ARP Filter Size\n");
+ pioctl_req->status_code = MLAN_ERROR_INVALID_PARAMETER;
+ ret = MLAN_STATUS_FAILURE;
+ } else if (len <= sizeof(MrvlIEtypesHeader_t)) {
+ pmadapter->arp_filter_size = 0;
+ PRINTM(MINFO, "Clear ARP filter\n");
+ } else {
+ memcpy(pmadapter, pmadapter->arp_filter, buf, len);
+ pmadapter->arp_filter_size = len;
+ HEXDUMP("ArpFilter", pmadapter->arp_filter, pmadapter->arp_filter_size);
+ }
+
+ done:
+ if (buf)
+ pcb->moal_mfree(pmadapter->pmoal_handle, buf);
+ LEAVE();
+ return ret;
+}
+
+#define FLTR_BUF_IP_OFFSET 39
+/**
+ * @brief Enable/Disable Auto ARP resonse
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ * @param ipv4_addr ipv4 Address
+ *
+ * @return MLAN_STATUS_PENDING --success, otherwise fail
+ */
+mlan_status
+wlan_ipaddr_auto_arp_resp(IN pmlan_adapter pmadapter,
+ IN pmlan_ioctl_req pioctl_req, IN t_u32 ipv4_addr)
+{
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ HostCmd_DS_GEN *hostcmd_hdr;
+ HostCmd_DS_MEF_CFG *mefcmd;
+ pmlan_callbacks pcb = &pmadapter->callbacks;
+ mlan_ds_misc_cmd *hostcmd;
+ t_u32 buf_len = 0;
+ t_u8 *buf, *filter;
+ t_u8 fltr_buf[] = { 0x01, 0x10, 0x30, 0x00, 0x06, 0x00, 0x00, 0x00,
+ 0x01, 0xff, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00,
+ 0x01, 0x41, 0x01, 0x00, 0x00, 0x00, 0x01, 0x08,
+ 0x06, 0x02, 0x02, 0x14, 0x00, 0x00, 0x00, 0x01,
+ 0x41, 0x44, 0x01, 0x00, 0x00, 0x00, 0x01, 0xc0,
+ 0xa8, 0x00, 0x68, 0x04, 0x02, 0x2e, 0x00, 0x00,
+ 0x00, 0x01, 0x41, 0x44
+ };
+
+ ENTER();
+
+ ret = pcb->moal_malloc(pmadapter->pmoal_handle,
+ sizeof(mlan_ds_misc_cmd),
+ MLAN_MEM_DEF, (t_u8 **) & hostcmd);
+
+ if (ret != MLAN_STATUS_SUCCESS || hostcmd == MNULL) {
+ PRINTM(MERROR, "Failed to allocate hostcmd buffer\n");
+ pioctl_req->status_code = MLAN_ERROR_NO_MEM;
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+
+ memset(pmpriv->adapter, hostcmd, 0, sizeof(mlan_ds_misc_cmd));
+ buf = hostcmd->cmd;
+
+ /* Prepare hostcmd buffer */
+ hostcmd_hdr = (HostCmd_DS_GEN *) (buf);
+ hostcmd_hdr->command = wlan_cpu_to_le16(HostCmd_CMD_MEF_CFG);
+ mefcmd = (HostCmd_DS_MEF_CFG *) (buf + S_DS_GEN);
+ buf_len = S_DS_GEN;
+
+ if (!ipv4_addr) {
+ PRINTM(MINFO, "Disable Auto ARP Response\n");
+ mefcmd->criteria = wlan_cpu_to_le32(0);
+ mefcmd->nentries = wlan_cpu_to_le16(0);
+ buf_len += sizeof(HostCmd_DS_MEF_CFG);
+ } else {
+ /* Event bit (bit2) of HS conditions should be masked out */
+ mefcmd->criteria =
+ wlan_cpu_to_le32(pmpriv->adapter->hs_cfg.conditions & ~MBIT(2));
+ mefcmd->nentries = wlan_cpu_to_le16(1);
+ buf_len += sizeof(HostCmd_DS_MEF_CFG);
+ filter = buf + buf_len;
+ memcpy(pmpriv->adapter, filter, fltr_buf, sizeof(fltr_buf));
+ memcpy(pmpriv->adapter, &filter[FLTR_BUF_IP_OFFSET], &ipv4_addr,
+ sizeof(ipv4_addr));
+ buf_len += sizeof(fltr_buf);
+ }
+ hostcmd_hdr->size = wlan_cpu_to_le16(buf_len);
+ hostcmd->len = buf_len;
+
+ /* Send command to firmware */
+ ret = wlan_prepare_cmd(pmpriv,
+ 0, 0, 0, (t_void *) pioctl_req, (t_void *) hostcmd);
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+
+ pcb->moal_mfree(pmadapter->pmoal_handle, (t_u8 *) hostcmd);
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief MEF configuration
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_PENDING --success, otherwise fail
+ */
+mlan_status
+wlan_misc_ioctl_mef_cfg(IN pmlan_adapter pmadapter,
+ IN pmlan_ioctl_req pioctl_req)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
+ mlan_ds_misc_mef_cfg *mef_cfg =
+ &((mlan_ds_misc_cfg *) pioctl_req->pbuf)->param.mef_cfg;
+ pmlan_callbacks pcb = &pmadapter->callbacks;
+ HostCmd_DS_GEN *hostcmd_hdr;
+ HostCmd_DS_MEF_CFG *mefcmd;
+ mlan_ds_misc_cmd *hostcmd = MNULL;
+ t_u32 buf_len = 0;
+ t_u8 *buf, *filter;
+ t_u8 fltr_buf[] = { 0x02, 0x00, 0x2f, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x01, 0x01, 0x00, 0x5e, 0x03, 0x02, 0x00, 0x00,
+ 0x00, 0x00, 0x01, 0x41, 0x06, 0x00, 0x00, 0x00,
+ 0x01, 0xff, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00,
+ 0x01, 0x41, 0x45, 0x01, 0x00, 0x00, 0x00, 0x01,
+ 0x33, 0x33, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00,
+ 0x01, 0x41, 0x45
+ };
+
+ ENTER();
+
+ /* GET operation */
+ if (pioctl_req->action == MLAN_ACT_GET) {
+ /* TODO: need to store for get operation */
+ goto done;
+ }
+
+ ret = pcb->moal_malloc(pmadapter->pmoal_handle,
+ sizeof(mlan_ds_misc_cmd),
+ MLAN_MEM_DEF, (t_u8 **) & hostcmd);
+
+ if (ret != MLAN_STATUS_SUCCESS || hostcmd == MNULL) {
+ PRINTM(MERROR, "Failed to allocate hostcmd buffer\n");
+ pioctl_req->status_code = MLAN_ERROR_NO_MEM;
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ memset(pmpriv->adapter, hostcmd, 0, sizeof(mlan_ds_misc_cmd));
+ buf = hostcmd->cmd;
+
+ /* Prepare hostcmd buffer */
+ hostcmd_hdr = (HostCmd_DS_GEN *) (buf);
+ hostcmd_hdr->command = wlan_cpu_to_le16(HostCmd_CMD_MEF_CFG);
+ mefcmd = (HostCmd_DS_MEF_CFG *) (buf + S_DS_GEN);
+ buf_len = S_DS_GEN;
+
+ switch (mef_cfg->sub_id) {
+ case MEF_CFG_DISABLE:
+ PRINTM(MINFO, "Disable MEF\n");
+ mefcmd->criteria = wlan_cpu_to_le32(0);
+ mefcmd->nentries = wlan_cpu_to_le16(0);
+ buf_len += sizeof(HostCmd_DS_MEF_CFG);
+ break;
+ case MEF_CFG_RX_FILTER_ENABLE:
+ PRINTM(MINFO, "Enable Rx filter\n");
+ mefcmd->criteria = wlan_cpu_to_le32((MBIT(3) | MBIT(0)));
+ mefcmd->nentries = wlan_cpu_to_le16(1);
+ buf_len += sizeof(HostCmd_DS_MEF_CFG);
+ filter = buf + buf_len;
+ memcpy(pmpriv->adapter, filter, fltr_buf, sizeof(fltr_buf));
+ buf_len += sizeof(fltr_buf);
+ break;
+ case MEF_CFG_AUTO_ARP_RESP:
+ PRINTM(MINFO, "Enable auto ARP response\n");
+ // TODO
+ break;
+ case MEF_CFG_HOSTCMD:
+ PRINTM(MINFO, "MEF hostcmd from MOAL\n");
+ filter = buf + buf_len;
+ memcpy(pmpriv->adapter, filter, mef_cfg->param.cmd_buf.cmd,
+ mef_cfg->param.cmd_buf.len);
+ buf_len += mef_cfg->param.cmd_buf.len;
+ break;
+ default:
+ PRINTM(MERROR, "Invalid sub ID parameter\n");
+ pioctl_req->status_code = MLAN_ERROR_INVALID_PARAMETER;
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ break;
+ }
+ hostcmd_hdr->size = wlan_cpu_to_le16(buf_len);
+ hostcmd->len = buf_len;
+
+ /* Send command to firmware */
+ ret = wlan_prepare_cmd(pmpriv,
+ 0, 0, 0, (t_void *) pioctl_req, (t_void *) hostcmd);
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+
+ done:
+ if (hostcmd)
+ pcb->moal_mfree(pmadapter->pmoal_handle, (t_u8 *) hostcmd);
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief ipaddr configuration
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_PENDING --success, otherwise fail
+ */
+mlan_status
+wlan_misc_ioctl_ipaddr_cfg(IN pmlan_adapter pmadapter,
+ IN pmlan_ioctl_req pioctl_req)
+{
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
+ mlan_ds_misc_cfg *misc = (mlan_ds_misc_cfg *) pioctl_req->pbuf;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ t_u32 ipv4_addr;
+
+ ENTER();
+
+ /* GET operation */
+ if (pioctl_req->action == MLAN_ACT_GET) {
+ memcpy(pmadapter, misc->param.ipaddr_cfg.ip_addr,
+ pmpriv->ip_addr, IPADDR_LEN);
+ misc->param.ipaddr_cfg.op_code = pmpriv->op_code;
+ goto done;
+ }
+ /* only one IP is supported in current firmware */
+ memcpy(pmadapter, &ipv4_addr, misc->param.ipaddr_cfg.ip_addr[0],
+ sizeof(t_u32));
+
+ if (misc->param.ipaddr_cfg.op_code != MLAN_IPADDR_OP_IP_REMOVE &&
+ !ipv4_addr) {
+ PRINTM(MERROR, "Invalid IPv4 address\n");
+ pioctl_req->status_code = MLAN_ERROR_INVALID_PARAMETER;
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ if (misc->param.ipaddr_cfg.op_code & MLAN_IPADDR_OP_ARP_FILTER)
+ ret = wlan_ipaddr_arp_filter(pmadapter, pioctl_req, ipv4_addr);
+ else if (pmpriv->op_code & MLAN_IPADDR_OP_ARP_FILTER)
+ ret = wlan_ipaddr_arp_filter(pmadapter, pioctl_req, 0);
+ if (ret == MLAN_STATUS_FAILURE)
+ goto done;
+ if (misc->param.ipaddr_cfg.op_code & MLAN_IPADDR_OP_AUTO_ARP_RESP)
+ ret = wlan_ipaddr_auto_arp_resp(pmadapter, pioctl_req, ipv4_addr);
+ else if (pmpriv->op_code & MLAN_IPADDR_OP_AUTO_ARP_RESP)
+ ret = wlan_ipaddr_auto_arp_resp(pmadapter, pioctl_req, 0);
+ if (ret == MLAN_STATUS_FAILURE)
+ goto done;
+
+ /* Save the values in MLAN */
+ if (pioctl_req->action == MLAN_ACT_SET) {
+ pmpriv->op_code = misc->param.ipaddr_cfg.op_code;
+ memcpy(pmadapter, pmpriv->ip_addr,
+ misc->param.ipaddr_cfg.ip_addr, IPADDR_LEN);
+ }
+
+ done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Miscellaneous configuration handler
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING --success, otherwise fail
+ */
+static mlan_status
+wlan_misc_cfg_ioctl(IN pmlan_adapter pmadapter, IN pmlan_ioctl_req pioctl_req)
+{
+ mlan_status status = MLAN_STATUS_SUCCESS;
+ mlan_ds_misc_cfg *misc = MNULL;
+
+ ENTER();
+
+ if (pioctl_req->buf_len < sizeof(mlan_ds_misc_cfg)) {
+ PRINTM(MWARN, "MLAN bss IOCTL length is too short.\n");
+ pioctl_req->data_read_written = 0;
+ pioctl_req->buf_len_needed = sizeof(mlan_ds_misc_cfg);
+ pioctl_req->status_code = MLAN_ERROR_INVALID_PARAMETER;
+ LEAVE();
+ return MLAN_STATUS_RESOURCE;
+ }
+ if ((pioctl_req == MNULL) || (pioctl_req->pbuf == MNULL)) {
+ PRINTM(MERROR, "Request buffer not found!\n");
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+ misc = (mlan_ds_misc_cfg *) pioctl_req->pbuf;
+ switch (misc->sub_command) {
+ case MLAN_OID_MISC_GEN_IE:
+ status = wlan_misc_ioctl_gen_ie(pmadapter, pioctl_req);
+ break;
+ case MLAN_OID_MISC_REGION:
+ status = wlan_misc_ioctl_region(pmadapter, pioctl_req);
+ break;
+ case MLAN_OID_MISC_WARM_RESET:
+ status = wlan_misc_ioctl_warm_reset(pmadapter, pioctl_req);
+ break;
+#if defined(SDIO_MULTI_PORT_TX_AGGR) || defined(SDIO_MULTI_PORT_RX_AGGR)
+ case MLAN_OID_MISC_SDIO_MPA_CTRL:
+ status = wlan_misc_ioctl_sdio_mpa_ctrl(pmadapter, pioctl_req);
+ break;
+#endif
+ case MLAN_OID_MISC_HOST_CMD:
+ status = wlan_misc_ioctl_host_cmd(pmadapter, pioctl_req);
+ break;
+ case MLAN_OID_MISC_SYS_CLOCK:
+ status = wlan_misc_ioctl_sysclock(pmadapter, pioctl_req);
+ break;
+ case MLAN_OID_MISC_WWS:
+ status = wlan_misc_ioctl_wws_cfg(pmadapter, pioctl_req);
+ break;
+ case MLAN_OID_MISC_INIT_SHUTDOWN:
+ status = wlan_misc_ioctl_init_shutdown(pmadapter, pioctl_req);
+ break;
+ case MLAN_OID_MISC_SOFT_RESET:
+ status = wlan_misc_ioctl_soft_reset(pmadapter, pioctl_req);
+ break;
+ case MLAN_OID_MISC_CUSTOM_IE:
+ status = wlan_misc_ioctl_custom_ie_list(pmadapter, pioctl_req, MTRUE);
+ break;
+ case MLAN_OID_MISC_MAC_CONTROL:
+ status = wlan_misc_ioctl_mac_control(pmadapter, pioctl_req);
+ break;
+ case MLAN_OID_MISC_MEF_CFG:
+ status = wlan_misc_ioctl_mef_cfg(pmadapter, pioctl_req);
+ break;
+ case MLAN_OID_MISC_RX_MGMT_IND:
+ status = wlan_reg_rx_mgmt_ind(pmadapter, pioctl_req);
+ break;
+#ifdef DEBUG_LEVEL1
+ case MLAN_OID_MISC_DRVDBG:
+ status = wlan_set_drvdbg(pmadapter, pioctl_req);
+ break;
+#endif
+ case MLAN_OID_MISC_IP_ADDR:
+ status = wlan_misc_ioctl_ipaddr_cfg(pmadapter, pioctl_req);
+ break;
+ case MLAN_OID_MISC_THERMAL:
+ status = wlan_misc_ioctl_thermal(pmadapter, pioctl_req);
+ break;
+ case MLAN_OID_MISC_SUBSCRIBE_EVENT:
+ status = wlan_misc_ioctl_subscribe_evt(pmadapter, pioctl_req);
+ break;
+ default:
+ if (pioctl_req)
+ pioctl_req->status_code = MLAN_ERROR_IOCTL_INVALID;
+ status = MLAN_STATUS_FAILURE;
+ break;
+ }
+ LEAVE();
+ return status;
+}
+
+/**
+ * @brief Set/Get scan configuration parameter
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ * @param action Set/Get
+ *
+ * @return MLAN_STATUS_SUCCESS --success
+ */
+static mlan_status
+wlan_set_get_scan_cfg(IN pmlan_adapter pmadapter,
+ IN pmlan_ioctl_req pioctl_req, IN t_u32 action)
+{
+ mlan_ds_scan *scan = MNULL;
+
+ ENTER();
+
+ scan = (mlan_ds_scan *) pioctl_req->pbuf;
+ if (action == MLAN_ACT_GET) {
+ scan->param.scan_cfg.scan_type = (t_u32) pmadapter->scan_type;
+ scan->param.scan_cfg.scan_mode = pmadapter->scan_mode;
+ scan->param.scan_cfg.scan_probe = (t_u32) pmadapter->scan_probes;
+ scan->param.scan_cfg.scan_time.specific_scan_time =
+ (t_u32) pmadapter->specific_scan_time;
+ scan->param.scan_cfg.scan_time.active_scan_time =
+ (t_u32) pmadapter->active_scan_time;
+ scan->param.scan_cfg.scan_time.passive_scan_time =
+ (t_u32) pmadapter->passive_scan_time;
+ scan->param.scan_cfg.ext_scan = pmadapter->ext_scan;
+ } else {
+ if (scan->param.scan_cfg.scan_type)
+ pmadapter->scan_type = (t_u8) scan->param.scan_cfg.scan_type;
+ if (scan->param.scan_cfg.scan_mode)
+ pmadapter->scan_mode = scan->param.scan_cfg.scan_mode;
+ if (scan->param.scan_cfg.scan_probe)
+ pmadapter->scan_probes = (t_u16) scan->param.scan_cfg.scan_probe;
+ if (scan->param.scan_cfg.scan_time.specific_scan_time)
+ pmadapter->specific_scan_time =
+ (t_u16) scan->param.scan_cfg.scan_time.specific_scan_time;
+ if (scan->param.scan_cfg.scan_time.active_scan_time)
+ pmadapter->active_scan_time =
+ (t_u16) scan->param.scan_cfg.scan_time.active_scan_time;
+ if (scan->param.scan_cfg.scan_time.passive_scan_time)
+ pmadapter->passive_scan_time =
+ (t_u16) scan->param.scan_cfg.scan_time.passive_scan_time;
+ pmadapter->ext_scan = scan->param.scan_cfg.ext_scan;
+ }
+ pioctl_req->data_read_written = sizeof(t_u32) + MLAN_SUB_COMMAND_SIZE;
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief Set/Get scan
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING --success, otherwise fail
+ */
+static mlan_status
+wlan_scan_ioctl(IN pmlan_adapter pmadapter, IN pmlan_ioctl_req pioctl_req)
+{
+ pmlan_private pmpriv = pmadapter->priv[pioctl_req->bss_index];
+ mlan_status status = MLAN_STATUS_SUCCESS;
+ mlan_ds_scan *pscan;
+
+ ENTER();
+
+ pscan = (mlan_ds_scan *) pioctl_req->pbuf;
+ if (pscan->sub_command == MLAN_OID_SCAN_CONFIG)
+ goto start_config;
+ if (pmadapter->scan_processing && pioctl_req->action == MLAN_ACT_SET &&
+ pscan->sub_command != MLAN_OID_SCAN_CANCEL) {
+ PRINTM(MINFO, "Scan already in process...\n");
+ LEAVE();
+ return status;
+ }
+
+ if (pmpriv->scan_block && pioctl_req->action == MLAN_ACT_SET) {
+ PRINTM(MINFO, "Scan is blocked during association...\n");
+ wlan_recv_event(pmpriv, MLAN_EVENT_ID_DRV_SCAN_REPORT, MNULL);
+ LEAVE();
+ return status;
+ }
+ start_config:
+ /* Set scan */
+ if (pioctl_req->action == MLAN_ACT_SET) {
+
+ switch (pscan->sub_command) {
+ case MLAN_OID_SCAN_NORMAL:
+ status = wlan_scan_networks(pmpriv, pioctl_req, MNULL);
+ break;
+ case MLAN_OID_SCAN_SPECIFIC_SSID:
+ status =
+ wlan_scan_specific_ssid(pmpriv, pioctl_req,
+ &pscan->param.scan_req.scan_ssid);
+ break;
+ case MLAN_OID_SCAN_USER_CONFIG:
+ status = wlan_scan_networks(pmpriv, pioctl_req,
+ (wlan_user_scan_cfg *) pscan->param.
+ user_scan.scan_cfg_buf);
+ break;
+ case MLAN_OID_SCAN_CONFIG:
+ status = wlan_set_get_scan_cfg(pmadapter, pioctl_req, MLAN_ACT_SET);
+ break;
+ case MLAN_OID_SCAN_CANCEL:
+ wlan_flush_scan_queue(pmadapter);
+ break;
+ case MLAN_OID_SCAN_TABLE_FLUSH:
+ status = wlan_flush_scan_table(pmadapter);
+ break;
+ case MLAN_OID_SCAN_BGSCAN_CONFIG:
+ /* Send request to firmware */
+ status = wlan_prepare_cmd(pmpriv,
+ HostCmd_CMD_802_11_BG_SCAN_CONFIG,
+ HostCmd_ACT_GEN_SET,
+ 0,
+ (t_void *) pioctl_req,
+ pscan->param.user_scan.scan_cfg_buf);
+ break;
+ default:
+ pioctl_req->status_code = MLAN_ERROR_IOCTL_INVALID;
+ status = MLAN_STATUS_FAILURE;
+ break;
+ }
+
+ if ((status == MLAN_STATUS_SUCCESS) &&
+ (pscan->sub_command != MLAN_OID_SCAN_TABLE_FLUSH) &&
+ (pscan->sub_command != MLAN_OID_SCAN_CANCEL) &&
+ (pscan->sub_command != MLAN_OID_SCAN_CONFIG)) {
+ PRINTM(MINFO, "wlan_scan_ioctl: return MLAN_STATUS_PENDING\n");
+ status = MLAN_STATUS_PENDING;
+ }
+ }
+ /* Get scan */
+ else {
+ if (pscan->sub_command == MLAN_OID_SCAN_CONFIG) {
+ status = wlan_set_get_scan_cfg(pmadapter, pioctl_req, MLAN_ACT_GET);
+ } else if (pscan->sub_command == MLAN_OID_SCAN_GET_CURRENT_BSS) {
+ pscan->param.scan_resp.num_in_scan_table =
+ pmadapter->num_in_scan_table;
+ pscan->param.scan_resp.pscan_table =
+ (t_u8 *) & pmpriv->curr_bss_params.bss_descriptor;
+ pioctl_req->data_read_written =
+ sizeof(mlan_scan_resp) + MLAN_SUB_COMMAND_SIZE;
+ } else {
+ pscan->param.scan_resp.pscan_table =
+ (t_u8 *) pmadapter->pscan_table;
+ pscan->param.scan_resp.num_in_scan_table =
+ pmadapter->num_in_scan_table;
+ pscan->param.scan_resp.age_in_secs = pmadapter->age_in_secs;
+ pioctl_req->data_read_written = sizeof(mlan_scan_resp) +
+ MLAN_SUB_COMMAND_SIZE;
+ }
+ }
+
+ LEAVE();
+ return status;
+}
+
+/********************************************************
+ Global Functions
+********************************************************/
+
+/**
+ * @brief Set ewpa mode
+ *
+ * @param priv A pointer to mlan_private structure
+ * @param psec_pp A pointer to mlan_ds_passphrase structure
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+mlan_status
+wlan_set_ewpa_mode(mlan_private * priv, mlan_ds_passphrase * psec_pp)
+{
+ ENTER();
+
+ if ((psec_pp->psk_type == MLAN_PSK_PASSPHRASE &&
+ psec_pp->psk.passphrase.passphrase_len > 0) ||
+ (psec_pp->psk_type == MLAN_PSK_PMK))
+ priv->sec_info.ewpa_enabled = MTRUE;
+ else
+ priv->sec_info.ewpa_enabled = MFALSE;
+
+ PRINTM(MINFO, "Set ewpa mode = %d\n", priv->sec_info.ewpa_enabled);
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief Search for a BSS
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+mlan_status
+wlan_find_bss(mlan_private * pmpriv, pmlan_ioctl_req pioctl_req)
+{
+ mlan_adapter *pmadapter = pmpriv->adapter;
+ mlan_ds_bss *bss = MNULL;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ t_u8 zero_mac[] = { 0, 0, 0, 0, 0, 0 };
+ t_u8 mac[MLAN_MAC_ADDR_LENGTH];
+ int i = 0;
+ BSSDescriptor_t *pbss_desc;
+
+ ENTER();
+
+ bss = (mlan_ds_bss *) pioctl_req->pbuf;
+
+ if (memcmp
+ (pmadapter, &bss->param.ssid_bssid.bssid, zero_mac, sizeof(zero_mac))) {
+ if (bss->param.ssid_bssid.ssid.ssid_len) /* ssid & bssid */
+ i = wlan_find_ssid_in_list(pmpriv, &bss->param.ssid_bssid.ssid,
+ (t_u8 *) & bss->param.ssid_bssid.bssid,
+ pmpriv->bss_mode);
+ else
+ i = wlan_find_bssid_in_list(pmpriv,
+ (t_u8 *) & bss->param.ssid_bssid.bssid,
+ pmpriv->bss_mode);
+ if (i < 0) {
+ memcpy(pmadapter, mac, &bss->param.ssid_bssid.bssid, sizeof(mac));
+ PRINTM(MERROR, "Can not find bssid %02x:%02x:%02x:%02x:%02x:%02x\n",
+ mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
+ pioctl_req->status_code = MLAN_ERROR_INVALID_PARAMETER;
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+ pbss_desc = &pmadapter->pscan_table[i];
+ memcpy(pmadapter, &bss->param.ssid_bssid.ssid, &pbss_desc->ssid,
+ sizeof(mlan_802_11_ssid));
+ /* index in bss list,start from 1 */
+ bss->param.ssid_bssid.idx = i + 1;
+ } else if (bss->param.ssid_bssid.ssid.ssid_len) {
+ i = wlan_find_ssid_in_list(pmpriv, &bss->param.ssid_bssid.ssid, MNULL,
+ pmpriv->bss_mode);
+ if (i < 0) {
+ PRINTM(MERROR, "Can not find ssid %s\n",
+ bss->param.ssid_bssid.ssid.ssid);
+ pioctl_req->status_code = MLAN_ERROR_INVALID_PARAMETER;
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+ pbss_desc = &pmadapter->pscan_table[i];
+ memcpy(pmadapter, (t_u8 *) & bss->param.ssid_bssid.bssid,
+ (t_u8 *) & pbss_desc->mac_address, MLAN_MAC_ADDR_LENGTH);
+ /* index in bss list, start from 1 */
+ bss->param.ssid_bssid.idx = i + 1;
+ } else {
+ ret = wlan_find_best_network(pmpriv, &bss->param.ssid_bssid);
+ }
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief MLAN station ioctl handler
+ *
+ * @param adapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING --success, otherwise fail
+ */
+mlan_status
+wlan_ops_sta_ioctl(t_void * adapter, pmlan_ioctl_req pioctl_req)
+{
+ pmlan_adapter pmadapter = (pmlan_adapter) adapter;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+ switch (pioctl_req->req_id) {
+ case MLAN_IOCTL_SCAN:
+ status = wlan_scan_ioctl(pmadapter, pioctl_req);
+ break;
+ case MLAN_IOCTL_BSS:
+ status = wlan_bss_ioctl(pmadapter, pioctl_req);
+ break;
+ case MLAN_IOCTL_RADIO_CFG:
+ status = wlan_radio_ioctl(pmadapter, pioctl_req);
+ break;
+ case MLAN_IOCTL_SNMP_MIB:
+ status = wlan_snmp_mib_ioctl(pmadapter, pioctl_req);
+ break;
+ case MLAN_IOCTL_GET_INFO:
+ status = wlan_get_info_ioctl(pmadapter, pioctl_req);
+ break;
+ case MLAN_IOCTL_SEC_CFG:
+ status = wlan_sec_cfg_ioctl(pmadapter, pioctl_req);
+ break;
+ case MLAN_IOCTL_RATE:
+ status = wlan_rate_ioctl(pmadapter, pioctl_req);
+ break;
+ case MLAN_IOCTL_POWER_CFG:
+ status = wlan_power_ioctl(pmadapter, pioctl_req);
+ break;
+ case MLAN_IOCTL_PM_CFG:
+ status = wlan_pm_ioctl(pmadapter, pioctl_req);
+ break;
+ case MLAN_IOCTL_WMM_CFG:
+ status = wlan_wmm_cfg_ioctl(pmadapter, pioctl_req);
+ break;
+ case MLAN_IOCTL_WPS_CFG:
+ status = wlan_wps_cfg_ioctl(pmadapter, pioctl_req);
+ break;
+ case MLAN_IOCTL_11N_CFG:
+ status = wlan_11n_cfg_ioctl(pmadapter, pioctl_req);
+ break;
+ case MLAN_IOCTL_11D_CFG:
+ status = wlan_11d_cfg_ioctl(pmadapter, pioctl_req);
+ break;
+ case MLAN_IOCTL_REG_MEM:
+ status = wlan_reg_mem_ioctl(pmadapter, pioctl_req);
+ break;
+ case MLAN_IOCTL_MISC_CFG:
+ status = wlan_misc_cfg_ioctl(pmadapter, pioctl_req);
+ break;
+ case MLAN_IOCTL_11H_CFG:
+ status = wlan_11h_cfg_ioctl(pmadapter, pioctl_req);
+ break;
+ default:
+ pioctl_req->status_code = MLAN_ERROR_IOCTL_INVALID;
+ status = MLAN_STATUS_FAILURE;
+ break;
+ }
+ LEAVE();
+ return status;
+}
diff --git a/drivers/net/wireless/sd8797/mlan/mlan_sta_rx.c b/drivers/net/wireless/sd8797/mlan/mlan_sta_rx.c
new file mode 100644
index 000000000000..eb1bd845a587
--- /dev/null
+++ b/drivers/net/wireless/sd8797/mlan/mlan_sta_rx.c
@@ -0,0 +1,287 @@
+/** @file mlan_sta_rx.c
+ *
+ * @brief This file contains the handling of RX in MLAN
+ * module.
+ *
+ * Copyright (C) 2008-2011, Marvell International Ltd.
+ *
+ * This software file (the "File") is distributed by Marvell International
+ * Ltd. under the terms of the GNU General Public License Version 2, June 1991
+ * (the "License"). You may use, redistribute and/or modify this File in
+ * accordance with the terms and conditions of the License, a copy of which
+ * is available by writing to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
+ * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
+ *
+ * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
+ * ARE EXPRESSLY DISCLAIMED. The License provides additional details about
+ * this warranty disclaimer.
+ */
+
+/********************************************************
+Change log:
+ 10/27/2008: initial version
+********************************************************/
+
+#include "mlan.h"
+#include "mlan_join.h"
+#include "mlan_util.h"
+#include "mlan_fw.h"
+#include "mlan_main.h"
+#include "mlan_11n_aggr.h"
+#include "mlan_11n_rxreorder.h"
+
+/********************************************************
+ Local Variables
+********************************************************/
+
+/** Ethernet II header */
+typedef struct
+{
+ /** Ethernet II header destination address */
+ t_u8 dest_addr[MLAN_MAC_ADDR_LENGTH];
+ /** Ethernet II header source address */
+ t_u8 src_addr[MLAN_MAC_ADDR_LENGTH];
+ /** Ethernet II header length */
+ t_u16 ethertype;
+
+} EthII_Hdr_t;
+
+/********************************************************
+ Global Variables
+********************************************************/
+
+/********************************************************
+ Local Functions
+********************************************************/
+
+/********************************************************
+ Global functions
+********************************************************/
+/**
+ * @brief This function processes received packet and forwards it
+ * to kernel/upper layer
+ *
+ * @param pmadapter A pointer to mlan_adapter
+ * @param pmbuf A pointer to mlan_buffer which includes the received packet
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status
+wlan_process_rx_packet(pmlan_adapter pmadapter, pmlan_buffer pmbuf)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ pmlan_private priv = pmadapter->priv[pmbuf->bss_index];
+ RxPacketHdr_t *prx_pkt;
+ RxPD *prx_pd;
+ int hdr_chop;
+ EthII_Hdr_t *peth_hdr;
+ t_u8 rfc1042_eth_hdr[MLAN_MAC_ADDR_LENGTH] =
+ { 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00 };
+ t_u8 snap_oui_802_h[MLAN_MAC_ADDR_LENGTH] =
+ { 0xaa, 0xaa, 0x03, 0x00, 0x00, 0xf8 };
+ t_u8 appletalk_aarp_type[2] = { 0x80, 0xf3 };
+ t_u8 ipx_snap_type[2] = { 0x81, 0x37 };
+
+ ENTER();
+
+ prx_pd = (RxPD *) (pmbuf->pbuf + pmbuf->data_offset);
+ prx_pkt = (RxPacketHdr_t *) ((t_u8 *) prx_pd + prx_pd->rx_pkt_offset);
+
+/** Small debug type */
+#define DBG_TYPE_SMALL 2
+/** Size of debugging structure */
+#define SIZE_OF_DBG_STRUCT 4
+ if (prx_pd->rx_pkt_type == PKT_TYPE_DEBUG) {
+ t_u8 dbgType;
+ dbgType = *(t_u8 *) & prx_pkt->eth803_hdr;
+ if (dbgType == DBG_TYPE_SMALL) {
+ PRINTM(MFW_D, "\n");
+ DBG_HEXDUMP(MFW_D, "FWDBG",
+ (t_s8 *) ((t_u8 *) & prx_pkt->eth803_hdr +
+ SIZE_OF_DBG_STRUCT), prx_pd->rx_pkt_length);
+ PRINTM(MFW_D, "FWDBG::\n");
+ }
+ goto done;
+ }
+
+ PRINTM(MINFO, "RX Data: data_len - prx_pd->rx_pkt_offset = %d - %d = %d\n",
+ pmbuf->data_len, prx_pd->rx_pkt_offset,
+ pmbuf->data_len - prx_pd->rx_pkt_offset);
+
+ HEXDUMP("RX Data: Dest", prx_pkt->eth803_hdr.dest_addr,
+ sizeof(prx_pkt->eth803_hdr.dest_addr));
+ HEXDUMP("RX Data: Src", prx_pkt->eth803_hdr.src_addr,
+ sizeof(prx_pkt->eth803_hdr.src_addr));
+
+ if ((memcmp(pmadapter, &prx_pkt->rfc1042_hdr,
+ snap_oui_802_h, sizeof(snap_oui_802_h)) == 0) ||
+ ((memcmp(pmadapter, &prx_pkt->rfc1042_hdr,
+ rfc1042_eth_hdr, sizeof(rfc1042_eth_hdr)) == 0) &&
+ memcmp(pmadapter, &prx_pkt->rfc1042_hdr.snap_type,
+ appletalk_aarp_type, sizeof(appletalk_aarp_type)) &&
+ memcmp(pmadapter, &prx_pkt->rfc1042_hdr.snap_type,
+ ipx_snap_type, sizeof(ipx_snap_type)))) {
+ /*
+ * Replace the 803 header and rfc1042 header (llc/snap) with an
+ * EthernetII header, keep the src/dst and snap_type (ethertype).
+ * The firmware only passes up SNAP frames converting
+ * all RX Data from 802.11 to 802.2/LLC/SNAP frames.
+ * To create the Ethernet II, just move the src, dst address right
+ * before the snap_type.
+ */
+ peth_hdr = (EthII_Hdr_t *)
+ ((t_u8 *) & prx_pkt->eth803_hdr
+ + sizeof(prx_pkt->eth803_hdr) + sizeof(prx_pkt->rfc1042_hdr)
+ - sizeof(prx_pkt->eth803_hdr.dest_addr)
+ - sizeof(prx_pkt->eth803_hdr.src_addr)
+ - sizeof(prx_pkt->rfc1042_hdr.snap_type));
+
+ memcpy(pmadapter, peth_hdr->src_addr, prx_pkt->eth803_hdr.src_addr,
+ sizeof(peth_hdr->src_addr));
+ memcpy(pmadapter, peth_hdr->dest_addr, prx_pkt->eth803_hdr.dest_addr,
+ sizeof(peth_hdr->dest_addr));
+
+ /* Chop off the RxPD + the excess memory from the 802.2/llc/snap header
+ that was removed. */
+ hdr_chop = (t_u32) ((t_ptr) peth_hdr - (t_ptr) prx_pd);
+ } else {
+ HEXDUMP("RX Data: LLC/SNAP",
+ (t_u8 *) & prx_pkt->rfc1042_hdr, sizeof(prx_pkt->rfc1042_hdr));
+
+ /* Chop off the RxPD */
+ hdr_chop = (t_u32) ((t_ptr) & prx_pkt->eth803_hdr - (t_ptr) prx_pd);
+ }
+
+ /* Chop off the leading header bytes so the it points to the start of
+ either the reconstructed EthII frame or the 802.2/llc/snap frame */
+ pmbuf->data_len -= hdr_chop;
+ pmbuf->data_offset += hdr_chop;
+ pmbuf->pparent = MNULL;
+
+ DBG_HEXDUMP(MDAT_D, "RxPD", (t_u8 *) prx_pd,
+ MIN(sizeof(RxPD), MAX_DATA_DUMP_LEN));
+ DBG_HEXDUMP(MDAT_D, "Rx Payload", ((t_u8 *) prx_pd + prx_pd->rx_pkt_offset),
+ MIN(prx_pd->rx_pkt_length, MAX_DATA_DUMP_LEN));
+
+ priv->rxpd_rate = prx_pd->rx_rate;
+
+ priv->rxpd_htinfo = prx_pd->ht_info;
+ pmadapter->callbacks.moal_get_system_time(pmadapter->pmoal_handle,
+ &pmbuf->out_ts_sec,
+ &pmbuf->out_ts_usec);
+ PRINTM(MDATA, "%lu.%06lu : Data => kernel seq_num=%d tid=%d\n",
+ pmbuf->out_ts_sec, pmbuf->out_ts_usec, prx_pd->seq_num,
+ prx_pd->priority);
+ ret = pmadapter->callbacks.moal_recv_packet(pmadapter->pmoal_handle, pmbuf);
+ if (ret == MLAN_STATUS_FAILURE) {
+ pmbuf->status_code = MLAN_ERROR_PKT_INVALID;
+ PRINTM(MERROR, "STA Rx Error: moal_recv_packet returned error\n");
+ }
+ done:
+ if (ret != MLAN_STATUS_PENDING) {
+ wlan_free_mlan_buffer(pmadapter, pmbuf);
+ }
+ LEAVE();
+
+ return ret;
+}
+
+/**
+ * @brief This function processes the received buffer
+ *
+ * @param adapter A pointer to mlan_adapter
+ * @param pmbuf A pointer to the received buffer
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status
+wlan_ops_sta_process_rx_packet(IN t_void * adapter, IN pmlan_buffer pmbuf)
+{
+ pmlan_adapter pmadapter = (pmlan_adapter) adapter;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ RxPD *prx_pd;
+ RxPacketHdr_t *prx_pkt;
+ pmlan_private priv = pmadapter->priv[pmbuf->bss_index];
+ t_u8 ta[MLAN_MAC_ADDR_LENGTH];
+ t_u16 rx_pkt_type = 0;
+ wlan_mgmt_pkt *pmgmt_pkt_hdr = MNULL;
+ ENTER();
+
+ prx_pd = (RxPD *) (pmbuf->pbuf + pmbuf->data_offset);
+ /* Endian conversion */
+ endian_convert_RxPD(prx_pd);
+ rx_pkt_type = prx_pd->rx_pkt_type;
+ prx_pkt = (RxPacketHdr_t *) ((t_u8 *) prx_pd + prx_pd->rx_pkt_offset);
+
+ if ((prx_pd->rx_pkt_offset + prx_pd->rx_pkt_length) >
+ (t_u16) pmbuf->data_len) {
+ PRINTM(MERROR,
+ "Wrong rx packet: len=%d,rx_pkt_offset=%d,"
+ " rx_pkt_length=%d\n", pmbuf->data_len, prx_pd->rx_pkt_offset,
+ prx_pd->rx_pkt_length);
+ pmbuf->status_code = MLAN_ERROR_PKT_SIZE_INVALID;
+ ret = MLAN_STATUS_FAILURE;
+ wlan_free_mlan_buffer(pmadapter, pmbuf);
+ goto done;
+ }
+ pmbuf->data_len = prx_pd->rx_pkt_offset + prx_pd->rx_pkt_length;
+
+ if (pmadapter->priv[pmbuf->bss_index]->mgmt_frame_passthru_mask &&
+ prx_pd->rx_pkt_type == PKT_TYPE_MGMT_FRAME) {
+ /* Check if this is mgmt packet and needs to forwarded to app as an
+ event */
+ pmgmt_pkt_hdr =
+ (wlan_mgmt_pkt *) ((t_u8 *) prx_pd + prx_pd->rx_pkt_offset);
+ pmgmt_pkt_hdr->frm_len = wlan_le16_to_cpu(pmgmt_pkt_hdr->frm_len);
+
+ if ((pmgmt_pkt_hdr->wlan_header.frm_ctl
+ & IEEE80211_FC_MGMT_FRAME_TYPE_MASK) == 0)
+ wlan_process_802dot11_mgmt_pkt(pmadapter->priv[pmbuf->bss_index],
+ (t_u8 *) & pmgmt_pkt_hdr->
+ wlan_header,
+ pmgmt_pkt_hdr->frm_len +
+ sizeof(wlan_mgmt_pkt)
+ - sizeof(pmgmt_pkt_hdr->frm_len));
+ wlan_free_mlan_buffer(pmadapter, pmbuf);
+ goto done;
+ }
+
+ /*
+ * If the packet is not an unicast packet then send the packet
+ * directly to os. Don't pass thru rx reordering
+ */
+ if (!IS_11N_ENABLED(priv) ||
+ memcmp(priv->adapter, priv->curr_addr, prx_pkt->eth803_hdr.dest_addr,
+ MLAN_MAC_ADDR_LENGTH)) {
+ wlan_process_rx_packet(pmadapter, pmbuf);
+ goto done;
+ }
+
+ if (queuing_ra_based(priv)) {
+ memcpy(pmadapter, ta, prx_pkt->eth803_hdr.src_addr,
+ MLAN_MAC_ADDR_LENGTH);
+ } else {
+ if ((rx_pkt_type != PKT_TYPE_BAR) && (prx_pd->priority < MAX_NUM_TID))
+ priv->rx_seq[prx_pd->priority] = prx_pd->seq_num;
+ memcpy(pmadapter, ta,
+ priv->curr_bss_params.bss_descriptor.mac_address,
+ MLAN_MAC_ADDR_LENGTH);
+ }
+
+ /* Reorder and send to OS */
+ if ((ret = mlan_11n_rxreorder_pkt(priv, prx_pd->seq_num,
+ prx_pd->priority, ta,
+ (t_u8) prx_pd->rx_pkt_type,
+ (void *) pmbuf)) ||
+ (rx_pkt_type == PKT_TYPE_BAR)
+ ) {
+ wlan_free_mlan_buffer(pmadapter, pmbuf);
+ }
+
+ done:
+
+ LEAVE();
+ return (ret);
+}
diff --git a/drivers/net/wireless/sd8797/mlan/mlan_sta_tx.c b/drivers/net/wireless/sd8797/mlan/mlan_sta_tx.c
new file mode 100644
index 000000000000..f509468d586f
--- /dev/null
+++ b/drivers/net/wireless/sd8797/mlan/mlan_sta_tx.c
@@ -0,0 +1,276 @@
+/** @file mlan_sta_tx.c
+ *
+ * @brief This file contains the handling of data packet
+ * transmission in MLAN module.
+ *
+ * Copyright (C) 2008-2011, Marvell International Ltd.
+ *
+ * This software file (the "File") is distributed by Marvell International
+ * Ltd. under the terms of the GNU General Public License Version 2, June 1991
+ * (the "License"). You may use, redistribute and/or modify this File in
+ * accordance with the terms and conditions of the License, a copy of which
+ * is available by writing to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
+ * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
+ *
+ * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
+ * ARE EXPRESSLY DISCLAIMED. The License provides additional details about
+ * this warranty disclaimer.
+ */
+
+/********************************************************
+Change log:
+ 10/21/2008: initial version
+********************************************************/
+
+#include "mlan.h"
+#include "mlan_join.h"
+#include "mlan_util.h"
+#include "mlan_fw.h"
+#include "mlan_main.h"
+#include "mlan_wmm.h"
+#include "mlan_sdio.h"
+
+/********************************************************
+ Local Variables
+********************************************************/
+
+/********************************************************
+ Global Variables
+********************************************************/
+
+/********************************************************
+ Local Functions
+********************************************************/
+
+/********************************************************
+ Global functions
+********************************************************/
+/**
+ * @brief This function fill the txpd for tx packet
+ *
+ * @param priv A pointer to mlan_private structure
+ * @param pmbuf A pointer to the mlan_buffer for process
+ *
+ * @return headptr or MNULL
+ */
+t_void *
+wlan_ops_sta_process_txpd(IN t_void * priv, IN pmlan_buffer pmbuf)
+{
+ mlan_private *pmpriv = (mlan_private *) priv;
+ pmlan_adapter pmadapter = pmpriv->adapter;
+ TxPD *plocal_tx_pd;
+ t_u8 *head_ptr = MNULL;
+ t_u32 pkt_type;
+ t_u32 tx_control;
+
+ ENTER();
+
+ if (!pmbuf->data_len) {
+ PRINTM(MERROR, "STA Tx Error: Invalid packet length: %d\n",
+ pmbuf->data_len);
+ pmbuf->status_code = MLAN_ERROR_PKT_SIZE_INVALID;
+ goto done;
+ }
+ if (pmbuf->buf_type == MLAN_BUF_TYPE_RAW_DATA) {
+ memcpy(pmpriv->adapter, &pkt_type, pmbuf->pbuf + pmbuf->data_offset,
+ sizeof(pkt_type));
+ memcpy(pmpriv->adapter, &tx_control,
+ pmbuf->pbuf + pmbuf->data_offset + sizeof(pkt_type),
+ sizeof(tx_control));
+ pmbuf->data_offset += sizeof(pkt_type) + sizeof(tx_control);
+ pmbuf->data_len -= sizeof(pkt_type) + sizeof(tx_control);
+ }
+
+ if (pmbuf->data_offset < (sizeof(TxPD) + INTF_HEADER_LEN + DMA_ALIGNMENT)) {
+ PRINTM(MERROR, "not enough space for TxPD: %d\n", pmbuf->data_len);
+ pmbuf->status_code = MLAN_ERROR_PKT_SIZE_INVALID;
+ goto done;
+ }
+
+ /* head_ptr should be aligned */
+ head_ptr =
+ pmbuf->pbuf + pmbuf->data_offset - sizeof(TxPD) - INTF_HEADER_LEN;
+ head_ptr = (t_u8 *) ((t_ptr) head_ptr & ~((t_ptr) (DMA_ALIGNMENT - 1)));
+
+ plocal_tx_pd = (TxPD *) (head_ptr + INTF_HEADER_LEN);
+ memset(pmadapter, plocal_tx_pd, 0, sizeof(TxPD));
+ /* Set the BSS number to TxPD */
+ plocal_tx_pd->bss_num = GET_BSS_NUM(pmpriv);
+ plocal_tx_pd->bss_type = pmpriv->bss_type;
+
+ plocal_tx_pd->tx_pkt_length = (t_u16) pmbuf->data_len;
+
+ plocal_tx_pd->priority = (t_u8) pmbuf->priority;
+ plocal_tx_pd->pkt_delay_2ms =
+ wlan_wmm_compute_driver_packet_delay(pmpriv, pmbuf);
+
+ if (plocal_tx_pd->priority < NELEMENTS(pmpriv->wmm.user_pri_pkt_tx_ctrl))
+ /*
+ * Set the priority specific tx_control field, setting of 0 will
+ * cause the default value to be used later in this function
+ */
+ plocal_tx_pd->tx_control
+ = pmpriv->wmm.user_pri_pkt_tx_ctrl[plocal_tx_pd->priority];
+ if (pmadapter->pps_uapsd_mode) {
+ if (MTRUE == wlan_check_last_packet_indication(pmpriv)) {
+ pmadapter->tx_lock_flag = MTRUE;
+ plocal_tx_pd->flags = MRVDRV_TxPD_POWER_MGMT_LAST_PACKET;
+ }
+ }
+
+ /* Offset of actual data */
+ plocal_tx_pd->tx_pkt_offset =
+ (t_u16) ((t_ptr) pmbuf->pbuf + pmbuf->data_offset -
+ (t_ptr) plocal_tx_pd);
+
+ if (!plocal_tx_pd->tx_control) {
+ /* TxCtrl set by user or default */
+ plocal_tx_pd->tx_control = pmpriv->pkt_tx_ctrl;
+ }
+
+ if (pmbuf->buf_type == MLAN_BUF_TYPE_RAW_DATA) {
+ plocal_tx_pd->tx_pkt_type = (t_u16) pkt_type;
+ plocal_tx_pd->tx_control = tx_control;
+ }
+
+ endian_convert_TxPD(plocal_tx_pd);
+
+ /* Adjust the data offset and length to include TxPD in pmbuf */
+ pmbuf->data_len += pmbuf->data_offset;
+ pmbuf->data_offset = (t_u32) (head_ptr - pmbuf->pbuf);
+ pmbuf->data_len -= pmbuf->data_offset;
+
+ done:
+ LEAVE();
+ return head_ptr;
+}
+
+/**
+ * @brief This function tells firmware to send a NULL data packet.
+ *
+ * @param priv A pointer to mlan_private structure
+ * @param flags Transmit Pkt Flags
+ *
+ * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING --success, otherwise failure
+ */
+mlan_status
+wlan_send_null_packet(pmlan_private priv, t_u8 flags)
+{
+ pmlan_adapter pmadapter = priv->adapter;
+ TxPD *ptx_pd;
+/* sizeof(TxPD) + Interface specific header */
+#define NULL_PACKET_HDR 256
+ t_u32 data_len = NULL_PACKET_HDR;
+ pmlan_buffer pmbuf = MNULL;
+ t_u8 *ptr;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ t_u32 sec, usec;
+
+ ENTER();
+
+ if (pmadapter->surprise_removed == MTRUE) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ if (priv->media_connected == MFALSE) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ if (pmadapter->data_sent == MTRUE) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ pmbuf = wlan_alloc_mlan_buffer(pmadapter, data_len, 0, MTRUE);
+ if (!pmbuf) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ memset(pmadapter, pmbuf->pbuf, 0, data_len);
+ pmbuf->bss_index = priv->bss_index;
+ pmbuf->buf_type = MLAN_BUF_TYPE_DATA;
+ ptr = pmbuf->pbuf + pmbuf->data_offset;
+ pmbuf->data_len = sizeof(TxPD) + INTF_HEADER_LEN;
+ ptx_pd = (TxPD *) (ptr + INTF_HEADER_LEN);
+ ptx_pd->tx_control = priv->pkt_tx_ctrl;
+ ptx_pd->flags = flags;
+ ptx_pd->priority = WMM_HIGHEST_PRIORITY;
+ ptx_pd->tx_pkt_offset = sizeof(TxPD);
+ /* Set the BSS number to TxPD */
+ ptx_pd->bss_num = GET_BSS_NUM(priv);
+ ptx_pd->bss_type = priv->bss_type;
+
+ endian_convert_TxPD(ptx_pd);
+
+ ret = wlan_sdio_host_to_card(pmadapter, MLAN_TYPE_DATA, pmbuf, MNULL);
+
+ switch (ret) {
+ case MLAN_STATUS_RESOURCE:
+ pmadapter->data_sent = MTRUE;
+ /* Fall through FAILURE handling */
+ case MLAN_STATUS_FAILURE:
+ wlan_free_mlan_buffer(pmadapter, pmbuf);
+ PRINTM(MERROR, "STA Tx Error: Failed to send NULL packet!\n");
+ pmadapter->dbg.num_tx_host_to_card_failure++;
+ goto done;
+ case MLAN_STATUS_SUCCESS:
+ wlan_free_mlan_buffer(pmadapter, pmbuf);
+ PRINTM(MINFO, "STA Tx: Successfully send the NULL packet\n");
+ pmadapter->tx_lock_flag = MTRUE;
+ break;
+ case MLAN_STATUS_PENDING:
+ break;
+ default:
+ break;
+ }
+
+ pmadapter->callbacks.moal_get_system_time(pmadapter->pmoal_handle, &sec,
+ &usec);
+ PRINTM(MDATA, "%lu.%06lu : Null data => FW\n", sec, usec);
+ DBG_HEXDUMP(MDAT_D, "Null data", ptr, sizeof(TxPD) + INTF_HEADER_LEN);
+ done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function checks if we need to send last packet indication.
+ *
+ * @param priv A pointer to mlan_private structure
+ *
+ * @return MTRUE or MFALSE
+ */
+t_u8
+wlan_check_last_packet_indication(pmlan_private priv)
+{
+ pmlan_adapter pmadapter = priv->adapter;
+ t_u8 ret = MFALSE;
+ t_u8 prop_ps = MTRUE;
+
+ ENTER();
+
+ if (!pmadapter->sleep_period.period) {
+ LEAVE();
+ return ret;
+ }
+ if (wlan_bypass_tx_list_empty(pmadapter) && wlan_wmm_lists_empty(pmadapter)) {
+ if (((priv->curr_bss_params.wmm_uapsd_enabled == MTRUE) &&
+ priv->wmm_qosinfo) || prop_ps)
+
+ ret = MTRUE;
+ }
+ if (ret && !pmadapter->cmd_sent && !pmadapter->curr_cmd
+ && !IS_COMMAND_PENDING(pmadapter)) {
+ pmadapter->delay_null_pkt = MFALSE;
+ ret = MTRUE;
+ } else {
+ ret = MFALSE;
+ pmadapter->delay_null_pkt = MTRUE;
+ }
+ LEAVE();
+ return ret;
+}
diff --git a/drivers/net/wireless/sd8797/mlan/mlan_txrx.c b/drivers/net/wireless/sd8797/mlan/mlan_txrx.c
new file mode 100644
index 000000000000..f243fc191800
--- /dev/null
+++ b/drivers/net/wireless/sd8797/mlan/mlan_txrx.c
@@ -0,0 +1,374 @@
+/**
+ * @file mlan_txrx.c
+ *
+ * @brief This file contains the handling of TX/RX in MLAN
+ *
+ * Copyright (C) 2009-2011, Marvell International Ltd.
+ *
+ * This software file (the "File") is distributed by Marvell International
+ * Ltd. under the terms of the GNU General Public License Version 2, June 1991
+ * (the "License"). You may use, redistribute and/or modify this File in
+ * accordance with the terms and conditions of the License, a copy of which
+ * is available by writing to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
+ * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
+ *
+ * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
+ * ARE EXPRESSLY DISCLAIMED. The License provides additional details about
+ * this warranty disclaimer.
+ */
+
+/*************************************************************
+Change Log:
+ 05/11/2009: initial version
+************************************************************/
+
+#include "mlan.h"
+#ifdef STA_SUPPORT
+#include "mlan_join.h"
+#endif
+#include "mlan_util.h"
+#include "mlan_fw.h"
+#include "mlan_main.h"
+#include "mlan_wmm.h"
+#include "mlan_sdio.h"
+
+/********************************************************
+ Local Variables
+********************************************************/
+
+/********************************************************
+ Global Variables
+********************************************************/
+
+/********************************************************
+ Local Functions
+********************************************************/
+
+/********************************************************
+ Global Functions
+********************************************************/
+/**
+ * @brief This function processes the received buffer
+ *
+ * @param pmadapter A pointer to mlan_adapter
+ * @param pmbuf A pointer to the received buffer
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status
+wlan_handle_rx_packet(pmlan_adapter pmadapter, pmlan_buffer pmbuf)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ pmlan_private priv = wlan_get_priv(pmadapter, MLAN_BSS_ROLE_ANY);
+ RxPD *prx_pd;
+ t_u32 sec, usec;
+
+ ENTER();
+
+ prx_pd = (RxPD *) (pmbuf->pbuf + pmbuf->data_offset);
+ /* Get the BSS number from RxPD, get corresponding priv */
+ priv =
+ wlan_get_priv_by_id(pmadapter, prx_pd->bss_num & BSS_NUM_MASK,
+ prx_pd->bss_type);
+ if (!priv)
+ priv = wlan_get_priv(pmadapter, MLAN_BSS_ROLE_ANY);
+ pmbuf->bss_index = priv->bss_index;
+ pmadapter->callbacks.moal_get_system_time(pmadapter->pmoal_handle, &sec,
+ &usec);
+ PRINTM_NETINTF(MDATA, priv);
+ PRINTM(MDATA, "%lu.%06lu : Data <= FW\n", sec, usec);
+ ret = priv->ops.process_rx_packet(pmadapter, pmbuf);
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function checks the conditions and sends packet to device
+ *
+ * @param priv A pointer to mlan_private structure
+ * @param pmbuf A pointer to the mlan_buffer for process
+ * @param tx_param A pointer to mlan_tx_param structure
+ *
+ * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING --success, otherwise failure
+ */
+mlan_status
+wlan_process_tx(pmlan_private priv, pmlan_buffer pmbuf,
+ mlan_tx_param * tx_param)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ pmlan_adapter pmadapter = priv->adapter;
+ t_u8 *head_ptr = MNULL;
+ t_u32 sec, usec;
+#ifdef STA_SUPPORT
+ TxPD *plocal_tx_pd = MNULL;
+#endif
+
+ ENTER();
+
+ head_ptr = (t_u8 *) priv->ops.process_txpd(priv, pmbuf);
+ if (!head_ptr) {
+ pmbuf->status_code = MLAN_ERROR_PKT_INVALID;
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+#ifdef STA_SUPPORT
+ if (GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_STA)
+ plocal_tx_pd = (TxPD *) (head_ptr + INTF_HEADER_LEN);
+#endif
+ ret = wlan_sdio_host_to_card(pmadapter, MLAN_TYPE_DATA, pmbuf, tx_param);
+ done:
+ switch (ret) {
+ case MLAN_STATUS_RESOURCE:
+#ifdef STA_SUPPORT
+ if ((GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_STA) &&
+ pmadapter->pps_uapsd_mode && (pmadapter->tx_lock_flag == MTRUE)) {
+ pmadapter->tx_lock_flag = MFALSE;
+ plocal_tx_pd->flags = 0;
+ }
+#endif
+ PRINTM(MINFO, "MLAN_STATUS_RESOURCE is returned\n");
+ break;
+ case MLAN_STATUS_FAILURE:
+ pmadapter->data_sent = MFALSE;
+ PRINTM(MERROR, "Error: host_to_card failed: 0x%X\n", ret);
+ pmadapter->dbg.num_tx_host_to_card_failure++;
+ pmbuf->status_code = MLAN_ERROR_DATA_TX_FAIL;
+ wlan_write_data_complete(pmadapter, pmbuf, ret);
+ break;
+ case MLAN_STATUS_PENDING:
+ pmadapter->data_sent = MFALSE;
+ DBG_HEXDUMP(MDAT_D, "Tx", head_ptr + INTF_HEADER_LEN,
+ MIN(pmbuf->data_len + sizeof(TxPD), MAX_DATA_DUMP_LEN));
+ break;
+ case MLAN_STATUS_SUCCESS:
+ DBG_HEXDUMP(MDAT_D, "Tx", head_ptr + INTF_HEADER_LEN,
+ MIN(pmbuf->data_len + sizeof(TxPD), MAX_DATA_DUMP_LEN));
+ wlan_write_data_complete(pmadapter, pmbuf, ret);
+ break;
+ default:
+ break;
+ }
+
+ if ((ret == MLAN_STATUS_SUCCESS) || (ret == MLAN_STATUS_PENDING)) {
+ pmadapter->callbacks.moal_get_system_time(pmadapter->pmoal_handle, &sec,
+ &usec);
+ PRINTM_NETINTF(MDATA, priv);
+ PRINTM(MDATA, "%lu.%06lu : Data => FW\n", sec, usec);
+ }
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Packet send completion handling
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pmbuf A pointer to mlan_buffer structure
+ * @param status Callback status
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+mlan_status
+wlan_write_data_complete(IN pmlan_adapter pmadapter,
+ IN pmlan_buffer pmbuf, IN mlan_status status)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ pmlan_callbacks pcb;
+
+ ENTER();
+
+ MASSERT(pmadapter && pmbuf);
+
+ pcb = &pmadapter->callbacks;
+ if ((pmbuf->buf_type == MLAN_BUF_TYPE_DATA) ||
+ (pmbuf->buf_type == MLAN_BUF_TYPE_RAW_DATA)) {
+ PRINTM(MINFO, "wlan_write_data_complete: DATA %p\n", pmbuf);
+ if (pmbuf->flags & MLAN_BUF_FLAG_MOAL_TX_BUF) {
+ /* pmbuf was allocated by MOAL */
+ pcb->moal_send_packet_complete(pmadapter->pmoal_handle,
+ pmbuf, status);
+ } else {
+ if (pmbuf->flags & MLAN_BUF_FLAG_BRIDGE_BUF) {
+ pmadapter->pending_bridge_pkts--;
+ }
+ /* pmbuf was allocated by MLAN */
+ wlan_free_mlan_buffer(pmadapter, pmbuf);
+ }
+ }
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Packet receive completion callback handler
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pmbuf A pointer to mlan_buffer structure
+ * @param status Callback status
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+mlan_status
+wlan_recv_packet_complete(IN pmlan_adapter pmadapter,
+ IN pmlan_buffer pmbuf, IN mlan_status status)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ pmlan_private pmp;
+ pmlan_callbacks pcb;
+ pmlan_buffer pmbuf_parent;
+
+ ENTER();
+
+ MASSERT(pmadapter && pmbuf);
+ pcb = &pmadapter->callbacks;
+ MASSERT(pmbuf->bss_index < pmadapter->priv_num);
+
+ pmp = pmadapter->priv[pmbuf->bss_index];
+
+ if (pmbuf->pparent) {
+ pmbuf_parent = pmbuf->pparent;
+
+ pmadapter->callbacks.moal_spin_lock(pmadapter->pmoal_handle,
+ pmp->rx_pkt_lock);
+ --pmbuf_parent->use_count;
+ if (!pmbuf_parent->use_count) {
+ pmadapter->callbacks.moal_spin_unlock(pmadapter->pmoal_handle,
+ pmp->rx_pkt_lock);
+ wlan_free_mlan_buffer(pmadapter, pmbuf_parent);
+ } else {
+ pmadapter->callbacks.moal_spin_unlock(pmadapter->pmoal_handle,
+ pmp->rx_pkt_lock);
+ }
+ wlan_free_mlan_buffer(pmadapter, pmbuf);
+ } else {
+ wlan_free_mlan_buffer(pmadapter, pmbuf);
+ }
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Add packet to Bypass TX queue
+ *
+ * @param pmadapter Pointer to the mlan_adapter driver data struct
+ * @param pmbuf Pointer to the mlan_buffer data struct
+ *
+ * @return N/A
+ */
+t_void
+wlan_add_buf_bypass_txqueue(mlan_adapter * pmadapter, pmlan_buffer pmbuf)
+{
+ ENTER();
+
+ if (pmbuf->buf_type != MLAN_BUF_TYPE_RAW_DATA) {
+ pmbuf->buf_type = MLAN_BUF_TYPE_DATA;
+ }
+
+ util_enqueue_list_tail(pmadapter->pmoal_handle, &pmadapter->bypass_txq,
+ (pmlan_linked_list) pmbuf,
+ pmadapter->callbacks.moal_spin_lock,
+ pmadapter->callbacks.moal_spin_unlock);
+ LEAVE();
+}
+
+/**
+ * @brief Check if packets are available in Bypass TX queue
+ *
+ * @param pmadapter Pointer to the mlan_adapter driver data struct
+ *
+ * @return MFALSE if not empty; MTRUE if empty
+ */
+INLINE t_u8
+wlan_bypass_tx_list_empty(mlan_adapter * pmadapter)
+{
+ t_u8 q_empty = MTRUE;
+ pmlan_callbacks pcb = &pmadapter->callbacks;
+ ENTER();
+
+ q_empty = (util_peek_list(pmadapter->pmoal_handle, &pmadapter->bypass_txq,
+ pcb->moal_spin_lock,
+ pcb->moal_spin_unlock)) ? MFALSE : MTRUE;
+
+ LEAVE();
+ return q_empty;
+}
+
+/**
+ * @brief Clean up the By-pass TX queue
+ *
+ * @param pmadapter Pointer to the mlan_adapter driver data struct
+ *
+ * @return N/A
+ */
+t_void
+wlan_cleanup_bypass_txq(mlan_adapter * pmadapter)
+{
+ pmlan_buffer pmbuf;
+ ENTER();
+
+ pmadapter->callbacks.moal_spin_lock(pmadapter->pmoal_handle,
+ pmadapter->bypass_txq.plock);
+
+ while ((pmbuf =
+ (pmlan_buffer) util_peek_list(pmadapter->pmoal_handle,
+ &pmadapter->bypass_txq, MNULL,
+ MNULL))) {
+ util_unlink_list(pmadapter->pmoal_handle, &pmadapter->bypass_txq,
+ (pmlan_linked_list) pmbuf, MNULL, MNULL);
+ wlan_write_data_complete(pmadapter, pmbuf, MLAN_STATUS_FAILURE);
+ }
+
+ pmadapter->callbacks.moal_spin_unlock(pmadapter->pmoal_handle,
+ pmadapter->bypass_txq.plock);
+
+ LEAVE();
+}
+
+/**
+ * @brief Transmit the By-passed packet awaiting in by-pass queue
+ *
+ * @param pmadapter Pointer to the mlan_adapter driver data struct
+ *
+ * @return N/A
+ */
+t_void
+wlan_process_bypass_tx(pmlan_adapter pmadapter)
+{
+ pmlan_buffer pmbuf;
+ mlan_tx_param tx_param;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ if ((pmbuf = (pmlan_buffer) util_dequeue_list(pmadapter->pmoal_handle,
+ &pmadapter->bypass_txq,
+ pmadapter->callbacks.
+ moal_spin_lock,
+ pmadapter->callbacks.
+ moal_spin_unlock))) {
+ PRINTM(MINFO, "Dequeuing bypassed packet %p\n", pmbuf);
+ /* XXX: nex_pkt_len ??? */
+ tx_param.next_pkt_len = 0;
+ status =
+ wlan_process_tx(pmadapter->priv[pmbuf->bss_index], pmbuf,
+ &tx_param);
+
+ if (status == MLAN_STATUS_RESOURCE) {
+ /* Queue the packet again so that it will be TX'ed later */
+ util_enqueue_list_head(pmadapter->pmoal_handle,
+ &pmadapter->bypass_txq,
+ (pmlan_linked_list) pmbuf,
+ pmadapter->callbacks.moal_spin_lock,
+ pmadapter->callbacks.moal_spin_unlock);
+ }
+ } else {
+ PRINTM(MINFO, "Nothing to send\n");
+ }
+
+ LEAVE();
+}
diff --git a/drivers/net/wireless/sd8797/mlan/mlan_uap.h b/drivers/net/wireless/sd8797/mlan/mlan_uap.h
new file mode 100644
index 000000000000..c2d2800f1a2d
--- /dev/null
+++ b/drivers/net/wireless/sd8797/mlan/mlan_uap.h
@@ -0,0 +1,104 @@
+/** @file mlan_uap.h
+ *
+ * @brief This file contains related macros, enum, and struct
+ * of uap functionalities
+ *
+ * Copyright (C) 2009-2011, Marvell International Ltd.
+ *
+ * This software file (the "File") is distributed by Marvell International
+ * Ltd. under the terms of the GNU General Public License Version 2, June 1991
+ * (the "License"). You may use, redistribute and/or modify this File in
+ * accordance with the terms and conditions of the License, a copy of which
+ * is available by writing to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
+ * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
+ *
+ * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
+ * ARE EXPRESSLY DISCLAIMED. The License provides additional details about
+ * this warranty disclaimer.
+ */
+
+/********************************************************
+Change log:
+ 02/05/2009: initial version
+********************************************************/
+
+#ifndef _MLAN_UAP_H_
+#define _MLAN_UAP_H_
+
+#ifdef BIG_ENDIAN_SUPPORT
+/** Convert TxPD to little endian format from CPU format */
+#define uap_endian_convert_TxPD(x) \
+ { \
+ (x)->tx_pkt_length = wlan_cpu_to_le16((x)->tx_pkt_length); \
+ (x)->tx_pkt_offset = wlan_cpu_to_le16((x)->tx_pkt_offset); \
+ (x)->tx_pkt_type = wlan_cpu_to_le16((x)->tx_pkt_type); \
+ (x)->tx_control = wlan_cpu_to_le32((x)->tx_control); \
+ }
+
+/** Convert RxPD from little endian format to CPU format */
+#define uap_endian_convert_RxPD(x) \
+ { \
+ (x)->rx_pkt_length = wlan_le16_to_cpu((x)->rx_pkt_length); \
+ (x)->rx_pkt_offset = wlan_le16_to_cpu((x)->rx_pkt_offset); \
+ (x)->rx_pkt_type = wlan_le16_to_cpu((x)->rx_pkt_type); \
+ (x)->seq_num = wlan_le16_to_cpu((x)->seq_num); \
+ }
+#else
+/** Convert TxPD to little endian format from CPU format */
+#define uap_endian_convert_TxPD(x) do {} while (0)
+/** Convert RxPD from little endian format to CPU format */
+#define uap_endian_convert_RxPD(x) do {} while (0)
+#endif /* BIG_ENDIAN_SUPPORT */
+
+/** Band config 5GHz */
+#define UAP_BAND_CONFIG_5GHZ 0x01
+
+/** Packet forwarding to be done by FW or host */
+#define PKT_FWD_FW_BIT 0x01
+/** Intra-BSS broadcast packet forwarding allow bit */
+#define PKT_FWD_INTRA_BCAST 0x02
+/** Intra-BSS unicast packet forwarding allow bit */
+#define PKT_FWD_INTRA_UCAST 0x04
+/** Inter-BSS unicast packet forwarding allow bit */
+#define PKT_FWD_INTER_UCAST 0x08
+/** Intra-BSS unicast packet */
+#define PKT_INTRA_UCAST 0x01
+/** Inter-BSS unicast packet */
+#define PKT_INTER_UCAST 0x02
+/** Enable Host PKT forwarding */
+#define PKT_FWD_ENABLE_BIT 0x01
+
+mlan_status wlan_uap_get_channel(IN pmlan_private pmpriv);
+
+mlan_status wlan_uap_set_channel(IN pmlan_private pmpriv,
+ IN t_u8 uap_band_cfg, IN t_u8 channel);
+
+mlan_status wlan_uap_get_beacon_dtim(IN pmlan_private pmpriv);
+
+mlan_status wlan_ops_uap_ioctl(t_void * adapter, pmlan_ioctl_req pioctl_req);
+
+mlan_status wlan_ops_uap_prepare_cmd(IN t_void * priv,
+ IN t_u16 cmd_no,
+ IN t_u16 cmd_action,
+ IN t_u32 cmd_oid,
+ IN t_void * pioctl_buf,
+ IN t_void * pdata_buf,
+ IN t_void * pcmd_buf);
+
+mlan_status wlan_ops_uap_process_cmdresp(IN t_void * priv,
+ IN t_u16 cmdresp_no,
+ IN t_void * pcmd_buf,
+ IN t_void * pioctl);
+
+mlan_status wlan_ops_uap_process_rx_packet(IN t_void * adapter,
+ IN pmlan_buffer pmbuf);
+
+mlan_status wlan_ops_uap_process_event(IN t_void * priv);
+
+t_void *wlan_ops_uap_process_txpd(IN t_void * priv, IN pmlan_buffer pmbuf);
+
+mlan_status wlan_ops_uap_init_cmd(IN t_void * priv, IN t_u8 first_bss);
+
+#endif /* _MLAN_UAP_H_ */
diff --git a/drivers/net/wireless/sd8797/mlan/mlan_uap_cmdevent.c b/drivers/net/wireless/sd8797/mlan/mlan_uap_cmdevent.c
new file mode 100644
index 000000000000..8c041c8159c2
--- /dev/null
+++ b/drivers/net/wireless/sd8797/mlan/mlan_uap_cmdevent.c
@@ -0,0 +1,3021 @@
+/** @file mlan_uap_cmdevent.c
+ *
+ * @brief This file contains the handling of AP mode command and event
+ *
+ * Copyright (C) 2009-2011, Marvell International Ltd.
+ *
+ * This software file (the "File") is distributed by Marvell International
+ * Ltd. under the terms of the GNU General Public License Version 2, June 1991
+ * (the "License"). You may use, redistribute and/or modify this File in
+ * accordance with the terms and conditions of the License, a copy of which
+ * is available by writing to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
+ * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
+ *
+ * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
+ * ARE EXPRESSLY DISCLAIMED. The License provides additional details about
+ * this warranty disclaimer.
+ */
+
+/********************************************************
+Change log:
+ 02/05/2009: initial version
+********************************************************/
+
+#include "mlan.h"
+#include "mlan_util.h"
+#include "mlan_fw.h"
+#ifdef STA_SUPPORT
+#include "mlan_join.h"
+#endif
+#include "mlan_main.h"
+#include "mlan_uap.h"
+#include "mlan_sdio.h"
+#include "mlan_11n.h"
+#include "mlan_11h.h"
+
+/********************************************************
+ Local Functions
+********************************************************/
+/**
+ * @brief This function handles the command response error
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param resp A pointer to HostCmd_DS_COMMAND
+ * @param pioctl_buf A pointer to command buffer
+ *
+ * @return N/A
+ */
+static void
+uap_process_cmdresp_error(mlan_private * pmpriv, HostCmd_DS_COMMAND * resp,
+ mlan_ioctl_req * pioctl_buf)
+{
+ mlan_adapter *pmadapter = pmpriv->adapter;
+
+ ENTER();
+
+ PRINTM(MERROR, "CMD_RESP: cmd %#x error, result=%#x\n", resp->command,
+ resp->result);
+ if (pioctl_buf)
+ pioctl_buf->status_code = resp->result;
+ /*
+ * Handling errors here
+ */
+ wlan_insert_cmd_to_free_q(pmadapter, pmadapter->curr_cmd);
+
+ wlan_request_cmd_lock(pmadapter);
+ pmadapter->curr_cmd = MNULL;
+ wlan_release_cmd_lock(pmadapter);
+
+ LEAVE();
+ return;
+}
+
+/**
+ * @brief This function prepares command of hs_cfg.
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param cmd A pointer to HostCmd_DS_COMMAND structure
+ * @param cmd_action The action: GET or SET
+ * @param pdata_buf A pointer to data buffer
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+static mlan_status
+wlan_uap_cmd_802_11_hs_cfg(IN pmlan_private pmpriv,
+ IN HostCmd_DS_COMMAND * cmd,
+ IN t_u16 cmd_action, IN hs_config_param * pdata_buf)
+{
+ HostCmd_DS_802_11_HS_CFG_ENH *phs_cfg = &cmd->params.opt_hs_cfg;
+
+ ENTER();
+ cmd->command = wlan_cpu_to_le16(HostCmd_CMD_802_11_HS_CFG_ENH);
+ cmd->size =
+ wlan_cpu_to_le16(S_DS_GEN + sizeof(HostCmd_DS_802_11_HS_CFG_ENH));
+
+ if (pdata_buf == MNULL) {
+ phs_cfg->action = wlan_cpu_to_le16(HS_ACTIVATE);
+ phs_cfg->params.hs_activate.resp_ctrl = wlan_cpu_to_le16(RESP_NEEDED);
+ } else {
+ phs_cfg->action = wlan_cpu_to_le16(HS_CONFIGURE);
+ phs_cfg->params.hs_config.conditions =
+ wlan_cpu_to_le32(pdata_buf->conditions);
+ phs_cfg->params.hs_config.gpio = pdata_buf->gpio;
+ phs_cfg->params.hs_config.gap = pdata_buf->gap;
+ PRINTM(MCMND, "HS_CFG_CMD: condition:0x%x gpio:0x%x gap:0x%x\n",
+ phs_cfg->params.hs_config.conditions,
+ phs_cfg->params.hs_config.gpio, phs_cfg->params.hs_config.gap);
+ }
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function prepares command of Tx data pause
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param cmd A pointer to HostCmd_DS_COMMAND structure
+ * @param cmd_action the action: GET or SET
+ * @param pdata_buf A pointer to data buffer
+ * @return MLAN_STATUS_SUCCESS
+ */
+static mlan_status
+wlan_uap_cmd_txdatapause(pmlan_private pmpriv,
+ IN HostCmd_DS_COMMAND * cmd,
+ IN t_u16 cmd_action, IN t_void * pdata_buf)
+{
+ HostCmd_DS_CMD_TX_DATA_PAUSE *pause_cmd =
+ (HostCmd_DS_CMD_TX_DATA_PAUSE *) & cmd->params.tx_data_pause;
+ mlan_ds_misc_tx_datapause *data_pause =
+ (mlan_ds_misc_tx_datapause *) pdata_buf;
+
+ ENTER();
+
+ cmd->command = wlan_cpu_to_le16(HostCmd_CMD_CFG_TX_DATA_PAUSE);
+ cmd->size =
+ wlan_cpu_to_le16(sizeof(HostCmd_DS_CMD_TX_DATA_PAUSE) + S_DS_GEN);
+ pause_cmd->action = wlan_cpu_to_le16(cmd_action);
+
+ if (cmd_action == HostCmd_ACT_GEN_SET) {
+ pause_cmd->enable_tx_pause = (t_u8) data_pause->tx_pause;
+ pause_cmd->pause_tx_count = (t_u8) data_pause->tx_buf_cnt;
+ }
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function handles the command response of Tx data pause
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param resp A pointer to HostCmd_DS_COMMAND
+ * @param pioctl_buf A pointer to mlan_ioctl_req structure
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+static mlan_status
+wlan_uap_ret_txdatapause(IN pmlan_private pmpriv,
+ IN HostCmd_DS_COMMAND * resp,
+ IN mlan_ioctl_req * pioctl_buf)
+{
+ HostCmd_DS_CMD_TX_DATA_PAUSE *pause_cmd =
+ (HostCmd_DS_CMD_TX_DATA_PAUSE *) & resp->params.tx_data_pause;
+ mlan_ds_misc_cfg *misc_cfg = MNULL;
+
+ ENTER();
+
+ if (pioctl_buf) {
+ misc_cfg = (mlan_ds_misc_cfg *) pioctl_buf->pbuf;
+ misc_cfg->param.tx_datapause.tx_pause = pause_cmd->enable_tx_pause;
+ misc_cfg->param.tx_datapause.tx_buf_cnt = pause_cmd->pause_tx_count;
+ }
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function will process tx pause event
+ *
+ *
+ * @param priv A pointer to mlan_private
+ * @param pevent A pointer to event buf
+ *
+ * @return N/A
+ */
+static void
+wlan_process_tx_pause_event(pmlan_private priv, pmlan_buffer pevent)
+{
+ t_u16 tlv_type, tlv_len;
+ int tlv_buf_left = pevent->data_len - sizeof(t_u32);
+ MrvlIEtypesHeader_t *tlv =
+ (MrvlIEtypesHeader_t *) (pevent->pbuf + pevent->data_offset +
+ sizeof(t_u32));
+ MrvlIEtypes_tx_pause_t *tx_pause_tlv;
+ sta_node *sta_ptr = MNULL;
+
+ ENTER();
+
+ while (tlv_buf_left >= (int) sizeof(MrvlIEtypesHeader_t)) {
+ tlv_type = wlan_le16_to_cpu(tlv->type);
+ tlv_len = wlan_le16_to_cpu(tlv->len);
+ if ((sizeof(MrvlIEtypesHeader_t) + tlv_len) >
+ (unsigned int) tlv_buf_left) {
+ PRINTM(MERROR, "wrong tlv: tlvLen=%d, tlvBufLeft=%d\n", tlv_len,
+ tlv_buf_left);
+ break;
+ }
+ if (tlv_type == TLV_TYPE_TX_PAUSE) {
+ tx_pause_tlv = (MrvlIEtypes_tx_pause_t *) tlv;
+ PRINTM(MCMND,
+ "TxPause: %02x:%02x:%02x:%02x:%02x:%02x pause=%d, pkts=%d\n",
+ tx_pause_tlv->peermac[0], tx_pause_tlv->peermac[1],
+ tx_pause_tlv->peermac[2], tx_pause_tlv->peermac[3],
+ tx_pause_tlv->peermac[4], tx_pause_tlv->peermac[5],
+ tx_pause_tlv->tx_pause, tx_pause_tlv->pkt_cnt);
+ if ((sta_ptr = wlan_get_station_entry(priv, tx_pause_tlv->peermac))) {
+ if (sta_ptr->tx_pause != tx_pause_tlv->tx_pause) {
+ sta_ptr->tx_pause = tx_pause_tlv->tx_pause;
+ wlan_updata_ralist_tx_pause(priv, tx_pause_tlv->peermac,
+ tx_pause_tlv->tx_pause);
+ }
+ }
+ }
+ tlv_buf_left -= (sizeof(MrvlIEtypesHeader_t) + tlv_len);
+ tlv =
+ (MrvlIEtypesHeader_t *) ((t_u8 *) tlv + tlv_len +
+ sizeof(MrvlIEtypesHeader_t));
+ }
+
+ LEAVE();
+ return;
+}
+
+/**
+ * @brief This function prepares command for config uap settings
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param cmd A pointer to HostCmd_DS_COMMAND structure
+ * @param cmd_action the action: GET or SET
+ * @param pioctl_buf A pointer to mlan_ioctl_req structure
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+static mlan_status
+wlan_uap_cmd_ap_config(pmlan_private pmpriv,
+ IN HostCmd_DS_COMMAND * cmd,
+ IN t_u16 cmd_action, IN pmlan_ioctl_req pioctl_buf)
+{
+ mlan_ds_bss *bss = MNULL;
+ HostCmd_DS_SYS_CONFIG *sys_config =
+ (HostCmd_DS_SYS_CONFIG *) & cmd->params.sys_config;
+ t_u8 *tlv = MNULL;
+ MrvlIEtypes_MacAddr_t *tlv_mac = MNULL;
+ MrvlIEtypes_SsIdParamSet_t *tlv_ssid = MNULL;
+ MrvlIEtypes_beacon_period_t *tlv_beacon_period = MNULL;
+ MrvlIEtypes_dtim_period_t *tlv_dtim_period = MNULL;
+ MrvlIEtypes_RatesParamSet_t *tlv_rates = MNULL;
+ MrvlIEtypes_tx_rate_t *tlv_txrate = MNULL;
+ MrvlIEtypes_mcbc_rate_t *tlv_mcbc_rate = MNULL;
+ MrvlIEtypes_tx_power_t *tlv_tx_power = MNULL;
+ MrvlIEtypes_bcast_ssid_t *tlv_bcast_ssid = MNULL;
+ MrvlIEtypes_antenna_mode_t *tlv_antenna = MNULL;
+ MrvlIEtypes_pkt_forward_t *tlv_pkt_forward = MNULL;
+ MrvlIEtypes_max_sta_count_t *tlv_sta_count = MNULL;
+ MrvlIEtypes_sta_ageout_t *tlv_sta_ageout = MNULL;
+ MrvlIEtypes_ps_sta_ageout_t *tlv_ps_sta_ageout = MNULL;
+ MrvlIEtypes_rts_threshold_t *tlv_rts_threshold = MNULL;
+ MrvlIEtypes_frag_threshold_t *tlv_frag_threshold = MNULL;
+ MrvlIEtypes_retry_limit_t *tlv_retry_limit = MNULL;
+ MrvlIEtypes_eapol_pwk_hsk_timeout_t *tlv_pairwise_timeout = MNULL;
+ MrvlIEtypes_eapol_pwk_hsk_retries_t *tlv_pairwise_retries = MNULL;
+ MrvlIEtypes_eapol_gwk_hsk_timeout_t *tlv_groupwise_timeout = MNULL;
+ MrvlIEtypes_eapol_gwk_hsk_retries_t *tlv_groupwise_retries = MNULL;
+ MrvlIEtypes_mgmt_ie_passthru_t *tlv_mgmt_ie_passthru = MNULL;
+ MrvlIEtypes_2040_coex_enable_t *tlv_2040_coex_enable = MNULL;
+ MrvlIEtypes_mac_filter_t *tlv_mac_filter = MNULL;
+ MrvlIEtypes_channel_band_t *tlv_chan_band = MNULL;
+ MrvlIEtypes_ChanListParamSet_t *tlv_chan_list = MNULL;
+ ChanScanParamSet_t *pscan_chan = MNULL;
+ MrvlIEtypes_auth_type_t *tlv_auth_type = MNULL;
+ MrvlIEtypes_encrypt_protocol_t *tlv_encrypt_protocol = MNULL;
+ MrvlIEtypes_akmp_t *tlv_akmp = MNULL;
+ MrvlIEtypes_pwk_cipher_t *tlv_pwk_cipher = MNULL;
+ MrvlIEtypes_gwk_cipher_t *tlv_gwk_cipher = MNULL;
+ MrvlIEtypes_rsn_replay_prot_t *tlv_rsn_prot = MNULL;
+ MrvlIEtypes_passphrase_t *tlv_passphrase = MNULL;
+ MrvlIEtypes_group_rekey_time_t *tlv_rekey_time = MNULL;
+ MrvlIEtypes_wep_key_t *tlv_wep_key = MNULL;
+ MrvlIETypes_HTCap_t *tlv_htcap = MNULL;
+ MrvlIEtypes_wmm_parameter_t *tlv_wmm_parameter = MNULL;
+ t_u32 cmd_size = 0;
+ t_u8 zero_mac[] = { 0, 0, 0, 0, 0, 0 };
+ t_u16 i;
+ t_u16 ac;
+
+ ENTER();
+ if (pioctl_buf == MNULL) {
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+
+ bss = (mlan_ds_bss *) pioctl_buf->pbuf;
+
+ cmd->command = wlan_cpu_to_le16(HOST_CMD_APCMD_SYS_CONFIGURE);
+ sys_config->action = wlan_cpu_to_le16(cmd_action);
+ cmd_size = sizeof(HostCmd_DS_SYS_CONFIG) - 1 + S_DS_GEN;
+
+ tlv = (t_u8 *) sys_config->tlv_buffer;
+ if (memcmp
+ (pmpriv->adapter, zero_mac, &bss->param.bss_config.mac_addr,
+ MLAN_MAC_ADDR_LENGTH)) {
+ tlv_mac = (MrvlIEtypes_MacAddr_t *) tlv;
+ tlv_mac->header.type = wlan_cpu_to_le16(TLV_TYPE_UAP_MAC_ADDRESS);
+ tlv_mac->header.len = wlan_cpu_to_le16(MLAN_MAC_ADDR_LENGTH);
+ memcpy(pmpriv->adapter, tlv_mac->mac, &bss->param.bss_config.mac_addr,
+ MLAN_MAC_ADDR_LENGTH);
+ cmd_size += sizeof(MrvlIEtypes_MacAddr_t);
+ tlv += sizeof(MrvlIEtypes_MacAddr_t);
+ }
+
+ if (bss->param.bss_config.ssid.ssid_len) {
+ tlv_ssid = (MrvlIEtypes_SsIdParamSet_t *) tlv;
+ tlv_ssid->header.type = wlan_cpu_to_le16(TLV_TYPE_SSID);
+ tlv_ssid->header.len =
+ wlan_cpu_to_le16((t_u16) bss->param.bss_config.ssid.ssid_len);
+ memcpy(pmpriv->adapter, tlv_ssid->ssid, bss->param.bss_config.ssid.ssid,
+ bss->param.bss_config.ssid.ssid_len);
+ cmd_size +=
+ sizeof(MrvlIEtypesHeader_t) + bss->param.bss_config.ssid.ssid_len;
+ tlv +=
+ sizeof(MrvlIEtypesHeader_t) + bss->param.bss_config.ssid.ssid_len;
+ }
+
+ if ((bss->param.bss_config.beacon_period >= MIN_BEACON_PERIOD) &&
+ (bss->param.bss_config.beacon_period <= MAX_BEACON_PERIOD)) {
+ tlv_beacon_period = (MrvlIEtypes_beacon_period_t *) tlv;
+ tlv_beacon_period->header.type =
+ wlan_cpu_to_le16(TLV_TYPE_UAP_BEACON_PERIOD);
+ tlv_beacon_period->header.len = wlan_cpu_to_le16(sizeof(t_u16));
+ tlv_beacon_period->beacon_period =
+ wlan_cpu_to_le16(bss->param.bss_config.beacon_period);
+ cmd_size += sizeof(MrvlIEtypes_beacon_period_t);
+ tlv += sizeof(MrvlIEtypes_beacon_period_t);
+ }
+
+ if ((bss->param.bss_config.dtim_period >= MIN_DTIM_PERIOD) &&
+ (bss->param.bss_config.dtim_period <= MAX_DTIM_PERIOD)) {
+ tlv_dtim_period = (MrvlIEtypes_dtim_period_t *) tlv;
+ tlv_dtim_period->header.type =
+ wlan_cpu_to_le16(TLV_TYPE_UAP_DTIM_PERIOD);
+ tlv_dtim_period->header.len = wlan_cpu_to_le16(sizeof(t_u8));
+ tlv_dtim_period->dtim_period = bss->param.bss_config.dtim_period;
+ cmd_size += sizeof(MrvlIEtypes_dtim_period_t);
+ tlv += sizeof(MrvlIEtypes_dtim_period_t);
+ }
+
+ if (bss->param.bss_config.rates[0]) {
+ tlv_rates = (MrvlIEtypes_RatesParamSet_t *) tlv;
+ tlv_rates->header.type = wlan_cpu_to_le16(TLV_TYPE_RATES);
+ for (i = 0; i < MAX_DATA_RATES && bss->param.bss_config.rates[i]; i++) {
+ tlv_rates->rates[i] = bss->param.bss_config.rates[i];
+ }
+ tlv_rates->header.len = wlan_cpu_to_le16(i);
+ cmd_size += sizeof(MrvlIEtypesHeader_t) + i;
+ tlv += sizeof(MrvlIEtypesHeader_t) + i;
+ }
+
+ if (bss->param.bss_config.tx_data_rate <= DATA_RATE_54M) {
+ tlv_txrate = (MrvlIEtypes_tx_rate_t *) tlv;
+ tlv_txrate->header.type = wlan_cpu_to_le16(TLV_TYPE_UAP_TX_DATA_RATE);
+ tlv_txrate->header.len = wlan_cpu_to_le16(sizeof(t_u16));
+ tlv_txrate->tx_data_rate =
+ wlan_cpu_to_le16(bss->param.bss_config.tx_data_rate);
+ cmd_size += sizeof(MrvlIEtypes_tx_rate_t);
+ tlv += sizeof(MrvlIEtypes_tx_rate_t);
+ }
+
+ if (bss->param.bss_config.mcbc_data_rate <= DATA_RATE_54M) {
+ tlv_mcbc_rate = (MrvlIEtypes_mcbc_rate_t *) tlv;
+ tlv_mcbc_rate->header.type =
+ wlan_cpu_to_le16(TLV_TYPE_UAP_MCBC_DATA_RATE);
+ tlv_mcbc_rate->header.len = wlan_cpu_to_le16(sizeof(t_u16));
+ tlv_mcbc_rate->mcbc_data_rate =
+ wlan_cpu_to_le16(bss->param.bss_config.mcbc_data_rate);
+ cmd_size += sizeof(MrvlIEtypes_mcbc_rate_t);
+ tlv += sizeof(MrvlIEtypes_mcbc_rate_t);
+ }
+
+ if (bss->param.bss_config.tx_power_level <= MAX_TX_POWER) {
+ tlv_tx_power = (MrvlIEtypes_tx_power_t *) tlv;
+ tlv_tx_power->header.type = wlan_cpu_to_le16(TLV_TYPE_UAP_TX_POWER);
+ tlv_tx_power->header.len = wlan_cpu_to_le16(sizeof(t_u8));
+ tlv_tx_power->tx_power = bss->param.bss_config.tx_power_level;
+ cmd_size += sizeof(MrvlIEtypes_tx_power_t);
+ tlv += sizeof(MrvlIEtypes_tx_power_t);
+ }
+
+ if (bss->param.bss_config.bcast_ssid_ctl <= MTRUE) {
+ tlv_bcast_ssid = (MrvlIEtypes_bcast_ssid_t *) tlv;
+ tlv_bcast_ssid->header.type =
+ wlan_cpu_to_le16(TLV_TYPE_UAP_BCAST_SSID_CTL);
+ tlv_bcast_ssid->header.len = wlan_cpu_to_le16(sizeof(t_u8));
+ tlv_bcast_ssid->bcast_ssid_ctl = bss->param.bss_config.bcast_ssid_ctl;
+ cmd_size += sizeof(MrvlIEtypes_bcast_ssid_t);
+ tlv += sizeof(MrvlIEtypes_bcast_ssid_t);
+ }
+
+ if ((bss->param.bss_config.tx_antenna == ANTENNA_MODE_A) ||
+ (bss->param.bss_config.tx_antenna == ANTENNA_MODE_B)) {
+ tlv_antenna = (MrvlIEtypes_antenna_mode_t *) tlv;
+ tlv_antenna->header.type = wlan_cpu_to_le16(TLV_TYPE_UAP_ANTENNA_CTL);
+ tlv_antenna->header.len = wlan_cpu_to_le16(sizeof(t_u8) + sizeof(t_u8));
+ tlv_antenna->which_antenna = TX_ANTENNA;
+ tlv_antenna->antenna_mode = bss->param.bss_config.tx_antenna;
+ cmd_size += sizeof(MrvlIEtypes_antenna_mode_t);
+ tlv += sizeof(MrvlIEtypes_antenna_mode_t);
+ }
+
+ if ((bss->param.bss_config.rx_antenna == ANTENNA_MODE_A) ||
+ (bss->param.bss_config.rx_antenna == ANTENNA_MODE_B)) {
+ tlv_antenna = (MrvlIEtypes_antenna_mode_t *) tlv;
+ tlv_antenna->header.type = wlan_cpu_to_le16(TLV_TYPE_UAP_ANTENNA_CTL);
+ tlv_antenna->header.len = wlan_cpu_to_le16(sizeof(t_u8) + sizeof(t_u8));
+ tlv_antenna->which_antenna = RX_ANTENNA;
+ tlv_antenna->antenna_mode = bss->param.bss_config.rx_antenna;
+ cmd_size += sizeof(MrvlIEtypes_antenna_mode_t);
+ tlv += sizeof(MrvlIEtypes_antenna_mode_t);
+ }
+
+ if (bss->param.bss_config.pkt_forward_ctl <= MAX_PKT_FWD_CTRL) {
+ tlv_pkt_forward = (MrvlIEtypes_pkt_forward_t *) tlv;
+ tlv_pkt_forward->header.type =
+ wlan_cpu_to_le16(TLV_TYPE_UAP_PKT_FWD_CTL);
+ tlv_pkt_forward->header.len = wlan_cpu_to_le16(sizeof(t_u8));
+ tlv_pkt_forward->pkt_forward_ctl =
+ bss->param.bss_config.pkt_forward_ctl;
+ cmd_size += sizeof(MrvlIEtypes_pkt_forward_t);
+ tlv += sizeof(MrvlIEtypes_pkt_forward_t);
+ }
+
+ if (bss->param.bss_config.max_sta_count <= MAX_STA_COUNT) {
+ tlv_sta_count = (MrvlIEtypes_max_sta_count_t *) tlv;
+ tlv_sta_count->header.type = wlan_cpu_to_le16(TLV_TYPE_UAP_MAX_STA_CNT);
+ tlv_sta_count->header.len = wlan_cpu_to_le16(sizeof(t_u16));
+ tlv_sta_count->max_sta_count =
+ wlan_cpu_to_le16(bss->param.bss_config.max_sta_count);
+ cmd_size += sizeof(MrvlIEtypes_max_sta_count_t);
+ tlv += sizeof(MrvlIEtypes_max_sta_count_t);
+ }
+
+ if (((bss->param.bss_config.sta_ageout_timer >= MIN_STAGE_OUT_TIME) &&
+ (bss->param.bss_config.sta_ageout_timer <= MAX_STAGE_OUT_TIME)) ||
+ (bss->param.bss_config.sta_ageout_timer == 0)) {
+ tlv_sta_ageout = (MrvlIEtypes_sta_ageout_t *) tlv;
+ tlv_sta_ageout->header.type =
+ wlan_cpu_to_le16(TLV_TYPE_UAP_STA_AGEOUT_TIMER);
+ tlv_sta_ageout->header.len = wlan_cpu_to_le16(sizeof(t_u32));
+ tlv_sta_ageout->sta_ageout_timer =
+ wlan_cpu_to_le32(bss->param.bss_config.sta_ageout_timer);
+ cmd_size += sizeof(MrvlIEtypes_sta_ageout_t);
+ tlv += sizeof(MrvlIEtypes_sta_ageout_t);
+ }
+
+ if (((bss->param.bss_config.ps_sta_ageout_timer >= MIN_STAGE_OUT_TIME) &&
+ (bss->param.bss_config.ps_sta_ageout_timer <= MAX_STAGE_OUT_TIME)) ||
+ (bss->param.bss_config.ps_sta_ageout_timer == 0)) {
+ tlv_ps_sta_ageout = (MrvlIEtypes_ps_sta_ageout_t *) tlv;
+ tlv_ps_sta_ageout->header.type =
+ wlan_cpu_to_le16(TLV_TYPE_UAP_PS_STA_AGEOUT_TIMER);
+ tlv_ps_sta_ageout->header.len = wlan_cpu_to_le16(sizeof(t_u32));
+ tlv_ps_sta_ageout->ps_sta_ageout_timer =
+ wlan_cpu_to_le32(bss->param.bss_config.ps_sta_ageout_timer);
+ cmd_size += sizeof(MrvlIEtypes_ps_sta_ageout_t);
+ tlv += sizeof(MrvlIEtypes_ps_sta_ageout_t);
+ }
+ if (bss->param.bss_config.rts_threshold <= MAX_RTS_THRESHOLD) {
+ tlv_rts_threshold = (MrvlIEtypes_rts_threshold_t *) tlv;
+ tlv_rts_threshold->header.type =
+ wlan_cpu_to_le16(TLV_TYPE_UAP_RTS_THRESHOLD);
+ tlv_rts_threshold->header.len = wlan_cpu_to_le16(sizeof(t_u16));
+ tlv_rts_threshold->rts_threshold =
+ wlan_cpu_to_le16(bss->param.bss_config.rts_threshold);
+ cmd_size += sizeof(MrvlIEtypes_rts_threshold_t);
+ tlv += sizeof(MrvlIEtypes_rts_threshold_t);
+ }
+
+ if ((bss->param.bss_config.frag_threshold >= MIN_FRAG_THRESHOLD) &&
+ (bss->param.bss_config.frag_threshold <= MAX_FRAG_THRESHOLD)) {
+ tlv_frag_threshold = (MrvlIEtypes_frag_threshold_t *) tlv;
+ tlv_frag_threshold->header.type =
+ wlan_cpu_to_le16(TLV_TYPE_UAP_FRAG_THRESHOLD);
+ tlv_frag_threshold->header.len = wlan_cpu_to_le16(sizeof(t_u16));
+ tlv_frag_threshold->frag_threshold =
+ wlan_cpu_to_le16(bss->param.bss_config.frag_threshold);
+ cmd_size += sizeof(MrvlIEtypes_frag_threshold_t);
+ tlv += sizeof(MrvlIEtypes_frag_threshold_t);
+ }
+
+ if (bss->param.bss_config.retry_limit <= MAX_RETRY_LIMIT) {
+ tlv_retry_limit = (MrvlIEtypes_retry_limit_t *) tlv;
+ tlv_retry_limit->header.type =
+ wlan_cpu_to_le16(TLV_TYPE_UAP_RETRY_LIMIT);
+ tlv_retry_limit->header.len = wlan_cpu_to_le16(sizeof(t_u8));
+ tlv_retry_limit->retry_limit = (t_u8) bss->param.bss_config.retry_limit;
+ cmd_size += sizeof(MrvlIEtypes_retry_limit_t);
+ tlv += sizeof(MrvlIEtypes_retry_limit_t);
+ }
+
+ if (bss->param.bss_config.pairwise_update_timeout < (MAX_VALID_DWORD)) {
+ tlv_pairwise_timeout = (MrvlIEtypes_eapol_pwk_hsk_timeout_t *) tlv;
+ tlv_pairwise_timeout->header.type =
+ wlan_cpu_to_le16(TLV_TYPE_UAP_EAPOL_PWK_HSK_TIMEOUT);
+ tlv_pairwise_timeout->header.len = wlan_cpu_to_le16(sizeof(t_u32));
+ tlv_pairwise_timeout->pairwise_update_timeout =
+ wlan_cpu_to_le32(bss->param.bss_config.pairwise_update_timeout);
+ cmd_size += sizeof(MrvlIEtypes_eapol_pwk_hsk_timeout_t);
+ tlv += sizeof(MrvlIEtypes_eapol_pwk_hsk_timeout_t);
+ }
+
+ if (bss->param.bss_config.pwk_retries < (MAX_VALID_DWORD)) {
+ tlv_pairwise_retries = (MrvlIEtypes_eapol_pwk_hsk_retries_t *) tlv;
+ tlv_pairwise_retries->header.type =
+ wlan_cpu_to_le16(TLV_TYPE_UAP_EAPOL_PWK_HSK_RETRIES);
+ tlv_pairwise_retries->header.len = wlan_cpu_to_le16(sizeof(t_u32));
+ tlv_pairwise_retries->pwk_retries =
+ wlan_cpu_to_le32(bss->param.bss_config.pwk_retries);
+ cmd_size += sizeof(MrvlIEtypes_eapol_pwk_hsk_retries_t);
+ tlv += sizeof(MrvlIEtypes_eapol_pwk_hsk_retries_t);
+ }
+
+ if (bss->param.bss_config.groupwise_update_timeout < (MAX_VALID_DWORD)) {
+ tlv_groupwise_timeout = (MrvlIEtypes_eapol_gwk_hsk_timeout_t *) tlv;
+ tlv_groupwise_timeout->header.type =
+ wlan_cpu_to_le16(TLV_TYPE_UAP_EAPOL_GWK_HSK_TIMEOUT);
+ tlv_groupwise_timeout->header.len = wlan_cpu_to_le16(sizeof(t_u32));
+ tlv_groupwise_timeout->groupwise_update_timeout =
+ wlan_cpu_to_le32(bss->param.bss_config.groupwise_update_timeout);
+ cmd_size += sizeof(MrvlIEtypes_eapol_gwk_hsk_timeout_t);
+ tlv += sizeof(MrvlIEtypes_eapol_gwk_hsk_timeout_t);
+ }
+
+ if (bss->param.bss_config.gwk_retries < (MAX_VALID_DWORD)) {
+ tlv_groupwise_retries = (MrvlIEtypes_eapol_gwk_hsk_retries_t *) tlv;
+ tlv_groupwise_retries->header.type =
+ wlan_cpu_to_le16(TLV_TYPE_UAP_EAPOL_GWK_HSK_RETRIES);
+ tlv_groupwise_retries->header.len = wlan_cpu_to_le16(sizeof(t_u32));
+ tlv_groupwise_retries->gwk_retries =
+ wlan_cpu_to_le32(bss->param.bss_config.gwk_retries);
+ cmd_size += sizeof(MrvlIEtypes_eapol_gwk_hsk_retries_t);
+ tlv += sizeof(MrvlIEtypes_eapol_gwk_hsk_retries_t);
+ }
+
+ if ((bss->param.bss_config.filter.filter_mode <= MAC_FILTER_MODE_BLOCK_MAC)
+ && (bss->param.bss_config.filter.mac_count <= MAX_MAC_FILTER_NUM)) {
+ tlv_mac_filter = (MrvlIEtypes_mac_filter_t *) tlv;
+ tlv_mac_filter->header.type =
+ wlan_cpu_to_le16(TLV_TYPE_UAP_STA_MAC_ADDR_FILTER);
+ tlv_mac_filter->header.len =
+ wlan_cpu_to_le16(2 +
+ MLAN_MAC_ADDR_LENGTH *
+ bss->param.bss_config.filter.mac_count);
+ tlv_mac_filter->count = (t_u8) bss->param.bss_config.filter.mac_count;
+ tlv_mac_filter->filter_mode =
+ (t_u8) bss->param.bss_config.filter.filter_mode;
+ memcpy(pmpriv->adapter, tlv_mac_filter->mac_address,
+ (t_u8 *) bss->param.bss_config.filter.mac_list,
+ MLAN_MAC_ADDR_LENGTH * bss->param.bss_config.filter.mac_count);
+ cmd_size +=
+ sizeof(MrvlIEtypesHeader_t) + 2 +
+ MLAN_MAC_ADDR_LENGTH * bss->param.bss_config.filter.mac_count;
+ tlv +=
+ sizeof(MrvlIEtypesHeader_t) + 2 +
+ MLAN_MAC_ADDR_LENGTH * bss->param.bss_config.filter.mac_count;
+ }
+
+ if ((((bss->param.bss_config.band_cfg & BAND_CONFIG_ACS_MODE) ==
+ BAND_CONFIG_MANUAL) && (bss->param.bss_config.channel > 0) &&
+ (bss->param.bss_config.channel <= MLAN_MAX_CHANNEL)) ||
+ (bss->param.bss_config.band_cfg & BAND_CONFIG_ACS_MODE)) {
+ tlv_chan_band = (MrvlIEtypes_channel_band_t *) tlv;
+ tlv_chan_band->header.type =
+ wlan_cpu_to_le16(TLV_TYPE_UAP_CHAN_BAND_CONFIG);
+ tlv_chan_band->header.len =
+ wlan_cpu_to_le16(sizeof(t_u8) + sizeof(t_u8));
+ tlv_chan_band->band_config = bss->param.bss_config.band_cfg;
+ tlv_chan_band->channel = bss->param.bss_config.channel;
+ cmd_size += sizeof(MrvlIEtypes_channel_band_t);
+ tlv += sizeof(MrvlIEtypes_channel_band_t);
+ }
+
+ if ((bss->param.bss_config.num_of_chan) &&
+ (bss->param.bss_config.num_of_chan <= MLAN_MAX_CHANNEL)) {
+ tlv_chan_list = (MrvlIEtypes_ChanListParamSet_t *) tlv;
+ tlv_chan_list->header.type = wlan_cpu_to_le16(TLV_TYPE_CHANLIST);
+ tlv_chan_list->header.len =
+ wlan_cpu_to_le16((t_u16)
+ (sizeof(ChanScanParamSet_t) *
+ bss->param.bss_config.num_of_chan));
+ pscan_chan = tlv_chan_list->chan_scan_param;
+ for (i = 0; i < bss->param.bss_config.num_of_chan; i++) {
+ pscan_chan->chan_number =
+ bss->param.bss_config.chan_list[i].chan_number;
+ pscan_chan->radio_type =
+ bss->param.bss_config.chan_list[i].band_config_type;
+ pscan_chan++;
+ }
+ cmd_size += sizeof(tlv_chan_list->header) +
+ (sizeof(ChanScanParamSet_t) * bss->param.bss_config.num_of_chan);
+ tlv += sizeof(tlv_chan_list->header) +
+ (sizeof(ChanScanParamSet_t) * bss->param.bss_config.num_of_chan);
+ }
+
+ if ((bss->param.bss_config.auth_mode <= MLAN_AUTH_MODE_SHARED) ||
+ (bss->param.bss_config.auth_mode == MLAN_AUTH_MODE_AUTO)) {
+ tlv_auth_type = (MrvlIEtypes_auth_type_t *) tlv;
+ tlv_auth_type->header.type = wlan_cpu_to_le16(TLV_TYPE_AUTH_TYPE);
+ tlv_auth_type->header.len = wlan_cpu_to_le16(sizeof(t_u8));
+ tlv_auth_type->auth_type = (t_u8) bss->param.bss_config.auth_mode;
+ cmd_size += sizeof(MrvlIEtypes_auth_type_t);
+ tlv += sizeof(MrvlIEtypes_auth_type_t);
+ }
+
+ if (bss->param.bss_config.protocol) {
+ tlv_encrypt_protocol = (MrvlIEtypes_encrypt_protocol_t *) tlv;
+ tlv_encrypt_protocol->header.type =
+ wlan_cpu_to_le16(TLV_TYPE_UAP_ENCRYPT_PROTOCOL);
+ tlv_encrypt_protocol->header.len = wlan_cpu_to_le16(sizeof(t_u16));
+ tlv_encrypt_protocol->protocol =
+ wlan_cpu_to_le16(bss->param.bss_config.protocol);
+ cmd_size += sizeof(MrvlIEtypes_encrypt_protocol_t);
+ tlv += sizeof(MrvlIEtypes_encrypt_protocol_t);
+ }
+
+ if ((bss->param.bss_config.protocol & PROTOCOL_WPA) ||
+ (bss->param.bss_config.protocol & PROTOCOL_WPA2) ||
+ (bss->param.bss_config.protocol & PROTOCOL_EAP)) {
+ tlv_akmp = (MrvlIEtypes_akmp_t *) tlv;
+ tlv_akmp->header.type = wlan_cpu_to_le16(TLV_TYPE_UAP_AKMP);
+ tlv_akmp->key_mgmt = wlan_cpu_to_le16(bss->param.bss_config.key_mgmt);
+ tlv_akmp->header.len = sizeof(t_u16);
+ tlv_akmp->key_mgmt_operation =
+ wlan_cpu_to_le16(bss->param.bss_config.key_mgmt_operation);
+ tlv_akmp->header.len += sizeof(t_u16);
+ tlv_akmp->header.len = wlan_cpu_to_le16(tlv_akmp->header.len);
+ cmd_size += sizeof(MrvlIEtypes_akmp_t);
+ tlv += sizeof(MrvlIEtypes_akmp_t);
+
+ if (bss->param.bss_config.wpa_cfg.
+ pairwise_cipher_wpa & VALID_CIPHER_BITMAP) {
+ tlv_pwk_cipher = (MrvlIEtypes_pwk_cipher_t *) tlv;
+ tlv_pwk_cipher->header.type = wlan_cpu_to_le16(TLV_TYPE_PWK_CIPHER);
+ tlv_pwk_cipher->header.len =
+ wlan_cpu_to_le16(sizeof(t_u16) + sizeof(t_u8) + sizeof(t_u8));
+ tlv_pwk_cipher->protocol = wlan_cpu_to_le16(PROTOCOL_WPA);
+ tlv_pwk_cipher->pairwise_cipher =
+ bss->param.bss_config.wpa_cfg.pairwise_cipher_wpa;
+ cmd_size += sizeof(MrvlIEtypes_pwk_cipher_t);
+ tlv += sizeof(MrvlIEtypes_pwk_cipher_t);
+ }
+
+ if (bss->param.bss_config.wpa_cfg.
+ pairwise_cipher_wpa2 & VALID_CIPHER_BITMAP) {
+ tlv_pwk_cipher = (MrvlIEtypes_pwk_cipher_t *) tlv;
+ tlv_pwk_cipher->header.type = wlan_cpu_to_le16(TLV_TYPE_PWK_CIPHER);
+ tlv_pwk_cipher->header.len =
+ wlan_cpu_to_le16(sizeof(t_u16) + sizeof(t_u8) + sizeof(t_u8));
+ tlv_pwk_cipher->protocol = wlan_cpu_to_le16(PROTOCOL_WPA2);
+ tlv_pwk_cipher->pairwise_cipher =
+ bss->param.bss_config.wpa_cfg.pairwise_cipher_wpa2;
+ cmd_size += sizeof(MrvlIEtypes_pwk_cipher_t);
+ tlv += sizeof(MrvlIEtypes_pwk_cipher_t);
+ }
+
+ if (bss->param.bss_config.wpa_cfg.group_cipher & VALID_CIPHER_BITMAP) {
+ tlv_gwk_cipher = (MrvlIEtypes_gwk_cipher_t *) tlv;
+ tlv_gwk_cipher->header.type = wlan_cpu_to_le16(TLV_TYPE_GWK_CIPHER);
+ tlv_gwk_cipher->header.len =
+ wlan_cpu_to_le16(sizeof(t_u8) + sizeof(t_u8));
+ tlv_gwk_cipher->group_cipher =
+ bss->param.bss_config.wpa_cfg.group_cipher;
+ cmd_size += sizeof(MrvlIEtypes_gwk_cipher_t);
+ tlv += sizeof(MrvlIEtypes_gwk_cipher_t);
+ }
+
+ if (bss->param.bss_config.wpa_cfg.rsn_protection <= MTRUE) {
+ tlv_rsn_prot = (MrvlIEtypes_rsn_replay_prot_t *) tlv;
+ tlv_rsn_prot->header.type =
+ wlan_cpu_to_le16(TLV_TYPE_UAP_RSN_REPLAY_PROTECT);
+ tlv_rsn_prot->header.len = wlan_cpu_to_le16(sizeof(t_u8));
+ tlv_rsn_prot->rsn_replay_prot =
+ bss->param.bss_config.wpa_cfg.rsn_protection;
+ cmd_size += sizeof(MrvlIEtypes_rsn_replay_prot_t);
+ tlv += sizeof(MrvlIEtypes_rsn_replay_prot_t);
+ }
+
+ if (bss->param.bss_config.wpa_cfg.length) {
+ tlv_passphrase = (MrvlIEtypes_passphrase_t *) tlv;
+ tlv_passphrase->header.type =
+ wlan_cpu_to_le16(TLV_TYPE_UAP_WPA_PASSPHRASE);
+ tlv_passphrase->header.len =
+ (t_u16) wlan_cpu_to_le16(bss->param.bss_config.wpa_cfg.length);
+ memcpy(pmpriv->adapter, tlv_passphrase->passphrase,
+ bss->param.bss_config.wpa_cfg.passphrase,
+ bss->param.bss_config.wpa_cfg.length);
+ cmd_size +=
+ sizeof(MrvlIEtypesHeader_t) +
+ bss->param.bss_config.wpa_cfg.length;
+ tlv +=
+ sizeof(MrvlIEtypesHeader_t) +
+ bss->param.bss_config.wpa_cfg.length;
+ }
+
+ if (bss->param.bss_config.wpa_cfg.gk_rekey_time < MAX_GRP_TIMER) {
+ tlv_rekey_time = (MrvlIEtypes_group_rekey_time_t *) tlv;
+ tlv_rekey_time->header.type =
+ wlan_cpu_to_le16(TLV_TYPE_UAP_GRP_REKEY_TIME);
+ tlv_rekey_time->header.len = wlan_cpu_to_le16(sizeof(t_u32));
+ tlv_rekey_time->gk_rekey_time =
+ wlan_cpu_to_le32(bss->param.bss_config.wpa_cfg.gk_rekey_time);
+ cmd_size += sizeof(MrvlIEtypes_group_rekey_time_t);
+ tlv += sizeof(MrvlIEtypes_group_rekey_time_t);
+ }
+ } else {
+ if ((bss->param.bss_config.wep_cfg.key0.length) &&
+ ((bss->param.bss_config.wep_cfg.key0.length == 5) ||
+ (bss->param.bss_config.wep_cfg.key0.length == 10) ||
+ (bss->param.bss_config.wep_cfg.key0.length == 13) ||
+ (bss->param.bss_config.wep_cfg.key0.length == 26))) {
+ tlv_wep_key = (MrvlIEtypes_wep_key_t *) tlv;
+ tlv_wep_key->header.type = wlan_cpu_to_le16(TLV_TYPE_UAP_WEP_KEY);
+ tlv_wep_key->header.len =
+ wlan_cpu_to_le16(2 + bss->param.bss_config.wep_cfg.key0.length);
+ tlv_wep_key->key_index =
+ bss->param.bss_config.wep_cfg.key0.key_index;
+ tlv_wep_key->is_default =
+ bss->param.bss_config.wep_cfg.key0.is_default;
+ memcpy(pmpriv->adapter, tlv_wep_key->key,
+ bss->param.bss_config.wep_cfg.key0.key,
+ bss->param.bss_config.wep_cfg.key0.length);
+ cmd_size +=
+ sizeof(MrvlIEtypesHeader_t) + 2 +
+ bss->param.bss_config.wep_cfg.key0.length;
+ tlv +=
+ sizeof(MrvlIEtypesHeader_t) + 2 +
+ bss->param.bss_config.wep_cfg.key0.length;
+ }
+
+ if ((bss->param.bss_config.wep_cfg.key1.length) &&
+ ((bss->param.bss_config.wep_cfg.key1.length == 5) ||
+ (bss->param.bss_config.wep_cfg.key1.length == 10) ||
+ (bss->param.bss_config.wep_cfg.key1.length == 13) ||
+ (bss->param.bss_config.wep_cfg.key1.length == 26))) {
+ tlv_wep_key = (MrvlIEtypes_wep_key_t *) tlv;
+ tlv_wep_key->header.type = wlan_cpu_to_le16(TLV_TYPE_UAP_WEP_KEY);
+ tlv_wep_key->header.len =
+ wlan_cpu_to_le16(2 + bss->param.bss_config.wep_cfg.key1.length);
+ tlv_wep_key->key_index =
+ bss->param.bss_config.wep_cfg.key1.key_index;
+ tlv_wep_key->is_default =
+ bss->param.bss_config.wep_cfg.key1.is_default;
+ memcpy(pmpriv->adapter, tlv_wep_key->key,
+ bss->param.bss_config.wep_cfg.key1.key,
+ bss->param.bss_config.wep_cfg.key1.length);
+ cmd_size +=
+ sizeof(MrvlIEtypesHeader_t) + 2 +
+ bss->param.bss_config.wep_cfg.key1.length;
+ tlv +=
+ sizeof(MrvlIEtypesHeader_t) + 2 +
+ bss->param.bss_config.wep_cfg.key1.length;
+ }
+
+ if ((bss->param.bss_config.wep_cfg.key2.length) &&
+ ((bss->param.bss_config.wep_cfg.key2.length == 5) ||
+ (bss->param.bss_config.wep_cfg.key2.length == 10) ||
+ (bss->param.bss_config.wep_cfg.key2.length == 13) ||
+ (bss->param.bss_config.wep_cfg.key2.length == 26))) {
+ tlv_wep_key = (MrvlIEtypes_wep_key_t *) tlv;
+ tlv_wep_key->header.type = wlan_cpu_to_le16(TLV_TYPE_UAP_WEP_KEY);
+ tlv_wep_key->header.len =
+ wlan_cpu_to_le16(2 + bss->param.bss_config.wep_cfg.key2.length);
+ tlv_wep_key->key_index =
+ bss->param.bss_config.wep_cfg.key2.key_index;
+ tlv_wep_key->is_default =
+ bss->param.bss_config.wep_cfg.key2.is_default;
+ memcpy(pmpriv->adapter, tlv_wep_key->key,
+ bss->param.bss_config.wep_cfg.key2.key,
+ bss->param.bss_config.wep_cfg.key2.length);
+ cmd_size +=
+ sizeof(MrvlIEtypesHeader_t) + 2 +
+ bss->param.bss_config.wep_cfg.key2.length;
+ tlv +=
+ sizeof(MrvlIEtypesHeader_t) + 2 +
+ bss->param.bss_config.wep_cfg.key2.length;
+ }
+
+ if ((bss->param.bss_config.wep_cfg.key3.length) &&
+ ((bss->param.bss_config.wep_cfg.key3.length == 5) ||
+ (bss->param.bss_config.wep_cfg.key3.length == 10) ||
+ (bss->param.bss_config.wep_cfg.key3.length == 13) ||
+ (bss->param.bss_config.wep_cfg.key3.length == 26))) {
+ tlv_wep_key = (MrvlIEtypes_wep_key_t *) tlv;
+ tlv_wep_key->header.type = wlan_cpu_to_le16(TLV_TYPE_UAP_WEP_KEY);
+ tlv_wep_key->header.len =
+ wlan_cpu_to_le16(2 + bss->param.bss_config.wep_cfg.key3.length);
+ tlv_wep_key->key_index =
+ bss->param.bss_config.wep_cfg.key3.key_index;
+ tlv_wep_key->is_default =
+ bss->param.bss_config.wep_cfg.key3.is_default;
+ memcpy(pmpriv->adapter, tlv_wep_key->key,
+ bss->param.bss_config.wep_cfg.key3.key,
+ bss->param.bss_config.wep_cfg.key3.length);
+ cmd_size +=
+ sizeof(MrvlIEtypesHeader_t) + 2 +
+ bss->param.bss_config.wep_cfg.key3.length;
+ tlv +=
+ sizeof(MrvlIEtypesHeader_t) + 2 +
+ bss->param.bss_config.wep_cfg.key3.length;
+ }
+ }
+ if ((bss->param.bss_config.ht_cap_info)
+ ) {
+ tlv_htcap = (MrvlIETypes_HTCap_t *) tlv;
+ tlv_htcap->header.type = wlan_cpu_to_le16(HT_CAPABILITY);
+ tlv_htcap->header.len = wlan_cpu_to_le16(sizeof(HTCap_t));
+ tlv_htcap->ht_cap.ht_cap_info =
+ wlan_cpu_to_le16(bss->param.bss_config.ht_cap_info);
+ tlv_htcap->ht_cap.ampdu_param = bss->param.bss_config.ampdu_param;
+ memcpy(pmpriv->adapter, tlv_htcap->ht_cap.supported_mcs_set,
+ bss->param.bss_config.supported_mcs_set, 16);
+ tlv_htcap->ht_cap.ht_ext_cap =
+ wlan_cpu_to_le16(bss->param.bss_config.ht_ext_cap);
+ tlv_htcap->ht_cap.tx_bf_cap =
+ wlan_cpu_to_le32(bss->param.bss_config.tx_bf_cap);
+ tlv_htcap->ht_cap.asel = bss->param.bss_config.asel;
+ cmd_size += sizeof(MrvlIETypes_HTCap_t);
+ tlv += sizeof(MrvlIETypes_HTCap_t);
+ }
+ if (bss->param.bss_config.mgmt_ie_passthru_mask < (MAX_VALID_DWORD)) {
+ tlv_mgmt_ie_passthru = (MrvlIEtypes_mgmt_ie_passthru_t *) tlv;
+ tlv_mgmt_ie_passthru->header.type =
+ wlan_cpu_to_le16(TLV_TYPE_UAP_MGMT_IE_PASSTHRU_MASK);
+ tlv_mgmt_ie_passthru->header.len = wlan_cpu_to_le16(sizeof(t_u32));
+ /* keep copy in private data */
+ pmpriv->mgmt_frame_passthru_mask =
+ bss->param.bss_config.mgmt_ie_passthru_mask;
+ tlv_mgmt_ie_passthru->mgmt_ie_mask =
+ wlan_cpu_to_le32(bss->param.bss_config.mgmt_ie_passthru_mask);
+ cmd_size += sizeof(MrvlIEtypes_mgmt_ie_passthru_t);
+ tlv += sizeof(MrvlIEtypes_mgmt_ie_passthru_t);
+ }
+ if (((bss->param.bss_config.enable_2040coex == 0) ||
+ (bss->param.bss_config.enable_2040coex == 1))
+ ) {
+ tlv_2040_coex_enable = (MrvlIEtypes_2040_coex_enable_t *) tlv;
+ tlv_2040_coex_enable->header.type =
+ wlan_cpu_to_le16(TLV_TYPE_2040_BSS_COEX_CONTROL);
+ tlv_2040_coex_enable->header.len = wlan_cpu_to_le16(sizeof(t_u8));
+ tlv_2040_coex_enable->enable_2040coex =
+ bss->param.bss_config.enable_2040coex;
+ cmd_size += sizeof(MrvlIEtypes_2040_coex_enable_t);
+ tlv += sizeof(MrvlIEtypes_2040_coex_enable_t);
+ }
+ if (bss->param.bss_config.wmm_para.qos_info == 0x80 ||
+ bss->param.bss_config.wmm_para.qos_info == 0x00) {
+ tlv_wmm_parameter = (MrvlIEtypes_wmm_parameter_t *) tlv;
+ tlv_wmm_parameter->header.type =
+ wlan_cpu_to_le16(TLV_TYPE_VENDOR_SPECIFIC_IE);
+ tlv_wmm_parameter->header.len =
+ wlan_cpu_to_le16(sizeof(bss->param.bss_config.wmm_para));
+ memcpy(pmpriv->adapter, tlv_wmm_parameter->wmm_para.ouitype,
+ bss->param.bss_config.wmm_para.ouitype,
+ sizeof(tlv_wmm_parameter->wmm_para.ouitype));
+ tlv_wmm_parameter->wmm_para.ouisubtype =
+ bss->param.bss_config.wmm_para.ouisubtype;
+ tlv_wmm_parameter->wmm_para.version =
+ bss->param.bss_config.wmm_para.version;
+ tlv_wmm_parameter->wmm_para.qos_info =
+ bss->param.bss_config.wmm_para.qos_info;
+ for (ac = 0; ac < 4; ac++) {
+ tlv_wmm_parameter->wmm_para.ac_params[ac].aci_aifsn.aifsn =
+ bss->param.bss_config.wmm_para.ac_params[ac].aci_aifsn.aifsn;
+ tlv_wmm_parameter->wmm_para.ac_params[ac].ecw.ecw_max =
+ bss->param.bss_config.wmm_para.ac_params[ac].ecw.ecw_max;
+ tlv_wmm_parameter->wmm_para.ac_params[ac].ecw.ecw_min =
+ bss->param.bss_config.wmm_para.ac_params[ac].ecw.ecw_min;
+ tlv_wmm_parameter->wmm_para.ac_params[ac].tx_op_limit =
+ wlan_cpu_to_le16(bss->param.bss_config.wmm_para.ac_params[ac].
+ tx_op_limit);
+ }
+ cmd_size += sizeof(MrvlIEtypes_wmm_parameter_t);
+ tlv += sizeof(MrvlIEtypes_wmm_parameter_t);
+ }
+
+ cmd->size = (t_u16) wlan_cpu_to_le16(cmd_size);
+ PRINTM(MCMND, "AP config: cmd_size=%d\n", cmd_size);
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function prepares command of sys_config
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param cmd A pointer to HostCmd_DS_COMMAND structure
+ * @param cmd_action the action: GET or SET
+ * @param pioctl_buf A pointer to mlan_ioctl_req structure
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+static mlan_status
+wlan_uap_cmd_sys_configure(pmlan_private pmpriv,
+ IN HostCmd_DS_COMMAND * cmd,
+ IN t_u16 cmd_action,
+ IN pmlan_ioctl_req pioctl_buf, IN t_void * pdata_buf)
+{
+ mlan_ds_bss *bss = MNULL;
+ HostCmd_DS_SYS_CONFIG *sys_config =
+ (HostCmd_DS_SYS_CONFIG *) & cmd->params.sys_config;
+ MrvlIEtypes_MacAddr_t *mac_tlv = MNULL;
+ MrvlIEtypes_channel_band_t *chan_band_tlv = MNULL, *pdat_tlv_cb = MNULL;
+ MrvlIEtypes_beacon_period_t *bcn_pd_tlv = MNULL, *pdat_tlv_bcnpd = MNULL;
+ MrvlIEtypes_dtim_period_t *dtim_pd_tlv = MNULL, *pdat_tlv_dtimpd = MNULL;
+ mlan_ds_misc_custom_ie *cust_ie = MNULL;
+ mlan_ds_misc_cfg *misc = MNULL;
+ MrvlIEtypesHeader_t *ie_header =
+ (MrvlIEtypesHeader_t *) sys_config->tlv_buffer;
+ t_u8 *ie = (t_u8 *) sys_config->tlv_buffer + sizeof(MrvlIEtypesHeader_t);
+ t_u16 req_len = 0, travel_len = 0;
+ custom_ie *cptr = MNULL;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ cmd->command = wlan_cpu_to_le16(HOST_CMD_APCMD_SYS_CONFIGURE);
+ sys_config->action = wlan_cpu_to_le16(cmd_action);
+ cmd->size = wlan_cpu_to_le16(sizeof(HostCmd_DS_SYS_CONFIG) - 1 + S_DS_GEN);
+ if (pioctl_buf == MNULL) {
+ if (pdata_buf) {
+ switch (*(t_u16 *) pdata_buf) {
+ case TLV_TYPE_UAP_CHAN_BAND_CONFIG:
+ pdat_tlv_cb = (MrvlIEtypes_channel_band_t *) pdata_buf;
+ chan_band_tlv =
+ (MrvlIEtypes_channel_band_t *) sys_config->tlv_buffer;
+ cmd->size =
+ wlan_cpu_to_le16(sizeof(HostCmd_DS_SYS_CONFIG) - 1 +
+ S_DS_GEN +
+ sizeof(MrvlIEtypes_channel_band_t));
+ chan_band_tlv->header.type =
+ wlan_cpu_to_le16(TLV_TYPE_UAP_CHAN_BAND_CONFIG);
+ chan_band_tlv->header.len =
+ wlan_cpu_to_le16(sizeof(MrvlIEtypes_channel_band_t)
+ - sizeof(MrvlIEtypesHeader_t));
+ if (cmd_action) {
+ chan_band_tlv->band_config = pdat_tlv_cb->band_config;
+ chan_band_tlv->channel = pdat_tlv_cb->channel;
+ }
+ ret = MLAN_STATUS_SUCCESS;
+ break;
+ case TLV_TYPE_UAP_BEACON_PERIOD:
+ pdat_tlv_bcnpd = (MrvlIEtypes_beacon_period_t *) pdata_buf;
+ bcn_pd_tlv =
+ (MrvlIEtypes_beacon_period_t *) sys_config->tlv_buffer;
+ cmd->size =
+ sizeof(HostCmd_DS_SYS_CONFIG) - 1 + S_DS_GEN +
+ sizeof(MrvlIEtypes_beacon_period_t);
+ bcn_pd_tlv->header.type =
+ wlan_cpu_to_le16(TLV_TYPE_UAP_BEACON_PERIOD);
+ bcn_pd_tlv->header.len =
+ wlan_cpu_to_le16(sizeof(MrvlIEtypes_beacon_period_t)
+ - sizeof(MrvlIEtypesHeader_t));
+ if (cmd_action) {
+ bcn_pd_tlv->beacon_period =
+ wlan_cpu_to_le16(pdat_tlv_bcnpd->beacon_period);
+ }
+ /* Add TLV_UAP_DTIM_PERIOD if it follws in pdata_buf */
+ pdat_tlv_dtimpd =
+ (MrvlIEtypes_dtim_period_t *) (((t_u8 *) pdata_buf)
+ +
+ sizeof
+ (MrvlIEtypes_beacon_period_t));
+ if (TLV_TYPE_UAP_DTIM_PERIOD == pdat_tlv_dtimpd->header.type) {
+ dtim_pd_tlv =
+ (MrvlIEtypes_dtim_period_t *) (sys_config->tlv_buffer +
+ sizeof
+ (MrvlIEtypes_beacon_period_t));
+ cmd->size += sizeof(MrvlIEtypes_dtim_period_t);
+ dtim_pd_tlv->header.type =
+ wlan_cpu_to_le16(TLV_TYPE_UAP_DTIM_PERIOD);
+ dtim_pd_tlv->header.len =
+ wlan_cpu_to_le16(sizeof(MrvlIEtypes_dtim_period_t)
+ - sizeof(MrvlIEtypesHeader_t));
+ if (cmd_action) {
+ dtim_pd_tlv->dtim_period = pdat_tlv_dtimpd->dtim_period;
+ }
+ }
+ /* Finalize cmd size */
+ cmd->size = wlan_cpu_to_le16(cmd->size);
+ ret = MLAN_STATUS_SUCCESS;
+ break;
+ case TLV_TYPE_MGMT_IE:
+ cust_ie = (mlan_ds_misc_custom_ie *) pdata_buf;
+ cmd->size =
+ wlan_cpu_to_le16(sizeof(HostCmd_DS_SYS_CONFIG) - 1 +
+ S_DS_GEN + sizeof(MrvlIEtypesHeader_t) +
+ cust_ie->len);
+ ie_header->type = wlan_cpu_to_le16(TLV_TYPE_MGMT_IE);
+ ie_header->len = wlan_cpu_to_le16(cust_ie->len);
+
+ if (ie && cust_ie->ie_data_list) {
+ req_len = cust_ie->len;
+ travel_len = 0;
+ /* conversion for index, mask, len */
+ if (req_len == sizeof(t_u16))
+ cust_ie->ie_data_list[0].ie_index =
+ wlan_cpu_to_le16(cust_ie->ie_data_list[0].ie_index);
+ while (req_len > sizeof(t_u16)) {
+ cptr =
+ (custom_ie *) (((t_u8 *) & cust_ie->ie_data_list) +
+ travel_len);
+ travel_len +=
+ cptr->ie_length + sizeof(custom_ie) - MAX_IE_SIZE;
+ req_len -=
+ cptr->ie_length + sizeof(custom_ie) - MAX_IE_SIZE;
+ cptr->ie_index = wlan_cpu_to_le16(cptr->ie_index);
+ cptr->mgmt_subtype_mask =
+ wlan_cpu_to_le16(cptr->mgmt_subtype_mask);
+ cptr->ie_length = wlan_cpu_to_le16(cptr->ie_length);
+ }
+ memcpy(pmpriv->adapter, ie, cust_ie->ie_data_list,
+ cust_ie->len);
+ }
+ break;
+ default:
+ PRINTM(MERROR,
+ "Wrong data, or missing TLV_TYPE 0x%04x handler.\n",
+ *(t_u16 *) pdata_buf);
+ break;
+ }
+ goto done;
+ } else {
+ mac_tlv = (MrvlIEtypes_MacAddr_t *) sys_config->tlv_buffer;
+ cmd->size =
+ wlan_cpu_to_le16(sizeof(HostCmd_DS_SYS_CONFIG) - 1 + S_DS_GEN +
+ sizeof(MrvlIEtypes_MacAddr_t));
+ mac_tlv->header.type = wlan_cpu_to_le16(TLV_TYPE_UAP_MAC_ADDRESS);
+ mac_tlv->header.len = wlan_cpu_to_le16(MLAN_MAC_ADDR_LENGTH);
+ ret = MLAN_STATUS_SUCCESS;
+ goto done;
+ }
+ }
+ if (pioctl_buf->req_id == MLAN_IOCTL_BSS) {
+ bss = (mlan_ds_bss *) pioctl_buf->pbuf;
+ if (bss->sub_command == MLAN_OID_BSS_MAC_ADDR) {
+ mac_tlv = (MrvlIEtypes_MacAddr_t *) sys_config->tlv_buffer;
+ cmd->size =
+ wlan_cpu_to_le16(sizeof(HostCmd_DS_SYS_CONFIG) - 1 + S_DS_GEN +
+ sizeof(MrvlIEtypes_MacAddr_t));
+ mac_tlv->header.type = wlan_cpu_to_le16(TLV_TYPE_UAP_MAC_ADDRESS);
+ mac_tlv->header.len = wlan_cpu_to_le16(MLAN_MAC_ADDR_LENGTH);
+ if (cmd_action == HostCmd_ACT_GEN_SET)
+ memcpy(pmpriv->adapter, mac_tlv->mac, &bss->param.mac_addr,
+ MLAN_MAC_ADDR_LENGTH);
+ } else if ((bss->sub_command == MLAN_OID_UAP_BSS_CONFIG) &&
+ (cmd_action == HostCmd_ACT_GEN_SET)) {
+ ret = wlan_uap_cmd_ap_config(pmpriv, cmd, cmd_action, pioctl_buf);
+ goto done;
+ }
+ } else if (pioctl_buf->req_id == MLAN_IOCTL_MISC_CFG) {
+ misc = (mlan_ds_misc_cfg *) pioctl_buf->pbuf;
+ if ((misc->sub_command == MLAN_OID_MISC_GEN_IE) &&
+ (misc->param.gen_ie.type == MLAN_IE_TYPE_GEN_IE)
+ ) {
+ cmd->size =
+ wlan_cpu_to_le16(sizeof(HostCmd_DS_SYS_CONFIG) - 1 + S_DS_GEN +
+ sizeof(MrvlIEtypesHeader_t) +
+ misc->param.gen_ie.len);
+ ie_header->type = wlan_cpu_to_le16(TLV_TYPE_WAPI_IE);
+ ie_header->len = wlan_cpu_to_le16(misc->param.gen_ie.len);
+ if (cmd_action == HostCmd_ACT_GEN_SET)
+ memcpy(pmpriv->adapter, ie, misc->param.gen_ie.ie_data,
+ misc->param.gen_ie.len);
+ }
+ if ((misc->sub_command == MLAN_OID_MISC_CUSTOM_IE) &&
+ (misc->param.cust_ie.type == TLV_TYPE_MGMT_IE)) {
+ cmd->size =
+ wlan_cpu_to_le16(sizeof(HostCmd_DS_SYS_CONFIG) - 1 + S_DS_GEN +
+ sizeof(MrvlIEtypesHeader_t) +
+ misc->param.cust_ie.len);
+ ie_header->type = wlan_cpu_to_le16(TLV_TYPE_MGMT_IE);
+ ie_header->len = wlan_cpu_to_le16(misc->param.cust_ie.len);
+
+ if (ie && misc->param.cust_ie.ie_data_list) {
+ req_len = misc->param.cust_ie.len;
+ travel_len = 0;
+ /* conversion for index, mask, len */
+ if (req_len == sizeof(t_u16))
+ misc->param.cust_ie.ie_data_list[0].ie_index =
+ wlan_cpu_to_le16(misc->param.cust_ie.ie_data_list[0].
+ ie_index);
+ while (req_len > sizeof(t_u16)) {
+ cptr =
+ (custom_ie
+ *) (((t_u8 *) & misc->param.cust_ie.ie_data_list) +
+ travel_len);
+ travel_len +=
+ cptr->ie_length + sizeof(custom_ie) - MAX_IE_SIZE;
+ req_len -=
+ cptr->ie_length + sizeof(custom_ie) - MAX_IE_SIZE;
+ cptr->ie_index = wlan_cpu_to_le16(cptr->ie_index);
+ cptr->mgmt_subtype_mask =
+ wlan_cpu_to_le16(cptr->mgmt_subtype_mask);
+ cptr->ie_length = wlan_cpu_to_le16(cptr->ie_length);
+ }
+ if (misc->param.cust_ie.len)
+ memcpy(pmpriv->adapter, ie,
+ misc->param.cust_ie.ie_data_list,
+ misc->param.cust_ie.len);
+ }
+ }
+ }
+ done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function handles command resp for get uap settings
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param resp A pointer to HostCmd_DS_COMMAND
+ * @param pioctl_buf A pointer to mlan_ioctl_req structure
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+static mlan_status
+wlan_uap_ret_cmd_ap_config(IN pmlan_private pmpriv,
+ IN HostCmd_DS_COMMAND * resp,
+ IN mlan_ioctl_req * pioctl_buf)
+{
+ HostCmd_DS_SYS_CONFIG *sys_config =
+ (HostCmd_DS_SYS_CONFIG *) & resp->params.sys_config;
+ mlan_ds_bss *bss = MNULL;
+ MrvlIEtypesHeader_t *tlv = MNULL;
+ t_u16 tlv_buf_left = 0;
+ t_u16 tlv_type = 0;
+ t_u16 tlv_len = 0;
+ MrvlIEtypes_MacAddr_t *tlv_mac = MNULL;
+ MrvlIEtypes_SsIdParamSet_t *tlv_ssid = MNULL;
+ MrvlIEtypes_beacon_period_t *tlv_beacon_period = MNULL;
+ MrvlIEtypes_dtim_period_t *tlv_dtim_period = MNULL;
+ MrvlIEtypes_RatesParamSet_t *tlv_rates = MNULL;
+ MrvlIEtypes_tx_rate_t *tlv_txrate = MNULL;
+ MrvlIEtypes_mcbc_rate_t *tlv_mcbc_rate = MNULL;
+ MrvlIEtypes_tx_power_t *tlv_tx_power = MNULL;
+ MrvlIEtypes_bcast_ssid_t *tlv_bcast_ssid = MNULL;
+ MrvlIEtypes_antenna_mode_t *tlv_antenna = MNULL;
+ MrvlIEtypes_pkt_forward_t *tlv_pkt_forward = MNULL;
+ MrvlIEtypes_max_sta_count_t *tlv_sta_count = MNULL;
+ MrvlIEtypes_sta_ageout_t *tlv_sta_ageout = MNULL;
+ MrvlIEtypes_ps_sta_ageout_t *tlv_ps_sta_ageout = MNULL;
+ MrvlIEtypes_rts_threshold_t *tlv_rts_threshold = MNULL;
+ MrvlIEtypes_frag_threshold_t *tlv_frag_threshold = MNULL;
+ MrvlIEtypes_retry_limit_t *tlv_retry_limit = MNULL;
+ MrvlIEtypes_eapol_pwk_hsk_timeout_t *tlv_pairwise_timeout = MNULL;
+ MrvlIEtypes_eapol_pwk_hsk_retries_t *tlv_pairwise_retries = MNULL;
+ MrvlIEtypes_eapol_gwk_hsk_timeout_t *tlv_groupwise_timeout = MNULL;
+ MrvlIEtypes_eapol_gwk_hsk_retries_t *tlv_groupwise_retries = MNULL;
+ MrvlIEtypes_mgmt_ie_passthru_t *tlv_mgmt_ie_passthru = MNULL;
+ MrvlIEtypes_2040_coex_enable_t *tlv_2040_coex_enable = MNULL;
+ MrvlIEtypes_mac_filter_t *tlv_mac_filter = MNULL;
+ MrvlIEtypes_channel_band_t *tlv_chan_band = MNULL;
+ MrvlIEtypes_ChanListParamSet_t *tlv_chan_list = MNULL;
+ ChanScanParamSet_t *pscan_chan = MNULL;
+ MrvlIEtypes_auth_type_t *tlv_auth_type = MNULL;
+ MrvlIEtypes_encrypt_protocol_t *tlv_encrypt_protocol = MNULL;
+ MrvlIEtypes_akmp_t *tlv_akmp = MNULL;
+ MrvlIEtypes_pwk_cipher_t *tlv_pwk_cipher = MNULL;
+ MrvlIEtypes_gwk_cipher_t *tlv_gwk_cipher = MNULL;
+ MrvlIEtypes_rsn_replay_prot_t *tlv_rsn_prot = MNULL;
+ MrvlIEtypes_passphrase_t *tlv_passphrase = MNULL;
+#ifdef WIFI_DIRECT_SUPPORT
+ MrvlIEtypes_psk_t *tlv_psk = MNULL;
+#endif /* WIFI_DIRECT_SUPPORT */
+ MrvlIEtypes_group_rekey_time_t *tlv_rekey_time = MNULL;
+ MrvlIEtypes_wep_key_t *tlv_wep_key = MNULL;
+ MrvlIEtypes_preamble_t *tlv_preamble = MNULL;
+ MrvlIEtypes_bss_status_t *tlv_bss_status = MNULL;
+ MrvlIETypes_HTCap_t *tlv_htcap = MNULL;
+ MrvlIEtypes_wmm_parameter_t *tlv_wmm_parameter = MNULL;
+
+ wep_key *pkey = MNULL;
+ t_u16 i;
+ t_u16 ac;
+
+ ENTER();
+
+ bss = (mlan_ds_bss *) pioctl_buf->pbuf;
+ tlv = (MrvlIEtypesHeader_t *) sys_config->tlv_buffer;
+ tlv_buf_left = resp->size - (sizeof(HostCmd_DS_SYS_CONFIG) - 1 + S_DS_GEN);
+
+ while (tlv_buf_left >= sizeof(MrvlIEtypesHeader_t)) {
+
+ tlv_type = wlan_le16_to_cpu(tlv->type);
+ tlv_len = wlan_le16_to_cpu(tlv->len);
+
+ if (tlv_buf_left < (tlv_len + sizeof(MrvlIEtypesHeader_t))) {
+ PRINTM(MERROR,
+ "Error processing uAP sys config TLVs, bytes left < TLV length\n");
+ break;
+ }
+
+ switch (tlv_type) {
+ case TLV_TYPE_UAP_MAC_ADDRESS:
+ tlv_mac = (MrvlIEtypes_MacAddr_t *) tlv;
+ memcpy(pmpriv->adapter, &bss->param.bss_config.mac_addr,
+ tlv_mac->mac, MLAN_MAC_ADDR_LENGTH);
+ break;
+ case TLV_TYPE_SSID:
+ tlv_ssid = (MrvlIEtypes_SsIdParamSet_t *) tlv;
+ bss->param.bss_config.ssid.ssid_len =
+ MIN(MLAN_MAX_SSID_LENGTH, tlv_len);
+ memcpy(pmpriv->adapter, bss->param.bss_config.ssid.ssid,
+ tlv_ssid->ssid, MIN(MLAN_MAX_SSID_LENGTH, tlv_len));
+ break;
+ case TLV_TYPE_UAP_BEACON_PERIOD:
+ tlv_beacon_period = (MrvlIEtypes_beacon_period_t *) tlv;
+ bss->param.bss_config.beacon_period =
+ wlan_le16_to_cpu(tlv_beacon_period->beacon_period);
+ pmpriv->uap_state_chan_cb.beacon_period =
+ wlan_le16_to_cpu(tlv_beacon_period->beacon_period);
+ break;
+ case TLV_TYPE_UAP_DTIM_PERIOD:
+ tlv_dtim_period = (MrvlIEtypes_dtim_period_t *) tlv;
+ bss->param.bss_config.dtim_period = tlv_dtim_period->dtim_period;
+ pmpriv->uap_state_chan_cb.dtim_period =
+ tlv_dtim_period->dtim_period;
+ break;
+ case TLV_TYPE_RATES:
+ tlv_rates = (MrvlIEtypes_RatesParamSet_t *) tlv;
+ memcpy(pmpriv->adapter, bss->param.bss_config.rates,
+ tlv_rates->rates, MIN(MAX_DATA_RATES, tlv_len));
+ break;
+ case TLV_TYPE_UAP_TX_DATA_RATE:
+ tlv_txrate = (MrvlIEtypes_tx_rate_t *) tlv;
+ bss->param.bss_config.tx_data_rate =
+ wlan_le16_to_cpu(tlv_txrate->tx_data_rate);
+ break;
+ case TLV_TYPE_UAP_MCBC_DATA_RATE:
+ tlv_mcbc_rate = (MrvlIEtypes_mcbc_rate_t *) tlv;
+ bss->param.bss_config.mcbc_data_rate =
+ wlan_le16_to_cpu(tlv_mcbc_rate->mcbc_data_rate);
+ break;
+ case TLV_TYPE_UAP_TX_POWER:
+ tlv_tx_power = (MrvlIEtypes_tx_power_t *) tlv;
+ bss->param.bss_config.tx_power_level = tlv_tx_power->tx_power;
+ break;
+ case TLV_TYPE_UAP_BCAST_SSID_CTL:
+ tlv_bcast_ssid = (MrvlIEtypes_bcast_ssid_t *) tlv;
+ bss->param.bss_config.bcast_ssid_ctl =
+ tlv_bcast_ssid->bcast_ssid_ctl;
+ break;
+ case TLV_TYPE_UAP_ANTENNA_CTL:
+ tlv_antenna = (MrvlIEtypes_antenna_mode_t *) tlv;
+ if (tlv_antenna->which_antenna == TX_ANTENNA)
+ bss->param.bss_config.tx_antenna = tlv_antenna->antenna_mode;
+ else if (tlv_antenna->which_antenna == RX_ANTENNA)
+ bss->param.bss_config.rx_antenna = tlv_antenna->antenna_mode;
+ break;
+ case TLV_TYPE_UAP_PKT_FWD_CTL:
+ tlv_pkt_forward = (MrvlIEtypes_pkt_forward_t *) tlv;
+ bss->param.bss_config.pkt_forward_ctl =
+ tlv_pkt_forward->pkt_forward_ctl;
+ break;
+ case TLV_TYPE_UAP_MAX_STA_CNT:
+ tlv_sta_count = (MrvlIEtypes_max_sta_count_t *) tlv;
+ bss->param.bss_config.max_sta_count =
+ wlan_le16_to_cpu(tlv_sta_count->max_sta_count);
+ break;
+ case TLV_TYPE_UAP_STA_AGEOUT_TIMER:
+ tlv_sta_ageout = (MrvlIEtypes_sta_ageout_t *) tlv;
+ bss->param.bss_config.sta_ageout_timer =
+ wlan_le32_to_cpu(tlv_sta_ageout->sta_ageout_timer);
+ break;
+ case TLV_TYPE_UAP_PS_STA_AGEOUT_TIMER:
+ tlv_ps_sta_ageout = (MrvlIEtypes_ps_sta_ageout_t *) tlv;
+ bss->param.bss_config.ps_sta_ageout_timer =
+ wlan_le32_to_cpu(tlv_ps_sta_ageout->ps_sta_ageout_timer);
+ break;
+ case TLV_TYPE_UAP_RTS_THRESHOLD:
+ tlv_rts_threshold = (MrvlIEtypes_rts_threshold_t *) tlv;
+ bss->param.bss_config.rts_threshold =
+ wlan_le16_to_cpu(tlv_rts_threshold->rts_threshold);
+ break;
+ case TLV_TYPE_UAP_FRAG_THRESHOLD:
+ tlv_frag_threshold = (MrvlIEtypes_frag_threshold_t *) tlv;
+ bss->param.bss_config.frag_threshold =
+ wlan_le16_to_cpu(tlv_frag_threshold->frag_threshold);
+ break;
+ case TLV_TYPE_UAP_RETRY_LIMIT:
+ tlv_retry_limit = (MrvlIEtypes_retry_limit_t *) tlv;
+ bss->param.bss_config.retry_limit = tlv_retry_limit->retry_limit;
+ break;
+ case TLV_TYPE_UAP_EAPOL_PWK_HSK_TIMEOUT:
+ tlv_pairwise_timeout = (MrvlIEtypes_eapol_pwk_hsk_timeout_t *) tlv;
+ bss->param.bss_config.pairwise_update_timeout =
+ wlan_le32_to_cpu(tlv_pairwise_timeout->pairwise_update_timeout);
+ break;
+ case TLV_TYPE_UAP_EAPOL_PWK_HSK_RETRIES:
+ tlv_pairwise_retries = (MrvlIEtypes_eapol_pwk_hsk_retries_t *) tlv;
+ bss->param.bss_config.pwk_retries =
+ wlan_le32_to_cpu(tlv_pairwise_retries->pwk_retries);
+ break;
+ case TLV_TYPE_UAP_EAPOL_GWK_HSK_TIMEOUT:
+ tlv_groupwise_timeout = (MrvlIEtypes_eapol_gwk_hsk_timeout_t *) tlv;
+ bss->param.bss_config.groupwise_update_timeout =
+ wlan_le32_to_cpu(tlv_groupwise_timeout->
+ groupwise_update_timeout);
+ break;
+ case TLV_TYPE_UAP_EAPOL_GWK_HSK_RETRIES:
+ tlv_groupwise_retries = (MrvlIEtypes_eapol_gwk_hsk_retries_t *) tlv;
+ bss->param.bss_config.gwk_retries =
+ wlan_le32_to_cpu(tlv_groupwise_retries->gwk_retries);
+ break;
+ case TLV_TYPE_UAP_MGMT_IE_PASSTHRU_MASK:
+ tlv_mgmt_ie_passthru = (MrvlIEtypes_mgmt_ie_passthru_t *) tlv;
+ bss->param.bss_config.mgmt_ie_passthru_mask =
+ wlan_le32_to_cpu(tlv_mgmt_ie_passthru->mgmt_ie_mask);
+ break;
+ case TLV_TYPE_2040_BSS_COEX_CONTROL:
+ tlv_2040_coex_enable = (MrvlIEtypes_2040_coex_enable_t *) tlv;
+ bss->param.bss_config.enable_2040coex =
+ tlv_2040_coex_enable->enable_2040coex;
+ break;
+ case TLV_TYPE_UAP_STA_MAC_ADDR_FILTER:
+ tlv_mac_filter = (MrvlIEtypes_mac_filter_t *) tlv;
+ bss->param.bss_config.filter.mac_count =
+ MIN(MAX_MAC_FILTER_NUM, tlv_mac_filter->count);
+ bss->param.bss_config.filter.filter_mode =
+ tlv_mac_filter->filter_mode;
+ memcpy(pmpriv->adapter,
+ (t_u8 *) bss->param.bss_config.filter.mac_list,
+ tlv_mac_filter->mac_address,
+ MLAN_MAC_ADDR_LENGTH *
+ bss->param.bss_config.filter.mac_count);
+ break;
+ case TLV_TYPE_UAP_CHAN_BAND_CONFIG:
+ tlv_chan_band = (MrvlIEtypes_channel_band_t *) tlv;
+ bss->param.bss_config.band_cfg = tlv_chan_band->band_config;
+ bss->param.bss_config.channel = tlv_chan_band->channel;
+ pmpriv->uap_state_chan_cb.band_config = tlv_chan_band->band_config;
+ pmpriv->uap_state_chan_cb.channel = tlv_chan_band->channel;
+ break;
+ case TLV_TYPE_CHANLIST:
+ tlv_chan_list = (MrvlIEtypes_ChanListParamSet_t *) tlv;
+ bss->param.bss_config.num_of_chan =
+ tlv_len / sizeof(ChanScanParamSet_t);
+ pscan_chan = tlv_chan_list->chan_scan_param;
+ for (i = 0; i < bss->param.bss_config.num_of_chan; i++) {
+ bss->param.bss_config.chan_list[i].chan_number =
+ pscan_chan->chan_number;
+ bss->param.bss_config.chan_list[i].band_config_type =
+ pscan_chan->radio_type;
+ pscan_chan++;
+ }
+ break;
+ case TLV_TYPE_AUTH_TYPE:
+ tlv_auth_type = (MrvlIEtypes_auth_type_t *) tlv;
+ bss->param.bss_config.auth_mode = tlv_auth_type->auth_type;
+ break;
+ case TLV_TYPE_UAP_ENCRYPT_PROTOCOL:
+ tlv_encrypt_protocol = (MrvlIEtypes_encrypt_protocol_t *) tlv;
+ bss->param.bss_config.protocol =
+ wlan_le16_to_cpu(tlv_encrypt_protocol->protocol);
+ break;
+ case TLV_TYPE_UAP_AKMP:
+ tlv_akmp = (MrvlIEtypes_akmp_t *) tlv;
+ bss->param.bss_config.key_mgmt =
+ wlan_le16_to_cpu(tlv_akmp->key_mgmt);
+ if (tlv_len > sizeof(t_u16))
+ bss->param.bss_config.key_mgmt_operation =
+ wlan_le16_to_cpu(tlv_akmp->key_mgmt_operation);
+ break;
+ case TLV_TYPE_PWK_CIPHER:
+ tlv_pwk_cipher = (MrvlIEtypes_pwk_cipher_t *) tlv;
+ if (wlan_le16_to_cpu(tlv_pwk_cipher->protocol) & PROTOCOL_WPA)
+ bss->param.bss_config.wpa_cfg.pairwise_cipher_wpa =
+ tlv_pwk_cipher->pairwise_cipher;
+ if (wlan_le16_to_cpu(tlv_pwk_cipher->protocol) & PROTOCOL_WPA2)
+ bss->param.bss_config.wpa_cfg.pairwise_cipher_wpa2 =
+ tlv_pwk_cipher->pairwise_cipher;
+ break;
+ case TLV_TYPE_GWK_CIPHER:
+ tlv_gwk_cipher = (MrvlIEtypes_gwk_cipher_t *) tlv;
+ bss->param.bss_config.wpa_cfg.group_cipher =
+ tlv_gwk_cipher->group_cipher;
+ break;
+ case TLV_TYPE_UAP_RSN_REPLAY_PROTECT:
+ tlv_rsn_prot = (MrvlIEtypes_rsn_replay_prot_t *) tlv;
+ bss->param.bss_config.wpa_cfg.rsn_protection =
+ tlv_rsn_prot->rsn_replay_prot;
+ break;
+ case TLV_TYPE_UAP_WPA_PASSPHRASE:
+ tlv_passphrase = (MrvlIEtypes_passphrase_t *) tlv;
+ bss->param.bss_config.wpa_cfg.length =
+ MIN(MLAN_PMK_HEXSTR_LENGTH, tlv_len);
+ memcpy(pmpriv->adapter, bss->param.bss_config.wpa_cfg.passphrase,
+ tlv_passphrase->passphrase,
+ bss->param.bss_config.wpa_cfg.length);
+ break;
+#ifdef WIFI_DIRECT_SUPPORT
+ case TLV_TYPE_UAP_PSK:
+ tlv_psk = (MrvlIEtypes_psk_t *) tlv;
+ memcpy(pmpriv->adapter, bss->param.bss_config.psk, tlv_psk->psk,
+ MIN(MLAN_MAX_KEY_LENGTH, tlv_len));
+ break;
+#endif /* WIFI_DIRECT_SUPPORT */
+ case TLV_TYPE_UAP_GRP_REKEY_TIME:
+ tlv_rekey_time = (MrvlIEtypes_group_rekey_time_t *) tlv;
+ bss->param.bss_config.wpa_cfg.gk_rekey_time =
+ wlan_le32_to_cpu(tlv_rekey_time->gk_rekey_time);
+ break;
+ case TLV_TYPE_UAP_WEP_KEY:
+ tlv_wep_key = (MrvlIEtypes_wep_key_t *) tlv;
+ pkey = MNULL;
+ if (tlv_wep_key->key_index == 0)
+ pkey = &bss->param.bss_config.wep_cfg.key0;
+ else if (tlv_wep_key->key_index == 1)
+ pkey = &bss->param.bss_config.wep_cfg.key1;
+ else if (tlv_wep_key->key_index == 2)
+ pkey = &bss->param.bss_config.wep_cfg.key2;
+ else if (tlv_wep_key->key_index == 3)
+ pkey = &bss->param.bss_config.wep_cfg.key3;
+ if (pkey) {
+ pkey->key_index = tlv_wep_key->key_index;
+ pkey->is_default = tlv_wep_key->is_default;
+ pkey->length = MIN(MAX_WEP_KEY_SIZE, (tlv_len - 2));
+ memcpy(pmpriv->adapter, pkey->key, tlv_wep_key->key,
+ pkey->length);
+ }
+ break;
+ case TLV_TYPE_UAP_PREAMBLE_CTL:
+ tlv_preamble = (MrvlIEtypes_preamble_t *) tlv;
+ bss->param.bss_config.preamble_type = tlv_preamble->preamble_type;
+ break;
+ case TLV_TYPE_BSS_STATUS:
+ tlv_bss_status = (MrvlIEtypes_bss_status_t *) tlv;
+ bss->param.bss_config.bss_status =
+ wlan_le16_to_cpu(tlv_bss_status->bss_status);
+ pmpriv->uap_bss_started =
+ (bss->param.bss_config.bss_status) ? MTRUE : MFALSE;
+ break;
+ case HT_CAPABILITY:
+ tlv_htcap = (MrvlIETypes_HTCap_t *) tlv;
+ bss->param.bss_config.ht_cap_info =
+ wlan_le16_to_cpu(tlv_htcap->ht_cap.ht_cap_info);
+ bss->param.bss_config.ampdu_param = tlv_htcap->ht_cap.ampdu_param;
+ memcpy(pmpriv->adapter, bss->param.bss_config.supported_mcs_set,
+ tlv_htcap->ht_cap.supported_mcs_set, 16);
+ bss->param.bss_config.ht_ext_cap =
+ wlan_le16_to_cpu(tlv_htcap->ht_cap.ht_ext_cap);
+ bss->param.bss_config.tx_bf_cap =
+ wlan_le32_to_cpu(tlv_htcap->ht_cap.tx_bf_cap);
+ bss->param.bss_config.asel = tlv_htcap->ht_cap.asel;
+ break;
+ case TLV_TYPE_VENDOR_SPECIFIC_IE:
+ tlv_wmm_parameter = (MrvlIEtypes_wmm_parameter_t *) tlv;
+ bss->param.bss_config.wmm_para.qos_info =
+ tlv_wmm_parameter->wmm_para.qos_info;
+ for (ac = 0; ac < 4; ac++) {
+ bss->param.bss_config.wmm_para.ac_params[ac].aci_aifsn.aifsn =
+ tlv_wmm_parameter->wmm_para.ac_params[ac].aci_aifsn.aifsn;
+ bss->param.bss_config.wmm_para.ac_params[ac].ecw.ecw_max =
+ tlv_wmm_parameter->wmm_para.ac_params[ac].ecw.ecw_max;
+ bss->param.bss_config.wmm_para.ac_params[ac].ecw.ecw_min =
+ tlv_wmm_parameter->wmm_para.ac_params[ac].ecw.ecw_min;
+ bss->param.bss_config.wmm_para.ac_params[ac].tx_op_limit =
+ wlan_le16_to_cpu(tlv_wmm_parameter->wmm_para.ac_params[ac].
+ tx_op_limit);
+ }
+ break;
+ }
+
+ tlv_buf_left -= tlv_len + sizeof(MrvlIEtypesHeader_t);
+ tlv =
+ (MrvlIEtypesHeader_t *) ((t_u8 *) tlv + tlv_len +
+ sizeof(MrvlIEtypesHeader_t));
+ }
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function handles the command response of sys_reset
+ * Clear various private state variables used by DFS.
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param resp A pointer to HostCmd_DS_COMMAND
+ * @param pioctl_buf A pointer to mlan_ioctl_req structure
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+static mlan_status
+wlan_uap_ret_sys_reset(IN pmlan_private pmpriv,
+ IN HostCmd_DS_COMMAND * resp,
+ IN mlan_ioctl_req * pioctl_buf)
+{
+ ENTER();
+
+ pmpriv->uap_state_chan_cb.band_config = 0;
+ pmpriv->uap_state_chan_cb.channel = 0;
+ pmpriv->uap_state_chan_cb.beacon_period = 0;
+ pmpriv->uap_state_chan_cb.dtim_period = 0;
+
+ /* assume default 11d/11h states are off, should check with FW */
+ /* currently don't clear domain_info... global, could be from STA */
+ wlan_11d_priv_init(pmpriv);
+ wlan_11h_priv_init(pmpriv);
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function handles the command response of sys_config
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param resp A pointer to HostCmd_DS_COMMAND
+ * @param pioctl_buf A pointer to mlan_ioctl_req structure
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+static mlan_status
+wlan_uap_ret_sys_config(IN pmlan_private pmpriv,
+ IN HostCmd_DS_COMMAND * resp,
+ IN mlan_ioctl_req * pioctl_buf)
+{
+ int resp_len = 0, travel_len = 0;
+ int i = 0;
+ custom_ie *cptr;
+ HostCmd_DS_SYS_CONFIG *sys_config =
+ (HostCmd_DS_SYS_CONFIG *) & resp->params.sys_config;
+ mlan_ds_bss *bss = MNULL;
+ mlan_ds_misc_cfg *misc = MNULL;
+ MrvlIEtypes_MacAddr_t *tlv =
+ (MrvlIEtypes_MacAddr_t *) sys_config->tlv_buffer;
+ mlan_ds_misc_custom_ie *cust_ie = MNULL;
+ tlvbuf_max_mgmt_ie *max_mgmt_ie = MNULL;
+ MrvlIEtypes_channel_band_t *tlv_cb = MNULL;
+ MrvlIEtypes_beacon_period_t *tlv_bcnpd = MNULL;
+ MrvlIEtypes_dtim_period_t *tlv_dtimpd = MNULL;
+
+ ENTER();
+ if (pioctl_buf) {
+ if (pioctl_buf->req_id == MLAN_IOCTL_BSS) {
+ bss = (mlan_ds_bss *) pioctl_buf->pbuf;
+ if (bss->sub_command == MLAN_OID_BSS_MAC_ADDR) {
+ if (TLV_TYPE_UAP_MAC_ADDRESS ==
+ wlan_le16_to_cpu(tlv->header.type)) {
+ memcpy(pmpriv->adapter, &bss->param.mac_addr, tlv->mac,
+ MLAN_MAC_ADDR_LENGTH);
+ }
+ } else if ((bss->sub_command == MLAN_OID_UAP_BSS_CONFIG) &&
+ (pioctl_buf->action == MLAN_ACT_GET)) {
+ wlan_uap_ret_cmd_ap_config(pmpriv, resp, pioctl_buf);
+ }
+ }
+ if (pioctl_buf->req_id == MLAN_IOCTL_MISC_CFG) {
+ misc = (mlan_ds_misc_cfg *) pioctl_buf->pbuf;
+ cust_ie = (mlan_ds_misc_custom_ie *) sys_config->tlv_buffer;
+ max_mgmt_ie =
+ (tlvbuf_max_mgmt_ie *) (sys_config->tlv_buffer + cust_ie->len +
+ sizeof(MrvlIEtypesHeader_t));
+ if ((pioctl_buf->action == MLAN_ACT_GET) &&
+ (misc->sub_command == MLAN_OID_MISC_CUSTOM_IE)) {
+
+ cust_ie->type = wlan_le16_to_cpu(cust_ie->type);
+ resp_len = cust_ie->len = wlan_le16_to_cpu(cust_ie->len);
+ travel_len = 0;
+ /* conversion for index, mask, len */
+ if (resp_len == sizeof(t_u16))
+ cust_ie->ie_data_list[0].ie_index =
+ wlan_cpu_to_le16(cust_ie->ie_data_list[0].ie_index);
+
+ while (resp_len > sizeof(t_u16)) {
+ cptr =
+ (custom_ie *) (((t_u8 *) cust_ie->ie_data_list) +
+ travel_len);
+ cptr->ie_index = wlan_le16_to_cpu(cptr->ie_index);
+ cptr->mgmt_subtype_mask =
+ wlan_le16_to_cpu(cptr->mgmt_subtype_mask);
+ cptr->ie_length = wlan_le16_to_cpu(cptr->ie_length);
+ travel_len +=
+ cptr->ie_length + sizeof(custom_ie) - MAX_IE_SIZE;
+ resp_len -=
+ cptr->ie_length + sizeof(custom_ie) - MAX_IE_SIZE;
+ }
+ memcpy(pmpriv->adapter, &misc->param.cust_ie, cust_ie,
+ MIN(sizeof(mlan_ds_misc_custom_ie) -
+ sizeof(tlvbuf_max_mgmt_ie),
+ (cust_ie->len + sizeof(MrvlIEtypesHeader_t))));
+ if (max_mgmt_ie) {
+ max_mgmt_ie->type = wlan_le16_to_cpu(max_mgmt_ie->type);
+ if (max_mgmt_ie->type == TLV_TYPE_MAX_MGMT_IE) {
+ max_mgmt_ie->len = wlan_le16_to_cpu(max_mgmt_ie->len);
+ max_mgmt_ie->count =
+ wlan_le16_to_cpu(max_mgmt_ie->count);
+ for (i = 0; i < max_mgmt_ie->count; i++) {
+ max_mgmt_ie->info[i].buf_size =
+ wlan_le16_to_cpu(max_mgmt_ie->info[i].buf_size);
+ max_mgmt_ie->info[i].buf_count =
+ wlan_le16_to_cpu(max_mgmt_ie->info[i].
+ buf_count);
+ }
+ /* Append max_mgmt_ie TLV after custom_ie */
+ memcpy(pmpriv->adapter,
+ (t_u8 *) & misc->param.cust_ie + (cust_ie->len +
+ sizeof
+ (MrvlIEtypesHeader_t)),
+ max_mgmt_ie, MIN(sizeof(tlvbuf_max_mgmt_ie),
+ max_mgmt_ie->len +
+ sizeof(MrvlIEtypesHeader_t)));
+ }
+ }
+ }
+ }
+ } else { /* no ioctl: driver generated get/set */
+ switch (wlan_le16_to_cpu(tlv->header.type)) {
+ case TLV_TYPE_UAP_MAC_ADDRESS:
+ memcpy(pmpriv->adapter, pmpriv->curr_addr, tlv->mac,
+ MLAN_MAC_ADDR_LENGTH);
+ break;
+ case TLV_TYPE_UAP_CHAN_BAND_CONFIG:
+ tlv_cb = (MrvlIEtypes_channel_band_t *) tlv;
+ pmpriv->uap_state_chan_cb.band_config = tlv_cb->band_config;
+ pmpriv->uap_state_chan_cb.channel = tlv_cb->channel;
+ /* call callback waiting for channel info */
+ if (pmpriv->uap_state_chan_cb.get_chan_callback)
+ pmpriv->uap_state_chan_cb.get_chan_callback(pmpriv);
+ break;
+ case TLV_TYPE_UAP_BEACON_PERIOD:
+ tlv_bcnpd = (MrvlIEtypes_beacon_period_t *) tlv;
+ pmpriv->uap_state_chan_cb.beacon_period =
+ wlan_le16_to_cpu(tlv_bcnpd->beacon_period);
+ /* copy dtim_period as well if it follows */
+ tlv_dtimpd =
+ (MrvlIEtypes_dtim_period_t *) (((t_u8 *) tlv) +
+ sizeof
+ (MrvlIEtypes_beacon_period_t));
+ if (TLV_TYPE_UAP_DTIM_PERIOD ==
+ wlan_le16_to_cpu(tlv_dtimpd->header.type))
+ pmpriv->uap_state_chan_cb.dtim_period = tlv_dtimpd->dtim_period;
+ /* call callback waiting for beacon/dtim info */
+ if (pmpriv->uap_state_chan_cb.get_chan_callback)
+ pmpriv->uap_state_chan_cb.get_chan_callback(pmpriv);
+ break;
+ case TLV_TYPE_MGMT_IE:
+ if ((pmpriv->adapter->state_rdh.stage == RDH_SET_CUSTOM_IE) ||
+ (pmpriv->adapter->state_rdh.stage == RDH_REM_CUSTOM_IE))
+ wlan_11h_radar_detected_callback((t_void *) pmpriv);
+ break;
+ }
+ }
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function prepares command of snmp_mib
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param cmd A pointer to HostCmd_DS_COMMAND structure
+ * @param cmd_action the action: GET or SET
+ * @param cmd_oid Cmd oid: treated as sub command
+ * @param pioctl_buf A pointer to mlan_ioctl_req structure
+ * @param pdata_buf A pointer to information buffer
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+static mlan_status
+wlan_uap_cmd_snmp_mib(pmlan_private pmpriv,
+ IN HostCmd_DS_COMMAND * cmd,
+ IN t_u16 cmd_action,
+ IN t_u32 cmd_oid,
+ IN pmlan_ioctl_req pioctl_buf, IN t_void * pdata_buf)
+{
+ HostCmd_DS_802_11_SNMP_MIB *psnmp_mib = &cmd->params.smib;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ t_u8 *psnmp_oid = MNULL;
+ t_u32 ul_temp;
+ t_u8 i;
+
+ t_u8 snmp_oids[] = {
+ tkip_mic_failures,
+ ccmp_decrypt_errors,
+ wep_undecryptable_count,
+ wep_icv_error_count,
+ decrypt_failure_count,
+ dot11_mcast_tx_count,
+ dot11_failed_count,
+ dot11_retry_count,
+ dot11_multi_retry_count,
+ dot11_frame_dup_count,
+ dot11_rts_success_count,
+ dot11_rts_failure_count,
+ dot11_ack_failure_count,
+ dot11_rx_fragment_count,
+ dot11_mcast_rx_frame_count,
+ dot11_fcs_error_count,
+ dot11_tx_frame_count,
+ dot11_rsna_tkip_cm_invoked,
+ dot11_rsna_4way_hshk_failures,
+ };
+
+ ENTER();
+
+ if (cmd_action == HostCmd_ACT_GEN_GET) {
+ cmd->command = wlan_cpu_to_le16(HostCmd_CMD_802_11_SNMP_MIB);
+ psnmp_mib->query_type = wlan_cpu_to_le16(HostCmd_ACT_GEN_GET);
+ cmd->size =
+ wlan_cpu_to_le16(sizeof(t_u16) + S_DS_GEN +
+ sizeof(snmp_oids) *
+ sizeof(MrvlIEtypes_snmp_oid_t));
+ psnmp_oid = (t_u8 *) & psnmp_mib->oid;
+ for (i = 0; i < sizeof(snmp_oids); i++) {
+ /* SNMP OID header type */
+ *(t_u16 *) psnmp_oid = wlan_cpu_to_le16(snmp_oids[i]);
+ psnmp_oid += sizeof(t_u16);
+ /* SNMP OID header length */
+ *(t_u16 *) psnmp_oid = wlan_cpu_to_le16(sizeof(t_u32));
+ psnmp_oid += sizeof(t_u16) + sizeof(t_u32);
+ }
+ } else { /* cmd_action == ACT_SET */
+ cmd->command = wlan_cpu_to_le16(HostCmd_CMD_802_11_SNMP_MIB);
+ cmd->size = sizeof(HostCmd_DS_802_11_SNMP_MIB) - 1 + S_DS_GEN;
+ psnmp_mib->query_type = wlan_cpu_to_le16(HostCmd_ACT_GEN_SET);
+
+ switch (cmd_oid) {
+ case Dot11D_i:
+ case Dot11H_i:
+ psnmp_mib->oid = wlan_cpu_to_le16((t_u16) cmd_oid);
+ psnmp_mib->buf_size = wlan_cpu_to_le16(sizeof(t_u16));
+ ul_temp = *(t_u32 *) pdata_buf;
+ *((t_u16 *) (psnmp_mib->value)) = wlan_cpu_to_le16((t_u16) ul_temp);
+ cmd->size += sizeof(t_u16);
+ break;
+ default:
+ PRINTM(MERROR, "Unsupported OID.\n");
+ ret = MLAN_STATUS_FAILURE;
+ break;
+ }
+ cmd->size = wlan_cpu_to_le16(cmd->size);
+ }
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function handles the command response of snmp_mib
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param resp A pointer to HostCmd_DS_COMMAND
+ * @param pioctl_buf A pointer to mlan_ioctl_req structure
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+static mlan_status
+wlan_uap_ret_snmp_mib(IN pmlan_private pmpriv,
+ IN HostCmd_DS_COMMAND * resp,
+ IN mlan_ioctl_req * pioctl_buf)
+{
+ pmlan_adapter pmadapter = pmpriv->adapter;
+ HostCmd_DS_802_11_SNMP_MIB *psnmp_mib =
+ (HostCmd_DS_802_11_SNMP_MIB *) & resp->params.smib;
+ mlan_ds_get_info *info;
+ t_u8 *psnmp_oid = MNULL;
+ t_u32 data;
+ t_u16 tlv_buf_left = 0;
+ t_u16 tlv_type = 0;
+
+ ENTER();
+ if (psnmp_mib->query_type == HostCmd_ACT_GEN_GET) {
+ if (!pioctl_buf) {
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+ }
+ info = (mlan_ds_get_info *) pioctl_buf->pbuf;
+ tlv_buf_left = resp->size - (sizeof(t_u16) + S_DS_GEN);
+ psnmp_oid = (t_u8 *) & psnmp_mib->oid;
+ while (tlv_buf_left >= sizeof(MrvlIEtypes_snmp_oid_t)) {
+ tlv_type = wlan_le16_to_cpu(*(t_u16 *) psnmp_oid);
+ psnmp_oid += sizeof(t_u16) + sizeof(t_u16);
+ memcpy(pmadapter, &data, psnmp_oid, sizeof(t_u32));
+ switch (tlv_type) {
+ case tkip_mic_failures:
+ info->param.ustats.tkip_mic_failures = wlan_le32_to_cpu(data);
+ break;
+ case ccmp_decrypt_errors:
+ info->param.ustats.ccmp_decrypt_errors = wlan_le32_to_cpu(data);
+ break;
+ case wep_undecryptable_count:
+ info->param.ustats.wep_undecryptable_count =
+ wlan_le32_to_cpu(data);
+ break;
+ case wep_icv_error_count:
+ info->param.ustats.wep_icv_error_count = wlan_le32_to_cpu(data);
+ break;
+ case decrypt_failure_count:
+ info->param.ustats.decrypt_failure_count =
+ wlan_le32_to_cpu(data);
+ break;
+ case dot11_mcast_tx_count:
+ info->param.ustats.mcast_tx_count = wlan_le32_to_cpu(data);
+ break;
+ case dot11_failed_count:
+ info->param.ustats.failed_count = wlan_le32_to_cpu(data);
+ break;
+ case dot11_retry_count:
+ info->param.ustats.retry_count = wlan_le32_to_cpu(data);
+ break;
+ case dot11_multi_retry_count:
+ info->param.ustats.multi_retry_count = wlan_le32_to_cpu(data);
+ break;
+ case dot11_frame_dup_count:
+ info->param.ustats.frame_dup_count = wlan_le32_to_cpu(data);
+ break;
+ case dot11_rts_success_count:
+ info->param.ustats.rts_success_count = wlan_le32_to_cpu(data);
+ break;
+ case dot11_rts_failure_count:
+ info->param.ustats.rts_failure_count = wlan_le32_to_cpu(data);
+ break;
+ case dot11_ack_failure_count:
+ info->param.ustats.ack_failure_count = wlan_le32_to_cpu(data);
+ break;
+ case dot11_rx_fragment_count:
+ info->param.ustats.rx_fragment_count = wlan_le32_to_cpu(data);
+ break;
+ case dot11_mcast_rx_frame_count:
+ info->param.ustats.mcast_rx_frame_count =
+ wlan_le32_to_cpu(data);
+ break;
+ case dot11_fcs_error_count:
+ info->param.ustats.fcs_error_count = wlan_le32_to_cpu(data);
+ break;
+ case dot11_tx_frame_count:
+ info->param.ustats.tx_frame_count = wlan_le32_to_cpu(data);
+ break;
+ case dot11_rsna_tkip_cm_invoked:
+ info->param.ustats.rsna_tkip_cm_invoked =
+ wlan_le32_to_cpu(data);
+ break;
+ case dot11_rsna_4way_hshk_failures:
+ info->param.ustats.rsna_4way_hshk_failures =
+ wlan_le32_to_cpu(data);
+ break;
+ }
+ tlv_buf_left -= sizeof(MrvlIEtypes_snmp_oid_t);
+ psnmp_oid += sizeof(t_u32);
+ }
+ } else { /* ACT_SET */
+ switch (psnmp_mib->oid) {
+ case Dot11D_i:
+ data = wlan_le16_to_cpu(*((t_u16 *) (psnmp_mib->value)));
+ /* Set 11d state to private */
+ pmpriv->state_11d.enable_11d = data;
+ /* Set user enable flag if called from ioctl */
+ if (pioctl_buf)
+ pmpriv->state_11d.user_enable_11d = data;
+ break;
+ case Dot11H_i:
+ data = wlan_le16_to_cpu(*((t_u16 *) (psnmp_mib->value)));
+ /* Set 11h state to priv */
+ pmpriv->intf_state_11h.is_11h_active = (data & ENABLE_11H_MASK);
+ /* Set radar_det state to adapter */
+ pmpriv->adapter->state_11h.is_master_radar_det_active
+ = (data & MASTER_RADAR_DET_MASK) ? MTRUE : MFALSE;
+ pmpriv->adapter->state_11h.is_slave_radar_det_active
+ = (data & SLAVE_RADAR_DET_MASK) ? MTRUE : MFALSE;
+ break;
+ }
+ }
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function prepares command of deauth station
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param cmd A pointer to HostCmd_DS_COMMAND structure
+ * @param pdata_buf A pointer to data buffer
+ * @return MLAN_STATUS_SUCCESS
+ */
+static mlan_status
+wlan_uap_cmd_sta_deauth(pmlan_private pmpriv,
+ IN HostCmd_DS_COMMAND * cmd, IN t_void * pdata_buf)
+{
+ HostCmd_DS_STA_DEAUTH *pcmd_sta_deauth =
+ (HostCmd_DS_STA_DEAUTH *) & cmd->params.sta_deauth;
+ mlan_deauth_param *deauth = (mlan_deauth_param *) pdata_buf;
+
+ ENTER();
+ cmd->command = wlan_cpu_to_le16(HOST_CMD_APCMD_STA_DEAUTH);
+ cmd->size = wlan_cpu_to_le16(S_DS_GEN + sizeof(HostCmd_DS_STA_DEAUTH));
+ memcpy(pmpriv->adapter, pcmd_sta_deauth->mac, deauth->mac_addr,
+ MLAN_MAC_ADDR_LENGTH);
+ pcmd_sta_deauth->reason = wlan_cpu_to_le16(deauth->reason_code);
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function prepares command of key material
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param cmd A pointer to HostCmd_DS_COMMAND structure
+ * @param cmd_action The action: GET or SET
+ * @param cmd_oid OID: ENABLE or DISABLE
+ * @param pdata_buf A pointer to data buffer
+ * @return MLAN_STATUS_SUCCESS
+ */
+static mlan_status
+wlan_uap_cmd_key_material(IN pmlan_private pmpriv,
+ IN HostCmd_DS_COMMAND * cmd,
+ IN t_u16 cmd_action,
+ IN t_u16 cmd_oid, IN t_void * pdata_buf)
+{
+ HostCmd_DS_802_11_KEY_MATERIAL *pkey_material = &cmd->params.key_material;
+ mlan_ds_encrypt_key *pkey = (mlan_ds_encrypt_key *) pdata_buf;
+ MrvlIEtypes_MacAddr_t *tlv = MNULL;
+ const t_u8 bc_mac[] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
+ t_u16 key_param_len = 0;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ sta_node *sta_ptr = MNULL;
+
+ ENTER();
+
+ cmd->command = wlan_cpu_to_le16(HostCmd_CMD_802_11_KEY_MATERIAL);
+ pkey_material->action = wlan_cpu_to_le16(cmd_action);
+
+ if (cmd_action == HostCmd_ACT_GEN_GET) {
+ cmd->size = wlan_cpu_to_le16(sizeof(pkey_material->action) + S_DS_GEN);
+ goto done;
+ }
+
+ memset(pmpriv->adapter, &pkey_material->key_param_set, 0,
+ sizeof(MrvlIEtype_KeyParamSet_t));
+ if (pkey->is_wapi_key) {
+ PRINTM(MINFO, "Set WAPI Key\n");
+ pkey_material->key_param_set.key_type_id =
+ wlan_cpu_to_le16(KEY_TYPE_ID_WAPI);
+ if (cmd_oid == KEY_INFO_ENABLED)
+ pkey_material->key_param_set.key_info =
+ wlan_cpu_to_le16(KEY_INFO_WAPI_ENABLED);
+ else
+ pkey_material->key_param_set.key_info =
+ !(wlan_cpu_to_le16(KEY_INFO_WAPI_ENABLED));
+
+ pkey_material->key_param_set.key[0] = pkey->key_index;
+ if (!pmpriv->sec_info.wapi_key_on)
+ pkey_material->key_param_set.key[1] = 1;
+ else
+ pkey_material->key_param_set.key[1] = 0; /* set 0 when re-key */
+
+ if (0 != memcmp(pmpriv->adapter, pkey->mac_addr, bc_mac, sizeof(bc_mac))) { /* WAPI
+ pairwise
+ key:
+ unicast
+ */
+ pkey_material->key_param_set.key_info |=
+ wlan_cpu_to_le16(KEY_INFO_WAPI_UNICAST);
+ if ((sta_ptr = wlan_add_station_entry(pmpriv, pkey->mac_addr))) {
+ PRINTM(MCMND, "station: wapi_key_on\n");
+ sta_ptr->wapi_key_on = MTRUE;
+ }
+ } else { /* WAPI group key: multicast */
+ pkey_material->key_param_set.key_info |=
+ wlan_cpu_to_le16(KEY_INFO_WAPI_MCAST);
+ pmpriv->sec_info.wapi_key_on = MTRUE;
+ }
+ pkey_material->key_param_set.type =
+ wlan_cpu_to_le16(TLV_TYPE_KEY_MATERIAL);
+ pkey_material->key_param_set.key_len = wlan_cpu_to_le16(WAPI_KEY_LEN);
+ memcpy(pmpriv->adapter, &pkey_material->key_param_set.key[2],
+ pkey->key_material, pkey->key_len);
+ pkey_material->key_param_set.length =
+ wlan_cpu_to_le16(WAPI_KEY_LEN + KEYPARAMSET_FIXED_LEN);
+
+ key_param_len =
+ (WAPI_KEY_LEN + KEYPARAMSET_FIXED_LEN) +
+ sizeof(MrvlIEtypesHeader_t);
+ tlv =
+ (MrvlIEtypes_MacAddr_t *) ((t_u8 *) & pkey_material->key_param_set +
+ key_param_len);
+ tlv->header.type = wlan_cpu_to_le16(TLV_TYPE_STA_MAC_ADDRESS);
+ tlv->header.len = wlan_cpu_to_le16(MLAN_MAC_ADDR_LENGTH);
+ memcpy(pmpriv->adapter, tlv->mac, pkey->mac_addr, MLAN_MAC_ADDR_LENGTH);
+ cmd->size =
+ wlan_cpu_to_le16(key_param_len + sizeof(pkey_material->action) +
+ S_DS_GEN + sizeof(MrvlIEtypes_MacAddr_t));
+ goto done;
+ }
+ if (pkey->key_len == WPA_AES_KEY_LEN) {
+ PRINTM(MCMND, "WPA_AES\n");
+ pkey_material->key_param_set.key_type_id =
+ wlan_cpu_to_le16(KEY_TYPE_ID_AES);
+ if (cmd_oid == KEY_INFO_ENABLED)
+ pkey_material->key_param_set.key_info =
+ wlan_cpu_to_le16(KEY_INFO_AES_ENABLED);
+ else
+ pkey_material->key_param_set.key_info =
+ !(wlan_cpu_to_le16(KEY_INFO_AES_ENABLED));
+
+ if (memcmp(pmpriv->adapter, pkey->mac_addr, bc_mac, sizeof(bc_mac))) /* AES
+ pairwise
+ key:
+ unicast
+ */
+ pkey_material->key_param_set.key_info |=
+ wlan_cpu_to_le16(KEY_INFO_AES_UNICAST);
+ else /* AES group key: multicast */
+ pkey_material->key_param_set.key_info |=
+ wlan_cpu_to_le16(KEY_INFO_AES_MCAST);
+ } else if (pkey->key_len == WPA_TKIP_KEY_LEN) {
+ PRINTM(MCMND, "WPA_TKIP\n");
+ pkey_material->key_param_set.key_type_id =
+ wlan_cpu_to_le16(KEY_TYPE_ID_TKIP);
+ pkey_material->key_param_set.key_info =
+ wlan_cpu_to_le16(KEY_INFO_TKIP_ENABLED);
+
+ if (memcmp(pmpriv->adapter, pkey->mac_addr, bc_mac, sizeof(bc_mac))) /* TKIP
+ pairwise
+ key:
+ unicast
+ */
+ pkey_material->key_param_set.key_info |=
+ wlan_cpu_to_le16(KEY_INFO_TKIP_UNICAST);
+ else /* TKIP group key: multicast */
+ pkey_material->key_param_set.key_info |=
+ wlan_cpu_to_le16(KEY_INFO_TKIP_MCAST);
+ }
+
+ if (pkey_material->key_param_set.key_type_id) {
+ pkey_material->key_param_set.type =
+ wlan_cpu_to_le16(TLV_TYPE_KEY_MATERIAL);
+ pkey_material->key_param_set.key_len = wlan_cpu_to_le16(pkey->key_len);
+ memcpy(pmpriv->adapter, pkey_material->key_param_set.key,
+ pkey->key_material, pkey->key_len);
+ pkey_material->key_param_set.length =
+ wlan_cpu_to_le16((t_u16) pkey->key_len + KEYPARAMSET_FIXED_LEN);
+ key_param_len =
+ (pkey->key_len + KEYPARAMSET_FIXED_LEN) +
+ sizeof(MrvlIEtypesHeader_t);
+
+ tlv =
+ (MrvlIEtypes_MacAddr_t *) ((t_u8 *) & pkey_material->key_param_set +
+ key_param_len);
+ tlv->header.type = wlan_cpu_to_le16(TLV_TYPE_STA_MAC_ADDRESS);
+ tlv->header.len = wlan_cpu_to_le16(MLAN_MAC_ADDR_LENGTH);
+ memcpy(pmpriv->adapter, tlv->mac, pkey->mac_addr, MLAN_MAC_ADDR_LENGTH);
+ cmd->size =
+ wlan_cpu_to_le16(key_param_len + sizeof(pkey_material->action) +
+ S_DS_GEN + sizeof(MrvlIEtypes_MacAddr_t));
+ }
+ done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function handles the command response of sta_list
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param resp A pointer to HostCmd_DS_COMMAND
+ * @param pioctl_buf A pointer to mlan_ioctl_req structure
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+static mlan_status
+wlan_uap_ret_sta_list(IN pmlan_private pmpriv,
+ IN HostCmd_DS_COMMAND * resp,
+ IN mlan_ioctl_req * pioctl_buf)
+{
+ HostCmd_DS_STA_LIST *sta_list =
+ (HostCmd_DS_STA_LIST *) & resp->params.sta_list;
+ mlan_ds_get_info *info;
+ MrvlIEtypes_sta_info_t *tlv = MNULL;
+ t_u8 i = 0;
+
+ ENTER();
+ if (pioctl_buf) {
+ info = (mlan_ds_get_info *) pioctl_buf->pbuf;
+ info->param.sta_list.sta_count = wlan_le16_to_cpu(sta_list->sta_count);
+ tlv =
+ (MrvlIEtypes_sta_info_t *) ((t_u8 *) sta_list +
+ sizeof(HostCmd_DS_STA_LIST));
+ info->param.sta_list.sta_count =
+ MIN(info->param.sta_list.sta_count, MAX_NUM_CLIENTS);
+ for (i = 0; i < info->param.sta_list.sta_count; i++) {
+ memcpy(pmpriv->adapter, info->param.sta_list.info[i].mac_address,
+ tlv->mac_address, MLAN_MAC_ADDR_LENGTH);
+ info->param.sta_list.info[i].power_mfg_status =
+ tlv->power_mfg_status;
+ info->param.sta_list.info[i].rssi = tlv->rssi;
+ tlv++;
+ }
+ }
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function will search for the specific ie
+ *
+ *
+ * @param priv A pointer to mlan_private
+ * @param pevent A pointer to event buf
+ * @param sta_ptr A pointer to sta_node
+ *
+ * @return N/A
+ */
+static void
+wlan_check_sta_capability(pmlan_private priv, pmlan_buffer pevent,
+ sta_node * sta_ptr)
+{
+ t_u16 tlv_type, tlv_len;
+ t_u16 frame_control, frame_sub_type = 0;
+ t_u8 *assoc_req_ie = MNULL;
+ t_u8 ie_len = 0, assoc_ie_len = 0;
+ IEEEtypes_HTCap_t *pht_cap = MNULL;
+ int tlv_buf_left = pevent->data_len - ASSOC_EVENT_FIX_SIZE;
+ MrvlIEtypesHeader_t *tlv = (MrvlIEtypesHeader_t *)
+ (pevent->pbuf + pevent->data_offset + ASSOC_EVENT_FIX_SIZE);
+ MrvlIETypes_MgmtFrameSet_t *mgmt_tlv = MNULL;
+
+ ENTER();
+ while (tlv_buf_left >= (int) sizeof(MrvlIEtypesHeader_t)) {
+ tlv_type = wlan_le16_to_cpu(tlv->type);
+ tlv_len = wlan_le16_to_cpu(tlv->len);
+ if ((sizeof(MrvlIEtypesHeader_t) + tlv_len) >
+ (unsigned int) tlv_buf_left) {
+ PRINTM(MERROR, "wrong tlv: tlvLen=%d, tlvBufLeft=%d\n", tlv_len,
+ tlv_buf_left);
+ break;
+ }
+ if (tlv_type == TLV_TYPE_UAP_MGMT_FRAME) {
+ mgmt_tlv = (MrvlIETypes_MgmtFrameSet_t *) tlv;
+ memcpy(priv->adapter, &frame_control,
+ (t_u8 *) & (mgmt_tlv->frame_control), sizeof(frame_control));
+ frame_sub_type = IEEE80211_GET_FC_MGMT_FRAME_SUBTYPE(frame_control);
+ if ((mgmt_tlv->frame_control.type == 0) &&
+ ((frame_sub_type == SUBTYPE_ASSOC_REQUEST) ||
+ (frame_sub_type == SUBTYPE_REASSOC_REQUEST))) {
+
+ if (frame_sub_type == SUBTYPE_ASSOC_REQUEST)
+ assoc_ie_len = sizeof(IEEEtypes_AssocRqst_t);
+ else if (frame_sub_type == SUBTYPE_REASSOC_REQUEST)
+ assoc_ie_len = sizeof(IEEEtypes_ReAssocRqst_t);
+
+ ie_len = tlv_len - sizeof(IEEEtypes_FrameCtl_t) - assoc_ie_len;
+ assoc_req_ie =
+ (t_u8 *) tlv + sizeof(MrvlIETypes_MgmtFrameSet_t) +
+ assoc_ie_len;
+ pht_cap =
+ (IEEEtypes_HTCap_t *) wlan_get_specific_ie(priv,
+ assoc_req_ie,
+ ie_len,
+ HT_CAPABILITY);
+ if (pht_cap) {
+ PRINTM(MCMND, "STA supports 11n\n");
+ sta_ptr->is_11n_enabled = MTRUE;
+ if (GETHT_MAXAMSDU(pht_cap->ht_cap.ht_cap_info))
+ sta_ptr->max_amsdu = MLAN_TX_DATA_BUF_SIZE_8K;
+ else
+ sta_ptr->max_amsdu = MLAN_TX_DATA_BUF_SIZE_4K;
+ } else {
+ PRINTM(MCMND, "STA doesn't support 11n\n");
+ }
+ break;
+ }
+ }
+ tlv_buf_left -= (sizeof(MrvlIEtypesHeader_t) + tlv_len);
+ tlv =
+ (MrvlIEtypesHeader_t *) ((t_u8 *) tlv + tlv_len +
+ sizeof(MrvlIEtypesHeader_t));
+ }
+ LEAVE();
+
+ return;
+}
+
+/** Fixed size of bss start event */
+#define BSS_START_EVENT_FIX_SIZE 12
+
+/**
+ * @brief This function will search for the specific ie
+ *
+ *
+ * @param priv A pointer to mlan_private
+ * @param pevent A pointer to event buf
+ *
+ * @return N/A
+ */
+static void
+wlan_check_uap_capability(pmlan_private priv, pmlan_buffer pevent)
+{
+ t_u16 tlv_type, tlv_len;
+ int tlv_buf_left = pevent->data_len - BSS_START_EVENT_FIX_SIZE;
+ MrvlIEtypesHeader_t *tlv =
+ (MrvlIEtypesHeader_t *) (pevent->pbuf + pevent->data_offset +
+ BSS_START_EVENT_FIX_SIZE);
+ const t_u8 wmm_oui[4] = { 0x00, 0x50, 0xf2, 0x02 };
+ IEEEtypes_WmmParameter_t *pWmmParamIe = MNULL;
+ priv->wmm_enabled = MFALSE;
+ priv->pkt_fwd = MFALSE;
+ priv->is_11n_enabled = MFALSE;
+
+ ENTER();
+
+ while (tlv_buf_left >= (int) sizeof(MrvlIEtypesHeader_t)) {
+ tlv_type = wlan_le16_to_cpu(tlv->type);
+ tlv_len = wlan_le16_to_cpu(tlv->len);
+ if ((sizeof(MrvlIEtypesHeader_t) + tlv_len) >
+ (unsigned int) tlv_buf_left) {
+ PRINTM(MERROR, "wrong tlv: tlvLen=%d, tlvBufLeft=%d\n", tlv_len,
+ tlv_buf_left);
+ break;
+ }
+ if (tlv_type == HT_CAPABILITY) {
+ DBG_HEXDUMP(MCMD_D, "HT_CAP tlv", tlv,
+ tlv_len + sizeof(MrvlIEtypesHeader_t));
+ priv->is_11n_enabled = MTRUE;
+ }
+ if (tlv_type == VENDOR_SPECIFIC_221) {
+ if (!memcmp
+ (priv->adapter, (t_u8 *) tlv + sizeof(MrvlIEtypesHeader_t),
+ wmm_oui, sizeof(wmm_oui))) {
+ DBG_HEXDUMP(MCMD_D, "wmm ie tlv", tlv,
+ tlv_len + sizeof(MrvlIEtypesHeader_t));
+ priv->wmm_enabled = MFALSE;
+ wlan_wmm_setup_ac_downgrade(priv);
+ priv->wmm_enabled = MTRUE;
+ pWmmParamIe = (IEEEtypes_WmmParameter_t *) ((t_u8 *) tlv + 2);
+ pWmmParamIe->vend_hdr.len = (t_u8) tlv_len;
+ pWmmParamIe->vend_hdr.element_id = WMM_IE;
+ wlan_wmm_setup_queue_priorities(priv, pWmmParamIe);
+ }
+ }
+ if (tlv_type == TLV_TYPE_UAP_PKT_FWD_CTL) {
+ DBG_HEXDUMP(MCMD_D, "pkt_fwd tlv", tlv,
+ tlv_len + sizeof(MrvlIEtypesHeader_t));
+ priv->pkt_fwd = *((t_u8 *) tlv + sizeof(MrvlIEtypesHeader_t));
+ PRINTM(MCMND, "pkt_fwd FW: 0x%x\n", priv->pkt_fwd);
+ if (priv->pkt_fwd & PKT_FWD_FW_BIT)
+ priv->pkt_fwd = MFALSE;
+ else
+ priv->pkt_fwd |= PKT_FWD_ENABLE_BIT;
+ PRINTM(MCMND, "pkt_fwd DRV: 0x%x\n", priv->pkt_fwd);
+ }
+ tlv_buf_left -= (sizeof(MrvlIEtypesHeader_t) + tlv_len);
+ tlv =
+ (MrvlIEtypesHeader_t *) ((t_u8 *) tlv + tlv_len +
+ sizeof(MrvlIEtypesHeader_t));
+ }
+ if (priv->wmm_enabled == MFALSE) {
+ /* Since WMM is not enabled, setup the queues with the defaults */
+ wlan_wmm_setup_queues(priv);
+ }
+
+ LEAVE();
+}
+
+/**
+ * @brief This function will update WAPI PN in statation assoc event
+ *
+ *
+ * @param priv A pointer to mlan_private
+ * @param pevent A pointer to event buf
+ *
+ * @return MFALSE
+ */
+static t_u32
+wlan_update_wapi_info_tlv(pmlan_private priv, pmlan_buffer pevent)
+{
+ t_u32 ret = MFALSE;
+ t_u16 tlv_type, tlv_len;
+ t_u32 tx_pn[4];
+ t_u32 i = 0;
+ int tlv_buf_left = pevent->data_len - ASSOC_EVENT_FIX_SIZE;
+ MrvlIEtypesHeader_t *tlv = (MrvlIEtypesHeader_t *)
+ (pevent->pbuf + pevent->data_offset + ASSOC_EVENT_FIX_SIZE);
+ MrvlIEtypes_wapi_info_t *wapi_tlv = MNULL;
+
+ ENTER();
+ while (tlv_buf_left >= (int) sizeof(MrvlIEtypesHeader_t)) {
+ tlv_type = wlan_le16_to_cpu(tlv->type);
+ tlv_len = wlan_le16_to_cpu(tlv->len);
+ if ((sizeof(MrvlIEtypesHeader_t) + tlv_len) >
+ (unsigned int) tlv_buf_left) {
+ PRINTM(MERROR, "wrong tlv: tlvLen=%d, tlvBufLeft=%d\n", tlv_len,
+ tlv_buf_left);
+ break;
+ }
+ if (tlv_type == TLV_TYPE_AP_WAPI_INFO) {
+ wapi_tlv = (MrvlIEtypes_wapi_info_t *) tlv;
+ DBG_HEXDUMP(MCMD_D, "Fw:multicast_PN", wapi_tlv->multicast_PN,
+ PN_SIZE);
+ memcpy(priv->adapter, (t_u8 *) tx_pn, wapi_tlv->multicast_PN,
+ PN_SIZE);
+ for (i = 0; i < 4; i++)
+ tx_pn[i] = mlan_ntohl(tx_pn[i]);
+ memcpy(priv->adapter, wapi_tlv->multicast_PN, (t_u8 *) tx_pn,
+ PN_SIZE);
+ DBG_HEXDUMP(MCMD_D, "Host:multicast_PN", wapi_tlv->multicast_PN,
+ PN_SIZE);
+ break;
+ }
+ tlv_buf_left -= (sizeof(MrvlIEtypesHeader_t) + tlv_len);
+ tlv =
+ (MrvlIEtypesHeader_t *) ((t_u8 *) tlv + tlv_len +
+ sizeof(MrvlIEtypesHeader_t));
+ }
+ LEAVE();
+
+ return ret;
+}
+
+/**
+ * @brief This function send sta_assoc_event to moal
+ * payload with sta mac address and assoc ie.
+ *
+ * @param priv A pointer to mlan_private
+ * @param pevent A pointer to mlan_event buffer
+ * @param pbuf A pointer to mlan_buffer which has event content.
+ *
+ * @return MFALSE
+ */
+static t_u32
+wlan_process_sta_assoc_event(pmlan_private priv, mlan_event * pevent,
+ pmlan_buffer pmbuf)
+{
+ t_u32 ret = MFALSE;
+ t_u16 tlv_type, tlv_len;
+ t_u16 frame_control, frame_sub_type = 0;
+ t_u8 *assoc_req_ie = MNULL;
+ t_u8 ie_len = 0, assoc_ie_len = 0;
+ int tlv_buf_left = pmbuf->data_len - ASSOC_EVENT_FIX_SIZE;
+ MrvlIEtypesHeader_t *tlv = (MrvlIEtypesHeader_t *)
+ (pmbuf->pbuf + pmbuf->data_offset + ASSOC_EVENT_FIX_SIZE);
+ MrvlIETypes_MgmtFrameSet_t *mgmt_tlv = MNULL;
+
+ ENTER();
+ pevent->event_id = MLAN_EVENT_ID_UAP_FW_STA_CONNECT;
+ pevent->bss_index = priv->bss_index;
+ pevent->event_len = MLAN_MAC_ADDR_LENGTH;
+ memcpy(priv->adapter, pevent->event_buf,
+ pmbuf->pbuf + pmbuf->data_offset + 6, pevent->event_len);
+ while (tlv_buf_left >= (int) sizeof(MrvlIEtypesHeader_t)) {
+ tlv_type = wlan_le16_to_cpu(tlv->type);
+ tlv_len = wlan_le16_to_cpu(tlv->len);
+ if ((sizeof(MrvlIEtypesHeader_t) + tlv_len) >
+ (unsigned int) tlv_buf_left) {
+ PRINTM(MERROR, "wrong tlv: tlvLen=%d, tlvBufLeft=%d\n", tlv_len,
+ tlv_buf_left);
+ break;
+ }
+ if (tlv_type == TLV_TYPE_UAP_MGMT_FRAME) {
+ mgmt_tlv = (MrvlIETypes_MgmtFrameSet_t *) tlv;
+ memcpy(priv->adapter, &frame_control,
+ (t_u8 *) & (mgmt_tlv->frame_control), sizeof(frame_control));
+ frame_sub_type = IEEE80211_GET_FC_MGMT_FRAME_SUBTYPE(frame_control);
+ if ((mgmt_tlv->frame_control.type == 0) &&
+ ((frame_sub_type == SUBTYPE_ASSOC_REQUEST) ||
+ (frame_sub_type == SUBTYPE_REASSOC_REQUEST))) {
+
+ if (frame_sub_type == SUBTYPE_ASSOC_REQUEST)
+ assoc_ie_len = sizeof(IEEEtypes_AssocRqst_t);
+ else if (frame_sub_type == SUBTYPE_REASSOC_REQUEST)
+ assoc_ie_len = sizeof(IEEEtypes_ReAssocRqst_t);
+
+ ie_len = tlv_len - sizeof(IEEEtypes_FrameCtl_t) - assoc_ie_len;
+ assoc_req_ie =
+ (t_u8 *) tlv + sizeof(MrvlIETypes_MgmtFrameSet_t) +
+ assoc_ie_len;
+ memcpy(priv->adapter, pevent->event_buf + pevent->event_len,
+ assoc_req_ie, ie_len);
+ pevent->event_len += ie_len;
+ break;
+ }
+ }
+ tlv_buf_left -= (sizeof(MrvlIEtypesHeader_t) + tlv_len);
+ tlv =
+ (MrvlIEtypesHeader_t *) ((t_u8 *) tlv + tlv_len +
+ sizeof(MrvlIEtypesHeader_t));
+ }
+ PRINTM(MEVENT, "STA assoc event len=%d\n", pevent->event_len);
+ DBG_HEXDUMP(MCMD_D, "STA assoc event", pevent->event_buf,
+ pevent->event_len);
+ wlan_recv_event(priv, pevent->event_id, pevent);
+ LEAVE();
+ return ret;
+}
+
+/********************************************************
+ Global Functions
+********************************************************/
+/**
+ * @brief This function prepare the command before sending to firmware.
+ *
+ * @param priv A pointer to mlan_private structure
+ * @param cmd_no Command number
+ * @param cmd_action Command action: GET or SET
+ * @param cmd_oid Cmd oid: treated as sub command
+ * @param pioctl_buf A pointer to MLAN IOCTL Request buffer
+ * @param pdata_buf A pointer to information buffer
+ * @param pcmd_buf A pointer to cmd buf
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status
+wlan_ops_uap_prepare_cmd(IN t_void * priv,
+ IN t_u16 cmd_no,
+ IN t_u16 cmd_action,
+ IN t_u32 cmd_oid,
+ IN t_void * pioctl_buf,
+ IN t_void * pdata_buf, IN t_void * pcmd_buf)
+{
+ HostCmd_DS_COMMAND *cmd_ptr = (HostCmd_DS_COMMAND *) pcmd_buf;
+ mlan_private *pmpriv = (mlan_private *) priv;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ pmlan_ioctl_req pioctl_req = (mlan_ioctl_req *) pioctl_buf;
+
+ ENTER();
+
+ /* Prepare command */
+ switch (cmd_no) {
+ case HostCmd_CMD_SOFT_RESET:
+ case HOST_CMD_APCMD_BSS_STOP:
+ case HOST_CMD_APCMD_BSS_START:
+ case HOST_CMD_APCMD_SYS_INFO:
+ case HOST_CMD_APCMD_SYS_RESET:
+ case HOST_CMD_APCMD_STA_LIST:
+ cmd_ptr->command = wlan_cpu_to_le16(cmd_no);
+ cmd_ptr->size = wlan_cpu_to_le16(S_DS_GEN);
+ break;
+ case HOST_CMD_APCMD_SYS_CONFIGURE:
+ ret = wlan_uap_cmd_sys_configure(pmpriv, cmd_ptr, cmd_action,
+ (pmlan_ioctl_req) pioctl_buf,
+ pdata_buf);
+ break;
+ case HostCmd_CMD_802_11_PS_MODE_ENH:
+ ret =
+ wlan_cmd_enh_power_mode(pmpriv, cmd_ptr, cmd_action,
+ (t_u16) cmd_oid, pdata_buf);
+ break;
+ case HostCmd_CMD_SDIO_GPIO_INT_CONFIG:
+ ret = wlan_cmd_sdio_gpio_int(pmpriv, cmd_ptr, cmd_action, pdata_buf);
+ break;
+ case HostCmd_CMD_FUNC_INIT:
+ if (pmpriv->adapter->hw_status == WlanHardwareStatusReset)
+ pmpriv->adapter->hw_status = WlanHardwareStatusInitializing;
+ cmd_ptr->command = wlan_cpu_to_le16(cmd_no);
+ cmd_ptr->size = wlan_cpu_to_le16(S_DS_GEN);
+ break;
+ case HostCmd_CMD_FUNC_SHUTDOWN:
+ pmpriv->adapter->hw_status = WlanHardwareStatusReset;
+ cmd_ptr->command = wlan_cpu_to_le16(cmd_no);
+ cmd_ptr->size = wlan_cpu_to_le16(S_DS_GEN);
+ break;
+ case HostCmd_CMD_CFG_DATA:
+ ret = wlan_cmd_cfg_data(pmpriv, cmd_ptr, cmd_action, pdata_buf);
+ break;
+ case HostCmd_CMD_802_11_SNMP_MIB:
+ ret = wlan_uap_cmd_snmp_mib(pmpriv, cmd_ptr, cmd_action, cmd_oid,
+ (pmlan_ioctl_req) pioctl_buf, pdata_buf);
+ break;
+ case HostCmd_CMD_802_11D_DOMAIN_INFO:
+ ret = wlan_cmd_802_11d_domain_info(pmpriv, cmd_ptr, cmd_action);
+ break;
+ case HostCmd_CMD_CHAN_REPORT_REQUEST:
+ ret = wlan_11h_cmd_process(pmpriv, cmd_ptr, pdata_buf);
+ break;
+ case HOST_CMD_APCMD_STA_DEAUTH:
+ ret = wlan_uap_cmd_sta_deauth(pmpriv, cmd_ptr, pdata_buf);
+ break;
+ case HostCmd_CMD_802_11_KEY_MATERIAL:
+ ret =
+ wlan_uap_cmd_key_material(pmpriv, cmd_ptr, cmd_action, cmd_oid,
+ pdata_buf);
+ break;
+ case HostCmd_CMD_GET_HW_SPEC:
+ ret = wlan_cmd_get_hw_spec(pmpriv, cmd_ptr);
+ break;
+ case HostCmd_CMD_802_11_HS_CFG_ENH:
+ ret =
+ wlan_uap_cmd_802_11_hs_cfg(pmpriv, cmd_ptr, cmd_action,
+ (hs_config_param *) pdata_buf);
+ break;
+ case HostCmd_CMD_RECONFIGURE_TX_BUFF:
+ ret = wlan_cmd_recfg_tx_buf(pmpriv, cmd_ptr, cmd_action, pdata_buf);
+ break;
+ case HostCmd_CMD_AMSDU_AGGR_CTRL:
+ ret = wlan_cmd_amsdu_aggr_ctrl(pmpriv, cmd_ptr, cmd_action, pdata_buf);
+ break;
+ case HostCmd_CMD_11N_ADDBA_REQ:
+ ret = wlan_cmd_11n_addba_req(pmpriv, cmd_ptr, pdata_buf);
+ break;
+ case HostCmd_CMD_11N_DELBA:
+ ret = wlan_cmd_11n_delba(pmpriv, cmd_ptr, pdata_buf);
+ break;
+ case HostCmd_CMD_11N_ADDBA_RSP:
+ ret = wlan_cmd_11n_addba_rspgen(pmpriv, cmd_ptr, pdata_buf);
+ break;
+ case HostCmd_CMD_TX_BF_CFG:
+ ret = wlan_cmd_tx_bf_cfg(pmpriv, cmd_ptr, cmd_action, pdata_buf);
+ break;
+#if defined(WIFI_DIRECT_SUPPORT)
+ case HostCmd_CMD_SET_BSS_MODE:
+ cmd_ptr->command = wlan_cpu_to_le16(cmd_no);
+ if (pdata_buf)
+ cmd_ptr->params.bss_mode.con_type = *(t_u8 *) pdata_buf;
+ else
+ cmd_ptr->params.bss_mode.con_type = BSS_MODE_WIFIDIRECT_GO;
+ cmd_ptr->size =
+ wlan_cpu_to_le16(sizeof(HostCmd_DS_SET_BSS_MODE) + S_DS_GEN);
+ ret = MLAN_STATUS_SUCCESS;
+ break;
+#endif
+ case HostCmd_CMD_VERSION_EXT:
+ cmd_ptr->command = wlan_cpu_to_le16(cmd_no);
+ cmd_ptr->params.verext.version_str_sel =
+ (t_u8) (*((t_u32 *) pdata_buf));
+ cmd_ptr->size =
+ wlan_cpu_to_le16(sizeof(HostCmd_DS_VERSION_EXT) + S_DS_GEN);
+ ret = MLAN_STATUS_SUCCESS;
+ break;
+ case HostCmd_CMD_RX_MGMT_IND:
+ cmd_ptr->command = wlan_cpu_to_le16(cmd_no);
+ cmd_ptr->params.rx_mgmt_ind.action = wlan_cpu_to_le16(cmd_action);
+ cmd_ptr->params.rx_mgmt_ind.mgmt_subtype_mask =
+ (t_u32) (*((t_u32 *) pdata_buf));
+ cmd_ptr->size = wlan_cpu_to_le16(sizeof(t_u32) + S_DS_GEN);
+ break;
+ case HostCmd_CMD_CFG_TX_DATA_PAUSE:
+ ret = wlan_uap_cmd_txdatapause(pmpriv, cmd_ptr, cmd_action, pdata_buf);
+ break;
+ case HostCmd_CMD_802_11_RADIO_CONTROL:
+ ret =
+ wlan_cmd_802_11_radio_control(pmpriv, cmd_ptr, cmd_action,
+ pdata_buf);
+ break;
+ case HostCmd_CMD_TX_RATE_CFG:
+ ret = wlan_cmd_tx_rate_cfg(pmpriv, cmd_ptr, cmd_action, pdata_buf);
+ break;
+ case HostCmd_CMD_802_11_TX_RATE_QUERY:
+ cmd_ptr->command = wlan_cpu_to_le16(HostCmd_CMD_802_11_TX_RATE_QUERY);
+ cmd_ptr->size =
+ wlan_cpu_to_le16(sizeof(HostCmd_TX_RATE_QUERY) + S_DS_GEN);
+ pmpriv->tx_rate = 0;
+ ret = MLAN_STATUS_SUCCESS;
+ break;
+#ifdef WIFI_DIRECT_SUPPORT
+ case HostCmd_CMD_802_11_REMAIN_ON_CHANNEL:
+ ret =
+ wlan_cmd_remain_on_channel(pmpriv, cmd_ptr, cmd_action, pdata_buf);
+ break;
+ case HOST_CMD_WIFI_DIRECT_MODE_CONFIG:
+ ret = wlan_cmd_wifi_direct_mode(pmpriv, cmd_ptr, cmd_action, pdata_buf);
+ break;
+#endif
+ case HostCmd_CMD_802_11_RF_ANTENNA:
+ ret =
+ wlan_cmd_802_11_rf_antenna(pmpriv, cmd_ptr, cmd_action, pdata_buf);
+ break;
+ default:
+ PRINTM(MERROR, "PREP_CMD: unknown command- %#x\n", cmd_no);
+ if (pioctl_req)
+ pioctl_req->status_code = MLAN_ERROR_CMD_INVALID;
+ ret = MLAN_STATUS_FAILURE;
+ break;
+ }
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function handles the AP mode command response
+ *
+ * @param priv A pointer to mlan_private structure
+ * @param cmdresp_no cmd no
+ * @param pcmd_buf cmdresp buf
+ * @param pioctl A pointer to ioctl buf
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status
+wlan_ops_uap_process_cmdresp(IN t_void * priv,
+ IN t_u16 cmdresp_no,
+ IN t_void * pcmd_buf, IN t_void * pioctl)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_private *pmpriv = (mlan_private *) priv;
+ HostCmd_DS_COMMAND *resp = (HostCmd_DS_COMMAND *) pcmd_buf;
+ mlan_ioctl_req *pioctl_buf = (mlan_ioctl_req *) pioctl;
+ mlan_adapter *pmadapter = pmpriv->adapter;
+ int ctr;
+
+ ENTER();
+
+ /* If the command is not successful, cleanup and return failure */
+ if (resp->result != HostCmd_RESULT_OK) {
+ uap_process_cmdresp_error(pmpriv, resp, pioctl_buf);
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+
+ /* Command successful, handle response */
+ switch (cmdresp_no) {
+ case HOST_CMD_APCMD_BSS_STOP:
+ pmpriv->uap_bss_started = MFALSE;
+ wlan_11h_check_update_radar_det_state(pmpriv);
+
+ if (pmpriv->adapter->state_rdh.stage == RDH_STOP_INTFS)
+ wlan_11h_radar_detected_callback((t_void *) pmpriv);
+ break;
+ case HOST_CMD_APCMD_BSS_START:
+ if (pmpriv->adapter->state_rdh.stage == RDH_RESTART_INTFS)
+ wlan_11h_radar_detected_callback((t_void *) pmpriv);
+ break;
+ case HOST_CMD_APCMD_SYS_RESET:
+ ret = wlan_uap_ret_sys_reset(pmpriv, resp, pioctl_buf);
+
+ pmpriv->uap_bss_started = MFALSE;
+ wlan_11h_check_update_radar_det_state(pmpriv);
+ break;
+ case HOST_CMD_APCMD_SYS_INFO:
+ break;
+ case HOST_CMD_APCMD_SYS_CONFIGURE:
+ ret = wlan_uap_ret_sys_config(pmpriv, resp, pioctl_buf);
+ break;
+ case HostCmd_CMD_802_11_PS_MODE_ENH:
+ ret = wlan_ret_enh_power_mode(pmpriv, resp, pioctl_buf);
+ break;
+ case HostCmd_CMD_SDIO_GPIO_INT_CONFIG:
+ break;
+ case HostCmd_CMD_FUNC_INIT:
+ case HostCmd_CMD_FUNC_SHUTDOWN:
+ break;
+ case HostCmd_CMD_802_11_SNMP_MIB:
+ ret = wlan_uap_ret_snmp_mib(pmpriv, resp, pioctl_buf);
+ break;
+ case HostCmd_CMD_802_11D_DOMAIN_INFO:
+ ret = wlan_ret_802_11d_domain_info(pmpriv, resp);
+ break;
+ case HostCmd_CMD_CHAN_REPORT_REQUEST:
+ ret = wlan_11h_cmdresp_process(pmpriv, resp);
+ break;
+ case HOST_CMD_APCMD_STA_DEAUTH:
+ break;
+ case HostCmd_CMD_802_11_KEY_MATERIAL:
+ break;
+ case HOST_CMD_APCMD_STA_LIST:
+ ret = wlan_uap_ret_sta_list(pmpriv, resp, pioctl_buf);
+ break;
+ case HostCmd_CMD_GET_HW_SPEC:
+ ret = wlan_ret_get_hw_spec(pmpriv, resp, pioctl_buf);
+ break;
+ case HostCmd_CMD_CFG_DATA:
+ ret = wlan_ret_cfg_data(pmpriv, resp, pioctl_buf);
+ break;
+ case HostCmd_CMD_802_11_HS_CFG_ENH:
+ ret = wlan_ret_802_11_hs_cfg(pmpriv, resp, pioctl_buf);
+ break;
+ case HostCmd_CMD_11N_ADDBA_REQ:
+ ret = wlan_ret_11n_addba_req(pmpriv, resp);
+ break;
+ case HostCmd_CMD_11N_DELBA:
+ ret = wlan_ret_11n_delba(pmpriv, resp);
+ break;
+ case HostCmd_CMD_11N_ADDBA_RSP:
+ ret = wlan_ret_11n_addba_resp(pmpriv, resp);
+ break;
+ case HostCmd_CMD_SET_BSS_MODE:
+ break;
+ case HostCmd_CMD_RECONFIGURE_TX_BUFF:
+ pmadapter->tx_buf_size =
+ (t_u16) wlan_le16_to_cpu(resp->params.tx_buf.buff_size);
+ pmadapter->tx_buf_size =
+ (pmadapter->tx_buf_size / MLAN_SDIO_BLOCK_SIZE) *
+ MLAN_SDIO_BLOCK_SIZE;
+ pmadapter->curr_tx_buf_size = pmadapter->tx_buf_size;
+ pmadapter->mp_end_port =
+ wlan_le16_to_cpu(resp->params.tx_buf.mp_end_port);
+ pmadapter->mp_data_port_mask = DATA_PORT_MASK;
+
+ for (ctr = 1; ctr <= MAX_PORT - pmadapter->mp_end_port; ctr++) {
+ pmadapter->mp_data_port_mask &= ~(1 << (MAX_PORT - ctr));
+ }
+ pmadapter->curr_wr_port = 1;
+ PRINTM(MCMND, "end port %d, data port mask %x\n",
+ wlan_le16_to_cpu(resp->params.tx_buf.mp_end_port),
+ pmadapter->mp_data_port_mask);
+ PRINTM(MCMND, "max_tx_buf_size=%d, tx_buf_size=%d\n",
+ pmadapter->max_tx_buf_size, pmadapter->tx_buf_size);
+ break;
+ case HostCmd_CMD_AMSDU_AGGR_CTRL:
+ ret = wlan_ret_amsdu_aggr_ctrl(pmpriv, resp, pioctl_buf);
+ break;
+ case HostCmd_CMD_TX_BF_CFG:
+ ret = wlan_ret_tx_bf_cfg(pmpriv, resp, pioctl_buf);
+ break;
+ case HostCmd_CMD_VERSION_EXT:
+ ret = wlan_ret_ver_ext(pmpriv, resp, pioctl_buf);
+ break;
+ case HostCmd_CMD_RX_MGMT_IND:
+ ret = wlan_ret_rx_mgmt_ind(pmpriv, resp, pioctl_buf);
+ break;
+ case HostCmd_CMD_CFG_TX_DATA_PAUSE:
+ ret = wlan_uap_ret_txdatapause(pmpriv, resp, pioctl_buf);
+ break;
+ case HostCmd_CMD_802_11_RADIO_CONTROL:
+ ret = wlan_ret_802_11_radio_control(pmpriv, resp, pioctl_buf);
+ break;
+ case HostCmd_CMD_TX_RATE_CFG:
+ ret = wlan_ret_tx_rate_cfg(pmpriv, resp, pioctl_buf);
+ break;
+ case HostCmd_CMD_802_11_TX_RATE_QUERY:
+ ret = wlan_ret_802_11_tx_rate_query(pmpriv, resp, pioctl_buf);
+ break;
+#ifdef WIFI_DIRECT_SUPPORT
+ case HostCmd_CMD_802_11_REMAIN_ON_CHANNEL:
+ ret = wlan_ret_remain_on_channel(pmpriv, resp, pioctl_buf);
+ break;
+ case HOST_CMD_WIFI_DIRECT_MODE_CONFIG:
+ ret = wlan_ret_wifi_direct_mode(pmpriv, resp, pioctl_buf);
+ break;
+#endif
+ case HostCmd_CMD_802_11_RF_ANTENNA:
+ ret = wlan_ret_802_11_rf_antenna(pmpriv, resp, pioctl_buf);
+ break;
+ default:
+ PRINTM(MERROR, "CMD_RESP: Unknown command response %#x\n",
+ resp->command);
+ if (pioctl_buf)
+ pioctl_buf->status_code = MLAN_ERROR_CMD_RESP_FAIL;
+ break;
+ }
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function handles events generated by firmware
+ *
+ * @param priv A pointer to mlan_private structure
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status
+wlan_ops_uap_process_event(IN t_void * priv)
+{
+ pmlan_private pmpriv = (pmlan_private) priv;
+ pmlan_adapter pmadapter = pmpriv->adapter;
+ pmlan_callbacks pcb = &pmadapter->callbacks;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ t_u32 eventcause = pmadapter->event_cause;
+ pmlan_buffer pmbuf = pmadapter->pmlan_buffer_event;
+ t_u8 *event_buf = MNULL;
+ mlan_event *pevent = MNULL;
+ t_u8 sta_addr[MLAN_MAC_ADDR_LENGTH];
+ sta_node *sta_ptr = MNULL;
+ t_u8 i = 0;
+
+ ENTER();
+
+ /* Allocate memory for event buffer */
+ ret =
+ pcb->moal_malloc(pmadapter->pmoal_handle, MAX_EVENT_SIZE, MLAN_MEM_DEF,
+ &event_buf);
+ if ((ret != MLAN_STATUS_SUCCESS) || !event_buf) {
+ PRINTM(MERROR, "Could not allocate buffer for event buf\n");
+ if (pmbuf)
+ pmbuf->status_code = MLAN_ERROR_NO_MEM;
+ goto done;
+ }
+ pevent = (pmlan_event) event_buf;
+ memset(pmadapter, &pevent->event_id, 0, sizeof(pevent->event_id));
+
+ if (eventcause != EVENT_PS_SLEEP && eventcause != EVENT_PS_AWAKE &&
+ pmbuf->data_len > sizeof(eventcause))
+ DBG_HEXDUMP(MEVT_D, "EVENT", pmbuf->pbuf + pmbuf->data_offset,
+ pmbuf->data_len);
+
+ switch (eventcause) {
+ case EVENT_MICRO_AP_BSS_START:
+ PRINTM(MEVENT, "EVENT: MICRO_AP_BSS_START\n");
+ pmpriv->uap_bss_started = MTRUE;
+ memcpy(pmadapter, pmpriv->curr_addr, pmadapter->event_body + 2,
+ MLAN_MAC_ADDR_LENGTH);
+ pevent->event_id = MLAN_EVENT_ID_UAP_FW_BSS_START;
+ wlan_check_uap_capability(pmpriv, pmbuf);
+ break;
+ case EVENT_MICRO_AP_BSS_ACTIVE:
+ PRINTM(MEVENT, "EVENT: MICRO_AP_BSS_ACTIVE\n");
+ pmpriv->media_connected = MTRUE;
+ pevent->event_id = MLAN_EVENT_ID_UAP_FW_BSS_ACTIVE;
+ break;
+ case EVENT_MICRO_AP_BSS_IDLE:
+ PRINTM(MEVENT, "EVENT: MICRO_AP_BSS_IDLE\n");
+ pevent->event_id = MLAN_EVENT_ID_UAP_FW_BSS_IDLE;
+ pmpriv->media_connected = MFALSE;
+ wlan_clean_txrx(pmpriv);
+ wlan_delete_station_list(pmpriv);
+ break;
+ case EVENT_PS_AWAKE:
+ PRINTM(MINFO, "EVENT: AWAKE \n");
+ PRINTM(MEVENT, "||");
+ /* Handle unexpected PS AWAKE event */
+ if (pmadapter->ps_state == PS_STATE_SLEEP_CFM)
+ break;
+ pmadapter->pm_wakeup_card_req = MFALSE;
+ pmadapter->pm_wakeup_fw_try = MFALSE;
+ pmadapter->ps_state = PS_STATE_AWAKE;
+ break;
+ case EVENT_PS_SLEEP:
+ PRINTM(MINFO, "EVENT: SLEEP\n");
+ PRINTM(MEVENT, "__");
+ /* Handle unexpected PS SLEEP event */
+ if (pmadapter->ps_state == PS_STATE_SLEEP_CFM)
+ break;
+ pmadapter->ps_state = PS_STATE_PRE_SLEEP;
+ wlan_check_ps_cond(pmadapter);
+ break;
+ case EVENT_MICRO_AP_STA_ASSOC:
+ PRINTM(MEVENT, "EVENT: MICRO_AP_STA_ASSOC\n");
+ wlan_process_sta_assoc_event(pmpriv, pevent, pmbuf);
+ memcpy(pmadapter, sta_addr, pmadapter->event_body + 2,
+ MLAN_MAC_ADDR_LENGTH);
+ sta_ptr = wlan_add_station_entry(pmpriv, sta_addr);
+ if (pmpriv->is_11n_enabled) {
+ wlan_check_sta_capability(pmpriv, pmbuf, sta_ptr);
+ for (i = 0; i < MAX_NUM_TID; i++) {
+ if (sta_ptr->is_11n_enabled)
+ sta_ptr->ampdu_sta[i] = pmpriv->aggr_prio_tbl[i].ampdu_user;
+ else
+ sta_ptr->ampdu_sta[i] = BA_STREAM_NOT_ALLOWED;
+ }
+ memset(pmadapter, sta_ptr->rx_seq, 0xff, sizeof(sta_ptr->rx_seq));
+ }
+ if (pmpriv->sec_info.wapi_enabled)
+ wlan_update_wapi_info_tlv(pmpriv, pmbuf);
+ pevent->event_id = MLAN_EVENT_ID_DRV_PASSTHRU;
+ break;
+ case EVENT_MICRO_AP_STA_DEAUTH:
+ PRINTM(MEVENT, "EVENT: MICRO_AP_STA_DEAUTH\n");
+ pevent->event_id = MLAN_EVENT_ID_UAP_FW_STA_DISCONNECT;
+ pevent->bss_index = pmpriv->bss_index;
+ pevent->event_len = pmbuf->data_len - 4;
+ /* skip event length field */
+ memcpy(pmadapter, (t_u8 *) pevent->event_buf,
+ pmbuf->pbuf + pmbuf->data_offset + 4, pevent->event_len);
+ wlan_recv_event(pmpriv, pevent->event_id, pevent);
+ memcpy(pmadapter, sta_addr, pmadapter->event_body + 2,
+ MLAN_MAC_ADDR_LENGTH);
+ if (pmpriv->is_11n_enabled) {
+ wlan_cleanup_reorder_tbl(pmpriv, sta_addr);
+ pmadapter->callbacks.moal_spin_lock(pmadapter->pmoal_handle,
+ pmpriv->wmm.ra_list_spinlock);
+ wlan_11n_cleanup_txbastream_tbl(pmpriv, sta_addr);
+ pmadapter->callbacks.moal_spin_unlock(pmadapter->pmoal_handle,
+ pmpriv->wmm.ra_list_spinlock);
+ }
+ wlan_wmm_delete_peer_ralist(pmpriv, sta_addr);
+ wlan_delete_station_entry(pmpriv, sta_addr);
+ pevent->event_id = MLAN_EVENT_ID_DRV_PASSTHRU;
+ break;
+ case EVENT_HS_ACT_REQ:
+ PRINTM(MEVENT, "EVENT: HS_ACT_REQ\n");
+ ret =
+ wlan_prepare_cmd(pmpriv, HostCmd_CMD_802_11_HS_CFG_ENH, 0, 0, MNULL,
+ MNULL);
+ break;
+ case EVENT_ADDBA:
+ PRINTM(MEVENT, "EVENT: ADDBA Request\n");
+ wlan_prepare_cmd(pmpriv, HostCmd_CMD_11N_ADDBA_RSP,
+ HostCmd_ACT_GEN_SET, 0, MNULL, pmadapter->event_body);
+ break;
+ case EVENT_DELBA:
+ PRINTM(MEVENT, "EVENT: DELBA Request\n");
+ wlan_11n_delete_bastream(pmpriv, pmadapter->event_body);
+ break;
+ case EVENT_BA_STREAM_TIMEOUT:
+ PRINTM(MEVENT, "EVENT: BA Stream timeout\n");
+ wlan_11n_ba_stream_timeout(pmpriv,
+ (HostCmd_DS_11N_BATIMEOUT *) pmadapter->
+ event_body);
+ break;
+ case EVENT_RXBA_SYNC:
+ PRINTM(MEVENT, "EVENT: RXBA_SYNC\n");
+ wlan_11n_rxba_sync_event(pmpriv, pmadapter->event_body,
+ pmbuf->data_len - sizeof(eventcause));
+ break;
+ case EVENT_AMSDU_AGGR_CTRL:
+ PRINTM(MEVENT, "EVENT: AMSDU_AGGR_CTRL %d\n",
+ *(t_u16 *) pmadapter->event_body);
+ pmadapter->tx_buf_size =
+ MIN(pmadapter->curr_tx_buf_size,
+ wlan_le16_to_cpu(*(t_u16 *) pmadapter->event_body));
+ PRINTM(MEVENT, "tx_buf_size %d\n", pmadapter->tx_buf_size);
+ break;
+ case EVENT_TX_DATA_PAUSE:
+ PRINTM(MEVENT, "EVENT: TX_DATA_PAUSE\n");
+ wlan_process_tx_pause_event(priv, pmbuf);
+ break;
+ case EVENT_RADAR_DETECTED:
+ PRINTM(MEVENT, "EVENT: Radar Detected\n");
+
+ /* Send as passthru first, this event can cause other events */
+ memset(pmadapter, event_buf, 0x00, MAX_EVENT_SIZE);
+ pevent->bss_index = pmpriv->bss_index;
+ pevent->event_id = MLAN_EVENT_ID_DRV_PASSTHRU;
+ pevent->event_len = pmbuf->data_len;
+ memcpy(pmadapter, (t_u8 *) pevent->event_buf,
+ pmbuf->pbuf + pmbuf->data_offset, pevent->event_len);
+ wlan_recv_event(pmpriv, pevent->event_id, pevent);
+ pevent->event_id = 0; // clear to avoid resending at end of fcn
+
+ if (pmadapter->state_rdh.stage == RDH_OFF) {
+ pmadapter->state_rdh.stage = RDH_CHK_INTFS;
+ wlan_11h_radar_detected_handling(pmadapter);
+ } else {
+ PRINTM(MEVENT, "Ignore Event Radar Detected - handling"
+ " already in progress.\n");
+ }
+ break;
+ case EVENT_CHANNEL_REPORT_RDY:
+ PRINTM(MEVENT, "EVENT: Channel Report Ready\n");
+ memset(pmadapter, event_buf, 0x00, MAX_EVENT_SIZE);
+ /* Setup event buffer */
+ pevent->bss_index = pmpriv->bss_index;
+ pevent->event_id = MLAN_EVENT_ID_FW_CHANNEL_REPORT_RDY;
+ pevent->event_len = pmbuf->data_len - sizeof(eventcause);
+ /* Copy event data */
+ memcpy(pmadapter, (t_u8 *) pevent->event_buf,
+ pmbuf->pbuf + pmbuf->data_offset + sizeof(eventcause),
+ pevent->event_len);
+ /* Handle / pass event data, and free buffer */
+ ret = wlan_11h_handle_event_chanrpt_ready(pmpriv, pevent);
+
+ /* Send up this Event to unblock MOAL waitqueue */
+ wlan_recv_event(pmpriv, MLAN_EVENT_ID_DRV_MEAS_REPORT, MNULL);
+ pevent->event_id = MLAN_EVENT_ID_DRV_PASSTHRU;
+ break;
+#ifdef WIFI_DIRECT_SUPPORT
+ case EVENT_REMAIN_ON_CHANNEL_EXPIRED:
+ PRINTM(MEVENT, "EVENT: REMAIN_ON_CHANNEL_EXPIRED reason=%d\n",
+ *(t_u16 *) pmadapter->event_body);
+ pevent->event_id = MLAN_EVENT_ID_FW_REMAIN_ON_CHAN_EXPIRED;
+ break;
+#endif
+ default:
+ pevent->event_id = MLAN_EVENT_ID_DRV_PASSTHRU;
+ break;
+ }
+
+ if (pevent->event_id) {
+ pevent->bss_index = pmpriv->bss_index;
+ pevent->event_len = pmbuf->data_len;
+ memcpy(pmadapter, (t_u8 *) pevent->event_buf,
+ pmbuf->pbuf + pmbuf->data_offset, pevent->event_len);
+ wlan_recv_event(pmpriv, pevent->event_id, pevent);
+ }
+ done:
+ if (event_buf)
+ pcb->moal_mfree(pmadapter->pmoal_handle, event_buf);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function issues commands to initialize firmware
+ *
+ * @param priv A pointer to mlan_private structure
+ * @param first_bss flag for first BSS
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_PENDING or MLAN_STATUS_FAILURE
+ */
+mlan_status
+wlan_ops_uap_init_cmd(IN t_void * priv, IN t_u8 first_bss)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ pmlan_private pmpriv = (pmlan_private) priv;
+ t_u16 last_cmd = 0;
+
+ ENTER();
+
+ if (first_bss) {
+ if (wlan_adapter_init_cmd(pmpriv->adapter) == MLAN_STATUS_FAILURE) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ }
+
+ ret = wlan_prepare_cmd(pmpriv, HOST_CMD_APCMD_SYS_CONFIGURE,
+ HostCmd_ACT_GEN_GET, 0, MNULL, MNULL);
+ if (ret) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ last_cmd = HOST_CMD_APCMD_SYS_CONFIGURE;
+ /** set last_init_cmd */
+ if (last_cmd) {
+ pmpriv->adapter->last_init_cmd = last_cmd;
+ ret = MLAN_STATUS_PENDING;
+ }
+ done:
+ LEAVE();
+ return ret;
+}
diff --git a/drivers/net/wireless/sd8797/mlan/mlan_uap_ioctl.c b/drivers/net/wireless/sd8797/mlan/mlan_uap_ioctl.c
new file mode 100644
index 000000000000..be78d72de25c
--- /dev/null
+++ b/drivers/net/wireless/sd8797/mlan/mlan_uap_ioctl.c
@@ -0,0 +1,1393 @@
+/** @file mlan_uap_ioctl.c
+ *
+ * @brief This file contains the handling of AP mode ioctls
+ *
+ * Copyright (C) 2009-2011, Marvell International Ltd.
+ *
+ * This software file (the "File") is distributed by Marvell International
+ * Ltd. under the terms of the GNU General Public License Version 2, June 1991
+ * (the "License"). You may use, redistribute and/or modify this File in
+ * accordance with the terms and conditions of the License, a copy of which
+ * is available by writing to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
+ * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
+ *
+ * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
+ * ARE EXPRESSLY DISCLAIMED. The License provides additional details about
+ * this warranty disclaimer.
+ */
+
+/********************************************************
+Change log:
+ 02/05/2009: initial version
+********************************************************/
+
+#include "mlan.h"
+#include "mlan_util.h"
+#include "mlan_fw.h"
+#ifdef STA_SUPPORT
+#include "mlan_join.h"
+#endif
+#include "mlan_main.h"
+#include "mlan_uap.h"
+#include "mlan_sdio.h"
+#include "mlan_11n.h"
+#include "mlan_fw.h"
+#include "mlan_11h.h"
+
+/********************************************************
+ Global Variables
+********************************************************/
+extern t_u8 tos_to_tid_inv[];
+
+/********************************************************
+ Local Functions
+********************************************************/
+/**
+ * @brief Stop BSS
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_PENDING --success, otherwise fail
+ */
+static mlan_status
+wlan_uap_bss_ioctl_stop(IN pmlan_adapter pmadapter,
+ IN pmlan_ioctl_req pioctl_req)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ pmlan_private pmpriv = pmadapter->priv[pioctl_req->bss_index];
+
+ ENTER();
+
+ ret = wlan_prepare_cmd(pmpriv,
+ HOST_CMD_APCMD_BSS_STOP,
+ HostCmd_ACT_GEN_SET,
+ 0, (t_void *) pioctl_req, MNULL);
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Callback to finish BSS IOCTL START
+ * Not to be called directly to initiate bss_start
+ *
+ * @param priv A pointer to mlan_private structure (cast from t_void*)
+ *
+ * @return MLAN_STATUS_PENDING --success, otherwise fail
+ * @sa wlan_uap_bss_ioctl_start
+ */
+static mlan_status
+wlan_uap_callback_bss_ioctl_start(IN t_void * priv)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_private *pmpriv = (mlan_private *) priv;
+ mlan_callbacks *pcb = (mlan_callbacks *) & pmpriv->adapter->callbacks;
+ wlan_uap_get_info_cb_t *puap_state_chan_cb = &pmpriv->uap_state_chan_cb;
+ t_u8 old_channel;
+
+ ENTER();
+ /* clear callback now that we're here */
+ puap_state_chan_cb->get_chan_callback = MNULL;
+
+ /*
+ * Check if the region and channel requires we check for radar.
+ */
+ if ((puap_state_chan_cb->band_config & BAND_CONFIG_5GHZ) &&
+ wlan_11h_radar_detect_required(pmpriv, puap_state_chan_cb->channel)) {
+ /* first check if channel is under NOP */
+ if (wlan_11h_is_channel_under_nop(pmpriv->adapter,
+ puap_state_chan_cb->channel)) {
+ /* recently we've seen radar on this channel */
+ ret = MLAN_STATUS_FAILURE;
+ }
+
+ /* Check cached radar check on the channel */
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret =
+ wlan_11h_check_chan_report(pmpriv, puap_state_chan_cb->channel);
+
+ /* Found radar: try to switch to a non-dfs channel */
+ if (ret != MLAN_STATUS_SUCCESS) {
+ old_channel = puap_state_chan_cb->channel;
+ ret =
+ wlan_11h_switch_non_dfs_chan(pmpriv,
+ &puap_state_chan_cb->channel);
+
+ if (ret == MLAN_STATUS_SUCCESS) {
+ ret = wlan_uap_set_channel(pmpriv,
+ pmpriv->uap_state_chan_cb.
+ band_config,
+ puap_state_chan_cb->channel);
+ if (ret == MLAN_STATUS_SUCCESS) {
+ PRINTM(MMSG, "Radar found on channel %d,"
+ "switch to new channel %d.\n",
+ old_channel, puap_state_chan_cb->channel);
+ } else {
+ PRINTM(MMSG, "Radar found on channel %d,"
+ " switch to new channel %d failed.\n",
+ old_channel, puap_state_chan_cb->channel);
+ pcb->moal_ioctl_complete(pmpriv->adapter->pmoal_handle,
+ puap_state_chan_cb->
+ pioctl_req_curr,
+ MLAN_STATUS_FAILURE);
+ goto done;
+ }
+ } else {
+ PRINTM(MMSG,
+ "Radar found on channel %d, no switch channel available.\n",
+ old_channel);
+ /* No command sent with the ioctl, need manually signal
+ completion */
+ pcb->moal_ioctl_complete(pmpriv->adapter->pmoal_handle,
+ puap_state_chan_cb->pioctl_req_curr,
+ MLAN_STATUS_FAILURE);
+ goto done;
+ }
+ } else {
+ PRINTM(MINFO, "No Radar found on channel %d\n",
+ puap_state_chan_cb->channel);
+ }
+ }
+
+ /* else okay to send command: not DFS channel or no radar */
+ ret = wlan_prepare_cmd(pmpriv,
+ HOST_CMD_APCMD_BSS_START,
+ HostCmd_ACT_GEN_SET,
+ 0,
+ (t_void *) puap_state_chan_cb->pioctl_req_curr,
+ MNULL);
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+
+ done:
+ puap_state_chan_cb->pioctl_req_curr = MNULL; // prevent re-use
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Start BSS
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_PENDING --success, otherwise fail
+ */
+/**
+ * @sa wlan_uap_callback_bss_ioctl_start
+ */
+static mlan_status
+wlan_uap_bss_ioctl_start(IN pmlan_adapter pmadapter,
+ IN pmlan_ioctl_req pioctl_req)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ pmlan_private pmpriv = pmadapter->priv[pioctl_req->bss_index];
+
+ ENTER();
+
+ /* First check channel report, defer BSS_START CMD to callback. */
+ /* store params, issue command to get UAP channel, whose CMD_RESP will
+ callback remainder of bss_start handling */
+ pmpriv->uap_state_chan_cb.pioctl_req_curr = pioctl_req;
+ pmpriv->uap_state_chan_cb.get_chan_callback =
+ wlan_uap_callback_bss_ioctl_start;
+
+ ret = wlan_uap_get_channel(pmpriv);
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief reset BSS
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_PENDING --success, otherwise fail
+ */
+static mlan_status
+wlan_uap_bss_ioctl_reset(IN pmlan_adapter pmadapter,
+ IN pmlan_ioctl_req pioctl_req)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ pmlan_private pmpriv = pmadapter->priv[pioctl_req->bss_index];
+ t_u8 i = 0;
+
+ ENTER();
+
+ /*
+ * Reset any uap private parameters here
+ */
+ for (i = 0; i < pmadapter->max_mgmt_ie_index; i++) {
+ memset(pmadapter, &pmpriv->mgmt_ie[i], 0, sizeof(custom_ie));
+ }
+ pmpriv->add_ba_param.timeout = MLAN_DEFAULT_BLOCK_ACK_TIMEOUT;
+ pmpriv->add_ba_param.tx_win_size = MLAN_AMPDU_DEF_TXWINSIZE;
+ pmpriv->add_ba_param.rx_win_size = MLAN_AMPDU_DEF_RXWINSIZE;
+ for (i = 0; i < MAX_NUM_TID; i++) {
+ pmpriv->aggr_prio_tbl[i].ampdu_user = tos_to_tid_inv[i];
+ pmpriv->aggr_prio_tbl[i].amsdu = BA_STREAM_NOT_ALLOWED;
+ pmpriv->addba_reject[i] = ADDBA_RSP_STATUS_ACCEPT;
+ }
+
+ /* hs_configured, hs_activated are reset by main loop */
+ pmadapter->hs_cfg.conditions = HOST_SLEEP_DEF_COND;
+ pmadapter->hs_cfg.gpio = HOST_SLEEP_DEF_GPIO;
+ pmadapter->hs_cfg.gap = HOST_SLEEP_DEF_GAP;
+
+ ret = wlan_prepare_cmd(pmpriv,
+ HOST_CMD_APCMD_SYS_RESET,
+ HostCmd_ACT_GEN_SET,
+ 0, (t_void *) pioctl_req, MNULL);
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set/Get MAC address
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_PENDING --success, otherwise fail
+ */
+static mlan_status
+wlan_uap_bss_ioctl_mac_address(IN pmlan_adapter pmadapter,
+ IN pmlan_ioctl_req pioctl_req)
+{
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
+ mlan_ds_bss *bss = MNULL;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ t_u16 cmd_action = 0;
+
+ ENTER();
+
+ bss = (mlan_ds_bss *) pioctl_req->pbuf;
+ if (pioctl_req->action == MLAN_ACT_SET) {
+ memcpy(pmadapter, pmpriv->curr_addr, &bss->param.mac_addr,
+ MLAN_MAC_ADDR_LENGTH);
+ cmd_action = HostCmd_ACT_GEN_SET;
+ } else
+ cmd_action = HostCmd_ACT_GEN_GET;
+ /* Send request to firmware */
+ ret = wlan_prepare_cmd(pmpriv, HOST_CMD_APCMD_SYS_CONFIGURE,
+ cmd_action, 0, (t_void *) pioctl_req, MNULL);
+
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Get Uap statistics
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_PENDING --success, otherwise fail
+ */
+static mlan_status
+wlan_uap_get_stats(IN pmlan_adapter pmadapter, IN pmlan_ioctl_req pioctl_req)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ pmlan_private pmpriv = pmadapter->priv[pioctl_req->bss_index];
+
+ ENTER();
+
+ ret = wlan_prepare_cmd(pmpriv,
+ HostCmd_CMD_802_11_SNMP_MIB,
+ HostCmd_ACT_GEN_GET,
+ 0, (t_void *) pioctl_req, MNULL);
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set/Get AP config
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_PENDING --success, otherwise fail
+ */
+static mlan_status
+wlan_uap_bss_ioctl_config(IN pmlan_adapter pmadapter,
+ IN pmlan_ioctl_req pioctl_req)
+{
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ t_u16 cmd_action = 0;
+
+ ENTER();
+
+ if (pioctl_req->action == MLAN_ACT_SET)
+ cmd_action = HostCmd_ACT_GEN_SET;
+ else
+ cmd_action = HostCmd_ACT_GEN_GET;
+
+ /* Send request to firmware */
+ ret = wlan_prepare_cmd(pmpriv, HOST_CMD_APCMD_SYS_CONFIGURE,
+ cmd_action, 0, (t_void *) pioctl_req, MNULL);
+
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief deauth sta
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_PENDING --success, otherwise fail
+ */
+static mlan_status
+wlan_uap_bss_ioctl_deauth_sta(IN pmlan_adapter pmadapter,
+ IN pmlan_ioctl_req pioctl_req)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ pmlan_private pmpriv = pmadapter->priv[pioctl_req->bss_index];
+ mlan_ds_bss *bss = MNULL;
+
+ ENTER();
+
+ bss = (mlan_ds_bss *) pioctl_req->pbuf;
+ ret = wlan_prepare_cmd(pmpriv,
+ HOST_CMD_APCMD_STA_DEAUTH,
+ HostCmd_ACT_GEN_SET,
+ 0,
+ (t_void *) pioctl_req,
+ (t_void *) & bss->param.deauth_param);
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Get station list
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_PENDING --success, otherwise fail
+ */
+static mlan_status
+wlan_uap_get_sta_list(IN pmlan_adapter pmadapter, IN pmlan_ioctl_req pioctl_req)
+{
+ pmlan_private pmpriv = pmadapter->priv[pioctl_req->bss_index];
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ /* Send request to firmware */
+ ret = wlan_prepare_cmd(pmpriv,
+ HOST_CMD_APCMD_STA_LIST,
+ HostCmd_ACT_GEN_GET,
+ 0, (t_void *) pioctl_req, MNULL);
+
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief soft_reset
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_PENDING --success, otherwise fail
+ */
+static mlan_status
+wlan_uap_misc_ioctl_soft_reset(IN pmlan_adapter pmadapter,
+ IN pmlan_ioctl_req pioctl_req)
+{
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ ret = wlan_prepare_cmd(pmpriv,
+ HostCmd_CMD_SOFT_RESET,
+ HostCmd_ACT_GEN_SET,
+ 0, (t_void *) pioctl_req, MNULL);
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Tx data pause
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_PENDING --success, otherwise fail
+ */
+static mlan_status
+wlan_uap_misc_ioctl_txdatapause(IN pmlan_adapter pmadapter,
+ IN pmlan_ioctl_req pioctl_req)
+{
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
+ mlan_ds_misc_cfg *pmisc = (mlan_ds_misc_cfg *) pioctl_req->pbuf;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ t_u16 cmd_action = 0;
+
+ ENTER();
+
+ if (pioctl_req->action == MLAN_ACT_SET)
+ cmd_action = HostCmd_ACT_GEN_SET;
+ else
+ cmd_action = HostCmd_ACT_GEN_GET;
+ ret = wlan_prepare_cmd(pmpriv,
+ HostCmd_CMD_CFG_TX_DATA_PAUSE,
+ cmd_action,
+ 0,
+ (t_void *) pioctl_req, &(pmisc->param.tx_datapause));
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set/Get Power mode
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_PENDING --success, otherwise fail
+ */
+static mlan_status
+wlan_uap_pm_ioctl_mode(IN pmlan_adapter pmadapter,
+ IN pmlan_ioctl_req pioctl_req)
+{
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
+ mlan_ds_pm_cfg *pm = MNULL;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ t_u16 cmd_action = 0;
+ t_u32 cmd_oid = 0;
+
+ ENTER();
+
+ pm = (mlan_ds_pm_cfg *) pioctl_req->pbuf;
+ if (pioctl_req->action == MLAN_ACT_SET) {
+ if (pm->param.ps_mgmt.ps_mode == PS_MODE_INACTIVITY) {
+ cmd_action = EN_AUTO_PS;
+ cmd_oid = BITMAP_UAP_INACT_PS;
+ } else if (pm->param.ps_mgmt.ps_mode == PS_MODE_PERIODIC_DTIM) {
+ cmd_action = EN_AUTO_PS;
+ cmd_oid = BITMAP_UAP_DTIM_PS;
+ } else {
+ cmd_action = DIS_AUTO_PS;
+ cmd_oid = BITMAP_UAP_INACT_PS | BITMAP_UAP_DTIM_PS;
+ }
+ } else {
+ cmd_action = GET_PS;
+ cmd_oid = BITMAP_UAP_INACT_PS | BITMAP_UAP_DTIM_PS;
+ }
+ /* Send request to firmware */
+ ret = wlan_prepare_cmd(pmpriv,
+ HostCmd_CMD_802_11_PS_MODE_ENH,
+ cmd_action, cmd_oid, (t_void *) pioctl_req,
+ (t_void *) & pm->param.ps_mgmt);
+ if ((ret == MLAN_STATUS_SUCCESS) &&
+ (pioctl_req->action == MLAN_ACT_SET) && (cmd_action == DIS_AUTO_PS)) {
+ ret = wlan_prepare_cmd(pmpriv,
+ HostCmd_CMD_802_11_PS_MODE_ENH, GET_PS,
+ 0, MNULL, MNULL);
+ }
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set WAPI IE
+ *
+ * @param priv A pointer to mlan_private structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_PENDING --success, otherwise fail
+ */
+static mlan_status
+wlan_uap_set_wapi_ie(mlan_private * priv, pmlan_ioctl_req pioctl_req)
+{
+ mlan_ds_misc_cfg *misc = MNULL;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+ misc = (mlan_ds_misc_cfg *) pioctl_req->pbuf;
+ if (misc->param.gen_ie.len) {
+ if (misc->param.gen_ie.len > sizeof(priv->wapi_ie)) {
+ PRINTM(MWARN, "failed to copy WAPI IE, too big \n");
+ pioctl_req->status_code = MLAN_ERROR_INVALID_PARAMETER;
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+ memcpy(priv->adapter, priv->wapi_ie, misc->param.gen_ie.ie_data,
+ misc->param.gen_ie.len);
+ priv->wapi_ie_len = misc->param.gen_ie.len;
+ PRINTM(MIOCTL, "Set wapi_ie_len=%d IE=%#x\n", priv->wapi_ie_len,
+ priv->wapi_ie[0]);
+ DBG_HEXDUMP(MCMD_D, "wapi_ie", priv->wapi_ie, priv->wapi_ie_len);
+ if (priv->wapi_ie[0] == WAPI_IE)
+ priv->sec_info.wapi_enabled = MTRUE;
+ } else {
+ memset(priv->adapter, priv->wapi_ie, 0, sizeof(priv->wapi_ie));
+ priv->wapi_ie_len = misc->param.gen_ie.len;
+ PRINTM(MINFO, "Reset wapi_ie_len=%d IE=%#x\n", priv->wapi_ie_len,
+ priv->wapi_ie[0]);
+ priv->sec_info.wapi_enabled = MFALSE;
+ }
+
+ /* Send request to firmware */
+ ret = wlan_prepare_cmd(priv, HOST_CMD_APCMD_SYS_CONFIGURE,
+ HostCmd_ACT_GEN_SET, 0, (t_void *) pioctl_req,
+ MNULL);
+
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set generic IE
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING --success, otherwise fail
+ */
+static mlan_status
+wlan_uap_misc_ioctl_gen_ie(IN pmlan_adapter pmadapter,
+ IN pmlan_ioctl_req pioctl_req)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
+ mlan_ds_misc_cfg *misc = MNULL;
+ IEEEtypes_VendorHeader_t *pvendor_ie = MNULL;
+
+ ENTER();
+
+ misc = (mlan_ds_misc_cfg *) pioctl_req->pbuf;
+
+ if ((misc->param.gen_ie.type == MLAN_IE_TYPE_GEN_IE) &&
+ (pioctl_req->action == MLAN_ACT_SET)) {
+ if (misc->param.gen_ie.len) {
+ pvendor_ie =
+ (IEEEtypes_VendorHeader_t *) misc->param.gen_ie.ie_data;
+ if (pvendor_ie->element_id == WAPI_IE) {
+ /* IE is a WAPI IE so call set_wapi function */
+ ret = wlan_uap_set_wapi_ie(pmpriv, pioctl_req);
+ }
+ } else {
+ /* clear WAPI IE */
+ ret = wlan_uap_set_wapi_ie(pmpriv, pioctl_req);
+ }
+ }
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set/Get WAPI status
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_SUCCESS --success
+ */
+static mlan_status
+wlan_uap_sec_ioctl_wapi_enable(IN pmlan_adapter pmadapter,
+ IN pmlan_ioctl_req pioctl_req)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
+ mlan_ds_sec_cfg *sec = MNULL;
+ ENTER();
+ sec = (mlan_ds_sec_cfg *) pioctl_req->pbuf;
+ if (pioctl_req->action == MLAN_ACT_GET) {
+ if (pmpriv->wapi_ie_len)
+ sec->param.wapi_enabled = MTRUE;
+ else
+ sec->param.wapi_enabled = MFALSE;
+ } else {
+ if (sec->param.wapi_enabled == MFALSE) {
+ memset(pmpriv->adapter, pmpriv->wapi_ie, 0,
+ sizeof(pmpriv->wapi_ie));
+ pmpriv->wapi_ie_len = 0;
+ PRINTM(MINFO, "Reset wapi_ie_len=%d IE=%#x\n", pmpriv->wapi_ie_len,
+ pmpriv->wapi_ie[0]);
+ pmpriv->sec_info.wapi_enabled = MFALSE;
+ }
+ }
+ pioctl_req->data_read_written = sizeof(t_u32) + MLAN_SUB_COMMAND_SIZE;
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set encrypt key
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING --success, otherwise fail
+ */
+static mlan_status
+wlan_uap_sec_ioctl_set_encrypt_key(IN pmlan_adapter pmadapter,
+ IN pmlan_ioctl_req pioctl_req)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
+ mlan_ds_sec_cfg *sec = MNULL;
+
+ ENTER();
+ sec = (mlan_ds_sec_cfg *) pioctl_req->pbuf;
+ if (pioctl_req->action != MLAN_ACT_SET) {
+ pioctl_req->status_code = MLAN_ERROR_IOCTL_INVALID;
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+ if (!sec->param.encrypt_key.key_len) {
+ PRINTM(MCMND, "Skip set key with key_len = 0\n");
+ LEAVE();
+ return ret;
+ }
+ ret = wlan_prepare_cmd(pmpriv,
+ HostCmd_CMD_802_11_KEY_MATERIAL,
+ HostCmd_ACT_GEN_SET,
+ KEY_INFO_ENABLED,
+ (t_void *) pioctl_req, &sec->param.encrypt_key);
+
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Get BSS information
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_SUCCESS --success
+ */
+static mlan_status
+wlan_uap_get_bss_info(IN pmlan_adapter pmadapter, IN pmlan_ioctl_req pioctl_req)
+{
+ pmlan_private pmpriv = pmadapter->priv[pioctl_req->bss_index];
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_ds_get_info *info;
+
+ ENTER();
+
+ info = (mlan_ds_get_info *) pioctl_req->pbuf;
+ /* Connection status */
+ info->param.bss_info.media_connected = pmpriv->media_connected;
+
+ /* Radio status */
+ info->param.bss_info.radio_on = pmadapter->radio_on;
+
+ /* BSSID */
+ memcpy(pmadapter, &info->param.bss_info.bssid, pmpriv->curr_addr,
+ MLAN_MAC_ADDR_LENGTH);
+ info->param.bss_info.is_hs_configured = pmadapter->is_hs_configured;
+ pioctl_req->data_read_written =
+ sizeof(mlan_bss_info) + MLAN_SUB_COMMAND_SIZE;
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set Host Sleep configurations
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_SUCCES/MLAN_STATUS_PENDING --success, otherwise fail
+ */
+static mlan_status
+wlan_uap_pm_ioctl_deepsleep(IN pmlan_adapter pmadapter,
+ IN pmlan_ioctl_req pioctl_req)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
+ mlan_ds_pm_cfg *pm = MNULL;
+ mlan_ds_auto_ds auto_ds;
+ t_u32 mode;
+
+ ENTER();
+
+ if (pioctl_req->buf_len < sizeof(mlan_ds_pm_cfg)) {
+ PRINTM(MWARN, "MLAN bss IOCTL length is too short.\n");
+ pioctl_req->data_read_written = 0;
+ pioctl_req->buf_len_needed = sizeof(mlan_ds_pm_cfg);
+ pioctl_req->status_code = MLAN_ERROR_INVALID_PARAMETER;
+ LEAVE();
+ return MLAN_STATUS_RESOURCE;
+ }
+ pm = (mlan_ds_pm_cfg *) pioctl_req->pbuf;
+
+ if (pioctl_req->action == MLAN_ACT_GET) {
+ if (pmadapter->is_deep_sleep) {
+ pm->param.auto_deep_sleep.auto_ds = DEEP_SLEEP_ON;
+ pm->param.auto_deep_sleep.idletime = pmadapter->idle_time;
+ } else
+ pm->param.auto_deep_sleep.auto_ds = DEEP_SLEEP_OFF;
+ } else {
+ if (pmadapter->is_deep_sleep &&
+ pm->param.auto_deep_sleep.auto_ds == DEEP_SLEEP_ON) {
+ PRINTM(MMSG, "uAP already in deep sleep mode\n");
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+ if (((mlan_ds_pm_cfg *) pioctl_req->pbuf)->param.auto_deep_sleep.
+ auto_ds == DEEP_SLEEP_ON) {
+ auto_ds.auto_ds = DEEP_SLEEP_ON;
+ mode = EN_AUTO_PS;
+ PRINTM(MINFO, "Auto Deep Sleep: on\n");
+ } else {
+ mode = DIS_AUTO_PS;
+ auto_ds.auto_ds = DEEP_SLEEP_OFF;
+ PRINTM(MINFO, "Auto Deep Sleep: off\n");
+ }
+ if (((mlan_ds_pm_cfg *) pioctl_req->pbuf)->param.auto_deep_sleep.
+ idletime)
+ auto_ds.idletime =
+ ((mlan_ds_pm_cfg *) pioctl_req->pbuf)->param.auto_deep_sleep.
+ idletime;
+ else
+ auto_ds.idletime = pmadapter->idle_time;
+ ret = wlan_prepare_cmd(pmpriv,
+ HostCmd_CMD_802_11_PS_MODE_ENH,
+ (t_u16) mode,
+ BITMAP_AUTO_DS, (t_void *) pioctl_req, &auto_ds);
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+ }
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set SNMP MIB for 11D
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_PENDING --success, otherwise fail
+ */
+static mlan_status
+wlan_uap_snmp_mib_11d(IN pmlan_adapter pmadapter, IN pmlan_ioctl_req pioctl_req)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
+ mlan_ds_snmp_mib *snmp = MNULL;
+ state_11d_t flag;
+
+ ENTER();
+
+ if (pioctl_req->buf_len < sizeof(mlan_ds_snmp_mib)) {
+ PRINTM(MWARN, "MLAN snmp_mib IOCTL length is too short.\n");
+ pioctl_req->data_read_written = 0;
+ pioctl_req->buf_len_needed = sizeof(mlan_ds_snmp_mib);
+ LEAVE();
+ return MLAN_STATUS_RESOURCE;
+ }
+
+ if ((pioctl_req->action == MLAN_ACT_SET) && pmpriv->uap_bss_started) {
+ PRINTM(MIOCTL,
+ "11D setting cannot be changed while UAP bss is started.\n");
+ pioctl_req->data_read_written = 0;
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+
+ snmp = (mlan_ds_snmp_mib *) pioctl_req->pbuf;
+ flag = (snmp->param.oid_value) ? ENABLE_11D : DISABLE_11D;
+
+ ret = wlan_11d_enable(pmpriv, (t_void *) pioctl_req, flag);
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Callback to finish domain_info handling
+ * Not to be called directly to initiate domain_info setting.
+ *
+ * @param pmpriv A pointer to mlan_private structure (cast from t_void*)
+ *
+ * @return MLAN_STATUS_PENDING --success, otherwise fail
+ * @sa wlan_uap_domain_info
+ */
+static mlan_status
+wlan_uap_callback_domain_info(IN t_void * priv)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_private *pmpriv = (mlan_private *) priv;
+ wlan_uap_get_info_cb_t *puap_state_chan_cb = &pmpriv->uap_state_chan_cb;
+ mlan_ds_11d_cfg *cfg11d;
+ t_u8 band;
+
+ ENTER();
+ /* clear callback now that we're here */
+ puap_state_chan_cb->get_chan_callback = MNULL;
+
+ cfg11d = (mlan_ds_11d_cfg *) puap_state_chan_cb->pioctl_req_curr->pbuf;
+ band =
+ (puap_state_chan_cb->band_config & BAND_CONFIG_5GHZ) ? BAND_A : BAND_B;
+
+ ret =
+ wlan_11d_handle_uap_domain_info(pmpriv, band, cfg11d->param.domain_tlv,
+ puap_state_chan_cb->pioctl_req_curr);
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+
+ puap_state_chan_cb->pioctl_req_curr = MNULL; // prevent re-use
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set Domain Info for 11D
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_PENDING --success, otherwise fail
+ * @sa wlan_uap_callback_domain_info
+ */
+static mlan_status
+wlan_uap_domain_info(IN pmlan_adapter pmadapter, IN pmlan_ioctl_req pioctl_req)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
+
+ ENTER();
+
+ if (pioctl_req->buf_len < sizeof(mlan_ds_11d_cfg)) {
+ PRINTM(MWARN, "MLAN 11d_cfg IOCTL length is too short.\n");
+ pioctl_req->data_read_written = 0;
+ pioctl_req->buf_len_needed = sizeof(mlan_ds_11d_cfg);
+ LEAVE();
+ return MLAN_STATUS_RESOURCE;
+ }
+
+ if ((pioctl_req->action == MLAN_ACT_SET) && pmpriv->uap_bss_started) {
+ PRINTM(MIOCTL,
+ "Domain_info cannot be changed while UAP bss is started.\n");
+ pioctl_req->data_read_written = 0;
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+
+ /* store params, issue command to get UAP channel, whose CMD_RESP will
+ callback remainder of domain_info handling */
+ pmpriv->uap_state_chan_cb.pioctl_req_curr = pioctl_req;
+ pmpriv->uap_state_chan_cb.get_chan_callback = wlan_uap_callback_domain_info;
+
+ ret = wlan_uap_get_channel(pmpriv);
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Callback to finish 11H channel check handling.
+ * Not to be called directly to initiate channel check.
+ *
+ * @param priv A pointer to mlan_private structure (cast from t_void*)
+ *
+ * @return MLAN_STATUS_SUCCESS/PENDING --success, otherwise fail
+ * @sa wlan_uap_11h_channel_check_req
+ */
+static mlan_status
+wlan_uap_callback_11h_channel_check_req(IN t_void * priv)
+{
+ mlan_status ret = MLAN_STATUS_FAILURE;
+ mlan_private *pmpriv = (mlan_private *) priv;
+ mlan_callbacks *pcb = (mlan_callbacks *) & pmpriv->adapter->callbacks;
+ wlan_uap_get_info_cb_t *puap_state_chan_cb = &pmpriv->uap_state_chan_cb;
+ /* keep copy as local variable */
+ pmlan_ioctl_req pioctl = puap_state_chan_cb->pioctl_req_curr;
+
+ ENTER();
+ /* clear callback now that we're here */
+ puap_state_chan_cb->get_chan_callback = MNULL;
+ /* clear early to avoid race condition */
+ puap_state_chan_cb->pioctl_req_curr = MNULL;
+
+ /*
+ * Check if the region and channel requires a channel availability
+ * check.
+ */
+ if ((puap_state_chan_cb->band_config & BAND_CONFIG_5GHZ) &&
+ wlan_11h_radar_detect_required(pmpriv, puap_state_chan_cb->channel) &&
+ !wlan_11h_is_channel_under_nop(pmpriv->adapter,
+ puap_state_chan_cb->channel)) {
+
+ /*
+ * Radar detection is required for this channel, make sure
+ * 11h is activated in the firmware
+ */
+ ret = wlan_11h_activate(pmpriv, MNULL, MTRUE);
+ ret = wlan_11h_config_master_radar_det(pmpriv, MTRUE);
+ ret = wlan_11h_check_update_radar_det_state(pmpriv);
+
+ /* Check for radar on the channel */
+ ret = wlan_11h_issue_radar_detect(pmpriv,
+ pioctl, puap_state_chan_cb->channel);
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+ } else {
+ /* No command sent with the ioctl, need manually signal completion */
+ pcb->moal_ioctl_complete(pmpriv->adapter->pmoal_handle,
+ pioctl, MLAN_STATUS_FAILURE);
+ }
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief 802.11h uap start channel check
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_PENDING --success, otherwise fail
+ * @sa wlan_uap_callback_11h_channel_check_req
+ */
+static mlan_status
+wlan_uap_11h_channel_check_req(IN pmlan_adapter pmadapter,
+ IN pmlan_ioctl_req pioctl_req)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
+
+ ENTER();
+
+ if (pioctl_req->buf_len < sizeof(mlan_ds_11h_cfg)) {
+ PRINTM(MWARN, "MLAN 11h_cfg IOCTL length is too short.\n");
+ pioctl_req->data_read_written = 0;
+ pioctl_req->buf_len_needed = sizeof(mlan_ds_11h_cfg);
+ LEAVE();
+ return MLAN_STATUS_RESOURCE;
+ }
+
+ /* store params, issue command to get UAP channel, whose CMD_RESP will
+ callback remainder of 11H channel check handling */
+ pmpriv->uap_state_chan_cb.pioctl_req_curr = pioctl_req;
+ pmpriv->uap_state_chan_cb.get_chan_callback =
+ wlan_uap_callback_11h_channel_check_req;
+
+ ret = wlan_uap_get_channel(pmpriv);
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Callback to finish 11H handling
+ * Not to be called directly to initiate 11H setting.
+ *
+ * @param pmpriv A pointer to mlan_private structure (cast from t_void*)
+ *
+ * @return MLAN_STATUS_PENDING --success, otherwise fail
+ * @sa wlan_uap_snmp_mib_11h
+ */
+static mlan_status
+wlan_uap_callback_snmp_mib_11h(IN t_void * priv)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_private *pmpriv = (mlan_private *) priv;
+ wlan_uap_get_info_cb_t *puap_state_chan_cb = &pmpriv->uap_state_chan_cb;
+ mlan_ds_snmp_mib *snmp;
+ t_bool enable_11h;
+
+ ENTER();
+ /* clear callback now that we're here */
+ puap_state_chan_cb->get_chan_callback = MNULL;
+
+ snmp = (mlan_ds_snmp_mib *) puap_state_chan_cb->pioctl_req_curr->pbuf;
+ enable_11h = (snmp->param.oid_value) ? MTRUE : MFALSE;
+
+ if (enable_11h) {
+ if ((puap_state_chan_cb->band_config & BAND_CONFIG_5GHZ) &&
+ wlan_11h_radar_detect_required(pmpriv,
+ puap_state_chan_cb->channel)) {
+ if (!wlan_11h_is_master_radar_det_active(pmpriv))
+ wlan_11h_config_master_radar_det(pmpriv, MTRUE);
+ }
+ }
+
+ ret =
+ wlan_11h_activate(pmpriv,
+ (t_void *) puap_state_chan_cb->pioctl_req_curr,
+ enable_11h);
+ wlan_11h_check_update_radar_det_state(pmpriv);
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+
+ puap_state_chan_cb->pioctl_req_curr = MNULL; // prevent re-use
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set SNMP MIB for 11H
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_PENDING --success, otherwise fail
+ * @sa wlan_uap_callback_snmp_mib_11h
+ */
+static mlan_status
+wlan_uap_snmp_mib_11h(IN pmlan_adapter pmadapter, IN pmlan_ioctl_req pioctl_req)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
+ mlan_ds_snmp_mib *snmp = MNULL;
+ t_bool enable;
+
+ ENTER();
+
+ if (pioctl_req->buf_len < sizeof(mlan_ds_snmp_mib)) {
+ PRINTM(MWARN, "MLAN snmp_mib IOCTL length is too short.\n");
+ pioctl_req->data_read_written = 0;
+ pioctl_req->buf_len_needed = sizeof(mlan_ds_snmp_mib);
+ LEAVE();
+ return MLAN_STATUS_RESOURCE;
+ }
+ snmp = (mlan_ds_snmp_mib *) pioctl_req->pbuf;
+ enable = (snmp->param.oid_value) ? MTRUE : MFALSE;
+
+ if (enable) {
+ /* first enable 11D if it is not enabled */
+ if (!wlan_11d_is_enabled(pmpriv)) {
+ ret = wlan_11d_enable(pmpriv, MNULL, ENABLE_11D);
+ if (ret != MLAN_STATUS_SUCCESS) {
+ PRINTM(MERROR,
+ "Failed to first enable 11D before enabling 11H.\n");
+ LEAVE();
+ return ret;
+ }
+ }
+ }
+
+ /* store params, issue command to get UAP channel, whose CMD_RESP will
+ callback remainder of 11H handling (and radar detect if DFS chan) */
+ pmpriv->uap_state_chan_cb.pioctl_req_curr = pioctl_req;
+ pmpriv->uap_state_chan_cb.get_chan_callback =
+ wlan_uap_callback_snmp_mib_11h;
+
+ ret = wlan_uap_get_channel(pmpriv);
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+
+ LEAVE();
+ return ret;
+}
+
+/********************************************************
+ Global Functions
+********************************************************/
+
+/**
+ * @brief Issue CMD to UAP firmware to get current channel
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ *
+ * @return MLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+mlan_status
+wlan_uap_get_channel(IN pmlan_private pmpriv)
+{
+ MrvlIEtypes_channel_band_t tlv_chan_band;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+ memset(pmpriv->adapter, &tlv_chan_band, 0, sizeof(tlv_chan_band));
+ tlv_chan_band.header.type = TLV_TYPE_UAP_CHAN_BAND_CONFIG;
+ tlv_chan_band.header.len = sizeof(MrvlIEtypes_channel_band_t)
+ - sizeof(MrvlIEtypesHeader_t);
+
+ ret = wlan_prepare_cmd(pmpriv, HOST_CMD_APCMD_SYS_CONFIGURE,
+ HostCmd_ACT_GEN_GET, 0, MNULL, &tlv_chan_band);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Issue CMD to UAP firmware to set current channel
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param uap_band_cfg UAP band configuration
+ * @param channel New channel
+ *
+ * @return MLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+mlan_status
+wlan_uap_set_channel(IN pmlan_private pmpriv,
+ IN t_u8 uap_band_cfg, IN t_u8 channel)
+{
+ MrvlIEtypes_channel_band_t tlv_chan_band;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+ memset(pmpriv->adapter, &tlv_chan_band, 0, sizeof(tlv_chan_band));
+ tlv_chan_band.header.type = TLV_TYPE_UAP_CHAN_BAND_CONFIG;
+ tlv_chan_band.header.len = sizeof(MrvlIEtypes_channel_band_t)
+ - sizeof(MrvlIEtypesHeader_t);
+ tlv_chan_band.band_config = uap_band_cfg;
+ tlv_chan_band.channel = channel;
+
+ ret = wlan_prepare_cmd(pmpriv, HOST_CMD_APCMD_SYS_CONFIGURE,
+ HostCmd_ACT_GEN_SET, 0, MNULL, &tlv_chan_band);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Issue CMD to UAP firmware to get current beacon and dtim periods
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ *
+ * @return MLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+mlan_status
+wlan_uap_get_beacon_dtim(IN pmlan_private pmpriv)
+{
+ t_u8 tlv_buffer[sizeof(MrvlIEtypes_beacon_period_t) +
+ sizeof(MrvlIEtypes_dtim_period_t)];
+ MrvlIEtypes_beacon_period_t *ptlv_beacon_pd;
+ MrvlIEtypes_dtim_period_t *ptlv_dtim_pd;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ memset(pmpriv->adapter, &tlv_buffer, 0, sizeof(tlv_buffer));
+ ptlv_beacon_pd = (MrvlIEtypes_beacon_period_t *) tlv_buffer;
+ ptlv_beacon_pd->header.type = TLV_TYPE_UAP_BEACON_PERIOD;
+ ptlv_beacon_pd->header.len = sizeof(MrvlIEtypes_beacon_period_t)
+ - sizeof(MrvlIEtypesHeader_t);
+
+ ptlv_dtim_pd = (MrvlIEtypes_dtim_period_t *) (tlv_buffer
+ +
+ sizeof
+ (MrvlIEtypes_beacon_period_t));
+ ptlv_dtim_pd->header.type = TLV_TYPE_UAP_DTIM_PERIOD;
+ ptlv_dtim_pd->header.len = sizeof(MrvlIEtypes_dtim_period_t)
+ - sizeof(MrvlIEtypesHeader_t);
+
+ ret = wlan_prepare_cmd(pmpriv, HOST_CMD_APCMD_SYS_CONFIGURE,
+ HostCmd_ACT_GEN_GET, 0, MNULL, tlv_buffer);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief MLAN uap ioctl handler
+ *
+ * @param adapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+mlan_status
+wlan_ops_uap_ioctl(t_void * adapter, pmlan_ioctl_req pioctl_req)
+{
+ pmlan_adapter pmadapter = (pmlan_adapter) adapter;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+ mlan_ds_bss *bss = MNULL;
+ mlan_ds_get_info *pget_info = MNULL;
+ mlan_ds_misc_cfg *misc = MNULL;
+ mlan_ds_sec_cfg *sec = MNULL;
+ mlan_ds_pm_cfg *pm = MNULL;
+ mlan_ds_snmp_mib *snmp = MNULL;
+ mlan_ds_11d_cfg *cfg11d = MNULL;
+ mlan_ds_11h_cfg *cfg11h = MNULL;
+ mlan_ds_radio_cfg *radiocfg = MNULL;
+ mlan_ds_rate *rate = MNULL;
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
+
+ ENTER();
+
+ switch (pioctl_req->req_id) {
+ case MLAN_IOCTL_BSS:
+ bss = (mlan_ds_bss *) pioctl_req->pbuf;
+ if (bss->sub_command == MLAN_OID_BSS_MAC_ADDR)
+ status = wlan_uap_bss_ioctl_mac_address(pmadapter, pioctl_req);
+ else if (bss->sub_command == MLAN_OID_BSS_STOP)
+ status = wlan_uap_bss_ioctl_stop(pmadapter, pioctl_req);
+ else if (bss->sub_command == MLAN_OID_BSS_START)
+ status = wlan_uap_bss_ioctl_start(pmadapter, pioctl_req);
+ else if (bss->sub_command == MLAN_OID_UAP_BSS_CONFIG)
+ status = wlan_uap_bss_ioctl_config(pmadapter, pioctl_req);
+ else if (bss->sub_command == MLAN_OID_UAP_DEAUTH_STA)
+ status = wlan_uap_bss_ioctl_deauth_sta(pmadapter, pioctl_req);
+ else if (bss->sub_command == MLAN_OID_UAP_BSS_RESET)
+ status = wlan_uap_bss_ioctl_reset(pmadapter, pioctl_req);
+#if defined(STA_SUPPORT) && defined(UAP_SUPPORT)
+ else if (bss->sub_command == MLAN_OID_BSS_ROLE)
+ status = wlan_bss_ioctl_bss_role(pmadapter, pioctl_req);
+#endif
+#ifdef WIFI_DIRECT_SUPPORT
+ else if (bss->sub_command == MLAN_OID_WIFI_DIRECT_MODE)
+ status = wlan_bss_ioctl_wifi_direct_mode(pmadapter, pioctl_req);
+#endif
+ break;
+ case MLAN_IOCTL_GET_INFO:
+ pget_info = (mlan_ds_get_info *) pioctl_req->pbuf;
+ if (pget_info->sub_command == MLAN_OID_GET_VER_EXT)
+ status = wlan_get_info_ver_ext(pmadapter, pioctl_req);
+ else if (pget_info->sub_command == MLAN_OID_GET_DEBUG_INFO)
+ status = wlan_get_info_debug_info(pmadapter, pioctl_req);
+ else if (pget_info->sub_command == MLAN_OID_GET_STATS)
+ status = wlan_uap_get_stats(pmadapter, pioctl_req);
+ else if (pget_info->sub_command == MLAN_OID_UAP_STA_LIST)
+ status = wlan_uap_get_sta_list(pmadapter, pioctl_req);
+ else if (pget_info->sub_command == MLAN_OID_GET_BSS_INFO)
+ status = wlan_uap_get_bss_info(pmadapter, pioctl_req);
+ else if (pget_info->sub_command == MLAN_OID_GET_FW_INFO) {
+ pioctl_req->data_read_written =
+ sizeof(mlan_fw_info) + MLAN_SUB_COMMAND_SIZE;
+ memcpy(pmadapter, &pget_info->param.fw_info.mac_addr,
+ pmpriv->curr_addr, MLAN_MAC_ADDR_LENGTH);
+ pget_info->param.fw_info.fw_ver = pmadapter->fw_release_number;
+ pget_info->param.fw_info.fw_bands = pmadapter->fw_bands;
+ pget_info->param.fw_info.hw_dev_mcs_support =
+ pmadapter->hw_dev_mcs_support;
+ }
+ break;
+ case MLAN_IOCTL_MISC_CFG:
+ misc = (mlan_ds_misc_cfg *) pioctl_req->pbuf;
+ if (misc->sub_command == MLAN_OID_MISC_INIT_SHUTDOWN)
+ status = wlan_misc_ioctl_init_shutdown(pmadapter, pioctl_req);
+ if (misc->sub_command == MLAN_OID_MISC_SOFT_RESET)
+ status = wlan_uap_misc_ioctl_soft_reset(pmadapter, pioctl_req);
+ if (misc->sub_command == MLAN_OID_MISC_HOST_CMD)
+ status = wlan_misc_ioctl_host_cmd(pmadapter, pioctl_req);
+ if (misc->sub_command == MLAN_OID_MISC_GEN_IE)
+ status = wlan_uap_misc_ioctl_gen_ie(pmadapter, pioctl_req);
+ if (misc->sub_command == MLAN_OID_MISC_CUSTOM_IE)
+ status =
+ wlan_misc_ioctl_custom_ie_list(pmadapter, pioctl_req, MTRUE);
+ if (misc->sub_command == MLAN_OID_MISC_TX_DATAPAUSE)
+ status = wlan_uap_misc_ioctl_txdatapause(pmadapter, pioctl_req);
+ if (misc->sub_command == MLAN_OID_MISC_RX_MGMT_IND)
+ status = wlan_reg_rx_mgmt_ind(pmadapter, pioctl_req);
+#ifdef DEBUG_LEVEL1
+ if (misc->sub_command == MLAN_OID_MISC_DRVDBG)
+ status = wlan_set_drvdbg(pmadapter, pioctl_req);
+#endif
+ break;
+ case MLAN_IOCTL_PM_CFG:
+ pm = (mlan_ds_pm_cfg *) pioctl_req->pbuf;
+ if (pm->sub_command == MLAN_OID_PM_CFG_PS_MODE)
+ status = wlan_uap_pm_ioctl_mode(pmadapter, pioctl_req);
+ if (pm->sub_command == MLAN_OID_PM_CFG_DEEP_SLEEP)
+ status = wlan_uap_pm_ioctl_deepsleep(pmadapter, pioctl_req);
+ if (pm->sub_command == MLAN_OID_PM_CFG_HS_CFG) {
+ status = wlan_pm_ioctl_hscfg(pmadapter, pioctl_req);
+ }
+ if (pm->sub_command == MLAN_OID_PM_INFO) {
+ status = wlan_get_pm_info(pmadapter, pioctl_req);
+ }
+ break;
+ case MLAN_IOCTL_SNMP_MIB:
+ snmp = (mlan_ds_snmp_mib *) pioctl_req->pbuf;
+ if (snmp->sub_command == MLAN_OID_SNMP_MIB_DOT11D)
+ status = wlan_uap_snmp_mib_11d(pmadapter, pioctl_req);
+ if (snmp->sub_command == MLAN_OID_SNMP_MIB_DOT11H)
+ status = wlan_uap_snmp_mib_11h(pmadapter, pioctl_req);
+ break;
+ case MLAN_IOCTL_SEC_CFG:
+ sec = (mlan_ds_sec_cfg *) pioctl_req->pbuf;
+ if (sec->sub_command == MLAN_OID_SEC_CFG_ENCRYPT_KEY)
+ status = wlan_uap_sec_ioctl_set_encrypt_key(pmadapter, pioctl_req);
+ if (sec->sub_command == MLAN_OID_SEC_CFG_WAPI_ENABLED)
+ status = wlan_uap_sec_ioctl_wapi_enable(pmadapter, pioctl_req);
+ break;
+ case MLAN_IOCTL_11N_CFG:
+ status = wlan_11n_cfg_ioctl(pmadapter, pioctl_req);
+ break;
+ case MLAN_IOCTL_11D_CFG:
+ cfg11d = (mlan_ds_11d_cfg *) pioctl_req->pbuf;
+ if (cfg11d->sub_command == MLAN_OID_11D_DOMAIN_INFO)
+ status = wlan_uap_domain_info(pmadapter, pioctl_req);
+ break;
+ case MLAN_IOCTL_11H_CFG:
+ cfg11h = (mlan_ds_11h_cfg *) pioctl_req->pbuf;
+ if (cfg11h->sub_command == MLAN_OID_11H_CHANNEL_CHECK)
+ status = wlan_uap_11h_channel_check_req(pmadapter, pioctl_req);
+#if defined(DFS_TESTING_SUPPORT)
+ if (cfg11h->sub_command == MLAN_OID_11H_DFS_TESTING)
+ status = wlan_11h_ioctl_dfs_testing(pmadapter, pioctl_req);
+#endif
+ break;
+ case MLAN_IOCTL_RADIO_CFG:
+ radiocfg = (mlan_ds_radio_cfg *) pioctl_req->pbuf;
+ if (radiocfg->sub_command == MLAN_OID_RADIO_CTRL)
+ status = wlan_radio_ioctl_radio_ctl(pmadapter, pioctl_req);
+#ifdef WIFI_DIRECT_SUPPORT
+ if (radiocfg->sub_command == MLAN_OID_REMAIN_CHAN_CFG)
+ status = wlan_radio_ioctl_remain_chan_cfg(pmadapter, pioctl_req);
+#endif
+ if (radiocfg->sub_command == MLAN_OID_ANT_CFG)
+ status = wlan_radio_ioctl_ant_cfg(pmadapter, pioctl_req);
+ break;
+ case MLAN_IOCTL_RATE:
+ rate = (mlan_ds_rate *) pioctl_req->pbuf;
+ if (rate->sub_command == MLAN_OID_RATE_CFG)
+ status = wlan_rate_ioctl_cfg(pmadapter, pioctl_req);
+ break;
+ default:
+ pioctl_req->status_code = MLAN_ERROR_IOCTL_INVALID;
+ break;
+ }
+ LEAVE();
+ return status;
+}
diff --git a/drivers/net/wireless/sd8797/mlan/mlan_uap_txrx.c b/drivers/net/wireless/sd8797/mlan/mlan_uap_txrx.c
new file mode 100644
index 000000000000..1dad10bce62a
--- /dev/null
+++ b/drivers/net/wireless/sd8797/mlan/mlan_uap_txrx.c
@@ -0,0 +1,556 @@
+/** @file mlan_uap_txrx.c
+ *
+ * @brief This file contains AP mode transmit and receive functions
+ *
+ * Copyright (C) 2009-2011, Marvell International Ltd.
+ *
+ * This software file (the "File") is distributed by Marvell International
+ * Ltd. under the terms of the GNU General Public License Version 2, June 1991
+ * (the "License"). You may use, redistribute and/or modify this File in
+ * accordance with the terms and conditions of the License, a copy of which
+ * is available by writing to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
+ * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
+ *
+ * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
+ * ARE EXPRESSLY DISCLAIMED. The License provides additional details about
+ * this warranty disclaimer.
+ */
+
+/********************************************************
+Change log:
+ 02/05/2009: initial version
+********************************************************/
+
+#include "mlan.h"
+#include "mlan_util.h"
+#include "mlan_fw.h"
+#ifdef STA_SUPPORT
+#include "mlan_join.h"
+#endif
+#include "mlan_main.h"
+#include "mlan_uap.h"
+#include "mlan_sdio.h"
+#include "mlan_wmm.h"
+#include "mlan_11n_aggr.h"
+#include "mlan_11n_rxreorder.h"
+
+/********************************************************
+ Local Functions
+********************************************************/
+
+/**
+ * @brief This function processes received packet and forwards it
+ * to kernel/upper layer
+ *
+ * @param pmadapter A pointer to mlan_adapter
+ * @param pmbuf A pointer to mlan_buffer which includes the received packet
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+static mlan_status
+wlan_upload_uap_rx_packet(pmlan_adapter pmadapter, pmlan_buffer pmbuf)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ UapRxPD *prx_pd;
+ ENTER();
+ prx_pd = (UapRxPD *) (pmbuf->pbuf + pmbuf->data_offset);
+
+ /* Chop off RxPD */
+ pmbuf->data_len -= prx_pd->rx_pkt_offset;
+ pmbuf->data_offset += prx_pd->rx_pkt_offset;
+ pmbuf->pparent = MNULL;
+
+ DBG_HEXDUMP(MDAT_D, "uAP RxPD", (t_u8 *) prx_pd,
+ MIN(sizeof(UapRxPD), MAX_DATA_DUMP_LEN));
+ DBG_HEXDUMP(MDAT_D, "uAP Rx Payload",
+ ((t_u8 *) prx_pd + prx_pd->rx_pkt_offset),
+ MIN(prx_pd->rx_pkt_length, MAX_DATA_DUMP_LEN));
+
+ pmadapter->callbacks.moal_get_system_time(pmadapter->pmoal_handle,
+ &pmbuf->out_ts_sec,
+ &pmbuf->out_ts_usec);
+ PRINTM(MDATA, "%lu.%06lu : Data => kernel seq_num=%d tid=%d\n",
+ pmbuf->out_ts_sec, pmbuf->out_ts_usec, prx_pd->seq_num,
+ prx_pd->priority);
+ ret = pmadapter->callbacks.moal_recv_packet(pmadapter->pmoal_handle, pmbuf);
+ if (ret == MLAN_STATUS_FAILURE) {
+ PRINTM(MERROR, "uAP Rx Error: moal_recv_packet returned error\n");
+ pmbuf->status_code = MLAN_ERROR_PKT_INVALID;
+ }
+
+ if (ret != MLAN_STATUS_PENDING) {
+ wlan_free_mlan_buffer(pmadapter, pmbuf);
+ }
+ LEAVE();
+
+ return ret;
+
+}
+
+/**
+ * @brief This function will check if unicast packet need be dropped
+ *
+ * @param priv A pointer to mlan_private
+ * @param mac mac address to find in station list table
+ *
+ * @return MLAN_STATUS_FAILURE -- drop packet, otherwise forward to network stack
+ */
+static mlan_status
+wlan_check_unicast_packet(mlan_private * priv, t_u8 * mac)
+{
+ int j;
+ sta_node *sta_ptr = MNULL;
+ pmlan_adapter pmadapter = priv->adapter;
+ pmlan_private pmpriv = MNULL;
+ t_u8 pkt_type = 0;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ ENTER();
+ for (j = 0; j < MLAN_MAX_BSS_NUM; ++j) {
+ if ((pmpriv = pmadapter->priv[j])) {
+ if (GET_BSS_ROLE(pmpriv) == MLAN_BSS_ROLE_STA)
+ continue;
+ sta_ptr = wlan_get_station_entry(pmpriv, mac);
+ if (sta_ptr) {
+ if (pmpriv == priv)
+ pkt_type = PKT_INTRA_UCAST;
+ else
+ pkt_type = PKT_INTER_UCAST;
+ break;
+ }
+ }
+ }
+ if ((pkt_type == PKT_INTRA_UCAST) && (priv->pkt_fwd & PKT_FWD_INTRA_UCAST)) {
+ PRINTM(MDATA, "Drop INTRA_UCAST packet\n");
+ ret = MLAN_STATUS_FAILURE;
+ } else if ((pkt_type == PKT_INTER_UCAST) &&
+ (priv->pkt_fwd & PKT_FWD_INTER_UCAST)) {
+ PRINTM(MDATA, "Drop INTER_UCAST packet\n");
+ ret = MLAN_STATUS_FAILURE;
+ }
+ LEAVE();
+ return ret;
+}
+
+/********************************************************
+ Global Functions
+********************************************************/
+/**
+ * @brief This function fill the txpd for tx packet
+ *
+ * @param priv A pointer to mlan_private structure
+ * @param pmbuf A pointer to the mlan_buffer for process
+ *
+ * @return headptr or MNULL
+ */
+t_void *
+wlan_ops_uap_process_txpd(IN t_void * priv, IN pmlan_buffer pmbuf)
+{
+ pmlan_private pmpriv = (pmlan_private) priv;
+ UapTxPD *plocal_tx_pd;
+ t_u8 *head_ptr = MNULL;
+ t_u32 pkt_type;
+ t_u32 tx_control;
+ ENTER();
+
+ if (!pmbuf->data_len) {
+ PRINTM(MERROR, "uAP Tx Error: Invalid packet length: %d\n",
+ pmbuf->data_len);
+ pmbuf->status_code = MLAN_ERROR_PKT_SIZE_INVALID;
+ goto done;
+ }
+ if (pmbuf->buf_type == MLAN_BUF_TYPE_RAW_DATA) {
+ memcpy(pmpriv->adapter, &pkt_type, pmbuf->pbuf + pmbuf->data_offset,
+ sizeof(pkt_type));
+ memcpy(pmpriv->adapter, &tx_control,
+ pmbuf->pbuf + pmbuf->data_offset + sizeof(pkt_type),
+ sizeof(tx_control));
+ pmbuf->data_offset += sizeof(pkt_type) + sizeof(tx_control);
+ pmbuf->data_len -= sizeof(pkt_type) + sizeof(tx_control);
+ }
+ if (pmbuf->data_offset < (sizeof(UapTxPD) + INTF_HEADER_LEN +
+ DMA_ALIGNMENT)) {
+ PRINTM(MERROR, "not enough space for UapTxPD: len=%d, offset=%d\n",
+ pmbuf->data_len, pmbuf->data_offset);
+ DBG_HEXDUMP(MDAT_D, "drop pkt", pmbuf->pbuf + pmbuf->data_offset,
+ pmbuf->data_len);
+ pmbuf->status_code = MLAN_ERROR_PKT_SIZE_INVALID;
+ goto done;
+ }
+
+ /* head_ptr should be aligned */
+ head_ptr =
+ pmbuf->pbuf + pmbuf->data_offset - sizeof(UapTxPD) - INTF_HEADER_LEN;
+ head_ptr = (t_u8 *) ((t_ptr) head_ptr & ~((t_ptr) (DMA_ALIGNMENT - 1)));
+
+ plocal_tx_pd = (UapTxPD *) (head_ptr + INTF_HEADER_LEN);
+ memset(pmpriv->adapter, plocal_tx_pd, 0, sizeof(UapTxPD));
+
+ /* Set the BSS number to TxPD */
+ plocal_tx_pd->bss_num = GET_BSS_NUM(pmpriv);
+ plocal_tx_pd->bss_type = pmpriv->bss_type;
+
+ plocal_tx_pd->tx_pkt_length = (t_u16) pmbuf->data_len;
+
+ plocal_tx_pd->priority = (t_u8) pmbuf->priority;
+ plocal_tx_pd->pkt_delay_2ms =
+ wlan_wmm_compute_driver_packet_delay(pmpriv, pmbuf);
+
+ if (plocal_tx_pd->priority < NELEMENTS(pmpriv->wmm.user_pri_pkt_tx_ctrl))
+ /*
+ * Set the priority specific tx_control field, setting of 0 will
+ * cause the default value to be used later in this function
+ */
+ plocal_tx_pd->tx_control
+ = pmpriv->wmm.user_pri_pkt_tx_ctrl[plocal_tx_pd->priority];
+
+ /* Offset of actual data */
+ plocal_tx_pd->tx_pkt_offset =
+ (t_u16) ((t_ptr) pmbuf->pbuf + pmbuf->data_offset -
+ (t_ptr) plocal_tx_pd);
+
+ if (pmbuf->buf_type == MLAN_BUF_TYPE_RAW_DATA) {
+ plocal_tx_pd->tx_pkt_type = (t_u16) pkt_type;
+ plocal_tx_pd->tx_control = tx_control;
+ }
+ uap_endian_convert_TxPD(plocal_tx_pd);
+
+ /* Adjust the data offset and length to include TxPD in pmbuf */
+ pmbuf->data_len += pmbuf->data_offset;
+ pmbuf->data_offset = (t_u32) ((t_ptr) head_ptr - (t_ptr) pmbuf->pbuf);
+ pmbuf->data_len -= pmbuf->data_offset;
+
+ done:
+ LEAVE();
+ return head_ptr;
+}
+
+/**
+ * @brief This function processes received packet and forwards it
+ * to kernel/upper layer
+ *
+ * @param adapter A pointer to mlan_adapter
+ * @param pmbuf A pointer to mlan_buffer which includes the received packet
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status
+wlan_ops_uap_process_rx_packet(IN t_void * adapter, IN pmlan_buffer pmbuf)
+{
+ pmlan_adapter pmadapter = (pmlan_adapter) adapter;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ UapRxPD *prx_pd;
+ wlan_mgmt_pkt *puap_pkt_hdr = MNULL;
+
+ RxPacketHdr_t *prx_pkt;
+ pmlan_private priv = pmadapter->priv[pmbuf->bss_index];
+ t_u8 ta[MLAN_MAC_ADDR_LENGTH];
+ t_u16 rx_pkt_type = 0;
+ sta_node *sta_ptr = MNULL;
+
+ ENTER();
+
+ prx_pd = (UapRxPD *) (pmbuf->pbuf + pmbuf->data_offset);
+ /* Endian conversion */
+ uap_endian_convert_RxPD(prx_pd);
+ rx_pkt_type = prx_pd->rx_pkt_type;
+ prx_pkt = (RxPacketHdr_t *) ((t_u8 *) prx_pd + prx_pd->rx_pkt_offset);
+
+ PRINTM(MINFO, "RX Data: data_len - prx_pd->rx_pkt_offset = %d - %d = %d\n",
+ pmbuf->data_len, prx_pd->rx_pkt_offset,
+ pmbuf->data_len - prx_pd->rx_pkt_offset);
+
+ if ((prx_pd->rx_pkt_offset + prx_pd->rx_pkt_length) >
+ (t_u16) pmbuf->data_len) {
+ PRINTM(MERROR,
+ "Wrong rx packet: len=%d,rx_pkt_offset=%d,"
+ " rx_pkt_length=%d\n", pmbuf->data_len, prx_pd->rx_pkt_offset,
+ prx_pd->rx_pkt_length);
+ pmbuf->status_code = MLAN_ERROR_PKT_SIZE_INVALID;
+ ret = MLAN_STATUS_FAILURE;
+ wlan_free_mlan_buffer(pmadapter, pmbuf);
+ goto done;
+ }
+ pmbuf->data_len = prx_pd->rx_pkt_offset + prx_pd->rx_pkt_length;
+
+ if (pmadapter->priv[pmbuf->bss_index]->mgmt_frame_passthru_mask &&
+ prx_pd->rx_pkt_type == PKT_TYPE_MGMT_FRAME) {
+ /* Check if this is mgmt packet and needs to forwarded to app as an
+ event */
+ puap_pkt_hdr =
+ (wlan_mgmt_pkt *) ((t_u8 *) prx_pd + prx_pd->rx_pkt_offset);
+ puap_pkt_hdr->frm_len = wlan_le16_to_cpu(puap_pkt_hdr->frm_len);
+ if ((puap_pkt_hdr->wlan_header.
+ frm_ctl & IEEE80211_FC_MGMT_FRAME_TYPE_MASK) == 0)
+ wlan_process_802dot11_mgmt_pkt(pmadapter->priv[pmbuf->bss_index],
+ (t_u8 *) & puap_pkt_hdr->wlan_header,
+ puap_pkt_hdr->frm_len +
+ sizeof(wlan_mgmt_pkt) -
+ sizeof(puap_pkt_hdr->frm_len));
+ wlan_free_mlan_buffer(pmadapter, pmbuf);
+ goto done;
+ }
+
+ pmbuf->priority = prx_pd->priority;
+ memcpy(pmadapter, ta, prx_pkt->eth803_hdr.src_addr, MLAN_MAC_ADDR_LENGTH);
+ if ((rx_pkt_type != PKT_TYPE_BAR) && (prx_pd->priority < MAX_NUM_TID)) {
+ if ((sta_ptr = wlan_get_station_entry(priv, ta)))
+ sta_ptr->rx_seq[prx_pd->priority] = prx_pd->seq_num;
+ }
+ /* check if UAP enable 11n */
+ if (!priv->is_11n_enabled ||
+ (!wlan_11n_get_rxreorder_tbl
+ ((mlan_private *) priv, prx_pd->priority, ta)
+ && (prx_pd->rx_pkt_type != PKT_TYPE_AMSDU)
+ )) {
+ if (priv->pkt_fwd)
+ wlan_process_uap_rx_packet(priv, pmbuf);
+ else
+ wlan_upload_uap_rx_packet(pmadapter, pmbuf);
+ goto done;
+ }
+ /* Reorder and send to OS */
+ if ((ret = mlan_11n_rxreorder_pkt(priv, prx_pd->seq_num,
+ prx_pd->priority, ta,
+ (t_u8) prx_pd->rx_pkt_type,
+ (void *) pmbuf))
+ || (rx_pkt_type == PKT_TYPE_BAR)) {
+ wlan_free_mlan_buffer(pmadapter, pmbuf);
+ }
+ done:
+ if (priv->is_11n_enabled &&
+ (pmadapter->pending_bridge_pkts >= RX_MED_THRESHOLD))
+ wlan_send_delba_to_all_in_reorder_tbl(priv);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function processes received packet and forwards it
+ * to kernel/upper layer or send back to firmware
+ *
+ * @param priv A pointer to mlan_private
+ * @param pmbuf A pointer to mlan_buffer which includes the received packet
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status
+wlan_uap_recv_packet(IN mlan_private * priv, IN pmlan_buffer pmbuf)
+{
+ pmlan_adapter pmadapter = priv->adapter;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ RxPacketHdr_t *prx_pkt;
+ pmlan_buffer newbuf = MNULL;
+
+ ENTER();
+
+ prx_pkt = (RxPacketHdr_t *) ((t_u8 *) pmbuf->pbuf + pmbuf->data_offset);
+
+ DBG_HEXDUMP(MDAT_D, "uap_recv_packet", pmbuf->pbuf + pmbuf->data_offset,
+ MIN(pmbuf->data_len, MAX_DATA_DUMP_LEN));
+
+ PRINTM(MDATA, "AMSDU dest %02x:%02x:%02x:%02x:%02x:%02x\n",
+ prx_pkt->eth803_hdr.dest_addr[0], prx_pkt->eth803_hdr.dest_addr[1],
+ prx_pkt->eth803_hdr.dest_addr[2], prx_pkt->eth803_hdr.dest_addr[3],
+ prx_pkt->eth803_hdr.dest_addr[4], prx_pkt->eth803_hdr.dest_addr[5]);
+
+ /* don't do packet forwarding in disconnected state */
+ if ((priv->media_connected == MFALSE) ||
+ (pmbuf->data_len > MV_ETH_FRAME_LEN))
+ goto upload;
+
+ if (prx_pkt->eth803_hdr.dest_addr[0] & 0x01) {
+ if (!(priv->pkt_fwd & PKT_FWD_INTRA_BCAST)) {
+ /* Multicast pkt */
+ if ((newbuf =
+ wlan_alloc_mlan_buffer(pmadapter, MLAN_TX_DATA_BUF_SIZE_2K, 0,
+ MTRUE))) {
+ newbuf->bss_index = pmbuf->bss_index;
+ newbuf->buf_type = pmbuf->buf_type;
+ newbuf->priority = pmbuf->priority;
+ newbuf->in_ts_sec = pmbuf->in_ts_sec;
+ newbuf->in_ts_usec = pmbuf->in_ts_usec;
+ newbuf->data_offset =
+ (sizeof(UapTxPD) + INTF_HEADER_LEN + DMA_ALIGNMENT);
+ pmadapter->pending_bridge_pkts++;
+ newbuf->flags |= MLAN_BUF_FLAG_BRIDGE_BUF;
+
+ /* copy the data */
+ memcpy(pmadapter, (t_u8 *) newbuf->pbuf + newbuf->data_offset,
+ pmbuf->pbuf + pmbuf->data_offset, pmbuf->data_len);
+ newbuf->data_len = pmbuf->data_len;
+ wlan_wmm_add_buf_txqueue(pmadapter, newbuf);
+ if (pmadapter->pending_bridge_pkts > RX_HIGH_THRESHOLD)
+ wlan_drop_tx_pkts(priv);
+ }
+ }
+ } else {
+ if ((!(priv->pkt_fwd & PKT_FWD_INTRA_UCAST)) &&
+ (wlan_get_station_entry(priv, prx_pkt->eth803_hdr.dest_addr))) {
+ /* Intra BSS packet */
+ if ((newbuf =
+ wlan_alloc_mlan_buffer(pmadapter, MLAN_TX_DATA_BUF_SIZE_2K, 0,
+ MTRUE))) {
+ newbuf->bss_index = pmbuf->bss_index;
+ newbuf->buf_type = pmbuf->buf_type;
+ newbuf->priority = pmbuf->priority;
+ newbuf->in_ts_sec = pmbuf->in_ts_sec;
+ newbuf->in_ts_usec = pmbuf->in_ts_usec;
+ newbuf->data_offset =
+ (sizeof(UapTxPD) + INTF_HEADER_LEN + DMA_ALIGNMENT);
+ pmadapter->pending_bridge_pkts++;
+ newbuf->flags |= MLAN_BUF_FLAG_BRIDGE_BUF;
+
+ /* copy the data */
+ memcpy(pmadapter, (t_u8 *) newbuf->pbuf + newbuf->data_offset,
+ pmbuf->pbuf + pmbuf->data_offset, pmbuf->data_len);
+ newbuf->data_len = pmbuf->data_len;
+ wlan_wmm_add_buf_txqueue(pmadapter, newbuf);
+ if (pmadapter->pending_bridge_pkts > RX_HIGH_THRESHOLD)
+ wlan_drop_tx_pkts(priv);
+ }
+ goto done;
+ } else if (MLAN_STATUS_FAILURE ==
+ wlan_check_unicast_packet(priv,
+ prx_pkt->eth803_hdr.dest_addr)) {
+ /* drop packet */
+ PRINTM(MDATA, "Drop AMSDU dest %02x:%02x:%02x:%02x:%02x:%02x\n",
+ prx_pkt->eth803_hdr.dest_addr[0],
+ prx_pkt->eth803_hdr.dest_addr[1],
+ prx_pkt->eth803_hdr.dest_addr[2],
+ prx_pkt->eth803_hdr.dest_addr[3],
+ prx_pkt->eth803_hdr.dest_addr[4],
+ prx_pkt->eth803_hdr.dest_addr[5]);
+ goto done;
+ }
+ }
+ upload:
+ /** send packet to moal */
+ ret = pmadapter->callbacks.moal_recv_packet(pmadapter->pmoal_handle, pmbuf);
+ done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function processes received packet and forwards it
+ * to kernel/upper layer or send back to firmware
+ *
+ * @param priv A pointer to mlan_private
+ * @param pmbuf A pointer to mlan_buffer which includes the received packet
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status
+wlan_process_uap_rx_packet(IN mlan_private * priv, IN pmlan_buffer pmbuf)
+{
+ pmlan_adapter pmadapter = priv->adapter;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ UapRxPD *prx_pd;
+ RxPacketHdr_t *prx_pkt;
+ pmlan_buffer newbuf = MNULL;
+
+ ENTER();
+
+ prx_pd = (UapRxPD *) (pmbuf->pbuf + pmbuf->data_offset);
+ prx_pkt = (RxPacketHdr_t *) ((t_u8 *) prx_pd + prx_pd->rx_pkt_offset);
+
+ DBG_HEXDUMP(MDAT_D, "uAP RxPD", prx_pd,
+ MIN(sizeof(UapRxPD), MAX_DATA_DUMP_LEN));
+ DBG_HEXDUMP(MDAT_D, "uAP Rx Payload",
+ ((t_u8 *) prx_pd + prx_pd->rx_pkt_offset),
+ MIN(prx_pd->rx_pkt_length, MAX_DATA_DUMP_LEN));
+
+ PRINTM(MINFO, "RX Data: data_len - prx_pd->rx_pkt_offset = %d - %d = %d\n",
+ pmbuf->data_len, prx_pd->rx_pkt_offset,
+ pmbuf->data_len - prx_pd->rx_pkt_offset);
+ PRINTM(MDATA, "Rx dest %02x:%02x:%02x:%02x:%02x:%02x\n",
+ prx_pkt->eth803_hdr.dest_addr[0], prx_pkt->eth803_hdr.dest_addr[1],
+ prx_pkt->eth803_hdr.dest_addr[2], prx_pkt->eth803_hdr.dest_addr[3],
+ prx_pkt->eth803_hdr.dest_addr[4], prx_pkt->eth803_hdr.dest_addr[5]);
+
+ /* don't do packet forwarding in disconnected state */
+ /* don't do packet forwarding when packet > 1514 */
+ if ((priv->media_connected == MFALSE) ||
+ ((pmbuf->data_len - prx_pd->rx_pkt_offset) > MV_ETH_FRAME_LEN))
+ goto upload;
+
+ if (prx_pkt->eth803_hdr.dest_addr[0] & 0x01) {
+ if (!(priv->pkt_fwd & PKT_FWD_INTRA_BCAST)) {
+ /* Multicast pkt */
+ if ((newbuf =
+ wlan_alloc_mlan_buffer(pmadapter, MLAN_TX_DATA_BUF_SIZE_2K, 0,
+ MTRUE))) {
+ newbuf->bss_index = pmbuf->bss_index;
+ newbuf->buf_type = pmbuf->buf_type;
+ newbuf->priority = pmbuf->priority;
+ newbuf->in_ts_sec = pmbuf->in_ts_sec;
+ newbuf->in_ts_usec = pmbuf->in_ts_usec;
+ newbuf->data_offset =
+ (sizeof(UapTxPD) + INTF_HEADER_LEN + DMA_ALIGNMENT);
+ pmadapter->pending_bridge_pkts++;
+ newbuf->flags |= MLAN_BUF_FLAG_BRIDGE_BUF;
+
+ /* copy the data, skip rxpd */
+ memcpy(pmadapter, (t_u8 *) newbuf->pbuf + newbuf->data_offset,
+ pmbuf->pbuf + pmbuf->data_offset + prx_pd->rx_pkt_offset,
+ pmbuf->data_len - prx_pd->rx_pkt_offset);
+ newbuf->data_len = pmbuf->data_len - prx_pd->rx_pkt_offset;
+ wlan_wmm_add_buf_txqueue(pmadapter, newbuf);
+ if (pmadapter->pending_bridge_pkts > RX_HIGH_THRESHOLD)
+ wlan_drop_tx_pkts(priv);
+ }
+ }
+ } else {
+ if ((!(priv->pkt_fwd & PKT_FWD_INTRA_UCAST)) &&
+ (wlan_get_station_entry(priv, prx_pkt->eth803_hdr.dest_addr))) {
+ /* Forwarding Intra-BSS packet */
+ pmbuf->data_len -= prx_pd->rx_pkt_offset;
+ pmbuf->data_offset += prx_pd->rx_pkt_offset;
+ pmbuf->flags |= MLAN_BUF_FLAG_BRIDGE_BUF;
+ pmadapter->pending_bridge_pkts++;
+ wlan_wmm_add_buf_txqueue(pmadapter, pmbuf);
+ if (pmadapter->pending_bridge_pkts > RX_HIGH_THRESHOLD)
+ wlan_drop_tx_pkts(priv);
+ goto done;
+ } else if (MLAN_STATUS_FAILURE ==
+ wlan_check_unicast_packet(priv,
+ prx_pkt->eth803_hdr.dest_addr)) {
+ PRINTM(MDATA, "Drop Pkts: Rx dest %02x:%02x:%02x:%02x:%02x:%02x\n",
+ prx_pkt->eth803_hdr.dest_addr[0],
+ prx_pkt->eth803_hdr.dest_addr[1],
+ prx_pkt->eth803_hdr.dest_addr[2],
+ prx_pkt->eth803_hdr.dest_addr[3],
+ prx_pkt->eth803_hdr.dest_addr[4],
+ prx_pkt->eth803_hdr.dest_addr[5]);
+ pmbuf->status_code = MLAN_ERROR_PKT_INVALID;
+ wlan_free_mlan_buffer(pmadapter, pmbuf);
+ goto done;
+ }
+ }
+ upload:
+ /* Chop off RxPD */
+ pmbuf->data_len -= prx_pd->rx_pkt_offset;
+ pmbuf->data_offset += prx_pd->rx_pkt_offset;
+ pmbuf->pparent = MNULL;
+
+ pmadapter->callbacks.moal_get_system_time(pmadapter->pmoal_handle,
+ &pmbuf->out_ts_sec,
+ &pmbuf->out_ts_usec);
+ PRINTM(MDATA, "%lu.%06lu : Data => kernel seq_num=%d tid=%d\n",
+ pmbuf->out_ts_sec, pmbuf->out_ts_usec, prx_pd->seq_num,
+ prx_pd->priority);
+ ret = pmadapter->callbacks.moal_recv_packet(pmadapter->pmoal_handle, pmbuf);
+ if (ret == MLAN_STATUS_FAILURE) {
+ PRINTM(MERROR, "uAP Rx Error: moal_recv_packet returned error\n");
+ pmbuf->status_code = MLAN_ERROR_PKT_INVALID;
+ }
+
+ if (ret != MLAN_STATUS_PENDING) {
+ wlan_free_mlan_buffer(pmadapter, pmbuf);
+ }
+ done:
+ LEAVE();
+ return ret;
+}
diff --git a/drivers/net/wireless/sd8797/mlan/mlan_util.h b/drivers/net/wireless/sd8797/mlan/mlan_util.h
new file mode 100644
index 000000000000..c5231f6b775e
--- /dev/null
+++ b/drivers/net/wireless/sd8797/mlan/mlan_util.h
@@ -0,0 +1,526 @@
+/** @file mlan_util.h
+ *
+ * @brief This file contains wrappers for linked-list,
+ * spinlock and timer defines.
+ *
+ * Copyright (C) 2008-2011, Marvell International Ltd.
+ *
+ * This software file (the "File") is distributed by Marvell International
+ * Ltd. under the terms of the GNU General Public License Version 2, June 1991
+ * (the "License"). You may use, redistribute and/or modify this File in
+ * accordance with the terms and conditions of the License, a copy of which
+ * is available by writing to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
+ * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
+ *
+ * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
+ * ARE EXPRESSLY DISCLAIMED. The License provides additional details about
+ * this warranty disclaimer.
+ */
+
+/******************************************************
+Change log:
+ 10/28/2008: initial version
+******************************************************/
+
+#ifndef _MLAN_UTIL_H_
+#define _MLAN_UTIL_H_
+
+/** Circular doubly linked list */
+typedef struct _mlan_linked_list
+{
+ /** Pointer to previous node */
+ struct _mlan_linked_list *pprev;
+ /** Pointer to next node */
+ struct _mlan_linked_list *pnext;
+} mlan_linked_list, *pmlan_linked_list;
+
+/** List head */
+typedef struct _mlan_list_head
+{
+ /** Pointer to previous node */
+ struct _mlan_linked_list *pprev;
+ /** Pointer to next node */
+ struct _mlan_linked_list *pnext;
+ /** Pointer to lock */
+ t_void *plock;
+} mlan_list_head, *pmlan_list_head;
+
+/**
+ * @brief This function initializes a list without locking
+ *
+ * @param phead List head
+ *
+ * @return N/A
+ */
+static INLINE t_void
+util_init_list(pmlan_linked_list phead)
+{
+ /* Both next and prev point to self */
+ phead->pprev = phead->pnext = (pmlan_linked_list) phead;
+}
+
+/**
+ * @brief This function initializes a list
+ *
+ * @param phead List head
+ * @param lock_required A flag for spinlock requirement
+ * @param moal_init_lock A pointer to init lock handler
+ *
+ * @return N/A
+ */
+static INLINE t_void
+util_init_list_head(t_void * pmoal_handle,
+ pmlan_list_head phead,
+ t_u8 lock_required,
+ mlan_status(*moal_init_lock) (t_void * handle,
+ t_void ** pplock))
+{
+ /* Both next and prev point to self */
+ util_init_list((pmlan_linked_list) phead);
+ if (lock_required)
+ moal_init_lock(pmoal_handle, &phead->plock);
+ else
+ phead->plock = 0;
+}
+
+/**
+ * @brief This function frees a list
+ *
+ * @param phead List head
+ * @param moal_free_lock A pointer to free lock handler
+ *
+ * @return N/A
+ */
+static INLINE t_void
+util_free_list_head(t_void * pmoal_handle,
+ pmlan_list_head phead,
+ mlan_status(*moal_free_lock) (t_void * handle,
+ t_void * plock))
+{
+ phead->pprev = phead->pnext = 0;
+ if (phead->plock)
+ moal_free_lock(pmoal_handle, phead->plock);
+}
+
+/**
+ * @brief This function peeks into a list
+ *
+ * @param phead List head
+ * @param moal_spin_lock A pointer to spin lock handler
+ * @param moal_spin_unlock A pointer to spin unlock handler
+ *
+ * @return List node
+ */
+static INLINE pmlan_linked_list
+util_peek_list(t_void * pmoal_handle,
+ pmlan_list_head phead,
+ mlan_status(*moal_spin_lock) (t_void * handle, t_void * plock),
+ mlan_status(*moal_spin_unlock) (t_void * handle, t_void * plock))
+{
+ pmlan_linked_list pnode = 0;
+
+ if (moal_spin_lock)
+ moal_spin_lock(pmoal_handle, phead->plock);
+ if (phead->pnext != (pmlan_linked_list) phead) {
+ pnode = phead->pnext;
+ }
+ if (moal_spin_unlock)
+ moal_spin_unlock(pmoal_handle, phead->plock);
+ return pnode;
+}
+
+/**
+ * @brief This function queues a node at the list tail
+ *
+ * @param phead List head
+ * @param pnode List node to queue
+ * @param moal_spin_lock A pointer to spin lock handler
+ * @param moal_spin_unlock A pointer to spin unlock handler
+ *
+ * @return N/A
+ */
+static INLINE t_void
+util_enqueue_list_tail(t_void * pmoal_handle,
+ pmlan_list_head phead,
+ pmlan_linked_list pnode,
+ mlan_status(*moal_spin_lock) (t_void * handle,
+ t_void * plock),
+ mlan_status(*moal_spin_unlock) (t_void * handle,
+ t_void * plock))
+{
+ pmlan_linked_list pold_last;
+
+ if (moal_spin_lock)
+ moal_spin_lock(pmoal_handle, phead->plock);
+ pold_last = phead->pprev;
+ pnode->pprev = pold_last;
+ pnode->pnext = (pmlan_linked_list) phead;
+
+ phead->pprev = pold_last->pnext = pnode;
+ if (moal_spin_unlock)
+ moal_spin_unlock(pmoal_handle, phead->plock);
+}
+
+/**
+ * @brief This function adds a node at the list head
+ *
+ * @param phead List head
+ * @param pnode List node to add
+ * @param moal_spin_lock A pointer to spin lock handler
+ * @param moal_spin_unlock A pointer to spin unlock handler
+ *
+ * @return N/A
+ */
+static INLINE t_void
+util_enqueue_list_head(t_void * pmoal_handle,
+ pmlan_list_head phead,
+ pmlan_linked_list pnode,
+ mlan_status(*moal_spin_lock) (t_void * handle,
+ t_void * plock),
+ mlan_status(*moal_spin_unlock) (t_void * handle,
+ t_void * plock))
+{
+ pmlan_linked_list pold_first;
+
+ if (moal_spin_lock)
+ moal_spin_lock(pmoal_handle, phead->plock);
+ pold_first = phead->pnext;
+ pnode->pprev = (pmlan_linked_list) phead;
+ pnode->pnext = pold_first;
+
+ phead->pnext = pold_first->pprev = pnode;
+ if (moal_spin_unlock)
+ moal_spin_unlock(pmoal_handle, phead->plock);
+}
+
+/**
+ * @brief This function removes a node from the list
+ *
+ * @param phead List head
+ * @param pnode List node to remove
+ * @param moal_spin_lock A pointer to spin lock handler
+ * @param moal_spin_unlock A pointer to spin unlock handler
+ *
+ * @return N/A
+ */
+static INLINE t_void
+util_unlink_list(t_void * pmoal_handle,
+ pmlan_list_head phead,
+ pmlan_linked_list pnode,
+ mlan_status(*moal_spin_lock) (t_void * handle, t_void * plock),
+ mlan_status(*moal_spin_unlock) (t_void * handle,
+ t_void * plock))
+{
+ pmlan_linked_list pmy_prev;
+ pmlan_linked_list pmy_next;
+
+ if (moal_spin_lock)
+ moal_spin_lock(pmoal_handle, phead->plock);
+ pmy_prev = pnode->pprev;
+ pmy_next = pnode->pnext;
+ pmy_next->pprev = pmy_prev;
+ pmy_prev->pnext = pmy_next;
+
+ pnode->pnext = pnode->pprev = 0;
+ if (moal_spin_unlock)
+ moal_spin_unlock(pmoal_handle, phead->plock);
+}
+
+/**
+ * @brief This function dequeues a node from the list
+ *
+ * @param phead List head
+ * @param moal_spin_lock A pointer to spin lock handler
+ * @param moal_spin_unlock A pointer to spin unlock handler
+ *
+ * @return List node
+ */
+static INLINE pmlan_linked_list
+util_dequeue_list(t_void * pmoal_handle,
+ pmlan_list_head phead,
+ mlan_status(*moal_spin_lock) (t_void * handle,
+ t_void * plock),
+ mlan_status(*moal_spin_unlock) (t_void * handle,
+ t_void * plock))
+{
+ pmlan_linked_list pnode;
+
+ if (moal_spin_lock)
+ moal_spin_lock(pmoal_handle, phead->plock);
+ pnode = phead->pnext;
+ if (pnode && (pnode != (pmlan_linked_list) phead)) {
+ util_unlink_list(pmoal_handle, phead, pnode, 0, 0);
+ } else {
+ pnode = 0;
+ }
+ if (moal_spin_unlock)
+ moal_spin_unlock(pmoal_handle, phead->plock);
+ return pnode;
+}
+
+/** Access controlled scalar variable */
+typedef struct _mlan_scalar
+{
+ /** Value */
+ t_s32 value;
+ /** Pointer to lock */
+ t_void *plock;
+ /** Control flags */
+ t_u32 flags;
+} mlan_scalar, *pmlan_scalar;
+
+/** Flag to scalar lock acquired */
+#define MLAN_SCALAR_FLAG_UNIQUE_LOCK MBIT(16)
+
+/** scalar conditional value list */
+typedef enum _MLAN_SCALAR_CONDITIONAL
+{
+ MLAN_SCALAR_COND_EQUAL,
+ MLAN_SCALAR_COND_NOT_EQUAL,
+ MLAN_SCALAR_COND_GREATER_THAN,
+ MLAN_SCALAR_COND_GREATER_OR_EQUAL,
+ MLAN_SCALAR_COND_LESS_THAN,
+ MLAN_SCALAR_COND_LESS_OR_EQUAL
+} MLAN_SCALAR_CONDITIONAL;
+
+/**
+ * @brief This function initializes a scalar
+ *
+ * @param pscalar Pointer to scalar
+ * @param val Initial scalar value
+ * @param plock_to_use A new lock is created if NULL, else lock to use
+ * @param moal_init_lock A pointer to init lock handler
+ *
+ * @return N/A
+ */
+static INLINE t_void
+util_scalar_init(t_void * pmoal_handle,
+ pmlan_scalar pscalar,
+ t_s32 val,
+ t_void * plock_to_use,
+ mlan_status(*moal_init_lock) (t_void * handle,
+ t_void ** pplock))
+{
+ pscalar->value = val;
+ pscalar->flags = 0;
+ if (plock_to_use) {
+ pscalar->flags &= ~MLAN_SCALAR_FLAG_UNIQUE_LOCK;
+ pscalar->plock = plock_to_use;
+ } else {
+ pscalar->flags |= MLAN_SCALAR_FLAG_UNIQUE_LOCK;
+ moal_init_lock(pmoal_handle, &pscalar->plock);
+ }
+}
+
+/**
+ * @brief This function frees a scalar
+ *
+ * @param pscalar Pointer to scalar
+ * @param moal_free_lock A pointer to free lock handler
+ *
+ * @return N/A
+ */
+static INLINE t_void
+util_scalar_free(t_void * pmoal_handle,
+ pmlan_scalar pscalar,
+ mlan_status(*moal_free_lock) (t_void * handle, t_void * plock))
+{
+ if (pscalar->flags & MLAN_SCALAR_FLAG_UNIQUE_LOCK)
+ moal_free_lock(pmoal_handle, &pscalar->plock);
+}
+
+/**
+ * @brief This function reads value from scalar
+ *
+ * @param pscalar Pointer to scalar
+ * @param moal_spin_lock A pointer to spin lock handler
+ * @param moal_spin_unlock A pointer to spin unlock handler
+ *
+ * @return Stored value
+ */
+static INLINE t_s32
+util_scalar_read(t_void * pmoal_handle,
+ pmlan_scalar pscalar,
+ mlan_status(*moal_spin_lock) (t_void * handle, t_void * plock),
+ mlan_status(*moal_spin_unlock) (t_void * handle,
+ t_void * plock))
+{
+ t_s32 val;
+
+ if (moal_spin_lock)
+ moal_spin_lock(pmoal_handle, pscalar->plock);
+ val = pscalar->value;
+ if (moal_spin_unlock)
+ moal_spin_unlock(pmoal_handle, pscalar->plock);
+
+ return val;
+}
+
+/**
+ * @brief This function writes value to scalar
+ *
+ * @param pscalar Pointer to scalar
+ * @param val Value to write
+ * @param moal_spin_lock A pointer to spin lock handler
+ * @param moal_spin_unlock A pointer to spin unlock handler
+ *
+ * @return N/A
+ */
+static INLINE t_void
+util_scalar_write(t_void * pmoal_handle,
+ pmlan_scalar pscalar,
+ t_s32 val,
+ mlan_status(*moal_spin_lock) (t_void * handle,
+ t_void * plock),
+ mlan_status(*moal_spin_unlock) (t_void * handle,
+ t_void * plock))
+{
+ if (moal_spin_lock)
+ moal_spin_lock(pmoal_handle, pscalar->plock);
+ pscalar->value = val;
+ if (moal_spin_unlock)
+ moal_spin_unlock(pmoal_handle, pscalar->plock);
+}
+
+/**
+ * @brief This function increments the value in scalar
+ *
+ * @param pscalar Pointer to scalar
+ * @param moal_spin_lock A pointer to spin lock handler
+ * @param moal_spin_unlock A pointer to spin unlock handler
+ *
+ * @return N/A
+ */
+static INLINE t_void
+util_scalar_increment(t_void * pmoal_handle,
+ pmlan_scalar pscalar,
+ mlan_status(*moal_spin_lock) (t_void * handle,
+ t_void * plock),
+ mlan_status(*moal_spin_unlock) (t_void * handle,
+ t_void * plock))
+{
+ if (moal_spin_lock)
+ moal_spin_lock(pmoal_handle, pscalar->plock);
+ pscalar->value++;
+ if (moal_spin_unlock)
+ moal_spin_unlock(pmoal_handle, pscalar->plock);
+}
+
+/**
+ * @brief This function decrements the value in scalar
+ *
+ * @param pscalar Pointer to scalar
+ * @param moal_spin_lock A pointer to spin lock handler
+ * @param moal_spin_unlock A pointer to spin unlock handler
+ *
+ * @return N/A
+ */
+static INLINE t_void
+util_scalar_decrement(t_void * pmoal_handle,
+ pmlan_scalar pscalar,
+ mlan_status(*moal_spin_lock) (t_void * handle,
+ t_void * plock),
+ mlan_status(*moal_spin_unlock) (t_void * handle,
+ t_void * plock))
+{
+ if (moal_spin_lock)
+ moal_spin_lock(pmoal_handle, pscalar->plock);
+ pscalar->value--;
+ if (moal_spin_unlock)
+ moal_spin_unlock(pmoal_handle, pscalar->plock);
+}
+
+/**
+ * @brief This function adds an offset to the value in scalar,
+ * and returns the new value
+ *
+ * @param pscalar Pointer to scalar
+ * @param offset Offset value (can be negative)
+ * @param moal_spin_lock A pointer to spin lock handler
+ * @param moal_spin_unlock A pointer to spin unlock handler
+ *
+ * @return Value after offset
+ */
+static INLINE t_s32
+util_scalar_offset(t_void * pmoal_handle,
+ pmlan_scalar pscalar,
+ t_s32 offset,
+ mlan_status(*moal_spin_lock) (t_void * handle,
+ t_void * plock),
+ mlan_status(*moal_spin_unlock) (t_void * handle,
+ t_void * plock))
+{
+ t_s32 newval;
+
+ if (moal_spin_lock)
+ moal_spin_lock(pmoal_handle, pscalar->plock);
+ newval = (pscalar->value += offset);
+ if (moal_spin_unlock)
+ moal_spin_unlock(pmoal_handle, pscalar->plock);
+
+ return newval;
+}
+
+/**
+ * @brief This function writes the value to the scalar
+ * if existing value compared with other value is true.
+ *
+ * @param pscalar Pointer to scalar
+ * @param condition Condition to check
+ * @param val_compare Value to compare against current value
+ * ((A X B), where B = val_compare)
+ * @param val_to_set Value to set if comparison is true
+ * @param moal_spin_lock A pointer to spin lock handler
+ * @param moal_spin_unlock A pointer to spin unlock handler
+ *
+ * @return Comparison result (MTRUE or MFALSE)
+ */
+static INLINE t_u8
+util_scalar_conditional_write(t_void * pmoal_handle,
+ pmlan_scalar pscalar,
+ MLAN_SCALAR_CONDITIONAL condition,
+ t_s32 val_compare,
+ t_s32 val_to_set,
+ mlan_status(*moal_spin_lock) (t_void * handle,
+ t_void * plock),
+ mlan_status(*moal_spin_unlock) (t_void * handle,
+ t_void * plock))
+{
+ t_u8 update;
+ if (moal_spin_lock)
+ moal_spin_lock(pmoal_handle, pscalar->plock);
+
+ switch (condition) {
+ case MLAN_SCALAR_COND_EQUAL:
+ update = (pscalar->value == val_compare);
+ break;
+ case MLAN_SCALAR_COND_NOT_EQUAL:
+ update = (pscalar->value != val_compare);
+ break;
+ case MLAN_SCALAR_COND_GREATER_THAN:
+ update = (pscalar->value > val_compare);
+ break;
+ case MLAN_SCALAR_COND_GREATER_OR_EQUAL:
+ update = (pscalar->value >= val_compare);
+ break;
+ case MLAN_SCALAR_COND_LESS_THAN:
+ update = (pscalar->value < val_compare);
+ break;
+ case MLAN_SCALAR_COND_LESS_OR_EQUAL:
+ update = (pscalar->value <= val_compare);
+ break;
+ default:
+ update = MFALSE;
+ break;
+ }
+ if (update)
+ pscalar->value = val_to_set;
+
+ if (moal_spin_unlock)
+ moal_spin_unlock(pmoal_handle, pscalar->plock);
+ return (update) ? MTRUE : MFALSE;
+}
+
+#endif /* !_MLAN_UTIL_H_ */
diff --git a/drivers/net/wireless/sd8797/mlan/mlan_wmm.c b/drivers/net/wireless/sd8797/mlan/mlan_wmm.c
new file mode 100644
index 000000000000..9c9f90be295d
--- /dev/null
+++ b/drivers/net/wireless/sd8797/mlan/mlan_wmm.c
@@ -0,0 +1,2534 @@
+/** @file mlan_wmm.c
+ *
+ * @brief This file contains functions for WMM.
+ *
+ * Copyright (C) 2008-2011, Marvell International Ltd.
+ *
+ * This software file (the "File") is distributed by Marvell International
+ * Ltd. under the terms of the GNU General Public License Version 2, June 1991
+ * (the "License"). You may use, redistribute and/or modify this File in
+ * accordance with the terms and conditions of the License, a copy of which
+ * is available by writing to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
+ * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
+ *
+ * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
+ * ARE EXPRESSLY DISCLAIMED. The License provides additional details about
+ * this warranty disclaimer.
+ */
+
+/********************************************************
+Change log:
+ 10/24/2008: initial version
+********************************************************/
+
+#include "mlan.h"
+#ifdef STA_SUPPORT
+#include "mlan_join.h"
+#endif
+#include "mlan_util.h"
+#include "mlan_fw.h"
+#include "mlan_main.h"
+#include "mlan_wmm.h"
+#include "mlan_11n.h"
+#include "mlan_sdio.h"
+
+/********************************************************
+ Local Variables
+********************************************************/
+
+/** Maximum value FW can accept for driver delay in packet transmission */
+#define DRV_PKT_DELAY_TO_FW_MAX 512
+
+/*
+ * Upper and Lower threshold for packet queuing in the driver
+
+ * - When the number of packets queued reaches the upper limit,
+ * the driver will stop the net queue in the app/kernel space.
+
+ * - When the number of packets drops beneath the lower limit after
+ * having reached the upper limit, the driver will restart the net
+ * queue.
+ */
+
+/** Lower threshold for packet queuing in the driver.
+ * When the number of packets drops beneath the lower limit after having
+ * reached the upper limit, the driver will restart the net queue.
+ */
+#define WMM_QUEUED_PACKET_LOWER_LIMIT 180
+
+/** Upper threshold for packet queuing in the driver.
+ * When the number of packets queued reaches the upper limit, the driver
+ * will stop the net queue in the app/kernel space.
+ */
+#define WMM_QUEUED_PACKET_UPPER_LIMIT 200
+
+/** Offset for TOS field in the IP header */
+#define IPTOS_OFFSET 5
+
+/** WMM information IE */
+static const t_u8 wmm_info_ie[] = { WMM_IE, 0x07,
+ 0x00, 0x50, 0xf2, 0x02,
+ 0x00, 0x01, 0x00
+};
+
+/**
+ * AC Priorities go from AC_BK to AC_VO. The ACI enumeration for AC_BK (1)
+ * is higher than the enumeration for AC_BE (0); hence the needed
+ * mapping conversion for wmm AC to priority Queue Index
+ */
+static const t_u8 wmm_aci_to_qidx_map[] = { WMM_AC_BE,
+ WMM_AC_BK,
+ WMM_AC_VI,
+ WMM_AC_VO
+};
+
+/**
+ * This table will be used to store the tid values based on ACs.
+ * It is initialized to default values per TID.
+ */
+t_u8 tos_to_tid[] = {
+ /* TID DSCP_P2 DSCP_P1 DSCP_P0 WMM_AC */
+ 0x01, /* 0 1 0 AC_BK */
+ 0x02, /* 0 0 0 AC_BK */
+ 0x00, /* 0 0 1 AC_BE */
+ 0x03, /* 0 1 1 AC_BE */
+ 0x04, /* 1 0 0 AC_VI */
+ 0x05, /* 1 0 1 AC_VI */
+ 0x06, /* 1 1 0 AC_VO */
+ 0x07 /* 1 1 1 AC_VO */
+};
+
+/**
+ * This table inverses the tos_to_tid operation to get a priority
+ * which is in sequential order, and can be compared.
+ * Use this to compare the priority of two different TIDs.
+ */
+t_u8 tos_to_tid_inv[] = { 0x02, /* from tos_to_tid[2] = 0 */
+ 0x00, /* from tos_to_tid[0] = 1 */
+ 0x01, /* from tos_to_tid[1] = 2 */
+ 0x03,
+ 0x04,
+ 0x05,
+ 0x06,
+ 0x07
+};
+
+/**
+ * This table will provide the tid value for given ac. This table does not
+ * change and will be used to copy back the default values to tos_to_tid in
+ * case of disconnect.
+ */
+const t_u8 ac_to_tid[4][2] = { {1, 2}, {0, 3}, {4, 5}, {6, 7} };
+
+/* Map of TOS UP values to WMM AC */
+static const mlan_wmm_ac_e tos_to_ac[] = { WMM_AC_BE,
+ WMM_AC_BK,
+ WMM_AC_BK,
+ WMM_AC_BE,
+ WMM_AC_VI,
+ WMM_AC_VI,
+ WMM_AC_VO,
+ WMM_AC_VO
+};
+
+raListTbl *wlan_wmm_get_ralist_node(pmlan_private priv, t_u8 tid,
+ t_u8 * ra_addr);
+
+/********************************************************
+ Local Functions
+********************************************************/
+#ifdef DEBUG_LEVEL2
+/**
+ * @brief Debug print function to display the priority parameters for a WMM AC
+ *
+ * @param pac_param Pointer to the AC parameters to display
+ *
+ * @return N/A
+ */
+static void
+wlan_wmm_ac_debug_print(const IEEEtypes_WmmAcParameters_t * pac_param)
+{
+ const char *ac_str[] = { "BK", "BE", "VI", "VO" };
+
+ ENTER();
+
+ PRINTM(MINFO, "WMM AC_%s: ACI=%d, ACM=%d, Aifsn=%d, "
+ "EcwMin=%d, EcwMax=%d, TxopLimit=%d\n",
+ ac_str[wmm_aci_to_qidx_map[pac_param->aci_aifsn.aci]],
+ pac_param->aci_aifsn.aci, pac_param->aci_aifsn.acm,
+ pac_param->aci_aifsn.aifsn, pac_param->ecw.ecw_min,
+ pac_param->ecw.ecw_max, wlan_le16_to_cpu(pac_param->tx_op_limit));
+
+ LEAVE();
+}
+
+/** Print the WMM AC for debug purpose */
+#define PRINTM_AC(pac_param) wlan_wmm_ac_debug_print(pac_param)
+#else
+/** Print the WMM AC for debug purpose */
+#define PRINTM_AC(pac_param)
+#endif
+
+/**
+ * @brief Allocate route address
+ *
+ * @param pmadapter Pointer to the mlan_adapter structure
+ * @param ra Pointer to the route address
+ *
+ * @return ra_list
+ */
+static raListTbl *
+wlan_wmm_allocate_ralist_node(pmlan_adapter pmadapter, t_u8 * ra)
+{
+ raListTbl *ra_list = MNULL;
+
+ ENTER();
+
+ if (pmadapter->callbacks.
+ moal_malloc(pmadapter->pmoal_handle, sizeof(raListTbl), MLAN_MEM_DEF,
+ (t_u8 **) & ra_list)) {
+ PRINTM(MERROR, "Fail to allocate ra_list\n");
+ goto done;
+ }
+ util_init_list((pmlan_linked_list) ra_list);
+ util_init_list_head((t_void *) pmadapter->pmoal_handle,
+ &ra_list->buf_head, MFALSE,
+ pmadapter->callbacks.moal_init_lock);
+
+ memcpy(pmadapter, ra_list->ra, ra, MLAN_MAC_ADDR_LENGTH);
+
+ ra_list->total_pkts = 0;
+ ra_list->tx_pause = 0;
+ PRINTM(MINFO, "RAList: Allocating buffers for TID %p\n", ra_list);
+ done:
+ LEAVE();
+ return ra_list;
+}
+
+/**
+ * @brief Map ACs to TID
+ *
+ * @param priv Pointer to the mlan_private driver data struct
+ * @param queue_priority Queue_priority structure
+ *
+ * @return N/A
+ */
+static void
+wlan_wmm_queue_priorities_tid(pmlan_private priv, t_u8 queue_priority[])
+{
+ int i;
+
+ ENTER();
+
+ for (i = 0; i < 4; ++i) {
+ tos_to_tid[7 - (i * 2)] = ac_to_tid[queue_priority[i]][1];
+ tos_to_tid[6 - (i * 2)] = ac_to_tid[queue_priority[i]][0];
+ }
+
+ for (i = 0; i < MAX_NUM_TID; i++) {
+ tos_to_tid_inv[tos_to_tid[i]] = (t_u8) i;
+ }
+
+ /* in case priorities have changed, force highest priority so next packet
+ will check from top to re-establish the highest */
+ util_scalar_write(priv->adapter->pmoal_handle,
+ &priv->wmm.highest_queued_prio,
+ HIGH_PRIO_TID,
+ priv->adapter->callbacks.moal_spin_lock,
+ priv->adapter->callbacks.moal_spin_unlock);
+
+ LEAVE();
+}
+
+/**
+ * @brief Evaluate whether or not an AC is to be downgraded
+ *
+ * @param priv Pointer to the mlan_private driver data struct
+ * @param eval_ac AC to evaluate for downgrading
+ *
+ * @return WMM AC The eval_ac traffic is to be sent on.
+ */
+static mlan_wmm_ac_e
+wlan_wmm_eval_downgrade_ac(pmlan_private priv, mlan_wmm_ac_e eval_ac)
+{
+ int down_ac;
+ mlan_wmm_ac_e ret_ac;
+ WmmAcStatus_t *pac_status;
+
+ ENTER();
+
+ pac_status = &priv->wmm.ac_status[eval_ac];
+
+ if (pac_status->disabled == MFALSE) {
+ LEAVE();
+ /* Okay to use this AC, its enabled */
+ return eval_ac;
+ }
+
+ /* Setup a default return value of the lowest priority */
+ ret_ac = WMM_AC_BK;
+
+ /*
+ * Find the highest AC that is enabled and does not require admission
+ * control. The spec disallows downgrading to an AC, which is enabled
+ * due to a completed admission control. Unadmitted traffic is not
+ * to be sent on an AC with admitted traffic.
+ */
+ for (down_ac = WMM_AC_BK; down_ac < eval_ac; down_ac++) {
+ pac_status = &priv->wmm.ac_status[down_ac];
+
+ if ((pac_status->disabled == MFALSE)
+ && (pac_status->flow_required == MFALSE))
+ /* AC is enabled and does not require admission control */
+ ret_ac = (mlan_wmm_ac_e) down_ac;
+ }
+
+ LEAVE();
+ return ret_ac;
+}
+
+/**
+ * @brief Convert the IP TOS field to an WMM AC Queue assignment
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param tos IP TOS field
+ *
+ * @return WMM AC Queue mapping of the IP TOS field
+ */
+static mlan_wmm_ac_e INLINE
+wlan_wmm_convert_tos_to_ac(pmlan_adapter pmadapter, t_u32 tos)
+{
+ ENTER();
+
+ if (tos >= NELEMENTS(tos_to_ac)) {
+ LEAVE();
+ return WMM_AC_BE;
+ }
+
+ LEAVE();
+ return tos_to_ac[tos];
+}
+
+/**
+ * @brief Evaluate a given TID and downgrade it to a lower TID if the
+ * WMM Parameter IE received from the AP indicates that the AP
+ * is disabled (due to call admission control (ACM bit). Mapping
+ * of TID to AC is taken care internally
+ *
+ * @param priv Pointer to the mlan_private data struct
+ * @param tid tid to evaluate for downgrading
+ *
+ * @return Same tid as input if downgrading not required or
+ * the tid the traffic for the given tid should be downgraded to
+ */
+static t_u8 INLINE
+wlan_wmm_downgrade_tid(pmlan_private priv, t_u32 tid)
+{
+ mlan_wmm_ac_e ac_down;
+ pmlan_adapter pmadapter = priv->adapter;
+
+ ENTER();
+
+ ac_down =
+ priv->wmm.ac_down_graded_vals[wlan_wmm_convert_tos_to_ac(pmadapter,
+ tid)];
+ LEAVE();
+ /*
+ * Send the index to tid array, picking from the array will be
+ * taken care by dequeuing function
+ */
+ if (tid == 1 || tid == 2)
+ return ac_to_tid[ac_down][(tid + 1) % 2];
+ else if (tid >= MAX_NUM_TID)
+ return ac_to_tid[ac_down][0];
+ else
+ return ac_to_tid[ac_down][tid % 2];
+}
+
+/**
+ * @brief Delete packets in RA node
+ *
+ * @param priv Pointer to the mlan_private driver data struct
+ * @param ra_list Pointer to raListTbl
+ *
+ * @return N/A
+ */
+static INLINE void
+wlan_wmm_del_pkts_in_ralist_node(pmlan_private priv, raListTbl * ra_list)
+{
+ pmlan_buffer pmbuf;
+ pmlan_adapter pmadapter = priv->adapter;
+
+ ENTER();
+ while ((pmbuf =
+ (pmlan_buffer) util_peek_list(pmadapter->pmoal_handle,
+ &ra_list->buf_head, MNULL, MNULL))) {
+ util_unlink_list(pmadapter->pmoal_handle, &ra_list->buf_head,
+ (pmlan_linked_list) pmbuf, MNULL, MNULL);
+ wlan_write_data_complete(pmadapter, pmbuf, MLAN_STATUS_FAILURE);
+ }
+ util_free_list_head((t_void *) pmadapter->pmoal_handle, &ra_list->buf_head,
+ pmadapter->callbacks.moal_free_lock);
+
+ LEAVE();
+}
+
+/**
+ * @brief Delete packets in RA list
+ *
+ * @param priv Pointer to the mlan_private driver data struct
+ * @param ra_list_head ra list header
+ *
+ * @return N/A
+ */
+static INLINE void
+wlan_wmm_del_pkts_in_ralist(pmlan_private priv, mlan_list_head * ra_list_head)
+{
+ raListTbl *ra_list;
+
+ ENTER();
+
+ ra_list =
+ (raListTbl *) util_peek_list(priv->adapter->pmoal_handle, ra_list_head,
+ MNULL, MNULL);
+
+ while (ra_list && ra_list != (raListTbl *) ra_list_head) {
+ wlan_wmm_del_pkts_in_ralist_node(priv, ra_list);
+
+ ra_list = ra_list->pnext;
+ }
+
+ LEAVE();
+}
+
+/**
+ * @brief Clean up the wmm queue
+ *
+ * @param priv Pointer to the mlan_private driver data struct
+ *
+ * @return N/A
+ */
+static void
+wlan_wmm_cleanup_queues(pmlan_private priv)
+{
+ int i;
+
+ ENTER();
+
+ for (i = 0; i < MAX_NUM_TID; i++) {
+ wlan_wmm_del_pkts_in_ralist(priv, &priv->wmm.tid_tbl_ptr[i].ra_list);
+ priv->wmm.pkts_queued[i] = 0;
+ }
+ util_scalar_write(priv->adapter->pmoal_handle, &priv->wmm.tx_pkts_queued, 0,
+ MNULL, MNULL);
+ util_scalar_write(priv->adapter->pmoal_handle,
+ &priv->wmm.highest_queued_prio, HIGH_PRIO_TID, MNULL,
+ MNULL);
+
+ LEAVE();
+}
+
+/**
+ * @brief Delete all route address from RA list
+ *
+ * @param priv Pointer to the mlan_private driver data struct
+ *
+ * @return N/A
+ */
+static void
+wlan_wmm_delete_all_ralist(pmlan_private priv)
+{
+ raListTbl *ra_list;
+ int i;
+ pmlan_adapter pmadapter = priv->adapter;
+
+ ENTER();
+
+ for (i = 0; i < MAX_NUM_TID; ++i) {
+ PRINTM(MINFO, "RAList: Freeing buffers for TID %d\n", i);
+ while ((ra_list = (raListTbl *) util_peek_list(pmadapter->pmoal_handle,
+ &priv->wmm.
+ tid_tbl_ptr[i].ra_list,
+ MNULL, MNULL))) {
+ util_unlink_list(pmadapter->pmoal_handle,
+ &priv->wmm.tid_tbl_ptr[i].ra_list,
+ (pmlan_linked_list) ra_list, MNULL, MNULL);
+
+ pmadapter->callbacks.moal_mfree(pmadapter->pmoal_handle,
+ (t_u8 *) ra_list);
+ }
+
+ util_init_list((pmlan_linked_list)
+ & priv->wmm.tid_tbl_ptr[i].ra_list);
+ priv->wmm.tid_tbl_ptr[i].ra_list_curr = MNULL;
+ }
+
+ LEAVE();
+}
+
+/**
+ * @brief Get queue RA pointer
+ *
+ * @param priv Pointer to the mlan_private driver data struct
+ * @param tid TID
+ * @param ra_addr Pointer to the route address
+ *
+ * @return ra_list
+ */
+static raListTbl *
+wlan_wmm_get_queue_raptr(pmlan_private priv, t_u8 tid, t_u8 * ra_addr)
+{
+ raListTbl *ra_list;
+#if defined(UAP_SUPPORT)
+ t_u8 bcast_addr[] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
+#endif
+
+ ENTER();
+ ra_list = wlan_wmm_get_ralist_node(priv, tid, ra_addr);
+ if (ra_list) {
+ LEAVE();
+ return ra_list;
+ }
+#if defined(UAP_SUPPORT)
+ if ((GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_UAP) &&
+ (0 != memcmp(priv->adapter, ra_addr, bcast_addr, sizeof(bcast_addr)))) {
+ if (MNULL == wlan_get_station_entry(priv, ra_addr)) {
+ PRINTM(MDATA, "Drop packets to unknown station\n");
+ LEAVE();
+ return MNULL;
+ }
+ }
+#endif
+ wlan_ralist_add(priv, ra_addr);
+
+ ra_list = wlan_wmm_get_ralist_node(priv, tid, ra_addr);
+ LEAVE();
+ return ra_list;
+}
+
+#ifdef STA_SUPPORT
+/**
+ * @brief Sends wmmac host event
+ *
+ * @param priv Pointer to the mlan_private driver data struct
+ * @param typeStr Type of host event
+ * @param srcAddr Pointer to the source Address
+ * @param tid TID
+ * @param up User priority
+ * @param status Status code or Reason code
+ *
+ * @return N/A
+ */
+static void
+wlan_send_wmmac_host_event(pmlan_private priv,
+ char *typeStr,
+ t_u8 * srcAddr, t_u8 tid, t_u8 up, t_u8 status)
+{
+ t_u8 event_buf[100];
+ mlan_event *pevent;
+ t_u8 *pOutBuf;
+
+ ENTER();
+
+ /* Format one of the following two output strings: ** -
+ TSPEC:ADDTS_RSP:[<status code>]:TID=X:UP=Y ** - TSPEC:DELTS_RX:[<reason
+ code>]:TID=X:UP=Y */
+ pevent = (mlan_event *) event_buf;
+ pOutBuf = pevent->event_buf;
+
+ memcpy(priv->adapter, pOutBuf, (t_u8 *) "TSPEC:", 6);
+ pOutBuf += 6;
+
+ memcpy(priv->adapter, pOutBuf, (t_u8 *) typeStr, wlan_strlen(typeStr));
+ pOutBuf += wlan_strlen(typeStr);
+
+ *pOutBuf++ = ':';
+ *pOutBuf++ = '[';
+
+ if (status >= 100) {
+ *pOutBuf++ = (status / 100) + '0';
+ status = (status % 100);
+ }
+
+ if (status >= 10) {
+ *pOutBuf++ = (status / 10) + '0';
+ status = (status % 10);
+ }
+
+ *pOutBuf++ = status + '0';
+
+ memcpy(priv->adapter, pOutBuf, (t_u8 *) "]:TID", 5);
+ pOutBuf += 5;
+ *pOutBuf++ = tid + '0';
+
+ memcpy(priv->adapter, pOutBuf, (t_u8 *) ":UP", 3);
+ pOutBuf += 3;
+ *pOutBuf++ = up + '0';
+
+ *pOutBuf = '\0';
+
+ pevent->bss_index = priv->bss_index;
+ pevent->event_id = MLAN_EVENT_ID_DRV_REPORT_STRING;
+ pevent->event_len = wlan_strlen((const t_s8 *) (pevent->event_buf));
+
+ wlan_recv_event(priv, MLAN_EVENT_ID_DRV_REPORT_STRING, pevent);
+ LEAVE();
+}
+#endif /* STA_SUPPORT */
+
+/**
+ * @brief This function gets the highest priority list pointer
+ *
+ * @param pmadapter A pointer to mlan_adapter
+ * @param priv A pointer to mlan_private
+ * @param tid A pointer to return tid
+ *
+ * @return raListTbl
+ */
+static raListTbl *
+wlan_wmm_get_highest_priolist_ptr(pmlan_adapter pmadapter,
+ pmlan_private * priv, int *tid)
+{
+ pmlan_private priv_tmp;
+ raListTbl *ptr, *head;
+ mlan_bssprio_node *bssprio_node, *bssprio_head;
+ tid_tbl_t *tid_ptr;
+ int i, j;
+ int next_prio = 0;
+ int next_tid = 0;
+ ENTER();
+
+ PRINTM(MDAT_D, "POP\n");
+ for (j = pmadapter->priv_num - 1; j >= 0; --j) {
+ if (!(util_peek_list(pmadapter->pmoal_handle,
+ &pmadapter->bssprio_tbl[j].bssprio_head,
+ pmadapter->callbacks.moal_spin_lock,
+ pmadapter->callbacks.moal_spin_unlock)))
+ continue;
+
+ if (pmadapter->bssprio_tbl[j].bssprio_cur == (mlan_bssprio_node *)
+ & pmadapter->bssprio_tbl[j].bssprio_head) {
+ pmadapter->bssprio_tbl[j].bssprio_cur =
+ pmadapter->bssprio_tbl[j].bssprio_cur->pnext;
+ }
+
+ bssprio_head = bssprio_node = pmadapter->bssprio_tbl[j].bssprio_cur;
+
+ do {
+ priv_tmp = bssprio_node->priv;
+
+ if ((priv_tmp->port_ctrl_mode == MTRUE)
+ && (priv_tmp->port_open == MFALSE)) {
+ PRINTM(MINFO, "get_highest_prio_ptr(): "
+ "PORT_CLOSED Ignore pkts from BSS%d\n",
+ priv_tmp->bss_index);
+ /* Ignore data pkts from a BSS if port is closed */
+ goto next_intf;
+ }
+
+ pmadapter->callbacks.moal_spin_lock(pmadapter->pmoal_handle,
+ priv_tmp->wmm.ra_list_spinlock);
+
+ for (i = util_scalar_read(pmadapter->pmoal_handle,
+ &priv_tmp->wmm.highest_queued_prio,
+ MNULL, MNULL); i >= LOW_PRIO_TID; --i) {
+
+ tid_ptr = &(priv_tmp)->wmm.tid_tbl_ptr[tos_to_tid[i]];
+ if (!util_peek_list
+ (pmadapter->pmoal_handle, &tid_ptr->ra_list, MNULL, MNULL))
+ continue;
+
+ /*
+ * Always choose the next ra we transmitted
+ * last time, this way we pick the ra's in
+ * round robin fashion.
+ */
+ head = ptr = tid_ptr->ra_list_curr->pnext;
+ if (ptr == (raListTbl *) & tid_ptr->ra_list)
+ head = ptr = ptr->pnext;
+
+ do {
+ if (!ptr->tx_pause &&
+ util_peek_list(pmadapter->pmoal_handle, &ptr->buf_head,
+ MNULL, MNULL)) {
+
+ /* Because WMM only support BK/BE/VI/VO, we have 8 tid
+ We should balance the traffic of the same AC */
+ if (i % 2)
+ next_prio = i - 1;
+ else
+ next_prio = i + 1;
+ next_tid = tos_to_tid[next_prio];
+ if (priv_tmp->wmm.pkts_queued[next_tid])
+ util_scalar_write(pmadapter->pmoal_handle,
+ &priv_tmp->wmm.
+ highest_queued_prio, next_prio,
+ MNULL, MNULL);
+ else
+ /* if highest_queued_prio > i, set it to i */
+ util_scalar_conditional_write(pmadapter->
+ pmoal_handle,
+ &priv_tmp->wmm.
+ highest_queued_prio,
+ MLAN_SCALAR_COND_GREATER_THAN,
+ i, i, MNULL, MNULL);
+ *priv = priv_tmp;
+ *tid = tos_to_tid[i];
+ /* hold priv->ra_list_spinlock to maintain ptr */
+ PRINTM(MDAT_D, "get highest prio ptr %p, tid %d\n",
+ ptr, *tid);
+ LEAVE();
+ return ptr;
+ }
+
+ if ((ptr = ptr->pnext) == (raListTbl *) & tid_ptr->ra_list)
+ ptr = ptr->pnext;
+ } while (ptr != head);
+ }
+
+ /* No packet at any TID for this priv. Mark as such to skip
+ checking TIDs for this priv (until pkt is added). */
+ util_scalar_write(pmadapter->pmoal_handle,
+ &priv_tmp->wmm.highest_queued_prio,
+ NO_PKT_PRIO_TID, MNULL, MNULL);
+
+ pmadapter->callbacks.moal_spin_unlock(pmadapter->pmoal_handle,
+ priv_tmp->wmm.
+ ra_list_spinlock);
+
+ next_intf:
+ if ((bssprio_node = bssprio_node->pnext) == (mlan_bssprio_node *)
+ & pmadapter->bssprio_tbl[j].bssprio_head)
+ bssprio_node = bssprio_node->pnext;
+ } while (bssprio_node != bssprio_head);
+ }
+
+ LEAVE();
+ return MNULL;
+}
+
+/**
+ * @brief This function gets the number of packets in the Tx queue
+ *
+ * @param priv A pointer to mlan_private
+ * @param ptr A pointer to RA list table
+ * @param maxBufSize Maximum buffer size
+ *
+ * @return Packet count
+ */
+static int
+wlan_num_pkts_in_txq(mlan_private * priv, raListTbl * ptr, int maxBufSize)
+{
+ int count = 0, total_size = 0;
+ pmlan_buffer pmbuf;
+
+ ENTER();
+
+ for (pmbuf = (pmlan_buffer) ptr->buf_head.pnext;
+ pmbuf != (pmlan_buffer) (&ptr->buf_head); pmbuf = pmbuf->pnext) {
+
+ total_size += pmbuf->data_len;
+ if (total_size < maxBufSize)
+ ++count;
+ else
+ break;
+ }
+
+ LEAVE();
+ return count;
+}
+
+/**
+ * @brief This function sends a single packet
+ *
+ * @param priv A pointer to mlan_private
+ * @param ptr A pointer to RA list table
+ * @param ptrindex ptr's TID index
+ *
+ * @return N/A
+ */
+static void INLINE
+wlan_send_single_packet(pmlan_private priv, raListTbl * ptr, int ptrindex)
+{
+ pmlan_buffer pmbuf;
+ pmlan_buffer pmbuf_next;
+ mlan_tx_param tx_param;
+ pmlan_adapter pmadapter = priv->adapter;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ if ((pmbuf = (pmlan_buffer) util_dequeue_list(pmadapter->pmoal_handle,
+ &ptr->buf_head,
+ MNULL, MNULL))) {
+ PRINTM(MINFO, "Dequeuing the packet %p %p\n", ptr, pmbuf);
+ priv->wmm.pkts_queued[ptrindex]--;
+ util_scalar_decrement(pmadapter->pmoal_handle,
+ &priv->wmm.tx_pkts_queued, MNULL, MNULL);
+ ptr->total_pkts--;
+ pmbuf_next = (pmlan_buffer) util_peek_list(pmadapter->pmoal_handle,
+ &ptr->buf_head,
+ MNULL, MNULL);
+ pmadapter->callbacks.moal_spin_unlock(pmadapter->pmoal_handle,
+ priv->wmm.ra_list_spinlock);
+
+ tx_param.next_pkt_len = ((pmbuf_next)
+ ? pmbuf_next->data_len + sizeof(TxPD) : 0);
+ status = wlan_process_tx(priv, pmbuf, &tx_param);
+
+ if (status == MLAN_STATUS_RESOURCE) {
+ /** Queue the packet back at the head */
+ PRINTM(MDAT_D, "Queuing pkt back to raList %p %p\n", ptr, pmbuf);
+ pmadapter->callbacks.moal_spin_lock(pmadapter->pmoal_handle,
+ priv->wmm.ra_list_spinlock);
+
+ if (!wlan_is_ralist_valid(priv, ptr, ptrindex)) {
+ pmadapter->callbacks.moal_spin_unlock(pmadapter->pmoal_handle,
+ priv->wmm.
+ ra_list_spinlock);
+ wlan_write_data_complete(pmadapter, pmbuf, MLAN_STATUS_FAILURE);
+ LEAVE();
+ return;
+ }
+ priv->wmm.pkts_queued[ptrindex]++;
+ util_scalar_increment(pmadapter->pmoal_handle,
+ &priv->wmm.tx_pkts_queued, MNULL, MNULL);
+ util_enqueue_list_head(pmadapter->pmoal_handle, &ptr->buf_head,
+ (pmlan_linked_list) pmbuf, MNULL, MNULL);
+
+ ptr->total_pkts++;
+ pmbuf->flags |= MLAN_BUF_FLAG_REQUEUED_PKT;
+ pmadapter->callbacks.moal_spin_unlock(pmadapter->pmoal_handle,
+ priv->wmm.ra_list_spinlock);
+ } else {
+ pmadapter->callbacks.moal_spin_lock(pmadapter->pmoal_handle,
+ priv->wmm.ra_list_spinlock);
+ if (wlan_is_ralist_valid(priv, ptr, ptrindex)) {
+ priv->wmm.packets_out[ptrindex]++;
+ priv->wmm.tid_tbl_ptr[ptrindex].ra_list_curr = ptr;
+ }
+ pmadapter->bssprio_tbl[priv->bss_priority].bssprio_cur =
+ pmadapter->bssprio_tbl[priv->bss_priority].bssprio_cur->pnext;
+ pmadapter->callbacks.moal_spin_unlock(pmadapter->pmoal_handle,
+ priv->wmm.ra_list_spinlock);
+ }
+ } else {
+ pmadapter->callbacks.moal_spin_unlock(pmadapter->pmoal_handle,
+ priv->wmm.ra_list_spinlock);
+ PRINTM(MINFO, "Nothing to send\n");
+ }
+
+ LEAVE();
+}
+
+/**
+ * @brief This function checks if this mlan_buffer is already processed.
+ *
+ * @param priv A pointer to mlan_private
+ * @param ptr A pointer to RA list table
+ *
+ * @return MTRUE or MFALSE
+ */
+static int INLINE
+wlan_is_ptr_processed(mlan_private * priv, raListTbl * ptr)
+{
+ pmlan_buffer pmbuf;
+
+ if ((pmbuf = (pmlan_buffer) util_peek_list(priv->adapter->pmoal_handle,
+ &ptr->buf_head, MNULL, MNULL))
+ && (pmbuf->flags & MLAN_BUF_FLAG_REQUEUED_PKT))
+ return MTRUE;
+
+ return MFALSE;
+}
+
+/**
+ * @brief This function sends a single packet that has been processed
+ *
+ * @param priv A pointer to mlan_private
+ * @param ptr A pointer to RA list table
+ * @param ptrindex ptr's TID index
+ *
+ * @return N/A
+ */
+static void INLINE
+wlan_send_processed_packet(pmlan_private priv, raListTbl * ptr, int ptrindex)
+{
+ pmlan_buffer pmbuf_next;
+ mlan_tx_param tx_param;
+ pmlan_buffer pmbuf;
+ pmlan_adapter pmadapter = priv->adapter;
+ mlan_status ret = MLAN_STATUS_FAILURE;
+
+ if ((pmbuf = (pmlan_buffer) util_dequeue_list(pmadapter->pmoal_handle,
+ &ptr->buf_head,
+ MNULL, MNULL))) {
+ pmbuf_next =
+ (pmlan_buffer) util_peek_list(pmadapter->pmoal_handle,
+ &ptr->buf_head, MNULL, MNULL);
+ pmadapter->callbacks.moal_spin_unlock(pmadapter->pmoal_handle,
+ priv->wmm.ra_list_spinlock);
+ tx_param.next_pkt_len =
+ ((pmbuf_next) ? pmbuf_next->data_len + sizeof(TxPD) : 0);
+ ret =
+ wlan_sdio_host_to_card(pmadapter, MLAN_TYPE_DATA, pmbuf, &tx_param);
+ switch (ret) {
+ case MLAN_STATUS_RESOURCE:
+ PRINTM(MINFO, "MLAN_STATUS_RESOURCE is returned\n");
+ pmadapter->callbacks.moal_spin_lock(pmadapter->pmoal_handle,
+ priv->wmm.ra_list_spinlock);
+
+ if (!wlan_is_ralist_valid(priv, ptr, ptrindex)) {
+ pmadapter->callbacks.moal_spin_unlock(pmadapter->pmoal_handle,
+ priv->wmm.
+ ra_list_spinlock);
+ wlan_write_data_complete(pmadapter, pmbuf, MLAN_STATUS_FAILURE);
+ LEAVE();
+ return;
+ }
+ util_enqueue_list_head(pmadapter->pmoal_handle,
+ &ptr->buf_head,
+ (pmlan_linked_list) pmbuf, MNULL, MNULL);
+
+ pmbuf->flags |= MLAN_BUF_FLAG_REQUEUED_PKT;
+ pmadapter->callbacks.moal_spin_unlock(pmadapter->pmoal_handle,
+ priv->wmm.ra_list_spinlock);
+ break;
+ case MLAN_STATUS_FAILURE:
+ pmadapter->data_sent = MFALSE;
+ PRINTM(MERROR, "Error: Failed to write data\n");
+ pmadapter->dbg.num_tx_host_to_card_failure++;
+ pmbuf->status_code = MLAN_ERROR_DATA_TX_FAIL;
+ wlan_write_data_complete(pmadapter, pmbuf, ret);
+ break;
+ case MLAN_STATUS_PENDING:
+ pmadapter->data_sent = MFALSE;
+ default:
+ break;
+ }
+ if (ret != MLAN_STATUS_RESOURCE) {
+ pmadapter->callbacks.moal_spin_lock(pmadapter->pmoal_handle,
+ priv->wmm.ra_list_spinlock);
+ if (wlan_is_ralist_valid(priv, ptr, ptrindex)) {
+ priv->wmm.packets_out[ptrindex]++;
+ priv->wmm.tid_tbl_ptr[ptrindex].ra_list_curr = ptr;
+ ptr->total_pkts--;
+ }
+ pmadapter->bssprio_tbl[priv->bss_priority].bssprio_cur =
+ pmadapter->bssprio_tbl[priv->bss_priority].bssprio_cur->pnext;
+ priv->wmm.pkts_queued[ptrindex]--;
+ util_scalar_decrement(pmadapter->pmoal_handle,
+ &priv->wmm.tx_pkts_queued, MNULL, MNULL);
+ pmadapter->callbacks.moal_spin_unlock(pmadapter->pmoal_handle,
+ priv->wmm.ra_list_spinlock);
+ }
+ } else {
+ pmadapter->callbacks.moal_spin_unlock(pmadapter->pmoal_handle,
+ priv->wmm.ra_list_spinlock);
+ }
+}
+
+/**
+ * @brief This function dequeues a packet
+ *
+ * @param pmadapter A pointer to mlan_adapter
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+static int
+wlan_dequeue_tx_packet(pmlan_adapter pmadapter)
+{
+ raListTbl *ptr;
+ pmlan_private priv = MNULL;
+ int ptrindex = 0;
+ t_u8 ra[MLAN_MAC_ADDR_LENGTH];
+ int tid_del = 0;
+ int tid = 0;
+ t_u8 avail_ports = 0;
+ int i;
+
+ ENTER();
+
+ if (!(ptr = wlan_wmm_get_highest_priolist_ptr(pmadapter, &priv, &ptrindex))) {
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+
+ /* Note:- Spinlock is locked in wlan_wmm_get_highest_priolist_ptr when it
+ returns a pointer (for the priv it returns), and is unlocked in
+ wlan_send_processed_packet, wlan_send_single_packet or
+ wlan_11n_aggregate_pkt. The spinlock would be required for some parts
+ of both of function. But, the the bulk of these function will execute
+ w/o spinlock. Unlocking the spinlock inside these function will help
+ us avoid taking the spinlock again, check to see if the ptr is still
+ valid and then proceed. This is done purely to increase execution time.
+ */
+
+ /* Note:- Also, anybody adding code which does not get into
+ wlan_send_processed_packet, wlan_send_single_packet, or
+ wlan_11n_aggregate_pkt should make sure ra_list_spinlock is freed.
+ Otherwise there would be a lock up. */
+
+ tid = wlan_get_tid(priv->adapter, ptr);
+ if (tid >= MAX_NUM_TID)
+ tid = wlan_wmm_downgrade_tid(priv, tid);
+
+ for (i = 1; i < pmadapter->mp_end_port; i++) {
+ if ((pmadapter->mp_wr_bitmap >> i) & 1)
+ avail_ports++;
+ }
+
+ PRINTM(MINFO,
+ "mp_wr_bitmap=0x%08x avail_ports=%d tid=%d tx_eligibility[%d]=%d\n",
+ pmadapter->mp_wr_bitmap, avail_ports,
+ tid, tid, pmadapter->tx_eligibility[tid]);
+
+ if (avail_ports < pmadapter->tx_eligibility[tid]) {
+ pmadapter->callbacks.moal_spin_unlock(pmadapter->pmoal_handle,
+ priv->wmm.ra_list_spinlock);
+ pmadapter->data_sent = MTRUE;
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+
+ if (wlan_is_ptr_processed(priv, ptr)) {
+ wlan_send_processed_packet(priv, ptr, ptrindex);
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+ }
+
+ if (!ptr->is_11n_enabled || wlan_is_bastream_setup(priv, ptr, tid)
+#ifdef STA_SUPPORT
+ || ((priv->sec_info.ewpa_enabled == MFALSE) &&
+ ((priv->sec_info.wpa_enabled
+ || priv->sec_info.wpa2_enabled) &&
+ priv->wpa_is_gtk_set == MFALSE))
+ || priv->wps.session_enable
+#endif /* STA_SUPPORT */
+ ) {
+ if (ptr->is_11n_enabled && wlan_is_bastream_setup(priv, ptr, tid)
+ && wlan_is_amsdu_in_ampdu_allowed(priv, ptr, tid)
+ && wlan_is_amsdu_allowed(priv, ptr, tid)
+ && (wlan_num_pkts_in_txq(priv, ptr, pmadapter->tx_buf_size) >=
+ MIN_NUM_AMSDU)) {
+ wlan_11n_aggregate_pkt(priv, ptr, INTF_HEADER_LEN, ptrindex);
+ } else
+ wlan_send_single_packet(priv, ptr, ptrindex);
+ } else {
+ if (wlan_is_ampdu_allowed(priv, ptr, tid) &&
+ (ptr->packet_count > ptr->ba_packet_threshold)) {
+ if (wlan_is_bastream_avail(priv)) {
+ PRINTM(MINFO, "BA setup threshold %d reached. tid=%d\n",
+ ptr->packet_count, tid);
+ wlan_11n_create_txbastream_tbl(priv,
+ ptr->ra, tid,
+ BA_STREAM_SETUP_INPROGRESS);
+ wlan_send_addba(priv, tid, ptr->ra);
+ } else if (wlan_find_stream_to_delete(priv, ptr, tid, &tid_del, ra)) {
+ PRINTM(MDAT_D, "tid_del=%d tid=%d\n", tid_del, tid);
+ wlan_11n_create_txbastream_tbl(priv,
+ ptr->ra, tid,
+ BA_STREAM_SETUP_INPROGRESS);
+ wlan_send_delba(priv, tid_del, ra, 1);
+ }
+ }
+ if (wlan_is_amsdu_allowed(priv, ptr, tid) &&
+ (wlan_num_pkts_in_txq(priv, ptr,
+ pmadapter->tx_buf_size) >= MIN_NUM_AMSDU)) {
+ wlan_11n_aggregate_pkt(priv, ptr, INTF_HEADER_LEN, ptrindex);
+ } else {
+ wlan_send_single_packet(priv, ptr, ptrindex);
+ }
+ }
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief update tx_pause flag in ra_list
+ *
+ * @param priv A pointer to mlan_private
+ * @param mac peer mac address
+ * @param tx_pause tx_pause flag (0/1)
+ *
+ * @return N/A
+ */
+t_void
+wlan_updata_ralist_tx_pause(pmlan_private priv, t_u8 * mac, t_u8 tx_pause)
+{
+ raListTbl *ra_list;
+ int i;
+ pmlan_adapter pmadapter = priv->adapter;
+ t_u32 pkt_cnt = 0;
+ t_u32 tx_pkts_queued = 0;
+ ENTER();
+
+ pmadapter->callbacks.moal_spin_lock(pmadapter->pmoal_handle,
+ priv->wmm.ra_list_spinlock);
+ for (i = 0; i < MAX_NUM_TID; ++i) {
+ ra_list = wlan_wmm_get_ralist_node(priv, i, mac);
+ if (ra_list) {
+ pkt_cnt += ra_list->total_pkts;
+ ra_list->tx_pause = tx_pause;
+ }
+ }
+ if (pkt_cnt) {
+ tx_pkts_queued = util_scalar_read(pmadapter->pmoal_handle,
+ &priv->wmm.tx_pkts_queued, MNULL,
+ MNULL);
+ if (tx_pause)
+ tx_pkts_queued -= pkt_cnt;
+ else
+ tx_pkts_queued += pkt_cnt;
+ util_scalar_write(priv->adapter->pmoal_handle,
+ &priv->wmm.tx_pkts_queued, tx_pkts_queued, MNULL,
+ MNULL);
+ util_scalar_write(priv->adapter->pmoal_handle,
+ &priv->wmm.highest_queued_prio, HIGH_PRIO_TID, MNULL,
+ MNULL);
+ }
+ pmadapter->callbacks.moal_spin_unlock(pmadapter->pmoal_handle,
+ priv->wmm.ra_list_spinlock);
+ LEAVE();
+}
+
+#ifdef STA_SUPPORT
+#endif /* STA_SUPPORT */
+/********************************************************
+ Global Functions
+********************************************************/
+
+/**
+ * @brief Get the threshold value for BA setup using system time.
+ *
+ * @param pmadapter Pointer to the mlan_adapter structure
+ *
+ * @return threshold value.
+ */
+t_u8
+wlan_get_random_ba_threshold(pmlan_adapter pmadapter)
+{
+ t_u32 sec, usec;
+ t_u8 ba_threshold = 0;
+
+ ENTER();
+
+ /* setup ba_packet_threshold here random number between
+ [BA_SETUP_PACKET_OFFSET,
+ BA_SETUP_PACKET_OFFSET+BA_SETUP_MAX_PACKET_THRESHOLD-1] */
+
+#define BA_SETUP_MAX_PACKET_THRESHOLD 16
+#define BA_SETUP_PACKET_OFFSET 16
+
+ pmadapter->callbacks.moal_get_system_time(pmadapter->pmoal_handle, &sec,
+ &usec);
+ sec = (sec & 0xFFFF) + (sec >> 16);
+ usec = (usec & 0xFFFF) + (usec >> 16);
+
+ ba_threshold =
+ (((sec << 16) + usec) % BA_SETUP_MAX_PACKET_THRESHOLD) +
+ BA_SETUP_PACKET_OFFSET;
+ PRINTM(MINFO, "setup BA after %d packets\n", ba_threshold);
+
+ LEAVE();
+ return ba_threshold;
+}
+
+/**
+ * @brief This function cleans Tx/Rx queues
+ *
+ * @param priv A pointer to mlan_private
+ *
+ * @return N/A
+ */
+t_void
+wlan_clean_txrx(pmlan_private priv)
+{
+ mlan_adapter *pmadapter = priv->adapter;
+ t_u8 i = 0;
+
+ ENTER();
+
+ if (GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_STA) {
+ wlan_cleanup_bypass_txq(pmadapter);
+ }
+
+ wlan_11n_cleanup_reorder_tbl(priv);
+
+ pmadapter->callbacks.moal_spin_lock(pmadapter->pmoal_handle,
+ priv->wmm.ra_list_spinlock);
+
+ wlan_wmm_cleanup_queues(priv);
+ wlan_11n_deleteall_txbastream_tbl(priv);
+#ifdef SDIO_MULTI_PORT_TX_AGGR
+ MP_TX_AGGR_BUF_RESET(priv->adapter);
+#endif
+#ifdef SDIO_MULTI_PORT_RX_AGGR
+ MP_RX_AGGR_BUF_RESET(priv->adapter);
+#endif
+ wlan_wmm_delete_all_ralist(priv);
+ memcpy(pmadapter, tos_to_tid, ac_to_tid, sizeof(tos_to_tid));
+ for (i = 0; i < MAX_NUM_TID; i++) {
+ tos_to_tid_inv[tos_to_tid[i]] = (t_u8) i;
+ }
+#if defined(UAP_SUPPORT)
+ priv->num_drop_pkts = 0;
+#endif
+ pmadapter->callbacks.moal_spin_unlock(pmadapter->pmoal_handle,
+ priv->wmm.ra_list_spinlock);
+
+ LEAVE();
+}
+
+/**
+ * @brief Set the WMM queue priorities to their default values
+ *
+ * @param priv Pointer to the mlan_private driver data struct
+ *
+ * @return N/A
+ */
+void
+wlan_wmm_default_queue_priorities(pmlan_private priv)
+{
+ ENTER();
+
+ /* Default queue priorities: VO->VI->BE->BK */
+ priv->wmm.queue_priority[0] = WMM_AC_VO;
+ priv->wmm.queue_priority[1] = WMM_AC_VI;
+ priv->wmm.queue_priority[2] = WMM_AC_BE;
+ priv->wmm.queue_priority[3] = WMM_AC_BK;
+
+ LEAVE();
+}
+
+/**
+ * @brief Initialize WMM priority queues
+ *
+ * @param priv Pointer to the mlan_private driver data struct
+ * @param pwmm_ie Pointer to the IEEEtypes_WmmParameter_t data struct
+ *
+ * @return N/A
+ */
+void
+wlan_wmm_setup_queue_priorities(pmlan_private priv,
+ IEEEtypes_WmmParameter_t * pwmm_ie)
+{
+ t_u16 cw_min, avg_back_off, tmp[4];
+ t_u32 i, j, num_ac;
+ t_u8 ac_idx;
+
+ ENTER();
+
+ if (!pwmm_ie || priv->wmm_enabled == MFALSE) {
+ /* WMM is not enabled, just set the defaults and return */
+ wlan_wmm_default_queue_priorities(priv);
+ LEAVE();
+ return;
+ }
+
+ HEXDUMP("WMM: setup_queue_priorities: param IE",
+ (t_u8 *) pwmm_ie, sizeof(IEEEtypes_WmmParameter_t));
+
+ PRINTM(MINFO, "WMM Parameter IE: version=%d, "
+ "qos_info Parameter Set Count=%d, Reserved=%#x\n",
+ pwmm_ie->vend_hdr.version, pwmm_ie->qos_info.para_set_count,
+ pwmm_ie->reserved);
+
+ for (num_ac = 0; num_ac < NELEMENTS(pwmm_ie->ac_params); num_ac++) {
+ cw_min = (1 << pwmm_ie->ac_params[num_ac].ecw.ecw_min) - 1;
+ avg_back_off
+ = (cw_min >> 1) + pwmm_ie->ac_params[num_ac].aci_aifsn.aifsn;
+
+ ac_idx = wmm_aci_to_qidx_map[pwmm_ie->ac_params[num_ac].aci_aifsn.aci];
+ priv->wmm.queue_priority[ac_idx] = ac_idx;
+ tmp[ac_idx] = avg_back_off;
+
+ PRINTM(MCMND, "WMM: CWmax=%d CWmin=%d Avg Back-off=%d\n",
+ (1 << pwmm_ie->ac_params[num_ac].ecw.ecw_max) - 1,
+ cw_min, avg_back_off);
+ PRINTM_AC(&pwmm_ie->ac_params[num_ac]);
+ }
+
+ HEXDUMP("WMM: avg_back_off", (t_u8 *) tmp, sizeof(tmp));
+ HEXDUMP("WMM: queue_priority", priv->wmm.queue_priority,
+ sizeof(priv->wmm.queue_priority));
+
+ /* Bubble sort */
+ for (i = 0; i < num_ac; i++) {
+ for (j = 1; j < num_ac - i; j++) {
+ if (tmp[j - 1] > tmp[j]) {
+ SWAP_U16(tmp[j - 1], tmp[j]);
+ SWAP_U8(priv->wmm.queue_priority[j - 1],
+ priv->wmm.queue_priority[j]);
+ } else if (tmp[j - 1] == tmp[j]) {
+ if (priv->wmm.queue_priority[j - 1]
+ < priv->wmm.queue_priority[j]) {
+ SWAP_U8(priv->wmm.queue_priority[j - 1],
+ priv->wmm.queue_priority[j]);
+ }
+ }
+ }
+ }
+
+ wlan_wmm_queue_priorities_tid(priv, priv->wmm.queue_priority);
+
+ HEXDUMP("WMM: avg_back_off, sort", (t_u8 *) tmp, sizeof(tmp));
+ DBG_HEXDUMP(MCMD_D, "WMM: queue_priority, sort", priv->wmm.queue_priority,
+ sizeof(priv->wmm.queue_priority));
+ LEAVE();
+}
+
+/**
+ * @brief Downgrade WMM priority queue
+ *
+ * @param priv Pointer to the mlan_private driver data struct
+ *
+ * @return N/A
+ */
+void
+wlan_wmm_setup_ac_downgrade(pmlan_private priv)
+{
+ int ac_val;
+
+ ENTER();
+
+ PRINTM(MINFO, "WMM: AC Priorities: BK(0), BE(1), VI(2), VO(3)\n");
+
+ if (priv->wmm_enabled == MFALSE) {
+ /* WMM is not enabled, default priorities */
+ for (ac_val = WMM_AC_BK; ac_val <= WMM_AC_VO; ac_val++) {
+ priv->wmm.ac_down_graded_vals[ac_val] = (mlan_wmm_ac_e) ac_val;
+ }
+ } else {
+ for (ac_val = WMM_AC_BK; ac_val <= WMM_AC_VO; ac_val++) {
+ priv->wmm.ac_down_graded_vals[ac_val]
+ = wlan_wmm_eval_downgrade_ac(priv, (mlan_wmm_ac_e) ac_val);
+ PRINTM(MINFO, "WMM: AC PRIO %d maps to %d\n",
+ ac_val, priv->wmm.ac_down_graded_vals[ac_val]);
+ }
+ }
+
+ LEAVE();
+}
+
+/**
+ * @brief Allocate and add a RA list for all TIDs with the given RA
+ *
+ * @param priv Pointer to the mlan_private driver data struct
+ * @param ra Address of the receiver STA (AP in case of infra)
+ *
+ * @return N/A
+ */
+void
+wlan_ralist_add(mlan_private * priv, t_u8 * ra)
+{
+ int i;
+ raListTbl *ra_list;
+ pmlan_adapter pmadapter = priv->adapter;
+
+ ENTER();
+
+ for (i = 0; i < MAX_NUM_TID; ++i) {
+ ra_list = wlan_wmm_allocate_ralist_node(pmadapter, ra);
+ PRINTM(MINFO, "Creating RA List %p for tid %d\n", ra_list, i);
+ if (!ra_list)
+ break;
+ ra_list->max_amsdu = 0;
+ if (queuing_ra_based(priv)) {
+ ra_list->is_11n_enabled = wlan_is_11n_enabled(priv, ra);
+ if (ra_list->is_11n_enabled)
+ ra_list->max_amsdu = get_station_max_amsdu_size(priv, ra);
+ ra_list->tx_pause = wlan_is_tx_pause(priv, ra);
+ } else {
+ ra_list->is_11n_enabled = IS_11N_ENABLED(priv);
+ if (ra_list->is_11n_enabled)
+ ra_list->max_amsdu = priv->max_amsdu;
+ }
+
+ PRINTM(MDATA, "ralist %p: is_11n_enabled=%d max_amsdu=%d\n",
+ ra_list, ra_list->is_11n_enabled, ra_list->max_amsdu);
+
+ if (ra_list->is_11n_enabled) {
+ ra_list->packet_count = 0;
+ ra_list->ba_packet_threshold =
+ wlan_get_random_ba_threshold(pmadapter);
+ }
+
+ util_enqueue_list_tail(pmadapter->pmoal_handle,
+ &priv->wmm.tid_tbl_ptr[i].ra_list,
+ (pmlan_linked_list) ra_list, MNULL, MNULL);
+
+ if (!priv->wmm.tid_tbl_ptr[i].ra_list_curr)
+ priv->wmm.tid_tbl_ptr[i].ra_list_curr = ra_list;
+ }
+
+ LEAVE();
+}
+
+/**
+ * @brief Initialize the WMM state information and the WMM data path queues.
+ *
+ * @param pmadapter Pointer to the mlan_adapter data structure
+ *
+ * @return N/A
+ */
+t_void
+wlan_wmm_init(pmlan_adapter pmadapter)
+{
+ int i, j;
+ pmlan_private priv;
+
+ ENTER();
+
+ for (j = 0; j < pmadapter->priv_num; ++j) {
+ if ((priv = pmadapter->priv[j])) {
+ for (i = 0; i < MAX_NUM_TID; ++i) {
+ priv->aggr_prio_tbl[i].amsdu = BA_STREAM_NOT_ALLOWED;
+#ifdef WIFI_DIRECT_SUPPORT
+ if (priv->bss_type == MLAN_BSS_TYPE_WIFIDIRECT)
+ priv->aggr_prio_tbl[i].ampdu_ap =
+ priv->aggr_prio_tbl[i].ampdu_user =
+ BA_STREAM_NOT_ALLOWED;
+ else
+#endif
+ priv->aggr_prio_tbl[i].ampdu_ap =
+ priv->aggr_prio_tbl[i].ampdu_user = tos_to_tid_inv[i];
+ priv->wmm.pkts_queued[i] = 0;
+ priv->wmm.tid_tbl_ptr[i].ra_list_curr = MNULL;
+ }
+
+ priv->aggr_prio_tbl[6].ampdu_ap
+ = priv->aggr_prio_tbl[6].ampdu_user = BA_STREAM_NOT_ALLOWED;
+
+ priv->aggr_prio_tbl[7].ampdu_ap
+ = priv->aggr_prio_tbl[7].ampdu_user = BA_STREAM_NOT_ALLOWED;
+
+ priv->add_ba_param.timeout = MLAN_DEFAULT_BLOCK_ACK_TIMEOUT;
+ priv->add_ba_param.tx_win_size = MLAN_AMPDU_DEF_TXWINSIZE;
+ priv->add_ba_param.rx_win_size = MLAN_AMPDU_DEF_RXWINSIZE;
+ priv->add_ba_param.tx_amsdu = MTRUE;
+ priv->add_ba_param.rx_amsdu = MTRUE;
+ memset(priv->adapter, priv->rx_seq, 0xff, sizeof(priv->rx_seq));
+ wlan_wmm_default_queue_priorities(priv);
+ }
+ }
+
+ LEAVE();
+}
+
+/**
+ * @brief Setup the queue priorities and downgrade any queues as required
+ * by the WMM info. Setups default values if WMM is not active
+ * for this association.
+ *
+ * @param priv Pointer to the mlan_private driver data struct
+ *
+ * @return N/A
+ */
+void
+wlan_wmm_setup_queues(pmlan_private priv)
+{
+ ENTER();
+ wlan_wmm_setup_queue_priorities(priv, MNULL);
+ wlan_wmm_setup_ac_downgrade(priv);
+ LEAVE();
+}
+
+#ifdef STA_SUPPORT
+/**
+ * @brief Send a command to firmware to retrieve the current WMM status
+ *
+ * @param priv Pointer to the mlan_private driver data struct
+ *
+ * @return MLAN_STATUS_SUCCESS; MLAN_STATUS_FAILURE
+ */
+mlan_status
+wlan_cmd_wmm_status_change(pmlan_private priv)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ ret = wlan_prepare_cmd(priv, HostCmd_CMD_WMM_GET_STATUS, 0, 0, 0, MNULL);
+ LEAVE();
+ return ret;
+}
+#endif
+
+/**
+ * @brief Check if wmm TX queue is empty
+ *
+ * @param pmadapter Pointer to the mlan_adapter driver data struct
+ *
+ * @return MFALSE if not empty; MTRUE if empty
+ */
+int
+wlan_wmm_lists_empty(pmlan_adapter pmadapter)
+{
+ int j;
+ pmlan_private priv;
+
+ ENTER();
+
+ for (j = 0; j < pmadapter->priv_num; ++j) {
+ if ((priv = pmadapter->priv[j])) {
+ if ((priv->port_ctrl_mode == MTRUE) && (priv->port_open == MFALSE)) {
+ PRINTM(MINFO,
+ "wmm_lists_empty: PORT_CLOSED Ignore pkts from BSS%d\n",
+ j);
+ continue;
+ }
+
+ if (util_scalar_read(pmadapter->pmoal_handle,
+ &priv->wmm.tx_pkts_queued,
+ pmadapter->callbacks.moal_spin_lock,
+ pmadapter->callbacks.moal_spin_unlock)) {
+ LEAVE();
+ return MFALSE;
+ }
+ }
+ }
+
+ LEAVE();
+ return MTRUE;
+}
+
+/**
+ * @brief Get ralist node
+ *
+ * @param priv Pointer to the mlan_private driver data struct
+ * @param tid TID
+ * @param ra_addr Pointer to the route address
+ *
+ * @return ra_list or MNULL
+ */
+raListTbl *
+wlan_wmm_get_ralist_node(pmlan_private priv, t_u8 tid, t_u8 * ra_addr)
+{
+ raListTbl *ra_list;
+ ENTER();
+ ra_list =
+ (raListTbl *) util_peek_list(priv->adapter->pmoal_handle,
+ &priv->wmm.tid_tbl_ptr[tid].ra_list, MNULL,
+ MNULL);
+ while (ra_list && (ra_list != (raListTbl *)
+ & priv->wmm.tid_tbl_ptr[tid].ra_list)) {
+ if (!memcmp(priv->adapter, ra_list->ra, ra_addr, MLAN_MAC_ADDR_LENGTH)) {
+ LEAVE();
+ return ra_list;
+ }
+ ra_list = ra_list->pnext;
+ }
+ LEAVE();
+ return MNULL;
+}
+
+/**
+ * @brief Check if RA list is valid or not
+ *
+ * @param priv Pointer to the mlan_private driver data struct
+ * @param ra_list Pointer to raListTbl
+ * @param ptrindex TID pointer index
+ *
+ * @return MTRUE- valid. MFALSE- invalid.
+ */
+int
+wlan_is_ralist_valid(mlan_private * priv, raListTbl * ra_list, int ptrindex)
+{
+ raListTbl *rlist;
+
+ ENTER();
+
+ rlist =
+ (raListTbl *) util_peek_list(priv->adapter->pmoal_handle,
+ &priv->wmm.tid_tbl_ptr[ptrindex].ra_list,
+ MNULL, MNULL);
+
+ while (rlist && (rlist != (raListTbl *)
+ & priv->wmm.tid_tbl_ptr[ptrindex].ra_list)) {
+ if (rlist == ra_list) {
+ LEAVE();
+ return MTRUE;
+ }
+
+ rlist = rlist->pnext;
+ }
+ LEAVE();
+ return MFALSE;
+}
+
+/**
+ * @brief Update an existing raList with a new RA and 11n capability
+ *
+ * @param priv Pointer to the mlan_private driver data struct
+ * @param old_ra Old receiver address
+ * @param new_ra New receiver address
+ *
+ * @return integer count of updated nodes
+ */
+int
+wlan_ralist_update(mlan_private * priv, t_u8 * old_ra, t_u8 * new_ra)
+{
+ t_u8 tid;
+ int update_count;
+ raListTbl *ra_list;
+
+ ENTER();
+
+ update_count = 0;
+
+ for (tid = 0; tid < MAX_NUM_TID; ++tid) {
+
+ ra_list = wlan_wmm_get_ralist_node(priv, tid, old_ra);
+
+ if (ra_list) {
+ update_count++;
+
+ if (queuing_ra_based(priv))
+ ra_list->is_11n_enabled = wlan_is_11n_enabled(priv, new_ra);
+ else
+ ra_list->is_11n_enabled = IS_11N_ENABLED(priv);
+ ra_list->packet_count = 0;
+ ra_list->ba_packet_threshold =
+ wlan_get_random_ba_threshold(priv->adapter);
+ PRINTM(MINFO,
+ "ralist_update: %p, %d, %02x:%02x:%02x:%02x:%02x:%02x-->"
+ "%02x:%02x:%02x:%02x:%02x:%02x\n", ra_list,
+ ra_list->is_11n_enabled, ra_list->ra[0], ra_list->ra[1],
+ ra_list->ra[2], ra_list->ra[3], ra_list->ra[4],
+ ra_list->ra[5], new_ra[0], new_ra[1], new_ra[2], new_ra[3],
+ new_ra[4], new_ra[5]);
+
+ memcpy(priv->adapter, ra_list->ra, new_ra, MLAN_MAC_ADDR_LENGTH);
+ }
+ }
+
+ LEAVE();
+ return update_count;
+}
+
+/**
+ * @brief Add packet to WMM queue
+ *
+ * @param pmadapter Pointer to the mlan_adapter driver data struct
+ * @param pmbuf Pointer to the mlan_buffer data struct
+ *
+ * @return N/A
+ */
+t_void
+wlan_wmm_add_buf_txqueue(pmlan_adapter pmadapter, pmlan_buffer pmbuf)
+{
+ pmlan_private priv = pmadapter->priv[pmbuf->bss_index];
+ t_u32 tid;
+ raListTbl *ra_list;
+ t_u8 ra[MLAN_MAC_ADDR_LENGTH], tid_down;
+
+ ENTER();
+
+ pmbuf->buf_type = MLAN_BUF_TYPE_DATA;
+ if (!priv->media_connected) {
+ PRINTM(MWARN, "Drop packet in disconnect state\n");
+ wlan_write_data_complete(pmadapter, pmbuf, MLAN_STATUS_FAILURE);
+ LEAVE();
+ return;
+ }
+ tid = pmbuf->priority;
+ pmadapter->callbacks.moal_spin_lock(pmadapter->pmoal_handle,
+ priv->wmm.ra_list_spinlock);
+ tid_down = wlan_wmm_downgrade_tid(priv, tid);
+
+ /* In case of infra as we have already created the list during association
+ we just don't have to call get_queue_raptr, we will have only 1 raptr
+ for a tid in case of infra */
+ if (!queuing_ra_based(priv)) {
+ ra_list = (raListTbl *) util_peek_list(pmadapter->pmoal_handle,
+ &priv->wmm.tid_tbl_ptr[tid_down].
+ ra_list, MNULL, MNULL);
+ } else {
+ memcpy(pmadapter, ra, pmbuf->pbuf + pmbuf->data_offset,
+ MLAN_MAC_ADDR_LENGTH);
+ /** put multicast/broadcast packet in the same ralist */
+ if (ra[0] & 0x01)
+ memset(pmadapter, ra, 0xff, sizeof(ra));
+ ra_list = wlan_wmm_get_queue_raptr(priv, tid_down, ra);
+ }
+
+ if (!ra_list) {
+ PRINTM(MWARN, "Drop packet, ra_list=%p, "
+ "media_connected=%d\n", ra_list, priv->media_connected);
+ pmadapter->callbacks.moal_spin_unlock(pmadapter->pmoal_handle,
+ priv->wmm.ra_list_spinlock);
+ wlan_write_data_complete(pmadapter, pmbuf, MLAN_STATUS_FAILURE);
+ LEAVE();
+ return;
+ }
+
+ PRINTM(MDATA, "Adding pkt to ra_list %p %p priority=%d, tid_down=%d\n",
+ ra_list, pmbuf, pmbuf->priority, tid_down);
+ util_enqueue_list_tail(pmadapter->pmoal_handle, &ra_list->buf_head,
+ (pmlan_linked_list) pmbuf, MNULL, MNULL);
+
+ ra_list->total_pkts++;
+ ra_list->packet_count++;
+
+ priv->wmm.pkts_queued[tid_down]++;
+ if (!ra_list->tx_pause) {
+ util_scalar_increment(pmadapter->pmoal_handle,
+ &priv->wmm.tx_pkts_queued, MNULL, MNULL);
+ /* if highest_queued_prio < prio(tid_down), set it to prio(tid_down) */
+ util_scalar_conditional_write(pmadapter->pmoal_handle,
+ &priv->wmm.highest_queued_prio,
+ MLAN_SCALAR_COND_LESS_THAN,
+ tos_to_tid_inv[tid_down],
+ tos_to_tid_inv[tid_down], MNULL, MNULL);
+ }
+ /* Record the current time the packet was queued; used to determine the
+ amount of time the packet was queued in the driver before it was sent to
+ the firmware. The delay is then sent along with the packet to the
+ firmware for aggregate delay calculation for stats and MSDU lifetime
+ expiry. */
+ pmadapter->callbacks.moal_spin_unlock(pmadapter->pmoal_handle,
+ priv->wmm.ra_list_spinlock);
+ pmadapter->callbacks.moal_get_system_time(pmadapter->pmoal_handle,
+ &pmbuf->in_ts_sec,
+ &pmbuf->in_ts_usec);
+
+ LEAVE();
+}
+
+#ifdef STA_SUPPORT
+/**
+ * @brief Process the GET_WMM_STATUS command response from firmware
+ *
+ * The GET_WMM_STATUS response may contain multiple TLVs for:
+ * - AC Queue status TLVs
+ * - Current WMM Parameter IE TLV
+ * - Admission Control action frame TLVs
+ *
+ * This function parses the TLVs and then calls further functions
+ * to process any changes in the queue prioritize or state.
+ *
+ * @param priv Pointer to the mlan_private driver data struct
+ * @param ptlv Pointer to the tlv block returned in the response.
+ * @param resp_len Length of TLV block
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+mlan_status
+wlan_ret_wmm_get_status(pmlan_private priv, t_u8 * ptlv, int resp_len)
+{
+ t_u8 *pcurrent = ptlv;
+ t_u32 tlv_len;
+ t_u8 sendWmmEvent;
+ MrvlIEtypes_Data_t *pTlvHdr;
+ MrvlIEtypes_WmmQueueStatus_t *pTlvWmmQStatus;
+ IEEEtypes_WmmParameter_t *pWmmParamIe = MNULL;
+ WmmAcStatus_t *pac_status;
+
+ MrvlIETypes_ActionFrame_t *pTlvAction;
+ IEEEtypes_Action_WMM_AddTsRsp_t *pAddTsRsp;
+ IEEEtypes_Action_WMM_DelTs_t *pDelTs;
+
+ ENTER();
+
+ sendWmmEvent = MFALSE;
+
+ PRINTM(MINFO, "WMM: WMM_GET_STATUS cmdresp received: %d\n", resp_len);
+ HEXDUMP("CMD_RESP: WMM_GET_STATUS", pcurrent, resp_len);
+
+ while (resp_len >= sizeof(pTlvHdr->header)) {
+ pTlvHdr = (MrvlIEtypes_Data_t *) pcurrent;
+ tlv_len = wlan_le16_to_cpu(pTlvHdr->header.len);
+
+ switch (wlan_le16_to_cpu(pTlvHdr->header.type)) {
+ case TLV_TYPE_WMMQSTATUS:
+ pTlvWmmQStatus = (MrvlIEtypes_WmmQueueStatus_t *) pTlvHdr;
+ PRINTM(MEVENT, "WMM_STATUS: QSTATUS TLV: %d\n",
+ pTlvWmmQStatus->queue_index);
+
+ PRINTM(MINFO,
+ "CMD_RESP: WMM_GET_STATUS: QSTATUS TLV: %d, %d, %d\n",
+ pTlvWmmQStatus->queue_index,
+ pTlvWmmQStatus->flow_required, pTlvWmmQStatus->disabled);
+
+ pac_status = &priv->wmm.ac_status[pTlvWmmQStatus->queue_index];
+ pac_status->disabled = pTlvWmmQStatus->disabled;
+ pac_status->flow_required = pTlvWmmQStatus->flow_required;
+ pac_status->flow_created = pTlvWmmQStatus->flow_created;
+ break;
+
+ case WMM_IE:
+ /*
+ * Point the regular IEEE IE 2 bytes into the Marvell IE
+ * and setup the IEEE IE type and length byte fields
+ */
+
+ PRINTM(MEVENT, "WMM STATUS: WMM IE\n");
+
+ HEXDUMP("WMM: WMM TLV:", (t_u8 *) pTlvHdr, tlv_len + 4);
+
+ pWmmParamIe = (IEEEtypes_WmmParameter_t *) (pcurrent + 2);
+ pWmmParamIe->vend_hdr.len = (t_u8) tlv_len;
+ pWmmParamIe->vend_hdr.element_id = WMM_IE;
+
+ PRINTM(MINFO, "CMD_RESP: WMM_GET_STATUS: WMM Parameter Set: %d\n",
+ pWmmParamIe->qos_info.para_set_count);
+
+ memcpy(priv->adapter,
+ (t_u8 *) & priv->curr_bss_params.bss_descriptor.wmm_ie,
+ pWmmParamIe, MIN(sizeof(IEEEtypes_WmmParameter_t),
+ (pWmmParamIe->vend_hdr.len + 2)));
+ sendWmmEvent = MTRUE;
+ break;
+
+ case TLV_TYPE_IEEE_ACTION_FRAME:
+ PRINTM(MEVENT, "WMM_STATUS: IEEE Action Frame\n");
+ pTlvAction = (MrvlIETypes_ActionFrame_t *) pcurrent;
+
+ if (pTlvAction->actionFrame.wmmAc.tspecAct.category
+ == IEEE_MGMT_ACTION_CATEGORY_WMM_TSPEC) {
+
+ switch (pTlvAction->actionFrame.wmmAc.tspecAct.action) {
+ case TSPEC_ACTION_CODE_ADDTS_RSP:
+ pAddTsRsp = &pTlvAction->actionFrame.wmmAc.addTsRsp;
+ wlan_send_wmmac_host_event(priv, "ADDTS_RSP",
+ pTlvAction->srcAddr,
+ pAddTsRsp->tspecIE.TspecBody.
+ TSInfo.TID,
+ pAddTsRsp->tspecIE.TspecBody.
+ TSInfo.UserPri,
+ pAddTsRsp->statusCode);
+ break;
+
+ case TSPEC_ACTION_CODE_DELTS:
+ pDelTs = &pTlvAction->actionFrame.wmmAc.delTs;
+ wlan_send_wmmac_host_event(priv, "DELTS_RX",
+ pTlvAction->srcAddr,
+ pDelTs->tspecIE.TspecBody.TSInfo.
+ TID,
+ pDelTs->tspecIE.TspecBody.TSInfo.
+ UserPri, pDelTs->reasonCode);
+ break;
+
+ case TSPEC_ACTION_CODE_ADDTS_REQ:
+ default:
+ break;
+ }
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ pcurrent += (tlv_len + sizeof(pTlvHdr->header));
+ resp_len -= (tlv_len + sizeof(pTlvHdr->header));
+ }
+
+ wlan_wmm_setup_queue_priorities(priv, pWmmParamIe);
+ wlan_wmm_setup_ac_downgrade(priv);
+
+ if (sendWmmEvent) {
+ wlan_recv_event(priv, MLAN_EVENT_ID_FW_WMM_CONFIG_CHANGE, MNULL);
+ }
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief Call back from the command module to allow insertion of a WMM TLV
+ *
+ * If the BSS we are associating to supports WMM, add the required WMM
+ * Information IE to the association request command buffer in the form
+ * of a Marvell extended IEEE IE.
+ *
+ * @param priv Pointer to the mlan_private driver data struct
+ * @param ppAssocBuf Output parameter: Pointer to the TLV output buffer,
+ * modified on return to point after the appended WMM TLV
+ * @param pWmmIE Pointer to the WMM IE for the BSS we are joining
+ * @param pHTCap Pointer to the HT IE for the BSS we are joining
+ *
+ * @return Length of data appended to the association tlv buffer
+ */
+t_u32
+wlan_wmm_process_association_req(pmlan_private priv,
+ t_u8 ** ppAssocBuf,
+ IEEEtypes_WmmParameter_t * pWmmIE,
+ IEEEtypes_HTCap_t * pHTCap)
+{
+ MrvlIEtypes_WmmParamSet_t *pwmm_tlv;
+ t_u32 ret_len = 0;
+
+ ENTER();
+
+ /* Null checks */
+ if (!ppAssocBuf) {
+ LEAVE();
+ return 0;
+ }
+ if (!(*ppAssocBuf)) {
+ LEAVE();
+ return 0;
+ }
+
+ if (!pWmmIE) {
+ LEAVE();
+ return 0;
+ }
+
+ PRINTM(MINFO, "WMM: process assoc req: bss->wmmIe=0x%x\n",
+ pWmmIE->vend_hdr.element_id);
+
+ if ((priv->wmm_required
+ || (pHTCap && (pHTCap->ieee_hdr.element_id == HT_CAPABILITY)
+ && (priv->adapter->config_bands & BAND_GN
+ || priv->adapter->config_bands & BAND_AN))
+ )
+ && pWmmIE->vend_hdr.element_id == WMM_IE) {
+ pwmm_tlv = (MrvlIEtypes_WmmParamSet_t *) * ppAssocBuf;
+ pwmm_tlv->header.type = (t_u16) wmm_info_ie[0];
+ pwmm_tlv->header.type = wlan_cpu_to_le16(pwmm_tlv->header.type);
+ pwmm_tlv->header.len = (t_u16) wmm_info_ie[1];
+ memcpy(priv->adapter, pwmm_tlv->wmm_ie, &wmm_info_ie[2],
+ pwmm_tlv->header.len);
+ if (pWmmIE->qos_info.qos_uapsd)
+ memcpy(priv->adapter,
+ (t_u8 *) (pwmm_tlv->wmm_ie + pwmm_tlv->header.len -
+ sizeof(priv->wmm_qosinfo)), &priv->wmm_qosinfo,
+ sizeof(priv->wmm_qosinfo));
+
+ ret_len = sizeof(pwmm_tlv->header) + pwmm_tlv->header.len;
+ pwmm_tlv->header.len = wlan_cpu_to_le16(pwmm_tlv->header.len);
+
+ HEXDUMP("ASSOC_CMD: WMM IE", (t_u8 *) pwmm_tlv, ret_len);
+ *ppAssocBuf += ret_len;
+ }
+
+ LEAVE();
+ return ret_len;
+}
+#endif /* STA_SUPPORT */
+
+/**
+ * @brief Compute the time delay in the driver queues for a given packet.
+ *
+ * When the packet is received at the OS/Driver interface, the current
+ * time is set in the packet structure. The difference between the present
+ * time and that received time is computed in this function and limited
+ * based on pre-compiled limits in the driver.
+ *
+ * @param priv Ptr to the mlan_private driver data struct
+ * @param pmbuf Ptr to the mlan_buffer which has been previously timestamped
+ *
+ * @return Time delay of the packet in 2ms units after having limit applied
+ */
+t_u8
+wlan_wmm_compute_driver_packet_delay(pmlan_private priv,
+ const pmlan_buffer pmbuf)
+{
+ t_u8 ret_val = 0;
+ t_u32 out_ts_sec, out_ts_usec, queue_delay;
+
+ ENTER();
+
+ priv->adapter->callbacks.moal_get_system_time(priv->adapter->pmoal_handle,
+ &out_ts_sec, &out_ts_usec);
+
+ queue_delay = (out_ts_sec - pmbuf->in_ts_sec) * 1000;
+ queue_delay += (out_ts_usec - pmbuf->in_ts_usec) / 1000;
+
+ /*
+ * Queue delay is passed as a uint8 in units of 2ms (ms shifted
+ * by 1). Min value (other than 0) is therefore 2ms, max is 510ms.
+ *
+ * Pass max value if queue_delay is beyond the uint8 range
+ */
+ ret_val = (t_u8) (MIN(queue_delay, priv->wmm.drv_pkt_delay_max) >> 1);
+
+ PRINTM(MINFO, "WMM: Pkt Delay: %d ms, %d ms sent to FW\n",
+ queue_delay, ret_val);
+
+ LEAVE();
+ return ret_val;
+}
+
+/**
+ * @brief Transmit the highest priority packet awaiting in the WMM Queues
+ *
+ * @param pmadapter Pointer to the mlan_adapter driver data struct
+ *
+ * @return N/A
+ */
+void
+wlan_wmm_process_tx(pmlan_adapter pmadapter)
+{
+ ENTER();
+
+ do {
+ if (wlan_dequeue_tx_packet(pmadapter))
+ break;
+ /* Check if busy */
+ } while (!pmadapter->data_sent && !pmadapter->tx_lock_flag
+ && !wlan_wmm_lists_empty(pmadapter));
+
+ LEAVE();
+ return;
+}
+
+/**
+ * @brief select wmm queue
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param tid TID 0-7
+ *
+ * @return wmm_queue priority (0-3)
+ */
+t_u8
+wlan_wmm_select_queue(mlan_private * pmpriv, t_u8 tid)
+{
+ pmlan_adapter pmadapter = pmpriv->adapter;
+ t_u8 i;
+ mlan_wmm_ac_e ac_down =
+ pmpriv->wmm.
+ ac_down_graded_vals[wlan_wmm_convert_tos_to_ac(pmadapter, tid)];
+
+ ENTER();
+
+ for (i = 0; i < 4; i++) {
+ if (pmpriv->wmm.queue_priority[i] == ac_down) {
+ LEAVE();
+ return i;
+ }
+ }
+ LEAVE();
+ return 0;
+}
+
+#if defined(UAP_SUPPORT)
+/**
+ * @brief Delete tx packets in RA list
+ *
+ * @param priv Pointer to the mlan_private driver data struct
+ * @param ra_list_head ra list header
+ * @param tid tid
+ * @param tx_pause tx_pause flag
+ *
+ * @return N/A
+ */
+static INLINE t_u8
+wlan_del_tx_pkts_in_ralist(pmlan_private priv,
+ mlan_list_head * ra_list_head,
+ int tid, t_u8 tx_pause)
+{
+ raListTbl *ra_list = MNULL;
+ pmlan_adapter pmadapter = priv->adapter;
+ pmlan_buffer pmbuf = MNULL;
+ t_u8 ret = MFALSE;
+ ENTER();
+ ra_list =
+ (raListTbl *) util_peek_list(priv->adapter->pmoal_handle, ra_list_head,
+ MNULL, MNULL);
+ while (ra_list && ra_list != (raListTbl *) ra_list_head) {
+ if (ra_list->total_pkts && (ra_list->tx_pause ||
+ (!tx_pause &&
+ ra_list->total_pkts > RX_LOW_THRESHOLD))) {
+ if ((pmbuf =
+ (pmlan_buffer) util_dequeue_list(pmadapter->pmoal_handle,
+ &ra_list->buf_head, MNULL,
+ MNULL))) {
+ PRINTM(MDATA,
+ "Drop pkts: tid=%d tx_pause=%d pkts=%d brd_pkts=%d %02x:%02x:%02x:%02x:%02x:%02x\n",
+ tid, tx_pause, ra_list->total_pkts,
+ pmadapter->pending_bridge_pkts, ra_list->ra[0],
+ ra_list->ra[1], ra_list->ra[2], ra_list->ra[3],
+ ra_list->ra[4], ra_list->ra[5]);
+ wlan_write_data_complete(pmadapter, pmbuf, MLAN_STATUS_FAILURE);
+ priv->wmm.pkts_queued[tid]--;
+ priv->num_drop_pkts++;
+ ra_list->total_pkts--;
+ if (!ra_list->tx_pause)
+ util_scalar_decrement(pmadapter->pmoal_handle,
+ &priv->wmm.tx_pkts_queued, MNULL,
+ MNULL);
+ ret = MTRUE;
+ break;
+ }
+ }
+ ra_list = ra_list->pnext;
+ }
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Drop tx pkts
+ *
+ * @param priv Pointer to the mlan_private driver data struct
+ *
+ * @return N/A
+ */
+t_void
+wlan_drop_tx_pkts(pmlan_private priv)
+{
+ int j;
+ static int i = 0;
+ t_u8 tx_pause = 0;
+ pmlan_adapter pmadapter = priv->adapter;
+ pmadapter->callbacks.moal_spin_lock(pmadapter->pmoal_handle,
+ priv->wmm.ra_list_spinlock);
+ if (wlan_get_tx_pause_station_entry(priv))
+ tx_pause = 1;
+ for (j = 0; j < MAX_NUM_TID; j++, i++) {
+ if (i == MAX_NUM_TID)
+ i = 0;
+ if (wlan_del_tx_pkts_in_ralist
+ (priv, &priv->wmm.tid_tbl_ptr[i].ra_list, i, tx_pause)) {
+ i++;
+ break;
+ }
+ }
+ pmadapter->callbacks.moal_spin_unlock(pmadapter->pmoal_handle,
+ priv->wmm.ra_list_spinlock);
+ return;
+}
+
+/**
+ * @brief Remove peer ralist
+ *
+ * @param priv A pointer to mlan_private
+ * @param mac peer mac address
+ *
+ * @return N/A
+ */
+t_void
+wlan_wmm_delete_peer_ralist(pmlan_private priv, t_u8 * mac)
+{
+ raListTbl *ra_list;
+ int i;
+ pmlan_adapter pmadapter = priv->adapter;
+ t_u32 pkt_cnt = 0;
+ t_u32 tx_pkts_queued = 0;
+
+ ENTER();
+ pmadapter->callbacks.moal_spin_lock(pmadapter->pmoal_handle,
+ priv->wmm.ra_list_spinlock);
+ for (i = 0; i < MAX_NUM_TID; ++i) {
+ ra_list = wlan_wmm_get_ralist_node(priv, i, mac);
+ if (ra_list) {
+ PRINTM(MINFO, "delete sta ralist %p\n", ra_list);
+ if (!ra_list->tx_pause)
+ pkt_cnt += ra_list->total_pkts;
+ wlan_wmm_del_pkts_in_ralist_node(priv, ra_list);
+
+ util_unlink_list(pmadapter->pmoal_handle,
+ &priv->wmm.tid_tbl_ptr[i].ra_list,
+ (pmlan_linked_list) ra_list, MNULL, MNULL);
+ pmadapter->callbacks.moal_mfree(pmadapter->pmoal_handle,
+ (t_u8 *) ra_list);
+ if (priv->wmm.tid_tbl_ptr[i].ra_list_curr == ra_list)
+ priv->wmm.tid_tbl_ptr[i].ra_list_curr =
+ (raListTbl *) & priv->wmm.tid_tbl_ptr[i].ra_list;
+ }
+ }
+ if (pkt_cnt) {
+ tx_pkts_queued = util_scalar_read(pmadapter->pmoal_handle,
+ &priv->wmm.tx_pkts_queued, MNULL,
+ MNULL);
+ tx_pkts_queued -= pkt_cnt;
+ util_scalar_write(priv->adapter->pmoal_handle,
+ &priv->wmm.tx_pkts_queued, tx_pkts_queued, MNULL,
+ MNULL);
+ util_scalar_write(priv->adapter->pmoal_handle,
+ &priv->wmm.highest_queued_prio, HIGH_PRIO_TID, MNULL,
+ MNULL);
+ }
+ pmadapter->callbacks.moal_spin_unlock(pmadapter->pmoal_handle,
+ priv->wmm.ra_list_spinlock);
+ LEAVE();
+}
+#endif
+
+#ifdef STA_SUPPORT
+
+/**
+ * @brief This function prepares the command of ADDTS
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param cmd A pointer to HostCmd_DS_COMMAND structure
+ * @param pdata_buf A pointer to data buffer
+ * @return MLAN_STATUS_SUCCESS
+ */
+mlan_status
+wlan_cmd_wmm_addts_req(IN pmlan_private pmpriv,
+ OUT HostCmd_DS_COMMAND * cmd, IN t_void * pdata_buf)
+{
+ mlan_ds_wmm_addts *paddts = (mlan_ds_wmm_addts *) pdata_buf;
+ HostCmd_DS_WMM_ADDTS_REQ *pcmd_addts = &cmd->params.add_ts;
+
+ ENTER();
+
+ cmd->command = wlan_cpu_to_le16(HostCmd_CMD_WMM_ADDTS_REQ);
+ cmd->size = wlan_cpu_to_le16(sizeof(pcmd_addts->dialog_token)
+ + sizeof(pcmd_addts->timeout_ms)
+ + sizeof(pcmd_addts->command_result)
+ + sizeof(pcmd_addts->ieee_status_code)
+ + paddts->ie_data_len + S_DS_GEN);
+ cmd->result = 0;
+
+ pcmd_addts->timeout_ms = wlan_cpu_to_le32(paddts->timeout);
+ pcmd_addts->dialog_token = paddts->dialog_tok;
+ memcpy(pmpriv->adapter,
+ pcmd_addts->tspec_data,
+ paddts->ie_data, MIN(WMM_TSPEC_SIZE, paddts->ie_data_len));
+
+ LEAVE();
+
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function handles the command response of ADDTS
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param resp A pointer to HostCmd_DS_COMMAND
+ * @param pioctl_buf A pointer to mlan_ioctl_req structure
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+mlan_status
+wlan_ret_wmm_addts_req(IN pmlan_private pmpriv,
+ const IN HostCmd_DS_COMMAND * resp,
+ OUT mlan_ioctl_req * pioctl_buf)
+{
+ mlan_ds_wmm_cfg *pwmm = MNULL;
+ mlan_ds_wmm_addts *paddts = MNULL;
+ const HostCmd_DS_WMM_ADDTS_REQ *presp_addts = &resp->params.add_ts;
+
+ ENTER();
+
+ if (pioctl_buf) {
+ pwmm = (mlan_ds_wmm_cfg *) pioctl_buf->pbuf;
+ paddts = (mlan_ds_wmm_addts *) & pwmm->param.addts;
+ paddts->result = presp_addts->command_result;
+ paddts->dialog_tok = presp_addts->dialog_token;
+ paddts->status_code = (t_u32) presp_addts->ieee_status_code;
+
+ if (presp_addts->command_result == MLAN_CMD_RESULT_SUCCESS) {
+ /* The tspecData field is potentially variable in size due to extra
+ IEs that may have been in the ADDTS response action frame.
+ Calculate the data length from the firmware command response. */
+ paddts->ie_data_len
+ = (t_u8) (resp->size - sizeof(presp_addts->command_result)
+ - sizeof(presp_addts->timeout_ms)
+ - sizeof(presp_addts->dialog_token)
+ - sizeof(presp_addts->ieee_status_code)
+ - S_DS_GEN);
+
+ /* Copy the TSPEC data include any extra IEs after the TSPEC */
+ memcpy(pmpriv->adapter,
+ paddts->ie_data,
+ presp_addts->tspec_data, paddts->ie_data_len);
+ } else {
+ paddts->ie_data_len = 0;
+ }
+ PRINTM(MINFO, "TSPEC: ADDTS ret = %d,%d sz=%d\n",
+ paddts->result, paddts->status_code, paddts->ie_data_len);
+
+ HEXDUMP("TSPEC: ADDTS data", paddts->ie_data, paddts->ie_data_len);
+ }
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function prepares the command of DELTS
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param cmd A pointer to HostCmd_DS_COMMAND structure
+ * @param pdata_buf A pointer to data buffer
+ * @return MLAN_STATUS_SUCCESS
+ */
+mlan_status
+wlan_cmd_wmm_delts_req(IN pmlan_private pmpriv,
+ OUT HostCmd_DS_COMMAND * cmd, IN t_void * pdata_buf)
+{
+ mlan_ds_wmm_delts *pdelts = (mlan_ds_wmm_delts *) pdata_buf;
+ HostCmd_DS_WMM_DELTS_REQ *pcmd_delts = &cmd->params.del_ts;
+
+ ENTER();
+
+ cmd->command = wlan_cpu_to_le16(HostCmd_CMD_WMM_DELTS_REQ);
+ cmd->size = wlan_cpu_to_le16(sizeof(pcmd_delts->dialog_token)
+ + sizeof(pcmd_delts->command_result)
+ + sizeof(pcmd_delts->ieee_reason_code)
+ + pdelts->ie_data_len + S_DS_GEN);
+ cmd->result = 0;
+ pcmd_delts->ieee_reason_code = (t_u8) pdelts->status_code;
+ memcpy(pmpriv->adapter,
+ pcmd_delts->tspec_data,
+ pdelts->ie_data, MIN(WMM_TSPEC_SIZE, pdelts->ie_data_len));
+
+ LEAVE();
+
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function handles the command response of DELTS
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param resp A pointer to HostCmd_DS_COMMAND
+ * @param pioctl_buf A pointer to mlan_ioctl_req structure
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+mlan_status
+wlan_ret_wmm_delts_req(IN pmlan_private pmpriv,
+ const IN HostCmd_DS_COMMAND * resp,
+ OUT mlan_ioctl_req * pioctl_buf)
+{
+ mlan_ds_wmm_cfg *pwmm;
+ IEEEtypes_WMM_TSPEC_t *pTspecIE;
+ const HostCmd_DS_WMM_DELTS_REQ *presp_delts = &resp->params.del_ts;
+
+ ENTER();
+
+ if (pioctl_buf) {
+ pwmm = (mlan_ds_wmm_cfg *) pioctl_buf->pbuf;
+ pwmm->param.delts.result = presp_delts->command_result;
+
+ PRINTM(MINFO, "TSPEC: DELTS result = %d\n",
+ presp_delts->command_result);
+
+ if (presp_delts->command_result == 0) {
+ pTspecIE = (IEEEtypes_WMM_TSPEC_t *) presp_delts->tspec_data;
+ wlan_send_wmmac_host_event(pmpriv,
+ "DELTS_TX",
+ MNULL,
+ pTspecIE->TspecBody.TSInfo.TID,
+ pTspecIE->TspecBody.TSInfo.UserPri,
+ presp_delts->ieee_reason_code);
+
+ }
+ }
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function prepares the command of WMM_QUEUE_CONFIG
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param cmd A pointer to HostCmd_DS_COMMAND structure
+ * @param pdata_buf A pointer to data buffer
+ * @return MLAN_STATUS_SUCCESS
+ */
+mlan_status
+wlan_cmd_wmm_queue_config(IN pmlan_private pmpriv,
+ OUT HostCmd_DS_COMMAND * cmd, IN t_void * pdata_buf)
+{
+ mlan_ds_wmm_queue_config *pqcfg = (mlan_ds_wmm_queue_config *) pdata_buf;
+ HostCmd_DS_WMM_QUEUE_CONFIG *pcmd_qcfg = &cmd->params.queue_config;
+
+ ENTER();
+
+ cmd->command = wlan_cpu_to_le16(HostCmd_CMD_WMM_QUEUE_CONFIG);
+ cmd->size = wlan_cpu_to_le16(sizeof(pcmd_qcfg->action)
+ + sizeof(pcmd_qcfg->access_category)
+ + sizeof(pcmd_qcfg->msdu_lifetime_expiry)
+ + S_DS_GEN);
+ cmd->result = 0;
+
+ pcmd_qcfg->action = pqcfg->action;
+ pcmd_qcfg->access_category = pqcfg->access_category;
+ pcmd_qcfg->msdu_lifetime_expiry =
+ wlan_cpu_to_le16(pqcfg->msdu_lifetime_expiry);
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function handles the command response of WMM_QUEUE_CONFIG
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param resp A pointer to HostCmd_DS_COMMAND
+ * @param pioctl_buf A pointer to mlan_ioctl_req structure
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+mlan_status
+wlan_ret_wmm_queue_config(IN pmlan_private pmpriv,
+ const IN HostCmd_DS_COMMAND * resp,
+ OUT mlan_ioctl_req * pioctl_buf)
+{
+ mlan_ds_wmm_cfg *pwmm = MNULL;
+ const HostCmd_DS_WMM_QUEUE_CONFIG *presp_qcfg = &resp->params.queue_config;
+
+ ENTER();
+
+ if (pioctl_buf) {
+ pwmm = (mlan_ds_wmm_cfg *) pioctl_buf->pbuf;
+ pwmm->param.q_cfg.action = presp_qcfg->action;
+ pwmm->param.q_cfg.access_category = presp_qcfg->access_category;
+ pwmm->param.q_cfg.msdu_lifetime_expiry =
+ wlan_le16_to_cpu(presp_qcfg->msdu_lifetime_expiry);
+ }
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function prepares the command of WMM_QUEUE_STATS
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param cmd A pointer to HostCmd_DS_COMMAND structure
+ * @param pdata_buf A pointer to data buffer
+ * @return MLAN_STATUS_SUCCESS
+ */
+mlan_status
+wlan_cmd_wmm_queue_stats(IN pmlan_private pmpriv,
+ OUT HostCmd_DS_COMMAND * cmd, IN t_void * pdata_buf)
+{
+ mlan_ds_wmm_queue_stats *pqstats = (mlan_ds_wmm_queue_stats *) pdata_buf;
+ HostCmd_DS_WMM_QUEUE_STATS *pcmd_qstats = &cmd->params.queue_stats;
+ t_u8 id;
+
+ ENTER();
+
+ cmd->command = wlan_cpu_to_le16(HostCmd_CMD_WMM_QUEUE_STATS);
+ cmd->size = wlan_cpu_to_le16(sizeof(HostCmd_DS_WMM_QUEUE_STATS)
+ + S_DS_GEN);
+ cmd->result = 0;
+
+ pcmd_qstats->action = pqstats->action;
+ pcmd_qstats->select_is_userpri = 1;
+ pcmd_qstats->select_bin = pqstats->user_priority;
+ pcmd_qstats->pkt_count = wlan_cpu_to_le16(pqstats->pkt_count);
+ pcmd_qstats->pkt_loss = wlan_cpu_to_le16(pqstats->pkt_loss);
+ pcmd_qstats->avg_queue_delay = wlan_cpu_to_le32(pqstats->avg_queue_delay);
+ pcmd_qstats->avg_tx_delay = wlan_cpu_to_le32(pqstats->avg_tx_delay);
+ pcmd_qstats->used_time = wlan_cpu_to_le16(pqstats->used_time);
+ pcmd_qstats->policed_time = wlan_cpu_to_le16(pqstats->policed_time);
+ for (id = 0; id < MLAN_WMM_STATS_PKTS_HIST_BINS; id++) {
+ pcmd_qstats->delay_histogram[id] =
+ wlan_cpu_to_le16(pqstats->delay_histogram[id]);
+ }
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function handles the command response of WMM_QUEUE_STATS
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param resp A pointer to HostCmd_DS_COMMAND
+ * @param pioctl_buf A pointer to mlan_ioctl_req structure
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+mlan_status
+wlan_ret_wmm_queue_stats(IN pmlan_private pmpriv,
+ const IN HostCmd_DS_COMMAND * resp,
+ OUT mlan_ioctl_req * pioctl_buf)
+{
+ mlan_ds_wmm_cfg *pwmm = MNULL;
+ mlan_ds_wmm_queue_stats *pqstats = MNULL;
+ const HostCmd_DS_WMM_QUEUE_STATS *presp_qstats = &resp->params.queue_stats;
+ t_u8 id;
+
+ ENTER();
+
+ if (pioctl_buf) {
+ pwmm = (mlan_ds_wmm_cfg *) pioctl_buf->pbuf;
+ pqstats = (mlan_ds_wmm_queue_stats *) & pwmm->param.q_stats;
+
+ pqstats->action = presp_qstats->action;
+ pqstats->user_priority = presp_qstats->select_bin;
+ pqstats->pkt_count = wlan_le16_to_cpu(presp_qstats->pkt_count);
+ pqstats->pkt_loss = wlan_le16_to_cpu(presp_qstats->pkt_loss);
+ pqstats->avg_queue_delay
+ = wlan_le32_to_cpu(presp_qstats->avg_queue_delay);
+ pqstats->avg_tx_delay = wlan_le32_to_cpu(presp_qstats->avg_tx_delay);
+ pqstats->used_time = wlan_le16_to_cpu(presp_qstats->used_time);
+ pqstats->policed_time = wlan_le16_to_cpu(presp_qstats->policed_time);
+ for (id = 0; id < MLAN_WMM_STATS_PKTS_HIST_BINS; id++) {
+ pqstats->delay_histogram[id]
+ = wlan_le16_to_cpu(presp_qstats->delay_histogram[id]);
+ }
+ }
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function prepares the command of WMM_TS_STATUS
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param cmd A pointer to HostCmd_DS_COMMAND structure
+ * @param pdata_buf A pointer to data buffer
+ * @return MLAN_STATUS_SUCCESS
+ */
+mlan_status
+wlan_cmd_wmm_ts_status(IN pmlan_private pmpriv,
+ OUT HostCmd_DS_COMMAND * cmd, IN t_void * pdata_buf)
+{
+ mlan_ds_wmm_ts_status *pts_status = (mlan_ds_wmm_ts_status *) pdata_buf;
+ HostCmd_DS_WMM_TS_STATUS *pcmd_ts_status = &cmd->params.ts_status;
+
+ ENTER();
+
+ cmd->command = wlan_cpu_to_le16(HostCmd_CMD_WMM_TS_STATUS);
+ cmd->size = wlan_cpu_to_le16(sizeof(HostCmd_DS_WMM_TS_STATUS)
+ + S_DS_GEN);
+ cmd->result = 0;
+
+ memcpy(pmpriv->adapter, (t_void *) pcmd_ts_status, (t_void *) pts_status,
+ sizeof(HostCmd_DS_WMM_TS_STATUS));
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function handles the command response of WMM_TS_STATUS
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param resp A pointer to HostCmd_DS_COMMAND
+ * @param pioctl_buf A pointer to mlan_ioctl_req structure
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+mlan_status
+wlan_ret_wmm_ts_status(IN pmlan_private pmpriv,
+ IN HostCmd_DS_COMMAND * resp,
+ OUT mlan_ioctl_req * pioctl_buf)
+{
+ mlan_ds_wmm_cfg *pwmm = MNULL;
+ HostCmd_DS_WMM_TS_STATUS *presp_ts_status = &resp->params.ts_status;
+
+ ENTER();
+
+ if (pioctl_buf) {
+ pwmm = (mlan_ds_wmm_cfg *) pioctl_buf->pbuf;
+ presp_ts_status->medium_time
+ = wlan_le16_to_cpu(presp_ts_status->medium_time);
+ memcpy(pmpriv->adapter,
+ (t_void *) & pwmm->param.ts_status,
+ (t_void *) presp_ts_status, sizeof(mlan_ds_wmm_ts_status));
+ }
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+#endif /* STA_SUPPORT */
diff --git a/drivers/net/wireless/sd8797/mlan/mlan_wmm.h b/drivers/net/wireless/sd8797/mlan/mlan_wmm.h
new file mode 100644
index 000000000000..89a2c8f37e49
--- /dev/null
+++ b/drivers/net/wireless/sd8797/mlan/mlan_wmm.h
@@ -0,0 +1,182 @@
+/** @file mlan_wmm.h
+ *
+ * @brief This file contains related macros, enum, and struct
+ * of wmm functionalities
+ *
+ * Copyright (C) 2008-2011, Marvell International Ltd.
+ *
+ * This software file (the "File") is distributed by Marvell International
+ * Ltd. under the terms of the GNU General Public License Version 2, June 1991
+ * (the "License"). You may use, redistribute and/or modify this File in
+ * accordance with the terms and conditions of the License, a copy of which
+ * is available by writing to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
+ * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
+ *
+ * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
+ * ARE EXPRESSLY DISCLAIMED. The License provides additional details about
+ * this warranty disclaimer.
+ */
+
+/****************************************************
+Change log:
+ 10/24/2008: initial version
+****************************************************/
+
+#ifndef _MLAN_WMM_H_
+#define _MLAN_WMM_H_
+
+/**
+ * @brief This function gets the TID
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param ptr A pointer to RA list table
+ *
+ * @return TID
+ */
+static INLINE int
+wlan_get_tid(pmlan_adapter pmadapter, raListTbl * ptr)
+{
+ pmlan_buffer mbuf;
+
+ ENTER();
+ mbuf =
+ (pmlan_buffer) util_peek_list(pmadapter->pmoal_handle, &ptr->buf_head,
+ MNULL, MNULL);
+ LEAVE();
+
+ return mbuf->priority;
+}
+
+/**
+ * @brief This function gets the length of a list
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param head A pointer to mlan_list_head
+ *
+ * @return Length of list
+ */
+static INLINE int
+wlan_wmm_list_len(pmlan_adapter pmadapter, pmlan_list_head head)
+{
+ pmlan_linked_list pos;
+ int count = 0;
+
+ ENTER();
+
+ pos = head->pnext;
+
+ while (pos != (pmlan_linked_list) head) {
+ ++count;
+ pos = pos->pnext;
+ }
+
+ LEAVE();
+ return count;
+}
+
+/** Add buffer to WMM Tx queue */
+void wlan_wmm_add_buf_txqueue(pmlan_adapter pmadapter, pmlan_buffer pmbuf);
+/** Add to RA list */
+void wlan_ralist_add(mlan_private * priv, t_u8 * ra);
+/** Update the RA list */
+int wlan_ralist_update(mlan_private * priv, t_u8 * old_ra, t_u8 * new_ra);
+
+/** WMM status change command handler */
+mlan_status wlan_cmd_wmm_status_change(pmlan_private priv);
+/** Check if WMM lists are empty */
+int wlan_wmm_lists_empty(pmlan_adapter pmadapter);
+/** Process WMM transmission */
+t_void wlan_wmm_process_tx(pmlan_adapter pmadapter);
+/** Test to see if the ralist ptr is valid */
+int wlan_is_ralist_valid(mlan_private * priv, raListTbl * ra_list, int tid);
+
+raListTbl *wlan_wmm_get_ralist_node(pmlan_private priv, t_u8 tid,
+ t_u8 * ra_addr);
+t_u8 wlan_get_random_ba_threshold(pmlan_adapter pmadapter);
+
+/** Compute driver packet delay */
+t_u8 wlan_wmm_compute_driver_packet_delay(pmlan_private priv,
+ const pmlan_buffer pmbuf);
+/** Initialize WMM */
+t_void wlan_wmm_init(pmlan_adapter pmadapter);
+/** Setup WMM queues */
+extern void wlan_wmm_setup_queues(pmlan_private priv);
+/* Setup default queues */
+void wlan_wmm_default_queue_priorities(pmlan_private priv);
+
+#ifdef STA_SUPPORT
+/** Process WMM association request */
+extern t_u32 wlan_wmm_process_association_req(pmlan_private priv,
+ t_u8 ** ppAssocBuf,
+ IEEEtypes_WmmParameter_t * pWmmIE,
+ IEEEtypes_HTCap_t * pHTCap);
+#endif /* STA_SUPPORT */
+
+/** setup wmm queue priorities */
+void wlan_wmm_setup_queue_priorities(pmlan_private priv,
+ IEEEtypes_WmmParameter_t * wmm_ie);
+
+/** Downgrade WMM priority queue */
+void wlan_wmm_setup_ac_downgrade(pmlan_private priv);
+/** select WMM queue */
+t_u8 wlan_wmm_select_queue(mlan_private * pmpriv, t_u8 tid);
+#ifdef UAP_SUPPORT
+t_void wlan_wmm_delete_peer_ralist(pmlan_private priv, t_u8 * mac);
+#endif
+
+#ifdef STA_SUPPORT
+/*
+ * Functions used in the cmd handling routine
+ */
+/** WMM ADDTS request command handler */
+extern mlan_status wlan_cmd_wmm_addts_req(IN pmlan_private pmpriv,
+ OUT HostCmd_DS_COMMAND * cmd,
+ IN t_void * pdata_buf);
+/** WMM DELTS request command handler */
+extern mlan_status wlan_cmd_wmm_delts_req(IN pmlan_private pmpriv,
+ OUT HostCmd_DS_COMMAND * cmd,
+ IN t_void * pdata_buf);
+/** WMM QUEUE_CONFIG command handler */
+extern mlan_status wlan_cmd_wmm_queue_config(IN pmlan_private pmpriv,
+ OUT HostCmd_DS_COMMAND * cmd,
+ IN t_void * pdata_buf);
+/** WMM QUEUE_STATS command handler */
+extern mlan_status wlan_cmd_wmm_queue_stats(IN pmlan_private pmpriv,
+ OUT HostCmd_DS_COMMAND * cmd,
+ IN t_void * pdata_buf);
+/** WMM TS_STATUS command handler */
+extern mlan_status wlan_cmd_wmm_ts_status(IN pmlan_private pmpriv,
+ OUT HostCmd_DS_COMMAND * cmd,
+ IN t_void * pdata_buf);
+
+/*
+ * Functions used in the cmdresp handling routine
+ */
+/** WMM get status command response handler */
+extern mlan_status wlan_ret_wmm_get_status(IN pmlan_private priv,
+ IN t_u8 * ptlv, IN int resp_len);
+/** WMM ADDTS request command response handler */
+extern mlan_status wlan_ret_wmm_addts_req(IN pmlan_private pmpriv,
+ const IN HostCmd_DS_COMMAND * resp,
+ OUT mlan_ioctl_req * pioctl_buf);
+/** WMM DELTS request command response handler */
+extern mlan_status wlan_ret_wmm_delts_req(IN pmlan_private pmpriv,
+ const IN HostCmd_DS_COMMAND * resp,
+ OUT mlan_ioctl_req * pioctl_buf);
+/** WMM QUEUE_CONFIG command response handler */
+extern mlan_status wlan_ret_wmm_queue_config(IN pmlan_private pmpriv,
+ const IN HostCmd_DS_COMMAND * resp,
+ OUT mlan_ioctl_req * pioctl_buf);
+/** WMM QUEUE_STATS command response handler */
+extern mlan_status wlan_ret_wmm_queue_stats(IN pmlan_private pmpriv,
+ const IN HostCmd_DS_COMMAND * resp,
+ OUT mlan_ioctl_req * pioctl_buf);
+/** WMM TS_STATUS command response handler */
+extern mlan_status wlan_ret_wmm_ts_status(IN pmlan_private pmpriv,
+ IN HostCmd_DS_COMMAND * resp,
+ OUT mlan_ioctl_req * pioctl_buf);
+#endif /* STA_SUPPORT */
+
+#endif /* !_MLAN_WMM_H_ */
diff --git a/drivers/net/wireless/sd8797/mlinux/moal_cfg80211.c b/drivers/net/wireless/sd8797/mlinux/moal_cfg80211.c
new file mode 100644
index 000000000000..942fae4e991d
--- /dev/null
+++ b/drivers/net/wireless/sd8797/mlinux/moal_cfg80211.c
@@ -0,0 +1,1263 @@
+/** @file moal_cfg80211.c
+ *
+ * @brief This file contains the functions for CFG80211.
+ *
+ * Copyright (C) 2011-2012, Marvell International Ltd.
+ *
+ * This software file (the "File") is distributed by Marvell International
+ * Ltd. under the terms of the GNU General Public License Version 2, June 1991
+ * (the "License"). You may use, redistribute and/or modify this File in
+ * accordance with the terms and conditions of the License, a copy of which
+ * is available by writing to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
+ * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
+ *
+ * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
+ * ARE EXPRESSLY DISCLAIMED. The License provides additional details about
+ * this warranty disclaimer.
+ *
+ */
+
+#include "moal_cfg80211.h"
+#ifdef UAP_CFG80211
+#ifdef UAP_SUPPORT
+#include "moal_uap.h"
+#endif
+#endif
+
+/********************************************************
+ Local Variables
+********************************************************/
+/** Supported rates to be advertised to the cfg80211 */
+static struct ieee80211_rate cfg80211_rates[] = {
+ {.bitrate = 10,.hw_value = 2,},
+ {.bitrate = 20,.hw_value = 4,},
+ {.bitrate = 55,.hw_value = 11},
+ {.bitrate = 110,.hw_value = 22,},
+ {.bitrate = 220,.hw_value = 44,},
+ {.bitrate = 60,.hw_value = 12,},
+ {.bitrate = 90,.hw_value = 18,},
+ {.bitrate = 120,.hw_value = 24,},
+ {.bitrate = 180,.hw_value = 36,},
+ {.bitrate = 240,.hw_value = 48,},
+ {.bitrate = 360,.hw_value = 72,},
+ {.bitrate = 480,.hw_value = 96,},
+ {.bitrate = 540,.hw_value = 108,},
+ {.bitrate = 720,.hw_value = 144,},
+};
+
+/** Channel definitions for 2 GHz to be advertised to cfg80211 */
+static struct ieee80211_channel cfg80211_channels_2ghz[] = {
+ {.center_freq = 2412,.hw_value = 1,.max_power = 20},
+ {.center_freq = 2417,.hw_value = 2,.max_power = 20},
+ {.center_freq = 2422,.hw_value = 3,.max_power = 20},
+ {.center_freq = 2427,.hw_value = 4,.max_power = 20},
+ {.center_freq = 2432,.hw_value = 5,.max_power = 20},
+ {.center_freq = 2437,.hw_value = 6,.max_power = 20},
+ {.center_freq = 2442,.hw_value = 7,.max_power = 20},
+ {.center_freq = 2447,.hw_value = 8,.max_power = 20},
+ {.center_freq = 2452,.hw_value = 9,.max_power = 20},
+ {.center_freq = 2457,.hw_value = 10,.max_power = 20},
+ {.center_freq = 2462,.hw_value = 11,.max_power = 20},
+ {.center_freq = 2467,.hw_value = 12,.max_power = 20},
+ {.center_freq = 2472,.hw_value = 13,.max_power = 20},
+ {.center_freq = 2484,.hw_value = 14,.max_power = 20},
+};
+
+/** Channel definitions for 5 GHz to be advertised to cfg80211 */
+static struct ieee80211_channel cfg80211_channels_5ghz[] = {
+ {.center_freq = 5040,.hw_value = 8,.max_power = 20},
+ {.center_freq = 5060,.hw_value = 12,.max_power = 20},
+ {.center_freq = 5080,.hw_value = 16,.max_power = 20},
+ {.center_freq = 5170,.hw_value = 34,.max_power = 20},
+ {.center_freq = 5190,.hw_value = 38,.max_power = 20},
+ {.center_freq = 5210,.hw_value = 42,.max_power = 20},
+ {.center_freq = 5230,.hw_value = 46,.max_power = 20},
+ {.center_freq = 5180,.hw_value = 36,.max_power = 20},
+ {.center_freq = 5200,.hw_value = 40,.max_power = 20},
+ {.center_freq = 5220,.hw_value = 44,.max_power = 20},
+ {.center_freq = 5240,.hw_value = 48,.max_power = 20},
+ {.center_freq = 5260,.hw_value = 52,.max_power = 20},
+ {.center_freq = 5280,.hw_value = 56,.max_power = 20},
+ {.center_freq = 5300,.hw_value = 60,.max_power = 20},
+ {.center_freq = 5320,.hw_value = 64,.max_power = 20},
+ {.center_freq = 5500,.hw_value = 100,.max_power = 20},
+ {.center_freq = 5520,.hw_value = 104,.max_power = 20},
+ {.center_freq = 5540,.hw_value = 108,.max_power = 20},
+ {.center_freq = 5560,.hw_value = 112,.max_power = 20},
+ {.center_freq = 5580,.hw_value = 116,.max_power = 20},
+ {.center_freq = 5600,.hw_value = 120,.max_power = 20},
+ {.center_freq = 5620,.hw_value = 124,.max_power = 20},
+ {.center_freq = 5640,.hw_value = 128,.max_power = 20},
+ {.center_freq = 5660,.hw_value = 132,.max_power = 20},
+ {.center_freq = 5680,.hw_value = 136,.max_power = 20},
+ {.center_freq = 5700,.hw_value = 140,.max_power = 20},
+ {.center_freq = 5745,.hw_value = 149,.max_power = 20},
+ {.center_freq = 5765,.hw_value = 153,.max_power = 20},
+ {.center_freq = 5785,.hw_value = 157,.max_power = 20},
+ {.center_freq = 5805,.hw_value = 161,.max_power = 20},
+ {.center_freq = 5825,.hw_value = 165,.max_power = 20},
+};
+
+/********************************************************
+ Global Variables
+********************************************************/
+extern int cfg80211_wext;
+
+struct ieee80211_supported_band cfg80211_band_2ghz = {
+ .channels = cfg80211_channels_2ghz,
+ .n_channels = ARRAY_SIZE(cfg80211_channels_2ghz),
+ .bitrates = cfg80211_rates,
+ .n_bitrates = ARRAY_SIZE(cfg80211_rates),
+};
+
+struct ieee80211_supported_band cfg80211_band_5ghz = {
+ .channels = cfg80211_channels_5ghz,
+ .n_channels = ARRAY_SIZE(cfg80211_channels_5ghz),
+ .bitrates = cfg80211_rates + 5,
+ .n_bitrates = ARRAY_SIZE(cfg80211_rates) - 5,
+};
+
+#ifndef WLAN_CIPHER_SUITE_SMS4
+#define WLAN_CIPHER_SUITE_SMS4 0x00000020
+#endif
+
+/* Supported crypto cipher suits to be advertised to cfg80211 */
+const u32 cfg80211_cipher_suites[] = {
+ WLAN_CIPHER_SUITE_WEP40,
+ WLAN_CIPHER_SUITE_WEP104,
+ WLAN_CIPHER_SUITE_TKIP,
+ WLAN_CIPHER_SUITE_CCMP,
+ WLAN_CIPHER_SUITE_SMS4,
+};
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,29)
+#ifdef UAP_SUPPORT
+/** Network device handlers for uAP */
+extern const struct net_device_ops woal_uap_netdev_ops;
+#endif
+#ifdef STA_SUPPORT
+/** Network device handlers for STA */
+extern const struct net_device_ops woal_netdev_ops;
+#endif
+#endif
+
+/********************************************************
+ Local Functions
+********************************************************/
+
+/********************************************************
+ Global Functions
+********************************************************/
+/**
+ * @brief Get the private structure from wiphy
+ *
+ * @param wiphy A pointer to wiphy structure
+ *
+ * @return Pointer to moal_private
+ */
+void *
+woal_get_wiphy_priv(struct wiphy *wiphy)
+{
+ return (void *) (*(unsigned long *) wiphy_priv(wiphy));
+}
+
+/**
+ * @brief Set/Enable encryption key
+ *
+ * @param priv A pointer to moal_private structure
+ * @param is_enable_wep Enable WEP default key
+ * @param cipher Cipher suite selector
+ * @param key A pointer to key
+ * @param key_len Key length
+ * @param seq A pointer to sequence
+ * @param seq_len Sequence length
+ * @param key_index Key index
+ * @param addr Mac for which key is to be set
+ * @param disable Key disabled or not
+ *
+ * @return MLAN_STATUS_SUCCESS -- success, otherwise fail
+ */
+mlan_status
+woal_cfg80211_set_key(moal_private * priv, t_u8 is_enable_wep,
+ t_u32 cipher, const t_u8 * key, int key_len,
+ const t_u8 * seq, int seq_len, t_u8 key_index,
+ const t_u8 * addr, int disable)
+{
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_sec_cfg *sec = NULL;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ t_u8 bcast_addr[] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
+
+ ENTER();
+
+ /* Allocate an IOCTL request buffer */
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_sec_cfg));
+ if (req == NULL) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ /* Fill request buffer */
+ sec = (mlan_ds_sec_cfg *) req->pbuf;
+ sec->sub_command = MLAN_OID_SEC_CFG_ENCRYPT_KEY;
+ req->req_id = MLAN_IOCTL_SEC_CFG;
+ req->action = MLAN_ACT_SET;
+
+ if (is_enable_wep) {
+ sec->param.encrypt_key.key_index = key_index;
+ sec->param.encrypt_key.is_current_wep_key = MTRUE;
+ } else if (!disable) {
+#ifdef UAP_CFG80211
+#ifdef UAP_SUPPORT
+ if (GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_UAP) {
+ if (key && key_len) {
+ priv->key_len = key_len;
+ memcpy(priv->key_material, key, key_len);
+ priv->cipher = cipher;
+ priv->key_index = key_index;
+ }
+ if ((cipher == WLAN_CIPHER_SUITE_WEP40) ||
+ (cipher == WLAN_CIPHER_SUITE_WEP104)) {
+ PRINTM(MIOCTL, "Set WEP key\n");
+ ret = MLAN_STATUS_SUCCESS;
+ goto done;
+ }
+ }
+#endif
+#endif
+ if (cipher != WLAN_CIPHER_SUITE_WEP40 &&
+ cipher != WLAN_CIPHER_SUITE_WEP104 &&
+ cipher != WLAN_CIPHER_SUITE_TKIP &&
+ cipher != WLAN_CIPHER_SUITE_SMS4 &&
+ cipher != WLAN_CIPHER_SUITE_CCMP) {
+ PRINTM(MERROR, "Invalid cipher suite specified\n");
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ sec->param.encrypt_key.key_index = key_index;
+ if (key && key_len) {
+ memcpy(sec->param.encrypt_key.key_material, key, key_len);
+ sec->param.encrypt_key.key_len = key_len;
+ }
+ /* Set WAPI key */
+ if (cipher == WLAN_CIPHER_SUITE_SMS4) {
+ sec->param.encrypt_key.is_wapi_key = MTRUE;
+ if (seq_len) {
+ memcpy(sec->param.encrypt_key.pn, seq, PN_SIZE);
+ DBG_HEXDUMP(MCMD_D, "WAPI PN", sec->param.encrypt_key.pn,
+ seq_len);
+ }
+ }
+ if (cipher != WLAN_CIPHER_SUITE_WEP40 &&
+ cipher != WLAN_CIPHER_SUITE_WEP104) {
+ if (addr) {
+ memcpy(sec->param.encrypt_key.mac_addr, addr, ETH_ALEN);
+ if (0 ==
+ memcmp(sec->param.encrypt_key.mac_addr, bcast_addr,
+ ETH_ALEN))
+ sec->param.encrypt_key.key_flags = KEY_FLAG_GROUP_KEY;
+ else
+ sec->param.encrypt_key.key_flags = KEY_FLAG_SET_TX_KEY;
+ } else {
+ memcpy(sec->param.encrypt_key.mac_addr, bcast_addr, ETH_ALEN);
+ sec->param.encrypt_key.key_flags = KEY_FLAG_GROUP_KEY;
+ }
+ if (seq && seq_len) {
+ memcpy(sec->param.encrypt_key.pn, seq, seq_len);
+ sec->param.encrypt_key.key_flags |= KEY_FLAG_RX_SEQ_VALID;
+ }
+ }
+ } else {
+ sec->param.encrypt_key.key_remove = MTRUE;
+ sec->param.encrypt_key.key_index = key_index;
+ sec->param.encrypt_key.key_flags = KEY_FLAG_REMOVE_KEY;
+ if (addr)
+ memcpy(sec->param.encrypt_key.mac_addr, addr, ETH_ALEN);
+ }
+
+ /* Send IOCTL request to MLAN */
+ if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ done:
+ if (req && (ret != MLAN_STATUS_PENDING))
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set/Enable the WEP key to driver
+ *
+ * @param priv A pointer to moal_private structure
+ * @param key A pointer to key data
+ * @param key_len Length of the key data
+ * @param index Key index
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status
+woal_cfg80211_set_wep_keys(moal_private * priv, const t_u8 * key, int key_len,
+ t_u8 index)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ t_u32 cipher = 0;
+
+ ENTER();
+
+ if (key_len) {
+ if (key_len == 5)
+ cipher = WLAN_CIPHER_SUITE_WEP40;
+ else
+ cipher = WLAN_CIPHER_SUITE_WEP104;
+ ret =
+ woal_cfg80211_set_key(priv, 0, cipher, key, key_len, NULL, 0, index,
+ NULL, 0);
+ } else {
+ /* No key provided so it is enable key. We want to just set the
+ transmit key index */
+ woal_cfg80211_set_key(priv, 1, cipher, key, key_len, NULL, 0, index,
+ NULL, 0);
+ }
+
+ LEAVE();
+ return ret;
+}
+
+#if defined(WIFI_DIRECT_SUPPORT)
+#if LINUX_VERSION_CODE >= WIFI_DIRECT_KERNEL_VERSION
+/**
+ * @brief set bss role
+ *
+ * @param priv A pointer to moal private structure
+ * @param action Action: set or get
+ * @param role A pointer to bss role
+ *
+ * @return 0 -- success, otherwise fail
+ */
+static int
+woal_cfg80211_bss_role_cfg(moal_private * priv, t_u16 action, t_u8 * bss_role)
+{
+ int ret = 0;
+ mlan_ds_bss *bss = NULL;
+ mlan_ioctl_req *req = NULL;
+ struct net_device *dev = priv->netdev;
+
+ ENTER();
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_bss));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+ bss = (mlan_ds_bss *) req->pbuf;
+ bss->sub_command = MLAN_OID_BSS_ROLE;
+ req->req_id = MLAN_IOCTL_BSS;
+ req->action = action;
+ bss->param.bss_role = *bss_role;
+
+ if (req->action == MLAN_ACT_SET) {
+ /* Reset interface */
+ woal_reset_intf(priv, MOAL_IOCTL_WAIT, MFALSE);
+ }
+ if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ if (req->action == MLAN_ACT_GET) {
+ *bss_role = bss->param.bss_role;
+ } else {
+ /* Update moal_private */
+ priv->bss_role = *bss_role;
+ if (priv->bss_type == MLAN_BSS_TYPE_UAP)
+ priv->bss_type = MLAN_BSS_TYPE_STA;
+ else if (priv->bss_type == MLAN_BSS_TYPE_STA)
+ priv->bss_type = MLAN_BSS_TYPE_UAP;
+
+ /* Initialize private structures */
+ woal_init_priv(priv, MOAL_IOCTL_WAIT);
+
+ if (*bss_role == MLAN_BSS_ROLE_UAP) {
+ /* Switch: STA -> uAP */
+ /* Setup the OS Interface to our functions */
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,29)
+ dev->do_ioctl = woal_uap_do_ioctl;
+ dev->set_multicast_list = woal_uap_set_multicast_list;
+#else
+ dev->netdev_ops = &woal_uap_netdev_ops;
+#endif
+#ifdef WIRELESS_EXT
+#ifdef UAP_WEXT
+ if (IS_UAP_WEXT(cfg80211_wext)) {
+#if WIRELESS_EXT < 21
+ dev->get_wireless_stats = woal_get_uap_wireless_stats;
+#endif
+ dev->wireless_handlers =
+ (struct iw_handler_def *) &woal_uap_handler_def;
+ init_waitqueue_head(&priv->w_stats_wait_q);
+ }
+#endif /* UAP_WEXT */
+#endif /* WIRELESS_EXT */
+ } else if (*bss_role == MLAN_BSS_ROLE_STA) {
+ /* Switch: uAP -> STA */
+ /* Setup the OS Interface to our functions */
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,29)
+ dev->do_ioctl = woal_do_ioctl;
+ dev->set_multicast_list = woal_set_multicast_list;
+#else
+ dev->netdev_ops = &woal_netdev_ops;
+#endif
+#ifdef WIRELESS_EXT
+#ifdef STA_WEXT
+ if (IS_STA_WEXT(cfg80211_wext)) {
+#if WIRELESS_EXT < 21
+ dev->get_wireless_stats = woal_get_wireless_stats;
+#endif
+ dev->wireless_handlers =
+ (struct iw_handler_def *) &woal_handler_def;
+ init_waitqueue_head(&priv->w_stats_wait_q);
+ }
+#endif /* STA_WEXT */
+#endif
+ }
+ /* Enable interfaces */
+ netif_device_attach(dev);
+ woal_start_queue(dev);
+ }
+
+ done:
+ if (req)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief initialize p2p client for wpa_supplicant
+ *
+ * @param priv A pointer to moal private structure
+ *
+ * @return 0 -- success, otherwise fail
+ */
+int
+woal_cfg80211_init_p2p_client(moal_private * priv)
+{
+ int ret = MLAN_STATUS_SUCCESS;
+ t_u16 wifi_direct_mode = WIFI_DIRECT_MODE_DISABLE;
+ t_u8 bss_role;
+
+ ENTER();
+
+ /* bss type check */
+ if (priv->bss_type != MLAN_BSS_TYPE_WIFIDIRECT) {
+ PRINTM(MERROR, "Unexpected bss type when init p2p client\n");
+ ret = -EFAULT;
+ goto done;
+ }
+
+ /* get the bss role */
+ if (MLAN_STATUS_SUCCESS !=
+ woal_cfg80211_bss_role_cfg(priv, MLAN_ACT_GET, &bss_role)) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ if (bss_role != MLAN_BSS_ROLE_STA) {
+ bss_role = MLAN_BSS_ROLE_STA;
+ if (MLAN_STATUS_SUCCESS !=
+ woal_cfg80211_bss_role_cfg(priv, MLAN_ACT_SET, &bss_role)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ }
+
+ wifi_direct_mode = WIFI_DIRECT_MODE_DISABLE;
+ if (MLAN_STATUS_SUCCESS !=
+ woal_cfg80211_wifi_direct_mode_cfg(priv,
+ MLAN_ACT_SET, &wifi_direct_mode)) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ /* first, init wifi direct to listen mode */
+ wifi_direct_mode = WIFI_DIRECT_MODE_LISTEN;
+ if (MLAN_STATUS_SUCCESS !=
+ woal_cfg80211_wifi_direct_mode_cfg(priv, MLAN_ACT_SET,
+ &wifi_direct_mode)) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ /* second, init wifi direct client */
+ wifi_direct_mode = WIFI_DIRECT_MODE_CLIENT;
+ if (MLAN_STATUS_SUCCESS !=
+ woal_cfg80211_wifi_direct_mode_cfg(priv,
+ MLAN_ACT_SET, &wifi_direct_mode)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief initialize p2p GO for wpa_supplicant
+ *
+ * @param priv A pointer to moal private structure
+ *
+ * @return 0 -- success, otherwise fail
+ */
+int
+woal_cfg80211_init_p2p_go(moal_private * priv)
+{
+ int ret = MLAN_STATUS_SUCCESS;
+ t_u16 wifi_direct_mode;
+ t_u8 bss_role;
+
+ ENTER();
+
+ /* bss type check */
+ if (priv->bss_type != MLAN_BSS_TYPE_WIFIDIRECT) {
+ PRINTM(MERROR, "Unexpected bss type when init p2p GO\n");
+ ret = -EFAULT;
+ goto done;
+ }
+
+ wifi_direct_mode = WIFI_DIRECT_MODE_DISABLE;
+ if (MLAN_STATUS_SUCCESS !=
+ woal_cfg80211_wifi_direct_mode_cfg(priv,
+ MLAN_ACT_SET, &wifi_direct_mode)) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ /* first, init wifi direct to listen mode */
+ wifi_direct_mode = WIFI_DIRECT_MODE_LISTEN;
+ if (MLAN_STATUS_SUCCESS !=
+ woal_cfg80211_wifi_direct_mode_cfg(priv, MLAN_ACT_SET,
+ &wifi_direct_mode)) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ /* second, init wifi direct to GO mode */
+ wifi_direct_mode = WIFI_DIRECT_MODE_GO;
+ if (MLAN_STATUS_SUCCESS !=
+ woal_cfg80211_wifi_direct_mode_cfg(priv,
+ MLAN_ACT_SET, &wifi_direct_mode)) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ /* get the bss role, and set it to uAP */
+ if (MLAN_STATUS_SUCCESS !=
+ woal_cfg80211_bss_role_cfg(priv, MLAN_ACT_GET, &bss_role)) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ if (bss_role != MLAN_BSS_ROLE_UAP) {
+ bss_role = MLAN_BSS_ROLE_UAP;
+ if (MLAN_STATUS_SUCCESS !=
+ woal_cfg80211_bss_role_cfg(priv, MLAN_ACT_SET, &bss_role)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ }
+
+ done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief reset bss role and wifi direct mode for wpa_supplicant
+ *
+ * @param priv A pointer to moal private structure
+ *
+ * @return 0 -- success, otherwise fail
+ */
+int
+woal_cfg80211_deinit_p2p(moal_private * priv)
+{
+ int ret = MLAN_STATUS_SUCCESS;
+ t_u16 wifi_direct_mode;
+ t_u8 bss_role;
+ t_u8 channel_status;
+
+ ENTER();
+
+ /* bss type check */
+ if (priv->bss_type != MLAN_BSS_TYPE_WIFIDIRECT) {
+ PRINTM(MERROR, "Unexpected bss type when deinit p2p\n");
+ ret = -EFAULT;
+ goto done;
+ }
+
+ /* cancel previous remain on channel */
+ if (priv->phandle->remain_on_channel) {
+ if (woal_cfg80211_remain_on_channel_cfg
+ (priv->wdev->wiphy, MOAL_IOCTL_WAIT, MTRUE, &channel_status, NULL,
+ 0, 0)) {
+ PRINTM(MERROR, "Fail to cancel remain on channel\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ if (priv->phandle->cookie) {
+ cfg80211_remain_on_channel_expired(priv->netdev,
+ priv->phandle->cookie,
+ &priv->phandle->chan,
+ priv->phandle->channel_type,
+ GFP_ATOMIC);
+ priv->phandle->cookie = 0;
+ }
+ priv->phandle->remain_on_channel = MFALSE;
+ }
+
+ /* get the bss role */
+ if (MLAN_STATUS_SUCCESS != woal_cfg80211_bss_role_cfg(priv,
+ MLAN_ACT_GET,
+ &bss_role)) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ /* reset bss role */
+ if (bss_role != MLAN_BSS_ROLE_STA) {
+ bss_role = MLAN_BSS_ROLE_STA;
+ if (MLAN_STATUS_SUCCESS !=
+ woal_cfg80211_bss_role_cfg(priv, MLAN_ACT_SET, &bss_role)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ }
+
+ wifi_direct_mode = WIFI_DIRECT_MODE_DISABLE;
+ if (MLAN_STATUS_SUCCESS !=
+ woal_cfg80211_wifi_direct_mode_cfg(priv,
+ MLAN_ACT_SET, &wifi_direct_mode)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ done:
+ LEAVE();
+ return ret;
+}
+#endif /* KERNEL_VERSION */
+#endif /* WIFI_DIRECT_SUPPORT && V14_FEATURE */
+
+/**
+ * @brief Request the driver to change the interface type
+ *
+ * @param wiphy A pointer to wiphy structure
+ * @param dev A pointer to net_device structure
+ * @param type Virtual interface types
+ * @param flags Flags
+ * @param params A pointer to vif_params structure
+ *
+ * @return 0 -- success, otherwise fail
+ */
+int
+woal_cfg80211_change_virtual_intf(struct wiphy *wiphy,
+ struct net_device *dev,
+ enum nl80211_iftype type, u32 * flags,
+ struct vif_params *params)
+{
+ int ret = 0;
+ moal_private *priv = (moal_private *) woal_get_wiphy_priv(wiphy);
+ mlan_ds_bss *bss = NULL;
+ mlan_ioctl_req *req = NULL;
+
+ ENTER();
+
+ if (priv->wdev->iftype == type) {
+ PRINTM(MINFO, "Already set to required type\n");
+ goto done;
+ }
+ PRINTM(MIOCTL, "change virturl intf=%d\n", type);
+#if defined(WIFI_DIRECT_SUPPORT)
+#if LINUX_VERSION_CODE >= WIFI_DIRECT_KERNEL_VERSION
+ /** cancel previous remain on channel to avoid firmware hang */
+ if (priv->phandle->remain_on_channel) {
+ t_u8 channel_status;
+ if (woal_cfg80211_remain_on_channel_cfg
+ (wiphy, MOAL_IOCTL_WAIT, MTRUE, &channel_status, NULL, 0, 0)) {
+ PRINTM(MERROR, "Fail to cancel remain on channel\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ if (priv->phandle->cookie) {
+ cfg80211_remain_on_channel_expired(priv->netdev,
+ priv->phandle->cookie,
+ &priv->phandle->chan,
+ priv->phandle->channel_type,
+ GFP_ATOMIC);
+ priv->phandle->cookie = 0;
+ }
+ priv->phandle->remain_on_channel = MFALSE;
+ }
+#endif
+#endif
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_bss));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ bss = (mlan_ds_bss *) req->pbuf;
+ bss->sub_command = MLAN_OID_BSS_MODE;
+ req->req_id = MLAN_IOCTL_BSS;
+ req->action = MLAN_ACT_SET;
+
+ switch (type) {
+ case NL80211_IFTYPE_ADHOC:
+ bss->param.bss_mode = MLAN_BSS_MODE_IBSS;
+ priv->wdev->iftype = NL80211_IFTYPE_ADHOC;
+ PRINTM(MINFO, "Setting interface type to adhoc\n");
+ break;
+ case NL80211_IFTYPE_STATION:
+#if defined(WIFI_DIRECT_SUPPORT)
+#if LINUX_VERSION_CODE >= WIFI_DIRECT_KERNEL_VERSION
+ if (priv->bss_type == MLAN_BSS_TYPE_WIFIDIRECT
+ && (priv->wdev->iftype == NL80211_IFTYPE_AP
+ || priv->wdev->iftype == NL80211_IFTYPE_P2P_GO
+ || priv->wdev->iftype == NL80211_IFTYPE_P2P_CLIENT)) {
+ /* if we support wifi direct && priv->bss_type == wifi_direct, and
+ currently the interface type is AP or GO or client, that means
+ wpa_supplicant deinit() wifi direct interface, so we should
+ deinit bss_role and wifi direct mode, for other bss_type, we
+ should not update bss_role and wifi direct mode */
+
+ if (MLAN_STATUS_SUCCESS != woal_cfg80211_deinit_p2p(priv)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ }
+#endif /* KERNEL_VERSION */
+#endif /* WIFI_DIRECT_SUPPORT && V14_FEATURE */
+
+ bss->param.bss_mode = MLAN_BSS_MODE_INFRA;
+ priv->wdev->iftype = NL80211_IFTYPE_STATION;
+ PRINTM(MINFO, "Setting interface type to managed\n");
+ break;
+#if defined(WIFI_DIRECT_SUPPORT)
+#if LINUX_VERSION_CODE >= WIFI_DIRECT_KERNEL_VERSION
+ case NL80211_IFTYPE_P2P_CLIENT:
+
+ if (MLAN_STATUS_SUCCESS != woal_cfg80211_init_p2p_client(priv)) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ bss->param.bss_mode = MLAN_BSS_MODE_INFRA;
+ priv->wdev->iftype = NL80211_IFTYPE_P2P_CLIENT;
+ PRINTM(MINFO, "Setting interface type to P2P client\n");
+
+ break;
+#endif /* KERNEL_VERSION */
+#endif /* WIFI_DIRECT_SUPPORT && V14_FEATURE */
+ case NL80211_IFTYPE_AP:
+#if defined(WIFI_DIRECT_SUPPORT)
+#if LINUX_VERSION_CODE >= WIFI_DIRECT_KERNEL_VERSION
+ case NL80211_IFTYPE_P2P_GO:
+ if (priv->bss_type == MLAN_BSS_TYPE_WIFIDIRECT) {
+ if (MLAN_STATUS_SUCCESS != woal_cfg80211_init_p2p_go(priv)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ }
+ if (type == NL80211_IFTYPE_P2P_GO)
+ priv->wdev->iftype = NL80211_IFTYPE_P2P_GO;
+#endif
+#endif
+ if (type == NL80211_IFTYPE_AP)
+ priv->wdev->iftype = NL80211_IFTYPE_AP;
+ PRINTM(MINFO, "Setting interface type to P2P GO\n");
+
+ /* there is no need for P2P GO to set bss_mode */
+ goto done;
+
+ break;
+
+ case NL80211_IFTYPE_UNSPECIFIED:
+ bss->param.bss_mode = MLAN_BSS_MODE_AUTO;
+ priv->wdev->iftype = NL80211_IFTYPE_STATION;
+ PRINTM(MINFO, "Setting interface type to auto\n");
+ break;
+ default:
+ ret = -EINVAL;
+ break;
+ }
+ if (ret)
+ goto done;
+
+ if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ done:
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Request the driver to change the value of fragment
+ * threshold or rts threshold or retry limit
+ *
+ * @param wiphy A pointer to wiphy structure
+ * @param changed Change flags
+ *
+ * @return 0 -- success, otherwise fail
+ */
+int
+woal_cfg80211_set_wiphy_params(struct wiphy *wiphy, u32 changed)
+{
+ moal_private *priv = (moal_private *) woal_get_wiphy_priv(wiphy);
+#ifdef UAP_CFG80211
+#ifdef UAP_SUPPORT
+ mlan_uap_bss_param sys_cfg;
+#endif
+#endif
+ int frag_thr = wiphy->frag_threshold;
+ int rts_thr = wiphy->frag_threshold;
+ int retry = wiphy->retry_long;
+
+ ENTER();
+
+ if (rts_thr == MLAN_FRAG_RTS_DISABLED)
+ rts_thr = MLAN_RTS_MAX_VALUE;
+ if (frag_thr == MLAN_FRAG_RTS_DISABLED)
+ frag_thr = MLAN_FRAG_MAX_VALUE;
+
+#ifdef UAP_CFG80211
+#ifdef UAP_SUPPORT
+ if (GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_UAP) {
+ /* Initialize the invalid values so that the correct values below are
+ downloaded to firmware */
+ woal_set_sys_config_invalid_data(&sys_cfg);
+ sys_cfg.frag_threshold = frag_thr;
+ sys_cfg.rts_threshold = rts_thr;
+ sys_cfg.retry_limit = retry;
+
+ if ((changed & WIPHY_PARAM_RTS_THRESHOLD) ||
+ (changed & WIPHY_PARAM_FRAG_THRESHOLD) ||
+ (changed & (WIPHY_PARAM_RETRY_LONG | WIPHY_PARAM_RETRY_SHORT))) {
+ if (woal_set_get_sys_config(priv,
+ MLAN_ACT_SET, MOAL_IOCTL_WAIT,
+ &sys_cfg))
+ goto fail;
+ }
+ }
+#endif
+#endif
+
+#ifdef STA_CFG80211
+#ifdef STA_SUPPORT
+ if (GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_STA) {
+ if (changed & WIPHY_PARAM_RTS_THRESHOLD) {
+ if (woal_set_get_rts(priv, MLAN_ACT_SET, MOAL_IOCTL_WAIT, &rts_thr))
+ goto fail;
+ }
+ if (changed & WIPHY_PARAM_FRAG_THRESHOLD) {
+ if (woal_set_get_frag
+ (priv, MLAN_ACT_SET, MOAL_IOCTL_WAIT, &frag_thr))
+ goto fail;
+ }
+ if (changed & (WIPHY_PARAM_RETRY_LONG | WIPHY_PARAM_RETRY_SHORT))
+ if (woal_set_get_retry(priv, MLAN_ACT_SET, MOAL_IOCTL_WAIT, &retry))
+ goto fail;
+ }
+#endif
+#endif
+
+ LEAVE();
+ return 0;
+
+ fail:
+ PRINTM(MERROR, "Failed to change wiphy params %x\n", changed);
+ LEAVE();
+ return -EFAULT;
+}
+
+/**
+ * @brief Request the driver to add a key
+ *
+ * @param wiphy A pointer to wiphy structure
+ * @param netdev A pointer to net_device structure
+ * @param key_index Key index
+ * @param pairwise Flag to indicate pairwise or group (for kernel > 2.6.36)
+ * @param mac_addr MAC address (NULL for group key)
+ * @param params A pointer to key_params structure
+ *
+ * @return 0 -- success, otherwise fail
+ */
+int
+woal_cfg80211_add_key(struct wiphy *wiphy, struct net_device *netdev,
+ t_u8 key_index,
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,36) || defined(COMPAT_WIRELESS)
+ bool pairwise,
+#endif
+ const t_u8 * mac_addr, struct key_params *params)
+{
+ moal_private *priv = (moal_private *) woal_get_wiphy_priv(wiphy);
+
+ ENTER();
+
+ if (woal_cfg80211_set_key(priv, 0, params->cipher, params->key,
+ params->key_len, params->seq, params->seq_len,
+ key_index, mac_addr, 0)) {
+ PRINTM(MERROR, "Error adding the crypto keys\n");
+ LEAVE();
+ return -EFAULT;
+ }
+
+ PRINTM(MINFO, "Crypto keys added\n");
+
+ LEAVE();
+ return 0;
+}
+
+/**
+ * @brief Request the driver to delete a key
+ *
+ * @param wiphy A pointer to wiphy structure
+ * @param netdev A pointer to net_device structure
+ * @param key_index Key index
+ * @param pairwise Flag to indicate pairwise or group (for kernel > 2.6.36)
+ * @param mac_addr MAC address (NULL for group key)
+ *
+ * @return 0 -- success, otherwise fail
+ */
+int
+woal_cfg80211_del_key(struct wiphy *wiphy, struct net_device *netdev,
+ t_u8 key_index,
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,36) || defined(COMPAT_WIRELESS)
+ bool pairwise,
+#endif
+ const t_u8 * mac_addr)
+{
+ moal_private *priv = (moal_private *) woal_get_wiphy_priv(wiphy);
+
+ ENTER();
+
+ if (woal_cfg80211_set_key(priv, 0, 0, NULL, 0, NULL, 0, key_index,
+ mac_addr, 1)) {
+ PRINTM(MERROR, "Error deleting the crypto keys\n");
+ LEAVE();
+ return -EFAULT;
+ }
+
+ PRINTM(MINFO, "Crypto keys deleted\n");
+ LEAVE();
+ return 0;
+}
+
+/**
+ * @brief Request to enable WEP key to driver
+ *
+ * @param wiphy A pointer to wiphy structure
+ * @param netdev A pointer to net_device structure
+ * @param key_index Key index
+ * @param ucast Unicast flag (for kernel > 2.6.37)
+ * @param mcast Multicast flag (for kernel > 2.6.37)
+ *
+ * @return 0 -- success, otherwise fail
+ */
+int
+woal_cfg80211_set_default_key(struct wiphy *wiphy,
+ struct net_device *netdev, t_u8 key_index
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,37) || defined(COMPAT_WIRELESS)
+ , bool ucast, bool mcast
+#endif
+ )
+{
+ int ret = 0;
+ moal_private *priv = (moal_private *) woal_get_wiphy_priv(wiphy);
+ mlan_bss_info bss_info;
+
+ ENTER();
+
+ woal_get_bss_info(priv, MOAL_IOCTL_WAIT, &bss_info);
+ if (bss_info.wep_status) {
+ LEAVE();
+ return ret;
+ }
+
+ if (MLAN_STATUS_SUCCESS !=
+ woal_cfg80211_set_wep_keys(priv, NULL, 0, key_index)) {
+ ret = -EFAULT;
+ }
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Request the driver to change the channel
+ *
+ * @param wiphy A pointer to wiphy structure
+ * @param chan A pointer to ieee80211_channel structure
+ * @param channel_type Channel type of nl80211_channel_type
+ *
+ * @return 0 -- success, otherwise fail
+ */
+int
+woal_cfg80211_set_channel(struct wiphy *wiphy,
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,34) || defined(COMPAT_WIRELESS)
+ struct net_device *dev,
+#endif
+ struct ieee80211_channel *chan,
+ enum nl80211_channel_type channel_type)
+{
+ int ret = 0;
+ moal_private *priv = (moal_private *) woal_get_wiphy_priv(wiphy);
+
+ ENTER();
+#ifdef STA_CFG80211
+#ifdef STA_SUPPORT
+ if (GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_STA) {
+ if (priv->media_connected == MTRUE) {
+ PRINTM(MERROR, "This configuration is valid only when station "
+ "is not connected\n");
+ LEAVE();
+ return -EINVAL;
+ }
+ ret = woal_set_rf_channel(wiphy, chan, channel_type);
+ }
+#endif
+#endif
+ priv->channel = ieee80211_frequency_to_channel(chan->center_freq);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief register/unregister mgmt frame forwarding
+ *
+ * @param wiphy A pointer to wiphy structure
+ * @param dev A pointer to net_device structure
+ * @param frame_type Bit mask for mgmt frame type
+ * @param reg Register or unregister
+ *
+ * @return 0 -- success, otherwise fail
+ */
+void
+woal_cfg80211_mgmt_frame_register(struct wiphy *wiphy,
+ struct net_device *dev, u16 frame_type,
+ bool reg)
+{
+ moal_private *priv = (moal_private *) woal_get_wiphy_priv(wiphy);
+ mlan_status status = MLAN_STATUS_SUCCESS;
+ t_u32 mgmt_subtype_mask = 0x0;
+ static t_u32 last_mgmt_subtype_mask = 0x0;
+
+ ENTER();
+#ifdef UAP_SUPPORT
+ if ((priv->bss_type == MLAN_BSS_TYPE_UAP) &&
+ (frame_type == IEEE80211_STYPE_PROBE_REQ)) {
+ LEAVE();
+ return;
+ }
+#endif
+ if (reg == MTRUE) {
+ /* set mgmt_subtype_mask based on origin value */
+ last_mgmt_subtype_mask |= BIT(frame_type >> 4);
+ } else {
+ /* clear mgmt_subtype_mask */
+ last_mgmt_subtype_mask &= ~BIT(frame_type >> 4);
+ }
+ mgmt_subtype_mask = last_mgmt_subtype_mask;
+
+ /* Notify driver that a mgmt frame type was registered. Note that this
+ callback may not sleep, and cannot run concurrently with itself. */
+ status = woal_reg_rx_mgmt_ind(priv, MLAN_ACT_SET,
+ &mgmt_subtype_mask, MOAL_NO_WAIT);
+
+ LEAVE();
+}
+
+/**
+ * @brief tx mgmt frame
+ *
+ * @param wiphy A pointer to wiphy structure
+ * @param dev A pointer to net_device structure
+ * @param chan A pointer to ieee80211_channel structure
+ * @param offchan Off channel or not
+ * @param channel_type Channel type
+ * @param channel_type_valid Is channel type valid or not
+ * @param buf Frame buffer
+ * @param len Frame length
+ * @param cookie A pointer to frame cookie
+ *
+ * @return 0 -- success, otherwise fail
+ */
+int
+woal_cfg80211_mgmt_tx(struct wiphy *wiphy,
+ struct net_device *dev,
+ struct ieee80211_channel *chan, bool offchan,
+ enum nl80211_channel_type channel_type,
+ bool channel_type_valid, unsigned int wait,
+ const u8 * buf, size_t len,
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,2,0) || defined(COMPAT_WIRELESS)
+ bool no_cck,
+#endif
+ u64 * cookie)
+{
+ moal_private *priv = (moal_private *) woal_get_wiphy_priv(wiphy);
+ int ret = 0;
+ pmlan_buffer pmbuf = NULL;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+ t_u16 packet_len = 0;
+ t_u8 addr[] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
+ t_u16 framectrl;
+ t_u32 pkt_type;
+ t_u32 tx_control;
+#if defined(WIFI_DIRECT_SUPPORT)
+#if LINUX_VERSION_CODE >= WIFI_DIRECT_KERNEL_VERSION
+ t_u8 channel_status;
+ t_u32 duration;
+#endif
+#endif
+
+ ENTER();
+
+ if (buf == NULL || len == 0) {
+ PRINTM(MERROR, "woal_cfg80211_mgmt_tx() corrupt data\n");
+ ret = -EFAULT;
+ goto done;
+ }
+
+ /* frame subtype == probe response, that means we are in listen phase, so
+ we should not call remain_on_channel_cfg because remain_on_channl
+ already handled it. frame subtype == action, that means we are in
+ PD/GO negotiation, so we should call remain_on_channel_cfg in order to
+ receive action frame from peer device */
+ framectrl = ((const struct ieee80211_mgmt *) buf)->frame_control;
+ PRINTM(MIOCTL, "Mgmt: framectrl=0x%x\n", framectrl);
+#if defined(WIFI_DIRECT_SUPPORT)
+#if LINUX_VERSION_CODE >= WIFI_DIRECT_KERNEL_VERSION
+ if ((priv->bss_type == MLAN_BSS_TYPE_WIFIDIRECT) &&
+ (framectrl == IEEE80211_STYPE_ACTION)) {
+#define MGMT_TX_DEFAULT_WAIT_TIME 2000
+ /** cancel previous remain on channel */
+ if (priv->phandle->remain_on_channel) {
+ if (woal_cfg80211_remain_on_channel_cfg
+ (wiphy, MOAL_IOCTL_WAIT, MTRUE, &channel_status, NULL, 0, 0)) {
+ PRINTM(MERROR, "Fail to cancel remain on channel\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ if (priv->phandle->cookie) {
+ cfg80211_remain_on_channel_expired(priv->netdev,
+ priv->phandle->cookie,
+ &priv->phandle->chan,
+ priv->phandle->channel_type,
+ GFP_ATOMIC);
+ priv->phandle->cookie = 0;
+ }
+ priv->phandle->remain_on_channel = MFALSE;
+ }
+ duration = wait;
+ if (!wait)
+ duration = MGMT_TX_DEFAULT_WAIT_TIME;
+ if (channel_type_valid)
+ ret =
+ woal_cfg80211_remain_on_channel_cfg(wiphy, MOAL_IOCTL_WAIT,
+ MFALSE, &channel_status,
+ chan, channel_type,
+ duration);
+ else
+ ret =
+ woal_cfg80211_remain_on_channel_cfg(wiphy, MOAL_IOCTL_WAIT,
+ MFALSE, &channel_status,
+ chan, 0, duration);
+ if (ret) {
+ PRINTM(MERROR, "Fail to configure remain on channel\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ priv->phandle->remain_on_channel = MTRUE;
+ priv->phandle->channel_type = channel_type;
+ memcpy(&priv->phandle->chan, chan, sizeof(struct ieee80211_channel));
+ PRINTM(MIOCTL, "Mgmt Tx: Set remain channel=%d\n",
+ ieee80211_frequency_to_channel(chan->center_freq));
+ }
+#endif
+#endif
+#define MRVL_PKT_TYPE_MGMT_FRAME 0xE5
+ /* pkt_type + tx_control */
+#define HEADER_SIZE 8
+ packet_len = (t_u16) len + MLAN_MAC_ADDR_LENGTH;
+ pmbuf = woal_alloc_mlan_buffer(priv->phandle,
+ MLAN_MIN_DATA_HEADER_LEN + HEADER_SIZE +
+ packet_len + sizeof(packet_len));
+ if (!pmbuf) {
+ PRINTM(MERROR, "Fail to allocate mlan_buffer\n");
+ ret = -ENOMEM;
+ goto done;
+ }
+ *cookie = random32() | 1;
+ pmbuf->data_offset = MLAN_MIN_DATA_HEADER_LEN;
+ pkt_type = MRVL_PKT_TYPE_MGMT_FRAME;
+ tx_control = 0;
+ /* Add pkt_type and tx_control */
+ memcpy(pmbuf->pbuf + pmbuf->data_offset, &pkt_type, sizeof(pkt_type));
+ memcpy(pmbuf->pbuf + pmbuf->data_offset + sizeof(pkt_type), &tx_control,
+ sizeof(tx_control));
+ /* frmctl + durationid + addr1 + addr2 + addr3 + seqctl */
+#define PACKET_ADDR4_POS (2 + 2 + 6 + 6 + 6 + 2)
+ memcpy(pmbuf->pbuf + pmbuf->data_offset + HEADER_SIZE, &packet_len,
+ sizeof(packet_len));
+ memcpy(pmbuf->pbuf + pmbuf->data_offset + HEADER_SIZE + sizeof(packet_len),
+ buf, PACKET_ADDR4_POS);
+ memcpy(pmbuf->pbuf + pmbuf->data_offset + HEADER_SIZE + sizeof(packet_len)
+ + PACKET_ADDR4_POS, addr, MLAN_MAC_ADDR_LENGTH);
+ memcpy(pmbuf->pbuf + pmbuf->data_offset + HEADER_SIZE + sizeof(packet_len)
+ + PACKET_ADDR4_POS + MLAN_MAC_ADDR_LENGTH,
+ buf + PACKET_ADDR4_POS, len - PACKET_ADDR4_POS);
+
+ pmbuf->data_len = HEADER_SIZE + packet_len + sizeof(packet_len);
+ pmbuf->buf_type = MLAN_BUF_TYPE_RAW_DATA;
+ pmbuf->bss_index = priv->bss_index;
+
+ status = mlan_send_packet(priv->phandle->pmlan_adapter, pmbuf);
+
+ switch (status) {
+ case MLAN_STATUS_PENDING:
+ atomic_inc(&priv->phandle->tx_pending);
+ queue_work(priv->phandle->workqueue, &priv->phandle->main_work);
+
+ /* delay 20ms to guarantee the packet has been already tx'ed becuase if
+ we call cfg80211_mgmt_tx_status() immediately, then wpa_supplicant
+ will call cancel_remain_on_channel(), which may affect the mgmt
+ frame tx */
+ mdelay(20);
+
+ /* Notify the mgmt tx status */
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,37) || defined(COMPAT_WIRELESS)
+ cfg80211_mgmt_tx_status(dev, *cookie, buf, len, true, GFP_ATOMIC);
+#endif
+ break;
+ case MLAN_STATUS_SUCCESS:
+ woal_free_mlan_buffer(priv->phandle, pmbuf);
+ break;
+ case MLAN_STATUS_FAILURE:
+ default:
+ woal_free_mlan_buffer(priv->phandle, pmbuf);
+ ret = -EFAULT;
+ break;
+ }
+
+ done:
+ LEAVE();
+ return ret;
+}
diff --git a/drivers/net/wireless/sd8797/mlinux/moal_cfg80211.h b/drivers/net/wireless/sd8797/mlinux/moal_cfg80211.h
new file mode 100644
index 000000000000..e1683ed08a89
--- /dev/null
+++ b/drivers/net/wireless/sd8797/mlinux/moal_cfg80211.h
@@ -0,0 +1,195 @@
+/** @file moal_cfg80211.h
+ *
+ * @brief This file contains the CFG80211 specific defines.
+ *
+ * Copyright (C) 2011-2012, Marvell International Ltd.
+ *
+ * This software file (the "File") is distributed by Marvell International
+ * Ltd. under the terms of the GNU General Public License Version 2, June 1991
+ * (the "License"). You may use, redistribute and/or modify this File in
+ * accordance with the terms and conditions of the License, a copy of which
+ * is available by writing to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
+ * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
+ *
+ * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
+ * ARE EXPRESSLY DISCLAIMED. The License provides additional details about
+ * this warranty disclaimer.
+ *
+ */
+
+#ifndef _MOAL_CFG80211_H_
+#define _MOAL_CFG80211_H_
+
+#include "moal_main.h"
+
+/** RTS/FRAG disabled value */
+#define MLAN_FRAG_RTS_DISABLED (0xFFFFFFFF)
+
+#ifndef WLAN_CIPHER_SUITE_WAPI
+#define WLAN_CIPHER_SUITE_WAPI 0x00000020
+#endif
+
+/* define for custom ie operation */
+#define MLAN_CUSTOM_IE_AUTO_IDX_MASK 0xffff
+#define MLAN_CUSTOM_IE_DELETE_MASK 0x0
+#define TLV_TYPE_MGMT_IE 0x0169
+#define MGMT_MASK_ASSOC_REQ 0x01
+#define MGMT_MASK_REASSOC_REQ 0x04
+#define MGMT_MASK_ASSOC_RESP 0x02
+#define MGMT_MASK_REASSOC_RESP 0x08
+#define MGMT_MASK_PROBE_REQ 0x10
+#define MGMT_MASK_PROBE_RESP 0x20
+#define MGMT_MASK_BEACON 0x100
+
+/**
+ * If multiple wiphys are registered e.g. a regular netdev with
+ * assigned ieee80211_ptr and you won't know whether it points
+ * to a wiphy your driver has registered or not. Assign this to
+ * something global to your driver to help determine whether
+ * you own this wiphy or not.
+ */
+static const void *const mrvl_wiphy_privid = &mrvl_wiphy_privid;
+
+/* Get the private structure from wiphy */
+void *woal_get_wiphy_priv(struct wiphy *wiphy);
+
+int woal_cfg80211_change_virtual_intf(struct wiphy *wiphy,
+ struct net_device *dev,
+ enum nl80211_iftype type,
+ u32 * flags, struct vif_params *params);
+
+int woal_cfg80211_set_wiphy_params(struct wiphy *wiphy, u32 changed);
+
+int woal_cfg80211_add_key(struct wiphy *wiphy,
+ struct net_device *dev, t_u8 key_index,
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,36) || defined(COMPAT_WIRELESS)
+ bool pairwise,
+#endif
+ const t_u8 * mac_addr, struct key_params *params);
+
+int woal_cfg80211_del_key(struct wiphy *wiphy,
+ struct net_device *dev, t_u8 key_index,
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,36) || defined(COMPAT_WIRELESS)
+ bool pairwise,
+#endif
+ const t_u8 * mac_addr);
+
+#ifdef STA_CFG80211
+#ifdef STA_SUPPORT
+int woal_set_rf_channel(struct wiphy *wiphy,
+ struct ieee80211_channel *chan,
+ enum nl80211_channel_type channel_type);
+mlan_status woal_inform_bss_from_scan_result(moal_private * priv,
+ mlan_802_11_ssid * ssid);
+#endif
+#endif
+
+int woal_cfg80211_set_channel(struct wiphy *wiphy,
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,34) || defined(COMPAT_WIRELESS)
+ struct net_device *dev,
+#endif
+ struct ieee80211_channel *chan,
+ enum nl80211_channel_type channel_type);
+
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,37) || defined(COMPAT_WIRELESS)
+int woal_cfg80211_set_default_key(struct wiphy *wiphy,
+ struct net_device *dev, t_u8 key_index,
+ bool ucast, bool mcast);
+#else
+int woal_cfg80211_set_default_key(struct wiphy *wiphy,
+ struct net_device *dev, t_u8 key_index);
+#endif
+
+void woal_cfg80211_mgmt_frame_register(struct wiphy *wiphy,
+ struct net_device *dev, t_u16 frame_type,
+ bool reg);
+
+int woal_cfg80211_mgmt_tx(struct wiphy *wiphy,
+ struct net_device *dev,
+ struct ieee80211_channel *chan, bool offchan,
+ enum nl80211_channel_type channel_type,
+ bool channel_type_valid, unsigned int wait,
+ const u8 * buf, size_t len,
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,2,0) || defined(COMPAT_WIRELESS)
+ bool no_cck,
+#endif
+ u64 * cookie);
+
+extern struct ieee80211_supported_band cfg80211_band_2ghz;
+extern struct ieee80211_supported_band cfg80211_band_5ghz;
+extern const u32 cfg80211_cipher_suites[10];
+
+typedef struct _monitor_iface
+{
+ /* The priv data of interface on which the monitor iface is based */
+ moal_private *priv;
+ struct wireless_dev wdev;
+ int radiotap_enabled;
+ /* The net_device on which the monitor iface is based. */
+ struct net_device *base_ndev;
+ struct net_device *mon_ndev;
+ char ifname[IFNAMSIZ];
+ int flag;
+} monitor_iface;
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,37) || defined(COMPAT_WIRELESS)
+struct net_device *woal_cfg80211_add_virtual_intf(struct wiphy *wiphy,
+ char *name,
+ enum nl80211_iftype type,
+ u32 * flags,
+ struct vif_params *params);
+#else
+int woal_cfg80211_add_virtual_intf(struct wiphy *wiphy,
+ char *name, enum nl80211_iftype type,
+ u32 * flags, struct vif_params *params);
+#endif
+int woal_cfg80211_del_virtual_intf(struct wiphy *wiphy, struct net_device *dev);
+
+#if defined(WIFI_DIRECT_SUPPORT)
+/** Define kernel version for wifi direct */
+#if !defined(COMPAT_WIRELESS)
+#define WIFI_DIRECT_KERNEL_VERSION KERNEL_VERSION(3,0,0)
+#else
+#define WIFI_DIRECT_KERNEL_VERSION KERNEL_VERSION(2,6,33)
+#endif /* COMPAT_WIRELESS */
+#if LINUX_VERSION_CODE >= WIFI_DIRECT_KERNEL_VERSION
+/** Define for remain on channel duration timer */
+#define MAX_REMAIN_ON_CHANNEL_DURATION (1000 * 5)
+
+int woal_cfg80211_add_beacon(struct wiphy *wiphy,
+ struct net_device *dev,
+ struct beacon_parameters *params);
+
+int woal_cfg80211_set_beacon(struct wiphy *wiphy,
+ struct net_device *dev,
+ struct beacon_parameters *params);
+
+int woal_cfg80211_del_beacon(struct wiphy *wiphy, struct net_device *dev);
+
+int woal_cfg80211_init_p2p_client(moal_private * priv);
+
+int woal_cfg80211_init_p2p_go(moal_private * priv);
+
+int woal_cfg80211_deinit_p2p(moal_private * priv);
+
+int woal_cfg80211_remain_on_channel_cfg(struct wiphy *wiphy,
+ t_u8 wait_option, t_u8 remove,
+ t_u8 * status,
+ struct ieee80211_channel *chan,
+ enum nl80211_channel_type channel_type,
+ t_u32 duration);
+int woal_uap_cfg80211_get_station(struct wiphy *wiphy, struct net_device *dev,
+ u8 * mac, struct station_info *stainfo);
+#endif /* KERNEL_VERSION */
+#endif /* WIFI_DIRECT_SUPPORT && V14_FEATURE */
+
+int woal_cfg80211_mgmt_frame_ie(moal_private * priv,
+ const t_u8 * beacon_ies, size_t beacon_ies_len,
+ const t_u8 * proberesp_ies,
+ size_t proberesp_ies_len,
+ const t_u8 * assocresp_ies,
+ size_t assocresp_ies_len,
+ const t_u8 * probereq_ies,
+ size_t probereq_ies_len, t_u16 mask);
+#endif /* _MOAL_CFG80211_H_ */
diff --git a/drivers/net/wireless/sd8797/mlinux/moal_debug.c b/drivers/net/wireless/sd8797/mlinux/moal_debug.c
new file mode 100644
index 000000000000..fd74c3b5ae92
--- /dev/null
+++ b/drivers/net/wireless/sd8797/mlinux/moal_debug.c
@@ -0,0 +1,674 @@
+/** @file moal_debug.c
+ *
+ * @brief This file contains functions for debug proc file.
+ *
+ * Copyright (C) 2008-2011, Marvell International Ltd.
+ *
+ * This software file (the "File") is distributed by Marvell International
+ * Ltd. under the terms of the GNU General Public License Version 2, June 1991
+ * (the "License"). You may use, redistribute and/or modify this File in
+ * accordance with the terms and conditions of the License, a copy of which
+ * is available by writing to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
+ * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
+ *
+ * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
+ * ARE EXPRESSLY DISCLAIMED. The License provides additional details about
+ * this warranty disclaimer.
+ *
+ */
+
+/********************************************************
+Change log:
+ 11/03/2008: initial version
+********************************************************/
+
+#include "moal_main.h"
+
+/********************************************************
+ Global Variables
+********************************************************/
+/** MLAN debug info */
+extern mlan_debug_info info;
+
+/********************************************************
+ Local Variables
+********************************************************/
+#ifdef CONFIG_PROC_FS
+
+/** Get info item size */
+#define item_size(n) (sizeof(info.n))
+/** Get info item address */
+#define item_addr(n) ((t_ptr) &(info.n))
+
+/** Get moal_private member size */
+#define item_priv_size(n) (sizeof ((moal_private *)0)->n)
+/** Get moal_private member address */
+#define item_priv_addr(n) ((t_ptr) &((moal_private *)0)->n)
+
+/** Get moal_handle member size */
+#define item_handle_size(n) (sizeof ((moal_handle *)0)->n)
+/** Get moal_handle member address */
+#define item_handle_addr(n) ((t_ptr) &((moal_handle *)0)->n)
+
+#ifdef STA_SUPPORT
+static struct debug_data items[] = {
+#ifdef DEBUG_LEVEL1
+ {"drvdbg", sizeof(drvdbg), (t_ptr) & drvdbg}
+ ,
+#endif
+ {"wmm_ac_vo", item_size(wmm_ac_vo), item_addr(wmm_ac_vo)}
+ ,
+ {"wmm_ac_vi", item_size(wmm_ac_vi), item_addr(wmm_ac_vi)}
+ ,
+ {"wmm_ac_be", item_size(wmm_ac_be), item_addr(wmm_ac_be)}
+ ,
+ {"wmm_ac_bk", item_size(wmm_ac_bk), item_addr(wmm_ac_bk)}
+ ,
+ {"max_tx_buf_size", item_size(max_tx_buf_size), item_addr(max_tx_buf_size)}
+ ,
+ {"tx_buf_size", item_size(tx_buf_size), item_addr(tx_buf_size)}
+ ,
+ {"curr_tx_buf_size", item_size(curr_tx_buf_size),
+ item_addr(curr_tx_buf_size)}
+ ,
+ {"ps_mode", item_size(ps_mode), item_addr(ps_mode)}
+ ,
+ {"ps_state", item_size(ps_state), item_addr(ps_state)}
+ ,
+ {"is_deep_sleep", item_size(is_deep_sleep), item_addr(is_deep_sleep)}
+ ,
+ {"wakeup_dev_req", item_size(pm_wakeup_card_req),
+ item_addr(pm_wakeup_card_req)}
+ ,
+ {"wakeup_tries", item_size(pm_wakeup_fw_try), item_addr(pm_wakeup_fw_try)}
+ ,
+ {"hs_configured", item_size(is_hs_configured), item_addr(is_hs_configured)}
+ ,
+ {"hs_activated", item_size(hs_activated), item_addr(hs_activated)}
+ ,
+ {"tx_pkts_queued", item_size(tx_pkts_queued), item_addr(tx_pkts_queued)}
+ ,
+ {"pps_uapsd_mode", item_size(pps_uapsd_mode), item_addr(pps_uapsd_mode)}
+ ,
+ {"sleep_pd", item_size(sleep_pd), item_addr(sleep_pd)}
+ ,
+ {"qos_cfg", item_size(qos_cfg), item_addr(qos_cfg)}
+ ,
+ {"tx_lock_flag", item_size(tx_lock_flag), item_addr(tx_lock_flag)}
+ ,
+ {"port_open", item_size(port_open), item_addr(port_open)}
+ ,
+ {"scan_processing", item_size(scan_processing), item_addr(scan_processing)}
+ ,
+ {"num_tx_timeout", item_size(num_tx_timeout), item_addr(num_tx_timeout)}
+ ,
+ {"num_cmd_timeout", item_size(num_cmd_timeout), item_addr(num_cmd_timeout)}
+ ,
+ {"timeout_cmd_id", item_size(timeout_cmd_id), item_addr(timeout_cmd_id)}
+ ,
+ {"timeout_cmd_act", item_size(timeout_cmd_act), item_addr(timeout_cmd_act)}
+ ,
+ {"last_cmd_id", item_size(last_cmd_id), item_addr(last_cmd_id)}
+ ,
+ {"last_cmd_act", item_size(last_cmd_act), item_addr(last_cmd_act)}
+ ,
+ {"last_cmd_index", item_size(last_cmd_index), item_addr(last_cmd_index)}
+ ,
+ {"last_cmd_resp_id", item_size(last_cmd_resp_id),
+ item_addr(last_cmd_resp_id)}
+ ,
+ {"last_cmd_resp_index", item_size(last_cmd_resp_index),
+ item_addr(last_cmd_resp_index)}
+ ,
+ {"last_event", item_size(last_event), item_addr(last_event)}
+ ,
+ {"last_event_index", item_size(last_event_index),
+ item_addr(last_event_index)}
+ ,
+ {"num_cmd_h2c_fail", item_size(num_cmd_host_to_card_failure),
+ item_addr(num_cmd_host_to_card_failure)}
+ ,
+ {"num_cmd_sleep_cfm_fail",
+ item_size(num_cmd_sleep_cfm_host_to_card_failure),
+ item_addr(num_cmd_sleep_cfm_host_to_card_failure)}
+ ,
+ {"num_tx_h2c_fail", item_size(num_tx_host_to_card_failure),
+ item_addr(num_tx_host_to_card_failure)}
+ ,
+ {"num_cmdevt_c2h_fail", item_size(num_cmdevt_card_to_host_failure),
+ item_addr(num_cmdevt_card_to_host_failure)}
+ ,
+ {"num_rx_c2h_fail", item_size(num_rx_card_to_host_failure),
+ item_addr(num_rx_card_to_host_failure)}
+ ,
+ {"num_int_read_fail", item_size(num_int_read_failure),
+ item_addr(num_int_read_failure)}
+ ,
+ {"last_int_status", item_size(last_int_status), item_addr(last_int_status)}
+ ,
+ {"num_evt_deauth", item_size(num_event_deauth), item_addr(num_event_deauth)}
+ ,
+ {"num_evt_disassoc", item_size(num_event_disassoc),
+ item_addr(num_event_disassoc)}
+ ,
+ {"num_evt_link_lost", item_size(num_event_link_lost),
+ item_addr(num_event_link_lost)}
+ ,
+ {"num_cmd_deauth", item_size(num_cmd_deauth), item_addr(num_cmd_deauth)}
+ ,
+ {"num_cmd_assoc_ok", item_size(num_cmd_assoc_success),
+ item_addr(num_cmd_assoc_success)}
+ ,
+ {"num_cmd_assoc_fail", item_size(num_cmd_assoc_failure),
+ item_addr(num_cmd_assoc_failure)}
+ ,
+ {"cmd_sent", item_size(cmd_sent), item_addr(cmd_sent)}
+ ,
+ {"data_sent", item_size(data_sent), item_addr(data_sent)}
+ ,
+ {"mp_rd_bitmap", item_size(mp_rd_bitmap), item_addr(mp_rd_bitmap)}
+ ,
+ {"curr_rd_port", item_size(curr_rd_port), item_addr(curr_rd_port)}
+ ,
+ {"mp_wr_bitmap", item_size(mp_wr_bitmap), item_addr(mp_wr_bitmap)}
+ ,
+ {"curr_wr_port", item_size(curr_wr_port), item_addr(curr_wr_port)}
+ ,
+ {"cmd_resp_received", item_size(cmd_resp_received),
+ item_addr(cmd_resp_received)}
+ ,
+ {"event_received", item_size(event_received), item_addr(event_received)}
+ ,
+
+ {"ioctl_pending", item_handle_size(ioctl_pending),
+ item_handle_addr(ioctl_pending)}
+ ,
+ {"tx_pending", item_handle_size(tx_pending), item_handle_addr(tx_pending)}
+ ,
+ {"rx_pending", item_handle_size(rx_pending), item_handle_addr(rx_pending)}
+ ,
+ {"malloc_count", item_handle_size(malloc_count),
+ item_handle_addr(malloc_count)}
+ ,
+ {"lock_count", item_handle_size(lock_count), item_handle_addr(lock_count)}
+ ,
+ {"mbufalloc_count", item_handle_size(mbufalloc_count),
+ item_handle_addr(mbufalloc_count)}
+ ,
+ {"main_state", item_handle_size(main_state), item_handle_addr(main_state)}
+ ,
+#ifdef SDIO_MMC_DEBUG
+ {"sdiocmd53w", item_handle_size(cmd53w), item_handle_addr(cmd53w)}
+ ,
+ {"sdiocmd53r", item_handle_size(cmd53r), item_handle_addr(cmd53r)}
+ ,
+#endif
+#if defined(SDIO_SUSPEND_RESUME)
+ {"hs_skip_count", item_handle_size(hs_skip_count),
+ item_handle_addr(hs_skip_count)}
+ ,
+ {"hs_force_count", item_handle_size(hs_force_count),
+ item_handle_addr(hs_force_count)}
+ ,
+#endif
+};
+
+#endif
+
+#ifdef UAP_SUPPORT
+static struct debug_data uap_items[] = {
+#ifdef DEBUG_LEVEL1
+ {"drvdbg", sizeof(drvdbg), (t_ptr) & drvdbg}
+ ,
+#endif
+ {"wmm_ac_vo", item_size(wmm_ac_vo), item_addr(wmm_ac_vo)}
+ ,
+ {"wmm_ac_vi", item_size(wmm_ac_vi), item_addr(wmm_ac_vi)}
+ ,
+ {"wmm_ac_be", item_size(wmm_ac_be), item_addr(wmm_ac_be)}
+ ,
+ {"wmm_ac_bk", item_size(wmm_ac_bk), item_addr(wmm_ac_bk)}
+ ,
+ {"max_tx_buf_size", item_size(max_tx_buf_size), item_addr(max_tx_buf_size)}
+ ,
+ {"tx_buf_size", item_size(tx_buf_size), item_addr(tx_buf_size)}
+ ,
+ {"curr_tx_buf_size", item_size(curr_tx_buf_size),
+ item_addr(curr_tx_buf_size)}
+ ,
+ {"ps_mode", item_size(ps_mode), item_addr(ps_mode)}
+ ,
+ {"ps_state", item_size(ps_state), item_addr(ps_state)}
+ ,
+ {"wakeup_dev_req", item_size(pm_wakeup_card_req),
+ item_addr(pm_wakeup_card_req)}
+ ,
+ {"wakeup_tries", item_size(pm_wakeup_fw_try), item_addr(pm_wakeup_fw_try)}
+ ,
+ {"hs_configured", item_size(is_hs_configured), item_addr(is_hs_configured)}
+ ,
+ {"hs_activated", item_size(hs_activated), item_addr(hs_activated)}
+ ,
+ {"tx_pkts_queued", item_size(tx_pkts_queued), item_addr(tx_pkts_queued)}
+ ,
+ {"num_bridge_pkts", item_size(num_bridge_pkts), item_addr(num_bridge_pkts)}
+ ,
+ {"num_drop_pkts", item_size(num_drop_pkts), item_addr(num_drop_pkts)}
+ ,
+ {"num_tx_timeout", item_size(num_tx_timeout), item_addr(num_tx_timeout)}
+ ,
+ {"num_cmd_timeout", item_size(num_cmd_timeout), item_addr(num_cmd_timeout)}
+ ,
+ {"timeout_cmd_id", item_size(timeout_cmd_id), item_addr(timeout_cmd_id)}
+ ,
+ {"timeout_cmd_act", item_size(timeout_cmd_act), item_addr(timeout_cmd_act)}
+ ,
+ {"last_cmd_id", item_size(last_cmd_id), item_addr(last_cmd_id)}
+ ,
+ {"last_cmd_act", item_size(last_cmd_act), item_addr(last_cmd_act)}
+ ,
+ {"last_cmd_index", item_size(last_cmd_index), item_addr(last_cmd_index)}
+ ,
+ {"last_cmd_resp_id", item_size(last_cmd_resp_id),
+ item_addr(last_cmd_resp_id)}
+ ,
+ {"last_cmd_resp_index", item_size(last_cmd_resp_index),
+ item_addr(last_cmd_resp_index)}
+ ,
+ {"last_event", item_size(last_event), item_addr(last_event)}
+ ,
+ {"last_event_index", item_size(last_event_index),
+ item_addr(last_event_index)}
+ ,
+ {"num_cmd_h2c_fail", item_size(num_cmd_host_to_card_failure),
+ item_addr(num_cmd_host_to_card_failure)}
+ ,
+ {"num_cmd_sleep_cfm_fail",
+ item_size(num_cmd_sleep_cfm_host_to_card_failure),
+ item_addr(num_cmd_sleep_cfm_host_to_card_failure)}
+ ,
+ {"num_tx_h2c_fail", item_size(num_tx_host_to_card_failure),
+ item_addr(num_tx_host_to_card_failure)}
+ ,
+ {"num_cmdevt_c2h_fail", item_size(num_cmdevt_card_to_host_failure),
+ item_addr(num_cmdevt_card_to_host_failure)}
+ ,
+ {"num_rx_c2h_fail", item_size(num_rx_card_to_host_failure),
+ item_addr(num_rx_card_to_host_failure)}
+ ,
+ {"num_int_read_fail", item_size(num_int_read_failure),
+ item_addr(num_int_read_failure)}
+ ,
+ {"last_int_status", item_size(last_int_status), item_addr(last_int_status)}
+ ,
+ {"cmd_sent", item_size(cmd_sent), item_addr(cmd_sent)}
+ ,
+ {"data_sent", item_size(data_sent), item_addr(data_sent)}
+ ,
+ {"mp_rd_bitmap", item_size(mp_rd_bitmap), item_addr(mp_rd_bitmap)}
+ ,
+ {"curr_rd_port", item_size(curr_rd_port), item_addr(curr_rd_port)}
+ ,
+ {"mp_wr_bitmap", item_size(mp_wr_bitmap), item_addr(mp_wr_bitmap)}
+ ,
+ {"curr_wr_port", item_size(curr_wr_port), item_addr(curr_wr_port)}
+ ,
+ {"cmd_resp_received", item_size(cmd_resp_received),
+ item_addr(cmd_resp_received)}
+ ,
+ {"event_received", item_size(event_received), item_addr(event_received)}
+ ,
+
+ {"ioctl_pending", item_handle_size(ioctl_pending),
+ item_handle_addr(ioctl_pending)}
+ ,
+ {"tx_pending", item_handle_size(tx_pending), item_handle_addr(tx_pending)}
+ ,
+ {"rx_pending", item_handle_size(rx_pending), item_handle_addr(rx_pending)}
+ ,
+ {"malloc_count", item_handle_size(malloc_count),
+ item_handle_addr(malloc_count)}
+ ,
+ {"lock_count", item_handle_size(lock_count), item_handle_addr(lock_count)}
+ ,
+ {"mbufalloc_count", item_handle_size(mbufalloc_count),
+ item_handle_addr(mbufalloc_count)}
+ ,
+ {"main_state", item_handle_size(main_state), item_handle_addr(main_state)}
+ ,
+#ifdef SDIO_MMC_DEBUG
+ {"sdiocmd53w", item_handle_size(cmd53w), item_handle_addr(cmd53w)}
+ ,
+ {"sdiocmd53r", item_handle_size(cmd53r), item_handle_addr(cmd53r)}
+ ,
+#endif
+#if defined(SDIO_SUSPEND_RESUME)
+ {"hs_skip_count", item_handle_size(hs_skip_count),
+ item_handle_addr(hs_skip_count)}
+ ,
+ {"hs_force_count", item_handle_size(hs_force_count),
+ item_handle_addr(hs_force_count)}
+ ,
+#endif
+};
+#endif /* UAP_SUPPORT */
+
+/********************************************************
+ Local Functions
+********************************************************/
+/**
+ * @brief Proc read function
+ *
+ * @param page Pointer to buffer
+ * @param s Read data starting position
+ * @param off Offset
+ * @param cnt Counter
+ * @param eof End of file flag
+ * @param data Output data
+ *
+ * @return Number of output data or MLAN_STATUS_FAILURE
+ */
+static int
+woal_debug_read(char *page, char **s, off_t off, int cnt, int *eof, void *data)
+{
+ int val = 0;
+ unsigned int i;
+ char *p = page;
+ struct debug_data *d = ((struct debug_data_priv *) data)->items;
+ moal_private *priv = ((struct debug_data_priv *) data)->priv;
+
+ ENTER();
+
+ if (MODULE_GET == 0) {
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+
+ /* Get debug information */
+ if (woal_get_debug_info(priv, MOAL_PROC_WAIT, &info)) {
+ *eof = 1;
+ goto exit;
+ }
+ for (i = 0;
+ i < (unsigned int) ((struct debug_data_priv *) data)->num_of_items;
+ i++) {
+ if (d[i].size == 1)
+ val = *((t_u8 *) d[i].addr);
+ else if (d[i].size == 2)
+ val = *((t_u16 *) d[i].addr);
+ else if (d[i].size == 4)
+ val = *((t_ptr *) d[i].addr);
+ else {
+ unsigned int j;
+ p += sprintf(p, "%s=", d[i].name);
+ for (j = 0; j < d[i].size; j += 2) {
+ val = *(t_u16 *) (d[i].addr + j);
+ p += sprintf(p, "0x%x ", val);
+ }
+ p += sprintf(p, "\n");
+ continue;
+ }
+ if (strstr(d[i].name, "id") || strstr(d[i].name, "bitmap"))
+ p += sprintf(p, "%s=0x%x\n", d[i].name, val);
+ else
+ p += sprintf(p, "%s=%d\n", d[i].name, val);
+ }
+ if (info.tx_tbl_num) {
+ p += sprintf(p, "Tx BA stream table:\n");
+ for (i = 0; i < info.tx_tbl_num; i++) {
+ p += sprintf(p,
+ "tid = %d, ra = %02x:%02x:%02x:%02x:%02x:%02x amsdu=%d\n",
+ (int) info.tx_tbl[i].tid, info.tx_tbl[i].ra[0],
+ info.tx_tbl[i].ra[1], info.tx_tbl[i].ra[2],
+ info.tx_tbl[i].ra[3], info.tx_tbl[i].ra[4],
+ info.tx_tbl[i].ra[5], (int) info.tx_tbl[i].amsdu);
+ }
+ }
+ if (info.rx_tbl_num) {
+ p += sprintf(p, "Rx reorder table:\n");
+ for (i = 0; i < info.rx_tbl_num; i++) {
+ unsigned int j;
+
+ p += sprintf(p,
+ "tid = %d, ta = %02x:%02x:%02x:%02x:%02x:%02x, start_win = %d, "
+ "win_size = %d, amsdu=%d\n", (int) info.rx_tbl[i].tid,
+ info.rx_tbl[i].ta[0], info.rx_tbl[i].ta[1],
+ info.rx_tbl[i].ta[2], info.rx_tbl[i].ta[3],
+ info.rx_tbl[i].ta[4], info.rx_tbl[i].ta[5],
+ (int) info.rx_tbl[i].start_win,
+ (int) info.rx_tbl[i].win_size,
+ (int) info.rx_tbl[i].amsdu);
+ p += sprintf(p, "buffer: ");
+ for (j = 0; j < info.rx_tbl[i].win_size; j++) {
+ if (info.rx_tbl[i].buffer[j] == MTRUE)
+ p += sprintf(p, "1 ");
+ else
+ p += sprintf(p, "0 ");
+ }
+ p += sprintf(p, "\n");
+ }
+ }
+ exit:
+ MODULE_PUT;
+ LEAVE();
+ return p - page;
+}
+
+/**
+ * @brief Proc write function
+ *
+ * @param f File pointer
+ * @param buf Pointer to data buffer
+ * @param cnt Data number to write
+ * @param data Data to write
+ *
+ * @return Number of data or MLAN_STATUS_FAILURE
+ */
+static int
+woal_debug_write(struct file *f, const char *buf, unsigned long cnt, void *data)
+{
+ int r, i;
+ char *pdata;
+ char *p;
+ char *p0;
+ char *p1;
+ char *p2;
+ struct debug_data *d = ((struct debug_data_priv *) data)->items;
+ moal_private *priv = ((struct debug_data_priv *) data)->priv;
+#ifdef DEBUG_LEVEL1
+ t_u32 last_drvdbg = drvdbg;
+#endif
+
+ ENTER();
+
+ if (MODULE_GET == 0) {
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+
+ pdata = (char *) kmalloc(cnt, GFP_KERNEL);
+ if (pdata == NULL) {
+ MODULE_PUT;
+ LEAVE();
+ return 0;
+ }
+
+ if (copy_from_user(pdata, buf, cnt)) {
+ PRINTM(MERROR, "Copy from user failed\n");
+ kfree(pdata);
+ MODULE_PUT;
+ LEAVE();
+ return 0;
+ }
+
+ if (woal_get_debug_info(priv, MOAL_PROC_WAIT, &info)) {
+ kfree(pdata);
+ MODULE_PUT;
+ LEAVE();
+ return 0;
+ }
+
+ p0 = pdata;
+ for (i = 0; i < ((struct debug_data_priv *) data)->num_of_items; i++) {
+ do {
+ p = strstr(p0, d[i].name);
+ if (p == NULL)
+ break;
+ p1 = strchr(p, '\n');
+ if (p1 == NULL)
+ break;
+ p0 = p1++;
+ p2 = strchr(p, '=');
+ if (!p2)
+ break;
+ p2++;
+ r = woal_string_to_number(p2);
+ if (d[i].size == 1)
+ *((t_u8 *) d[i].addr) = (t_u8) r;
+ else if (d[i].size == 2)
+ *((t_u16 *) d[i].addr) = (t_u16) r;
+ else if (d[i].size == 4)
+ *((t_ptr *) d[i].addr) = (t_ptr) r;
+ break;
+ } while (MTRUE);
+ }
+ kfree(pdata);
+
+#ifdef DEBUG_LEVEL1
+ if (last_drvdbg != drvdbg)
+ woal_set_drvdbg(priv, drvdbg);
+#endif
+
+ /* Set debug information */
+ if (woal_set_debug_info(priv, MOAL_PROC_WAIT, &info)) {
+ MODULE_PUT;
+ LEAVE();
+ return 0;
+ }
+
+ MODULE_PUT;
+ LEAVE();
+ return cnt;
+}
+
+/********************************************************
+ Global Functions
+********************************************************/
+/**
+ * @brief Create debug proc file
+ *
+ * @param priv A pointer to a moal_private structure
+ *
+ * @return N/A
+ */
+void
+woal_debug_entry(moal_private * priv)
+{
+ struct proc_dir_entry *r;
+
+ ENTER();
+
+ if (priv->proc_entry == NULL) {
+ LEAVE();
+ return;
+ }
+#ifdef STA_SUPPORT
+ if (GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_STA) {
+ priv->items_priv.items =
+ (struct debug_data *) kmalloc(sizeof(items), GFP_KERNEL);
+ if (!priv->items_priv.items) {
+ PRINTM(MERROR, "Failed to allocate memory for debug data\n");
+ LEAVE();
+ return;
+ }
+ memcpy(priv->items_priv.items, items, sizeof(items));
+ priv->items_priv.num_of_items = sizeof(items) / sizeof(items[0]);
+ }
+#endif
+#ifdef UAP_SUPPORT
+ if (GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_UAP) {
+ priv->items_priv.items =
+ (struct debug_data *) kmalloc(sizeof(uap_items), GFP_KERNEL);
+ if (!priv->items_priv.items) {
+ PRINTM(MERROR, "Failed to allocate memory for debug data\n");
+ LEAVE();
+ return;
+ }
+ memcpy(priv->items_priv.items, uap_items, sizeof(uap_items));
+ priv->items_priv.num_of_items =
+ sizeof(uap_items) / sizeof(uap_items[0]);
+ }
+#endif
+ priv->items_priv.priv = priv;
+ priv->items_priv.items[priv->items_priv.num_of_items - 1].addr +=
+ (t_ptr) (priv->phandle);
+ priv->items_priv.items[priv->items_priv.num_of_items - 2].addr +=
+ (t_ptr) (priv->phandle);
+ priv->items_priv.items[priv->items_priv.num_of_items - 3].addr +=
+ (t_ptr) (priv->phandle);
+ priv->items_priv.items[priv->items_priv.num_of_items - 4].addr +=
+ (t_ptr) (priv->phandle);
+ priv->items_priv.items[priv->items_priv.num_of_items - 5].addr +=
+ (t_ptr) (priv->phandle);
+ priv->items_priv.items[priv->items_priv.num_of_items - 6].addr +=
+ (t_ptr) (priv->phandle);
+ priv->items_priv.items[priv->items_priv.num_of_items - 7].addr +=
+ (t_ptr) (priv->phandle);
+#ifdef SDIO_MMC_DEBUG
+ priv->items_priv.items[priv->items_priv.num_of_items - 8].addr +=
+ (t_ptr) (priv->phandle);
+ priv->items_priv.items[priv->items_priv.num_of_items - 9].addr +=
+ (t_ptr) (priv->phandle);
+#ifdef SDIO_SUSPEND_RESUME
+ priv->items_priv.items[priv->items_priv.num_of_items - 10].addr +=
+ (t_ptr) (priv->phandle);
+ priv->items_priv.items[priv->items_priv.num_of_items - 11].addr +=
+ (t_ptr) (priv->phandle);
+#endif
+#else
+#if defined(SDIO_SUSPEND_RESUME)
+ priv->items_priv.items[priv->items_priv.num_of_items - 8].addr +=
+ (t_ptr) (priv->phandle);
+ priv->items_priv.items[priv->items_priv.num_of_items - 9].addr +=
+ (t_ptr) (priv->phandle);
+#endif
+#endif
+
+ /* Create proc entry */
+ r = create_proc_entry("debug", 0644, priv->proc_entry);
+ if (r == NULL) {
+ LEAVE();
+ return;
+ }
+ r->data = &priv->items_priv;
+ r->read_proc = woal_debug_read;
+ r->write_proc = woal_debug_write;
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,30)
+ r->owner = THIS_MODULE;
+#endif
+
+ LEAVE();
+}
+
+/**
+ * @brief Remove proc file
+ *
+ * @param priv A pointer to a moal_private structure
+ *
+ * @return N/A
+ */
+void
+woal_debug_remove(moal_private * priv)
+{
+ ENTER();
+
+ if (priv->items_priv.items)
+ kfree(priv->items_priv.items);
+ /* Remove proc entry */
+ remove_proc_entry("debug", priv->proc_entry);
+
+ LEAVE();
+}
+#endif
diff --git a/drivers/net/wireless/sd8797/mlinux/moal_eth_ioctl.c b/drivers/net/wireless/sd8797/mlinux/moal_eth_ioctl.c
new file mode 100644
index 000000000000..984400cd532f
--- /dev/null
+++ b/drivers/net/wireless/sd8797/mlinux/moal_eth_ioctl.c
@@ -0,0 +1,1143 @@
+/** @file moal_eth_ioctl.c
+ *
+ * @brief This file contains private ioctl functions
+ *
+ * Copyright (C) 2012, Marvell International Ltd.
+ *
+ * This software file (the "File") is distributed by Marvell International
+ * Ltd. under the terms of the GNU General Public License Version 2, June 1991
+ * (the "License"). You may use, redistribute and/or modify this File in
+ * accordance with the terms and conditions of the License, a copy of which
+ * is available by writing to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
+ * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
+ *
+ * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
+ * ARE EXPRESSLY DISCLAIMED. The License provides additional details about
+ * this warranty disclaimer.
+ *
+ */
+
+/************************************************************************
+Change log:
+ 01/05/2012: initial version
+************************************************************************/
+
+#include "moal_main.h"
+#include "moal_eth_ioctl.h"
+#include "mlan_ioctl.h"
+#if defined(STA_WEXT) || defined(UAP_WEXT)
+#include "moal_priv.h"
+#endif
+
+#if defined(STA_CFG80211) && defined(UAP_CFG80211)
+#include "moal_cfg80211.h"
+#endif
+#ifdef UAP_SUPPORT
+#include "moal_uap.h"
+#endif
+/********************************************************
+ Local Variables
+********************************************************/
+
+/** Marvell private command identifier string */
+#define CMD_MARVELL "MRVL_CMD"
+
+/** Private command: Version */
+#define PRIV_CMD_VERSION "version"
+/** Private command: Band cfg */
+#define PRIV_CMD_BANDCFG "bandcfg"
+/** Private command: Host cmd */
+#define PRIV_CMD_HOSTCMD "hostcmd"
+/** Private command: HT Tx Cfg */
+#define PRIV_CMD_HTTXCFG "httxcfg"
+#define PRIV_CMD_DATARATE "getdatarate"
+#define PRIV_CMD_TXRATECFG "txratecfg"
+
+/** Bands supported in Infra mode */
+static t_u8 SupportedInfraBand[] = {
+ BAND_B,
+ BAND_B | BAND_G, BAND_G,
+ BAND_GN, BAND_B | BAND_G | BAND_GN, BAND_G | BAND_GN,
+ BAND_A, BAND_B | BAND_A, BAND_B | BAND_G | BAND_A, BAND_G | BAND_A,
+ BAND_A | BAND_B | BAND_G | BAND_AN | BAND_GN,
+ BAND_A | BAND_G | BAND_AN | BAND_GN, BAND_A | BAND_AN,
+};
+
+/** Bands supported in Ad-Hoc mode */
+static t_u8 SupportedAdhocBand[] = {
+ BAND_B, BAND_B | BAND_G, BAND_G,
+ BAND_GN, BAND_B | BAND_G | BAND_GN, BAND_G | BAND_GN,
+ BAND_A,
+ BAND_AN, BAND_A | BAND_AN,
+};
+
+/********************************************************
+ Global Variables
+********************************************************/
+
+/********************************************************
+ Local Functions
+********************************************************/
+/**
+ * @brief Parse a string to extract arguments
+ *
+ * @param pos Pointer to the arguments string
+ * @param data Pointer to the arguments buffer
+ * @param len Pointer to the number of arguments extracted
+ *
+ * @return MLAN_STATUS_SUCCESS
+ *
+ * N.B. No boundary check is done on 'data'. The caller must ensure there
+ * are enough space for all extracted arguments.
+ */
+mlan_status
+parse_arguments(t_u8 * pos, int *data, int *user_data_len)
+{
+ unsigned int i, j, k;
+ char cdata[10];
+ int is_hex = 0;
+
+ memset(cdata, 0, sizeof(cdata));
+ for (i = 0, j = 0, k = 0; i <= strlen(pos); i++) {
+ if ((k == 0) && (i <= (strlen(pos) - 2))) {
+ if ((pos[i] == '0') && (pos[i + 1] == 'x')) {
+ is_hex = 1;
+ i = i + 2;
+ }
+ }
+ if (pos[i] == '\0') {
+ if (is_hex) {
+ data[j] = woal_atox(cdata);
+ is_hex = 0;
+ } else {
+ woal_atoi(&data[j], cdata);
+ }
+ j++;
+ (*user_data_len)++;
+ k = 0;
+ memset(cdata, 0, sizeof(char) * 4);
+ break;
+ } else if (pos[i] == ' ') {
+ if (is_hex) {
+ data[j] = woal_atox(cdata);
+ is_hex = 0;
+ } else {
+ woal_atoi(&data[j], cdata);
+ }
+ j++;
+ (*user_data_len)++;
+ k = 0;
+ memset(cdata, 0, sizeof(char) * 4);
+ } else {
+ cdata[k] = pos[i];
+ k++;
+ }
+ }
+
+ return MLAN_STATUS_SUCCESS;
+}
+
+#if defined(STA_CFG80211) && defined(UAP_CFG80211)
+/**
+ * @brief Set wps & p2p ie in AP mode
+ *
+ * @param priv Pointer to priv stucture
+ * @param ie Pointer to ies data
+ * @param len Length of data
+ *
+ * @return MLAN_STATUS_SUCCESS -- success, otherwise fail
+ */
+mlan_status
+woal_set_ap_wps_p2p_ie(moal_private * priv, t_u8 * ie, size_t len)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ t_u8 *pos = ie;
+ t_u32 ie_len;
+
+ ENTER();
+
+ ie_len = len - 2;
+ if (ie_len <= 0 || ie_len > MAX_IE_SIZE) {
+ PRINTM(MERROR, "IE len error: %d\n", ie_len);
+ ret = -EFAULT;
+ goto done;
+ }
+
+ /* Android cmd format: "SET_AP_WPS_P2P_IE 1" -- beacon IE
+ "SET_AP_WPS_P2P_IE 2" -- proberesp IE "SET_AP_WPS_P2P_IE 4" -- assocresp
+ IE */
+ if (*pos == '1') {
+ PRINTM(MIOCTL, "Ignore set beacon ie\n");
+ goto done;
+ } else if (*pos == '2') {
+ /* set the probe resp ies */
+ pos += 2;
+ if (MLAN_STATUS_SUCCESS != woal_cfg80211_mgmt_frame_ie(priv, NULL,
+ 0, pos, ie_len,
+ NULL, 0, NULL, 0,
+ MGMT_MASK_PROBE_RESP))
+ {
+ PRINTM(MERROR, "Failed to set probe resp ie\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ } else if (*pos == '4') {
+ /* set the assoc resp ies */
+ pos += 2;
+ if (MLAN_STATUS_SUCCESS != woal_cfg80211_mgmt_frame_ie(priv, NULL,
+ 0, NULL, 0, pos,
+ ie_len, NULL, 0,
+ MGMT_MASK_ASSOC_RESP))
+ {
+ PRINTM(MERROR, "Failed to set assoc resp ie\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ }
+
+ done:
+ LEAVE();
+ return ret;
+}
+#endif
+
+/**
+ * @brief Get Driver Version
+ *
+ * @param priv A pointer to moal_private structure
+ * @param respbuf A pointer to response buffer
+ * @param respbuflen Available length of response buffer
+ *
+ * @return Number of bytes written, negative for failure.
+ */
+int
+woal_get_priv_driver_version(moal_private * priv, t_u8 * respbuf,
+ t_u32 respbuflen)
+{
+ int len = 0, ret = -1;
+ char buf[MLAN_MAX_VER_STR_LEN];
+
+ ENTER();
+
+ if (!respbuf) {
+ LEAVE();
+ return 0;
+ }
+
+ memset(buf, 0, sizeof(buf));
+
+ /* Get version string to local buffer */
+ woal_get_version(priv->phandle, buf, sizeof(buf) - 1);
+ len = strlen(buf);
+
+ if (len) {
+ /* Copy back the retrieved version string */
+ PRINTM(MINFO, "MOAL VERSION: %s\n", buf);
+ ret = MIN(len, (respbuflen - 1));
+ memcpy(respbuf, buf, ret);
+ } else {
+ ret = -1;
+ PRINTM(MERROR, "Get version failed!\n");
+ }
+
+ LEAVE();
+ return ret;
+}
+
+#ifdef WIFI_DIRECT_SUPPORT
+/**
+ * @brief Hostcmd interface from application
+ *
+ * @param priv A pointer to moal_private structure
+ * @param respbuf A pointer to response buffer
+ * @param respbuflen Available length of response buffer
+ *
+ * @return Number of bytes written, negative for failure.
+ */
+int
+woal_priv_hostcmd(moal_private * priv, t_u8 * respbuf, t_u32 respbuflen)
+{
+ int ret = 0;
+ t_u8 *data_ptr;
+ t_u32 buf_len = 0;
+ HostCmd_Header cmd_header;
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_misc_cfg *misc_cfg = NULL;
+
+ ENTER();
+
+ data_ptr = respbuf + (strlen(CMD_MARVELL) + strlen(PRIV_CMD_HOSTCMD));
+ buf_len = *((t_u32 *) data_ptr);
+ memcpy(&cmd_header, data_ptr + sizeof(buf_len), sizeof(HostCmd_Header));
+
+ PRINTM(MINFO, "Host command len = %d\n", woal_le16_to_cpu(cmd_header.size));
+ if (woal_le16_to_cpu(cmd_header.size) > MLAN_SIZE_OF_CMD_BUFFER) {
+ LEAVE();
+ return -EINVAL;
+ }
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto error;
+ }
+ misc_cfg = (mlan_ds_misc_cfg *) req->pbuf;
+ misc_cfg->sub_command = MLAN_OID_MISC_HOST_CMD;
+ req->req_id = MLAN_IOCTL_MISC_CFG;
+ req->action = MLAN_ACT_SET;
+ misc_cfg->param.hostcmd.len = woal_le16_to_cpu(cmd_header.size);
+ /* get the whole command */
+ memcpy(misc_cfg->param.hostcmd.cmd, data_ptr + sizeof(buf_len),
+ misc_cfg->param.hostcmd.len);
+
+ if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) {
+ ret = -EFAULT;
+ goto error;
+ }
+ sprintf(respbuf, "OK");
+ ret = 3;
+
+ error:
+ if (req)
+ kfree(req);
+
+ LEAVE();
+ return ret;
+}
+#endif
+
+/**
+ * @brief Set/Get Band and Adhoc-band setting
+ *
+ * @param priv A pointer to moal_private structure
+ * @param respbuf A pointer to response buffer
+ * @param respbuflen Available length of response buffer
+ *
+ * @return Number of bytes written, negative for failure.
+ */
+int
+woal_setget_priv_bandcfg(moal_private * priv, t_u8 * respbuf, t_u32 respbuflen)
+{
+ int ret = 0;
+ unsigned int i;
+ int data[4];
+ int user_data_len = 0;
+ t_u32 infra_band = 0;
+ t_u32 adhoc_band = 0;
+ t_u32 adhoc_channel = 0;
+ t_u32 adhoc_chan_bandwidth = 0;
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_radio_cfg *radio_cfg = NULL;
+ mlan_ds_band_cfg *band_cfg = NULL;
+
+ ENTER();
+
+ if (strlen(respbuf) == (strlen(CMD_MARVELL) + strlen(PRIV_CMD_BANDCFG))) {
+ /* GET operation */
+ user_data_len = 0;
+ } else {
+ /* SET operation */
+ memset((char *) data, 0, sizeof(data));
+ parse_arguments(respbuf + strlen(CMD_MARVELL) +
+ strlen(PRIV_CMD_BANDCFG), data, &user_data_len);
+ }
+
+ if (sizeof(int) * user_data_len > sizeof(data)) {
+ PRINTM(MERROR, "Too many arguments\n");
+ LEAVE();
+ return -EINVAL;
+ }
+
+ if (user_data_len > 0) {
+ if (priv->media_connected == MTRUE) {
+ LEAVE();
+ return -EOPNOTSUPP;
+ }
+ }
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_radio_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto error;
+ }
+ radio_cfg = (mlan_ds_radio_cfg *) req->pbuf;
+ radio_cfg->sub_command = MLAN_OID_BAND_CFG;
+ req->req_id = MLAN_IOCTL_RADIO_CFG;
+
+ if (user_data_len == 0) {
+ /* Get config_bands, adhoc_start_band and adhoc_channel values from
+ MLAN */
+ req->action = MLAN_ACT_GET;
+ } else {
+ /* To support only <b/bg/bgn/n/aac/gac> */
+ infra_band = data[0];
+ for (i = 0; i < sizeof(SupportedInfraBand); i++)
+ if (infra_band == SupportedInfraBand[i])
+ break;
+ if (i == sizeof(SupportedInfraBand)) {
+ ret = -EINVAL;
+ goto error;
+ }
+
+ /* Set Adhoc band */
+ if (user_data_len >= 2) {
+ adhoc_band = data[1];
+ for (i = 0; i < sizeof(SupportedAdhocBand); i++)
+ if (adhoc_band == SupportedAdhocBand[i])
+ break;
+ if (i == sizeof(SupportedAdhocBand)) {
+ ret = -EINVAL;
+ goto error;
+ }
+ }
+
+ /* Set Adhoc channel */
+ if (user_data_len >= 3) {
+ adhoc_channel = data[2];
+ if (adhoc_channel == 0) {
+ /* Check if specified adhoc channel is non-zero */
+ ret = -EINVAL;
+ goto error;
+ }
+ }
+ if (user_data_len == 4) {
+ if (!(adhoc_band & (BAND_GN | BAND_AN))) {
+ PRINTM(MERROR,
+ "11n is not enabled for adhoc, can not set HT/VHT channel bandwidth\n");
+ ret = -EINVAL;
+ goto error;
+ }
+ adhoc_chan_bandwidth = data[3];
+ /* sanity test */
+ if ((adhoc_chan_bandwidth != CHANNEL_BW_20MHZ) &&
+ (adhoc_chan_bandwidth != CHANNEL_BW_40MHZ_ABOVE) &&
+ (adhoc_chan_bandwidth != CHANNEL_BW_40MHZ_BELOW)
+ ) {
+ PRINTM(MERROR,
+ "Invalid secondary channel bandwidth, only allowed 0, 1, 3 or 4\n");
+ ret = -EINVAL;
+ goto error;
+ }
+
+ }
+ /* Set config_bands and adhoc_start_band values to MLAN */
+ req->action = MLAN_ACT_SET;
+ radio_cfg->param.band_cfg.config_bands = infra_band;
+ radio_cfg->param.band_cfg.adhoc_start_band = adhoc_band;
+ radio_cfg->param.band_cfg.adhoc_channel = adhoc_channel;
+ radio_cfg->param.band_cfg.sec_chan_offset = adhoc_chan_bandwidth;
+ }
+
+ if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) {
+ ret = -EFAULT;
+ goto error;
+ }
+
+ band_cfg = (mlan_ds_band_cfg *) respbuf;
+
+ memcpy(band_cfg, &radio_cfg->param.band_cfg, sizeof(mlan_ds_band_cfg));
+
+ ret = sizeof(mlan_ds_band_cfg);
+
+ error:
+ if (req)
+ kfree(req);
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set/Get 11n configurations
+ *
+ * @param priv A pointer to moal_private structure
+ * @param respbuf A pointer to response buffer
+ * @param respbuflen Available length of response buffer
+ *
+ * @return Number of bytes written, negative for failure.
+ */
+int
+woal_setget_priv_httxcfg(moal_private * priv, t_u8 * respbuf, t_u32 respbuflen)
+{
+ int data[2];
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_11n_cfg *cfg_11n = NULL;
+ int ret = 0;
+ int user_data_len = 0;
+
+ ENTER();
+
+ if (strlen(respbuf) == (strlen(CMD_MARVELL) + strlen(PRIV_CMD_HTTXCFG))) {
+ /* GET operation */
+ user_data_len = 0;
+ } else {
+ /* SET operation */
+ memset((char *) data, 0, sizeof(data));
+ parse_arguments(respbuf + strlen(CMD_MARVELL) +
+ strlen(PRIV_CMD_HTTXCFG), data, &user_data_len);
+ }
+
+ if (user_data_len > 2) {
+ PRINTM(MERROR, "Invalid number of arguments\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_11n_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ cfg_11n = (mlan_ds_11n_cfg *) req->pbuf;
+ cfg_11n->sub_command = MLAN_OID_11N_CFG_TX;
+ req->req_id = MLAN_IOCTL_11N_CFG;
+
+ if (user_data_len == 0) {
+ /* Get 11n tx parameters from MLAN */
+ req->action = MLAN_ACT_GET;
+ cfg_11n->param.tx_cfg.misc_cfg = BAND_SELECT_BG;
+ } else {
+ cfg_11n->param.tx_cfg.httxcap = data[0];
+ PRINTM(MINFO, "SET: httxcap:0x%x\n", data[0]);
+ cfg_11n->param.tx_cfg.misc_cfg = BAND_SELECT_BOTH;
+ if (user_data_len == 2) {
+ if (data[1] != BAND_SELECT_BG &&
+ data[1] != BAND_SELECT_A && data[1] != BAND_SELECT_BOTH) {
+ PRINTM(MERROR, "Invalid band selection\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ cfg_11n->param.tx_cfg.misc_cfg = data[1];
+ PRINTM(MINFO, "SET: httxcap band:0x%x\n", data[1]);
+ }
+ /* Update 11n tx parameters in MLAN */
+ req->action = MLAN_ACT_SET;
+ }
+ if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ data[0] = cfg_11n->param.tx_cfg.httxcap;
+
+ if (req->action == MLAN_ACT_GET) {
+ user_data_len = 1;
+ cfg_11n->param.tx_cfg.httxcap = 0;
+ cfg_11n->param.tx_cfg.misc_cfg = BAND_SELECT_A;
+ if (MLAN_STATUS_SUCCESS !=
+ woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ if (cfg_11n->param.tx_cfg.httxcap != data[0]) {
+ user_data_len = 2;
+ data[1] = cfg_11n->param.tx_cfg.httxcap;
+ PRINTM(MINFO, "GET: httxcap for 2.4GHz:0x%x\n", data[0]);
+ PRINTM(MINFO, "GET: httxcap for 5GHz:0x%x\n", data[1]);
+ } else
+ PRINTM(MINFO, "GET: httxcap:0x%x\n", data[0]);
+ }
+
+ sprintf(respbuf, "0x%x", data[0]);
+ ret = strlen(respbuf) + 1;
+
+ done:
+ if (req)
+ kfree(req);
+ LEAVE();
+ return ret;
+
+}
+
+/**
+ * @brief Set/Get 11AC configurations
+ *
+ * @param priv A pointer to moal_private structure
+ * @param respbuf A pointer to response buffer
+ * @param respbuflen Available length of response buffer
+ *
+ * @return Number of bytes written, negative for failure.
+ */
+int
+woal_get_priv_datarate(moal_private * priv, t_u8 * respbuf, t_u32 respbuflen)
+{
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_rate *rate = NULL;
+ mlan_data_rate *data_rate = NULL;
+ int ret = 0;
+
+ ENTER();
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_rate));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ rate = (mlan_ds_rate *) req->pbuf;
+ rate->sub_command = MLAN_OID_GET_DATA_RATE;
+ req->req_id = MLAN_IOCTL_RATE;
+ req->action = MLAN_ACT_GET;
+
+ if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ data_rate = (mlan_data_rate *) respbuf;
+
+ memcpy(data_rate, &rate->param.data_rate, sizeof(mlan_data_rate));
+
+ ret = sizeof(mlan_data_rate);
+
+ done:
+ if (req)
+ kfree(req);
+ LEAVE();
+ return ret;
+
+}
+
+/**
+ * @brief Set/Get tx rate configurations
+ *
+ * @param priv A pointer to moal_private structure
+ * @param respbuf A pointer to response buffer
+ * @param respbuflen Available length of response buffer
+ *
+ * @return Number of bytes written, negative for failure.
+ */
+int
+woal_setget_priv_txratecfg(moal_private * priv, t_u8 * respbuf,
+ t_u32 respbuflen)
+{
+ t_u32 data[3];
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_rate *rate = NULL;
+ woal_tx_rate_cfg *ratecfg = NULL;
+ int ret = 0;
+ int user_data_len = 0;
+
+ ENTER();
+
+ if (strlen(respbuf) == (strlen(CMD_MARVELL) + strlen(PRIV_CMD_TXRATECFG))) {
+ /* GET operation */
+ user_data_len = 0;
+ } else {
+ /* SET operation */
+ memset((char *) data, 0, sizeof(data));
+ parse_arguments(respbuf + strlen(CMD_MARVELL) +
+ strlen(PRIV_CMD_TXRATECFG), data, &user_data_len);
+ }
+
+ if (user_data_len >= 4) {
+ PRINTM(MERROR, "Invalid number of arguments\n");
+ ret = -EINVAL;
+ goto done;
+ }
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_rate));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ req->req_id = MLAN_IOCTL_RATE;
+ rate = (mlan_ds_rate *) req->pbuf;
+ rate->sub_command = MLAN_OID_RATE_CFG;
+ rate->param.rate_cfg.rate_type = MLAN_RATE_INDEX;
+
+ if (user_data_len == 0) {
+ /* Get operation */
+ req->action = MLAN_ACT_GET;
+ } else {
+ /* Set operation */
+ req->action = MLAN_ACT_SET;
+ /* format */
+ if ((data[0] != AUTO_RATE) && (data[0] >= 3)) {
+ PRINTM(MERROR, "Invalid format selection\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ if (data[0] == AUTO_RATE) {
+ /* auto */
+ rate->param.rate_cfg.is_rate_auto = 1;
+ } else {
+ /* fixed rate */
+ PRINTM(MINFO, "SET: txratefg format: 0x%x\n", data[0]);
+ if ((data[0] != AUTO_RATE) && (data[0] > MLAN_RATE_FORMAT_HT)
+ ) {
+ PRINTM(MERROR, "Invalid format selection\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ }
+
+ if ((user_data_len >= 2) && (data[0] != AUTO_RATE)) {
+ PRINTM(MINFO, "SET: txratefg index: 0x%x\n", data[1]);
+ /* sanity check */
+ if (((data[0] == MLAN_RATE_FORMAT_LG) &&
+ (data[1] > MLAN_RATE_INDEX_OFDM7))
+ || ((data[0] == MLAN_RATE_FORMAT_HT) && (data[1] != 32) &&
+ (data[1] > 15))
+ ) {
+ PRINTM(MERROR, "Invalid index selection\n");
+ ret = -EINVAL;
+ goto done;
+ }
+
+ PRINTM(MINFO, "SET: txratefg index: 0x%x\n", data[1]);
+ rate->param.rate_cfg.rate = data[1];
+
+ if (data[0] == MLAN_RATE_FORMAT_HT) {
+ rate->param.rate_cfg.rate = data[1] + MLAN_RATE_INDEX_MCS0;
+ }
+ }
+
+ }
+
+ if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ ratecfg = (woal_tx_rate_cfg *) respbuf;
+ if (rate->param.rate_cfg.is_rate_auto == MTRUE) {
+ ratecfg->rate_format = 0xFF;
+ } else {
+ /* fixed rate */
+ if (rate->param.rate_cfg.rate < MLAN_RATE_INDEX_MCS0) {
+ ratecfg->rate_format = MLAN_RATE_FORMAT_LG;
+ ratecfg->rate_index = rate->param.rate_cfg.rate;
+ } else {
+ ratecfg->rate_format = MLAN_RATE_FORMAT_HT;
+ ratecfg->rate_index =
+ rate->param.rate_cfg.rate - MLAN_RATE_INDEX_MCS0;
+ }
+ }
+
+ ret = sizeof(woal_tx_rate_cfg);
+
+ done:
+ if (req)
+ kfree(req);
+ LEAVE();
+ return ret;
+
+}
+
+/**
+ * @brief Set priv command for Android
+ * @param dev A pointer to net_device structure
+ * @param req A pointer to ifreq structure
+ *
+ * @return 0 --success, otherwise fail
+ */
+int
+woal_android_priv_cmd(struct net_device *dev, struct ifreq *req)
+{
+ int ret = 0;
+ android_wifi_priv_cmd priv_cmd;
+ moal_private *priv = (moal_private *) netdev_priv(dev);
+ char *buf = NULL;
+ char *pdata;
+#ifdef STA_SUPPORT
+ int power_mode = 0;
+ int band = 0;
+ char *pband = NULL;
+ mlan_bss_info bss_info;
+ mlan_ds_get_signal signal;
+ mlan_rate_cfg_t rate;
+ t_u8 country_code[COUNTRY_CODE_LEN];
+#endif
+ int len = 0;
+
+ ENTER();
+ if (copy_from_user(&priv_cmd, req->ifr_data, sizeof(android_wifi_priv_cmd))) {
+ ret = -EFAULT;
+ goto done;
+ }
+ buf = kzalloc(priv_cmd.total_len, GFP_KERNEL);
+ if (!buf) {
+ PRINTM(MERROR, "%s: failed to allocate memory\n", __FUNCTION__);
+ ret = -ENOMEM;
+ goto done;
+ }
+ if (copy_from_user(buf, priv_cmd.buf, priv_cmd.total_len)) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ PRINTM(MIOCTL, "Android priv cmd: [%s] on [%s]\n", buf, req->ifr_name);
+
+ if (strncmp(buf, CMD_MARVELL, strlen(CMD_MARVELL)) == 0) {
+ /* This command has come from mlanutl app */
+
+ /* Check command */
+ if (strnicmp
+ (buf + strlen(CMD_MARVELL), PRIV_CMD_VERSION,
+ strlen(PRIV_CMD_VERSION)) == 0) {
+ /* Get version */
+ len = woal_get_priv_driver_version(priv, buf, priv_cmd.total_len);
+ goto handled;
+ } else
+ if (strnicmp
+ (buf + strlen(CMD_MARVELL), PRIV_CMD_BANDCFG,
+ strlen(PRIV_CMD_BANDCFG)) == 0) {
+ /* Set/Get band configuration */
+ len = woal_setget_priv_bandcfg(priv, buf, priv_cmd.total_len);
+ goto handled;
+#ifdef WIFI_DIRECT_SUPPORT
+ } else
+ if (strnicmp
+ (buf + strlen(CMD_MARVELL), PRIV_CMD_HOSTCMD,
+ strlen(PRIV_CMD_HOSTCMD)) == 0) {
+ /* hostcmd configuration */
+ len = woal_priv_hostcmd(priv, buf, priv_cmd.total_len);
+ goto handled;
+#endif
+ } else
+ if (strnicmp
+ (buf + strlen(CMD_MARVELL), PRIV_CMD_HTTXCFG,
+ strlen(PRIV_CMD_HTTXCFG)) == 0) {
+ /* Set/Get HT Tx configuration */
+ len = woal_setget_priv_httxcfg(priv, buf, priv_cmd.total_len);
+ goto handled;
+ } else
+ if (strnicmp
+ (buf + strlen(CMD_MARVELL), PRIV_CMD_DATARATE,
+ strlen(PRIV_CMD_DATARATE)) == 0) {
+ /* Get data rate */
+ len = woal_get_priv_datarate(priv, buf, priv_cmd.total_len);
+ goto handled;
+ } else
+ if (strnicmp
+ (buf + strlen(CMD_MARVELL), PRIV_CMD_TXRATECFG,
+ strlen(PRIV_CMD_TXRATECFG)) == 0) {
+ /* Set/Get tx rate cfg */
+ len = woal_setget_priv_txratecfg(priv, buf, priv_cmd.total_len);
+ goto handled;
+ } else {
+ /* Fall through, after stripping off the custom header */
+ buf += strlen(CMD_MARVELL);
+ }
+ }
+#ifdef STA_SUPPORT
+ if (strncmp(buf, "RSSI", strlen("RSSI")) == 0) {
+ if (MLAN_STATUS_SUCCESS != woal_get_bss_info(priv,
+ MOAL_IOCTL_WAIT,
+ &bss_info)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ if (bss_info.media_connected) {
+ if (MLAN_STATUS_SUCCESS != woal_get_signal_info(priv,
+ MOAL_IOCTL_WAIT,
+ &signal)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ len = sprintf(buf, "%s rssi %d\n", bss_info.ssid.ssid,
+ signal.bcn_rssi_avg) + 1;
+ } else {
+ len = sprintf(buf, "OK\n") + 1;
+ }
+ } else if (strncmp(buf, "LINKSPEED", strlen("LINKSPEED")) == 0) {
+ if (MLAN_STATUS_SUCCESS != woal_set_get_data_rate(priv, MLAN_ACT_GET,
+ &rate)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ PRINTM(MIOCTL, "tx rate=%d\n", (int) rate.rate);
+ len =
+ sprintf(buf, "LinkSpeed %d\n", (int) (rate.rate * 500000 / 1000000))
+ + 1;
+ } else
+#endif
+ if (strncmp(buf, "MACADDR", strlen("MACADDR")) == 0) {
+ len = sprintf(buf, "Macaddr = %02X:%02X:%02X:%02X:%02X:%02X\n",
+ priv->current_addr[0], priv->current_addr[1],
+ priv->current_addr[2], priv->current_addr[3],
+ priv->current_addr[4], priv->current_addr[5]) + 1;
+ }
+#ifdef STA_SUPPORT
+ else if (strncmp(buf, "GETPOWER", strlen("GETPOWER")) == 0) {
+ if (MLAN_STATUS_SUCCESS != woal_get_powermode(priv, &power_mode)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ len = sprintf(buf, "powermode = %d\n", power_mode) + 1;
+ } else if (strncmp(buf, "SCAN-ACTIVE", strlen("SCAN-ACTIVE")) == 0) {
+ if (MLAN_STATUS_SUCCESS != woal_set_scan_type(priv,
+ MLAN_SCAN_TYPE_ACTIVE)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ priv->scan_type = MLAN_SCAN_TYPE_ACTIVE;
+ PRINTM(MIOCTL, "Set Active Scan\n");
+ len = sprintf(buf, "OK\n") + 1;
+ } else if (strncmp(buf, "SCAN-PASSIVE", strlen("SCAN-PASSIVE")) == 0) {
+ if (MLAN_STATUS_SUCCESS != woal_set_scan_type(priv,
+ MLAN_SCAN_TYPE_PASSIVE)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ priv->scan_type = MLAN_SCAN_TYPE_PASSIVE;
+ PRINTM(MIOCTL, "Set Passive Scan\n");
+ len = sprintf(buf, "OK\n") + 1;
+ } else if (strncmp(buf, "POWERMODE", strlen("POWERMODE")) == 0) {
+ pdata = buf + strlen("POWERMODE") + 1;
+ if (MLAN_STATUS_SUCCESS != woal_set_powermode(priv, pdata)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ len = sprintf(buf, "OK\n") + 1;
+ } else if (strncmp(buf, "COUNTRY", strlen("COUNTRY")) == 0) {
+ memset(country_code, 0, sizeof(country_code));
+ memcpy(country_code, buf + strlen("COUNTRY") + 1,
+ strlen(buf) - strlen("COUNTRY") - 1);
+ PRINTM(MIOCTL, "Set COUNTRY %s\n", country_code);
+ if (MLAN_STATUS_SUCCESS != woal_set_region_code(priv, country_code)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ len = sprintf(buf, "OK\n") + 1;
+ } else if (memcmp(buf, WEXT_CSCAN_HEADER, WEXT_CSCAN_HEADER_SIZE) == 0) {
+ PRINTM(MIOCTL, "Set Combo Scan\n");
+ if (MLAN_STATUS_SUCCESS != woal_set_combo_scan(priv, buf,
+ priv_cmd.total_len)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ len = sprintf(buf, "OK\n") + 1;
+ } else if (strncmp(buf, "GETBAND", strlen("GETBAND")) == 0) {
+ if (MLAN_STATUS_SUCCESS != woal_get_band(priv, &band)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ len = sprintf(buf, "Band %d\n", band) + 1;
+ } else if (strncmp(buf, "SETBAND", strlen("SETBAND")) == 0) {
+ pband = buf + strlen("SETBAND") + 1;
+ if (MLAN_STATUS_SUCCESS != woal_set_band(priv, pband)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ len = sprintf(buf, "OK\n") + 1;
+ }
+#endif
+ else if (strncmp(buf, "START", strlen("START")) == 0) {
+ len = sprintf(buf, "OK\n") + 1;
+ } else if (strncmp(buf, "STOP", strlen("STOP")) == 0) {
+ len = sprintf(buf, "OK\n") + 1;
+ }
+#ifdef UAP_SUPPORT
+ else if (strncmp(buf, "AP_BSS_START", strlen("AP_BSS_START")) == 0) {
+ if ((ret == woal_uap_bss_ctrl(priv, MOAL_IOCTL_WAIT, UAP_BSS_START)))
+ goto done;
+ len = sprintf(buf, "OK\n") + 1;
+ } else if (strncmp(buf, "AP_BSS_STOP", strlen("AP_BSS_STOP")) == 0) {
+ if ((ret == woal_uap_bss_ctrl(priv, MOAL_IOCTL_WAIT, UAP_BSS_STOP)))
+ goto done;
+ len = sprintf(buf, "OK\n") + 1;
+ } else if (strncmp(buf, "AP_SET_CFG", strlen("AP_SET_CFG")) == 0) {
+ pdata = buf + strlen("AP_SET_CFG") + 1;
+ if ((ret =
+ woal_uap_set_ap_cfg(priv, pdata,
+ priv_cmd.used_len - strlen("AP_SET_CFG") - 1)))
+ goto done;
+ len = sprintf(buf, "OK\n") + 1;
+ } else if (strncmp(buf, "WL_FW_RELOAD", strlen("WL_FW_RELOAD")) == 0) {
+ len = sprintf(buf, "OK\n") + 1;
+ } else if (strncmp(buf, "AP_GET_STA_LIST", strlen("AP_GET_STA_LIST")) == 0) {
+ // TODO Add STA list support
+ len = sprintf(buf, "OK\n") + 1;
+ }
+#endif
+ else if (strncmp(buf, "SETSUSPENDOPT", strlen("SETSUSPENDOPT")) == 0) {
+ /* it will be done by GUI */
+ len = sprintf(buf, "OK\n") + 1;
+ } else if (strncmp(buf, "BTCOEXMODE", strlen("BTCOEXMODE")) == 0) {
+ len = sprintf(buf, "OK\n") + 1;
+ } else if (strncmp(buf, "BTCOEXSCAN-START", strlen("BTCOEXSCAN-START")) ==
+ 0) {
+ len = sprintf(buf, "OK\n") + 1;
+ } else if (strncmp(buf, "BTCOEXSCAN-STOP", strlen("BTCOEXSCAN-STOP")) == 0) {
+ len = sprintf(buf, "OK\n") + 1;
+ } else if (strncmp(buf, "BTCOEXSCAN-START", strlen("BTCOEXSCAN-START")) ==
+ 0) {
+ len = sprintf(buf, "OK\n") + 1;
+ } else if (strncmp(buf, "BTCOEXSCAN-STOP", strlen("BTCOEXSCAN-STOP")) == 0) {
+ len = sprintf(buf, "OK\n") + 1;
+ }
+#ifdef STA_SUPPORT
+ else if (strncmp(buf, "BGSCAN-START", strlen("BGSCAN-START")) == 0) {
+ len = sprintf(buf, "OK\n") + 1;
+ } else if (strncmp(buf, "BGSCAN-CONFIG", strlen("BGSCAN-CONFIG")) == 0) {
+ if (MLAN_STATUS_SUCCESS !=
+ woal_set_bg_scan(priv, buf, priv_cmd.total_len)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ priv->bg_scan_start = MTRUE;
+ priv->bg_scan_reported = MFALSE;
+ len = sprintf(buf, "OK\n") + 1;
+ } else if (strncmp(buf, "BGSCAN-STOP", strlen("BGSCAN-STOP")) == 0) {
+ if (MLAN_STATUS_SUCCESS != woal_stop_bg_scan(priv)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ priv->bg_scan_start = MFALSE;
+ priv->bg_scan_reported = MFALSE;
+ len = sprintf(buf, "OK\n") + 1;
+ } else if (strncmp(buf, "RXFILTER-START", strlen("RXFILTER-START")) == 0) {
+#ifdef MEF_CFG_RX_FILTER
+ if ((ret = woal_set_rxfilter(priv, MTRUE))) {
+ goto done;
+ }
+#endif
+ len = sprintf(buf, "OK\n") + 1;
+ } else if (strncmp(buf, "RXFILTER-STOP", strlen("RXFILTER-STOP")) == 0) {
+#ifdef MEF_CFG_RX_FILTER
+ if ((ret = woal_set_rxfilter(priv, MFALSE))) {
+ goto done;
+ }
+#endif
+ len = sprintf(buf, "OK\n") + 1;
+ } else if (strncmp(buf, "RXFILTER-ADD", strlen("RXFILTER-ADD")) == 0) {
+ pdata = buf + strlen("RXFILTER-ADD") + 1;
+ if (MLAN_STATUS_SUCCESS != woal_add_rxfilter(priv, pdata)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ len = sprintf(buf, "OK\n") + 1;
+ } else if (strncmp(buf, "RXFILTER-REMOVE", strlen("RXFILTER-REMOVE")) == 0) {
+ pdata = buf + strlen("RXFILTER-REMOVE") + 1;
+ if (MLAN_STATUS_SUCCESS != woal_remove_rxfilter(priv, pdata)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ len = sprintf(buf, "OK\n") + 1;
+ } else if (strncmp(buf, "QOSINFO", strlen("QOSINFO")) == 0) {
+ pdata = buf + strlen("QOSINFO") + 1;
+ if (MLAN_STATUS_SUCCESS != woal_set_qos_cfg(priv, pdata)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ len = sprintf(buf, "OK\n") + 1;
+ } else if (strncmp(buf, "SLEEPPD", strlen("SLEEPPD")) == 0) {
+ pdata = buf + strlen("SLEEPPD") + 1;
+ if (MLAN_STATUS_SUCCESS != woal_set_sleeppd(priv, pdata)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ len = sprintf(buf, "OK\n") + 1;
+ } else if (strncmp(buf, "SET_AP_WPS_P2P_IE",
+ strlen("SET_AP_WPS_P2P_IE")) == 0) {
+ pdata = buf + strlen("SET_AP_WPS_P2P_IE") + 1;
+ /* Android cmd format: "SET_AP_WPS_P2P_IE 1" -- beacon IE
+ "SET_AP_WPS_P2P_IE 2" -- proberesp IE "SET_AP_WPS_P2P_IE 4" --
+ assocresp IE */
+#if defined(STA_CFG80211) && defined(UAP_CFG80211)
+ if (MLAN_STATUS_SUCCESS != woal_set_ap_wps_p2p_ie(priv, (t_u8 *) pdata,
+ priv_cmd.used_len -
+ strlen
+ ("SET_AP_WPS_P2P_IE")
+ - 1)) {
+ ret = -EFAULT;
+ goto done;
+ }
+#endif
+ len = sprintf(buf, "OK\n") + 1;
+ }
+#endif
+ else if (strncmp(buf, "P2P_DEV_ADDR", strlen("P2P_DEV_ADDR")) == 0) {
+ memset(buf, 0x0, priv_cmd.total_len);
+ memcpy(buf, priv->current_addr, ETH_ALEN);
+ len = ETH_ALEN;
+ } else if (strncmp(buf, ("P2P_GET_NOA"), strlen("P2P_GET_NOA")) == 0) {
+ /* TODO Just return '\0' */
+ memset(buf, 0x0, priv_cmd.total_len);
+ *buf = 0;
+ len = 1;
+ } else {
+ PRINTM(MIOCTL, "Unknow PRIVATE command: %s, ignored\n", buf);
+ ret = -EFAULT;
+ goto done;
+ }
+
+ handled:
+ PRINTM(MIOCTL, "PRIV Command return: %s, length=%d\n", buf, len);
+
+ if (len > 0) {
+ priv_cmd.used_len = len;
+ if (copy_to_user(priv_cmd.buf, buf, len)) {
+ PRINTM(MERROR, "%s: failed to copy data to user buffer\n",
+ __FUNCTION__);
+ ret = -EFAULT;
+ }
+ } else {
+ ret = len;
+ }
+
+ done:
+ if (buf)
+ kfree(buf);
+ LEAVE();
+ return ret;
+}
+
+/********************************************************
+ Global Functions
+********************************************************/
+/**
+ * @brief ioctl function - entry point
+ *
+ * @param dev A pointer to net_device structure
+ * @param req A pointer to ifreq structure
+ * @param cmd Command
+ *
+ * @return 0 --success, otherwise fail
+ */
+int
+woal_do_ioctl(struct net_device *dev, struct ifreq *req, int cmd)
+{
+ int ret = 0;
+
+ ENTER();
+
+ PRINTM(MINFO, "woal_do_ioctl: ioctl cmd = 0x%x\n", cmd);
+ switch (cmd) {
+#ifdef WIFI_DIRECT_SUPPORT
+ case WOAL_WIFIDIRECT_HOST_CMD:
+ ret = woal_hostcmd_ioctl(dev, req);
+ break;
+#endif
+ case WOAL_CUSTOM_IE_CFG:
+ ret = woal_custom_ie_ioctl(dev, req);
+ break;
+ case WOAL_MGMT_FRAME_TX:
+ ret = woal_send_host_packet(dev, req);
+ break;
+ case WOAL_ANDROID_PRIV_CMD:
+ ret = woal_android_priv_cmd(dev, req);
+ break;
+ case WOAL_GET_BSS_TYPE:
+ ret = woal_get_bss_type(dev, req);
+ break;
+ default:
+#if defined(STA_WEXT)
+#ifdef STA_SUPPORT
+ ret = woal_wext_do_ioctl(dev, req, cmd);
+#else
+ ret = -EINVAL;
+#endif
+#else
+ ret = -EINVAL;
+#endif
+ break;
+ }
+
+ LEAVE();
+ return ret;
+}
diff --git a/drivers/net/wireless/sd8797/mlinux/moal_eth_ioctl.h b/drivers/net/wireless/sd8797/mlinux/moal_eth_ioctl.h
new file mode 100644
index 000000000000..a1481e88ff21
--- /dev/null
+++ b/drivers/net/wireless/sd8797/mlinux/moal_eth_ioctl.h
@@ -0,0 +1,69 @@
+/** @file moal_eth_ioctl.h
+ *
+ * @brief This file contains definition for private IOCTL call.
+ *
+ * Copyright (C) 2012, Marvell International Ltd.
+ *
+ * This software file (the "File") is distributed by Marvell International
+ * Ltd. under the terms of the GNU General Public License Version 2, June 1991
+ * (the "License"). You may use, redistribute and/or modify this File in
+ * accordance with the terms and conditions of the License, a copy of which
+ * is available by writing to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
+ * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
+ *
+ * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
+ * ARE EXPRESSLY DISCLAIMED. The License provides additional details about
+ * this warranty disclaimer.
+ *
+ */
+
+/********************************************************
+Change log:
+ 01/05/2012: initial version
+********************************************************/
+
+#ifndef _WOAL_ETH_PRIV_H_
+#define _WOAL_ETH_PRIV_H_
+
+#ifdef WIFI_DIRECT_SUPPORT
+/** Private command ID to Host command */
+#define WOAL_WIFIDIRECT_HOST_CMD (SIOCDEVPRIVATE + 1)
+#endif
+
+/** Private command ID to pass mgmt frame */
+#define WOAL_MGMT_FRAME_TX WOAL_MGMT_FRAME_TX_IOCTL
+
+/** Private command ID to pass custom IE list */
+#define WOAL_CUSTOM_IE_CFG (SIOCDEVPRIVATE + 13)
+
+/** Private command ID for Android ICS priv CMDs */
+#define WOAL_ANDROID_PRIV_CMD (SIOCDEVPRIVATE + 14)
+
+/** Private command ID to get BSS type */
+#define WOAL_GET_BSS_TYPE (SIOCDEVPRIVATE + 15)
+
+int woal_do_ioctl(struct net_device *dev, struct ifreq *req, int i);
+
+typedef struct _android_wifi_priv_cmd
+{
+ char *buf;
+ int used_len;
+ int total_len;
+} android_wifi_priv_cmd;
+
+/** data structure for cmd txratecfg */
+typedef struct woal_priv_tx_rate_cfg
+{
+ /* LG rate: 0, HT rate: 1, VHT rate: 2 */
+ t_u32 rate_format;
+ /** Rate/MCS index (0xFF: auto) */
+ t_u32 rate_index;
+} woal_tx_rate_cfg;
+
+mlan_status woal_set_ap_wps_p2p_ie(moal_private * priv, t_u8 * ie, size_t len);
+
+int woal_android_priv_cmd(struct net_device *dev, struct ifreq *req);
+
+#endif /* _WOAL_ETH_PRIV_H_ */
diff --git a/drivers/net/wireless/sd8797/mlinux/moal_ioctl.c b/drivers/net/wireless/sd8797/mlinux/moal_ioctl.c
new file mode 100644
index 000000000000..7928d37ad015
--- /dev/null
+++ b/drivers/net/wireless/sd8797/mlinux/moal_ioctl.c
@@ -0,0 +1,4307 @@
+/** @file moal_ioctl.c
+ *
+ * @brief This file contains ioctl function to MLAN
+ *
+ * Copyright (C) 2008-2011, Marvell International Ltd.
+ *
+ * This software file (the "File") is distributed by Marvell International
+ * Ltd. under the terms of the GNU General Public License Version 2, June 1991
+ * (the "License"). You may use, redistribute and/or modify this File in
+ * accordance with the terms and conditions of the License, a copy of which
+ * is available by writing to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
+ * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
+ *
+ * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
+ * ARE EXPRESSLY DISCLAIMED. The License provides additional details about
+ * this warranty disclaimer.
+ *
+ */
+
+/********************************************************
+Change log:
+ 10/21/2008: initial version
+********************************************************/
+
+#include "moal_main.h"
+#include "moal_eth_ioctl.h"
+#include "moal_sdio.h"
+#ifdef UAP_SUPPORT
+#include "moal_uap.h"
+#endif
+
+#if defined(STA_CFG80211) || defined(UAP_CFG80211)
+#include "moal_cfg80211.h"
+#endif
+
+/********************************************************
+ Local Variables
+********************************************************/
+/* CAC Measure report default time 60 seconds */
+#define MEAS_REPORT_TIME 60*HZ
+#define MRVL_TLV_HEADER_SIZE 4
+/* Marvell Channel config TLV ID */
+#define MRVL_CHANNELCONFIG_TLV_ID (0x0100 + 0x2a) // 0x012a
+
+typedef struct _hostcmd_header
+{
+ /** Command Header : Command */
+ t_u16 command;
+ /** Command Header : Size */
+ t_u16 size;
+ /** Command Header : Sequence number */
+ t_u16 seq_num;
+ /** Command Header : Result */
+ t_u16 result;
+ /** Command action */
+ t_u16 action;
+} hostcmd_header, *phostcmd_header;
+
+#ifdef STA_SUPPORT
+/** Region code mapping */
+typedef struct _region_code_mapping_t
+{
+ /** Region */
+ t_u8 region[COUNTRY_CODE_LEN];
+ /** Code */
+ t_u8 code;
+} region_code_mapping_t;
+
+/** Region code mapping table */
+static region_code_mapping_t region_code_mapping[] = {
+ {"US ", 0x10}, /* US FCC */
+ {"CA ", 0x20}, /* IC Canada */
+ {"SG ", 0x10}, /* Singapore */
+ {"EU ", 0x30}, /* ETSI */
+ {"AU ", 0x30}, /* Australia */
+ {"KR ", 0x30}, /* Republic Of Korea */
+ {"FR ", 0x32}, /* France */
+ {"CN ", 0x50}, /* China */
+ {"JP ", 0xFF}, /* Japan special */
+};
+#endif
+
+/********************************************************
+ Global Variables
+********************************************************/
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,29)
+#ifdef UAP_SUPPORT
+/** Network device handlers for uAP */
+extern const struct net_device_ops woal_uap_netdev_ops;
+#endif
+#ifdef STA_SUPPORT
+/** Network device handlers for STA */
+extern const struct net_device_ops woal_netdev_ops;
+#endif
+#endif
+extern int cfg80211_wext;
+
+/********************************************************
+ Local Functions
+********************************************************/
+#ifdef STA_SUPPORT
+/**
+ * @brief This function converts region string to region code
+ *
+ * @param region_string Region string
+ *
+ * @return Region code
+ */
+static t_u8
+region_string_2_region_code(char *region_string)
+{
+ t_u8 i;
+ t_u8 size = sizeof(region_code_mapping) / sizeof(region_code_mapping_t);
+
+ ENTER();
+ for (i = 0; i < size; i++) {
+ if (!memcmp(region_string,
+ region_code_mapping[i].region, strlen(region_string))) {
+ LEAVE();
+ return (region_code_mapping[i].code);
+ }
+ }
+ /* Default is US */
+ LEAVE();
+ return (region_code_mapping[0].code);
+}
+#endif
+
+/**
+ * @brief Copy multicast table
+ *
+ * @param mlist A pointer to mlan_multicast_list structure
+ * @param dev A pointer to net_device structure
+ *
+ * @return Number of multicast addresses
+ */
+static inline int
+woal_copy_mcast_addr(mlan_multicast_list * mlist, struct net_device *dev)
+{
+ int i = 0;
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,35)
+ struct dev_mc_list *mcptr = dev->mc_list;
+#else
+ struct netdev_hw_addr *mcptr = NULL;
+#endif /* < 2.6.35 */
+
+ ENTER();
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,35)
+ for (i = 0; i < dev->mc_count && mcptr; i++) {
+ memcpy(&mlist->mac_list[i], mcptr->dmi_addr, ETH_ALEN);
+ mcptr = mcptr->next;
+ }
+#else
+ netdev_for_each_mc_addr(mcptr, dev)
+ memcpy(&mlist->mac_list[i++], mcptr->addr, ETH_ALEN);
+#endif /* < 2.6.35 */
+ LEAVE();
+ return i;
+}
+
+/**
+ * @brief Fill in wait queue
+ *
+ * @param priv A pointer to moal_private structure
+ * @param wait A pointer to wait_queue structure
+ * @param wait_option Wait option
+ *
+ * @return N/A
+ */
+static inline void
+woal_fill_wait_queue(moal_private * priv, wait_queue * wait, t_u8 wait_option)
+{
+ ENTER();
+ wait->start_time = jiffies;
+ wait->condition = MFALSE;
+ switch (wait_option) {
+ case MOAL_NO_WAIT:
+ break;
+ case MOAL_IOCTL_WAIT:
+ wait->wait = &priv->ioctl_wait_q;
+ break;
+ case MOAL_CMD_WAIT:
+ wait->wait = &priv->cmd_wait_q;
+ break;
+ case MOAL_PROC_WAIT:
+ wait->wait = &priv->proc_wait_q;
+ break;
+#if defined(STA_WEXT) || defined(UAP_WEXT)
+ case MOAL_WSTATS_WAIT:
+ if (IS_STA_OR_UAP_WEXT(cfg80211_wext))
+ wait->wait = &priv->w_stats_wait_q;
+ break;
+#endif
+ }
+ LEAVE();
+ return;
+}
+
+/**
+ * @brief Wait mlan ioctl complete
+ *
+ * @param priv A pointer to moal_private structure
+ * @param req A pointer to mlan_ioctl_req structure
+ * @param wait_option Wait option
+ *
+ * @return N/A
+ */
+static inline void
+woal_wait_ioctl_complete(moal_private * priv, mlan_ioctl_req * req,
+ t_u8 wait_option)
+{
+ mlan_status status;
+ wait_queue *wait = (wait_queue *) req->reserved_1;
+
+ ENTER();
+
+ switch (wait_option) {
+ case MOAL_NO_WAIT:
+ break;
+ case MOAL_IOCTL_WAIT:
+ wait_event_interruptible(priv->ioctl_wait_q, wait->condition);
+ break;
+ case MOAL_CMD_WAIT:
+ wait_event_interruptible(priv->cmd_wait_q, wait->condition);
+ break;
+ case MOAL_PROC_WAIT:
+ wait_event_interruptible(priv->proc_wait_q, wait->condition);
+ break;
+#if defined(STA_WEXT) || defined(UAP_WEXT)
+ case MOAL_WSTATS_WAIT:
+ if (IS_STA_OR_UAP_WEXT(cfg80211_wext))
+ wait_event_interruptible(priv->w_stats_wait_q, wait->condition);
+ break;
+#endif
+ }
+ if (wait->condition == MFALSE) {
+ req->action = MLAN_ACT_CANCEL;
+ status = mlan_ioctl(priv->phandle->pmlan_adapter, req);
+ PRINTM(MIOCTL,
+ "IOCTL cancel: id=0x%x, sub_id=0x%x, wait_option=%d, action=%d, status=%d\n",
+ req->req_id, (*(t_u32 *) req->pbuf), wait_option,
+ (int) req->action, status);
+ }
+ LEAVE();
+ return;
+}
+
+/**
+ * @brief CAC period block cmd handler
+ *
+ * @param priv A pointer to moal_private structure
+ * @param req A pointer to mlan_ioctl_req buffer
+ *
+ * @return MTRUE/MFALSE
+ */
+static inline t_bool
+woal_cac_period_block_cmd(moal_private * priv, pmlan_ioctl_req req)
+{
+ mlan_status ret = MFALSE;
+ t_u32 sub_command;
+
+ ENTER();
+ if (req == NULL || req->pbuf == NULL) {
+ goto done;
+ }
+
+ sub_command = *(t_u32 *) req->pbuf;
+
+ switch (req->req_id) {
+ case MLAN_IOCTL_SCAN:
+ if (sub_command == MLAN_OID_SCAN_NORMAL ||
+ sub_command == MLAN_OID_SCAN_SPECIFIC_SSID ||
+ sub_command == MLAN_OID_SCAN_USER_CONFIG) {
+ ret = MTRUE;
+ }
+ break;
+ case MLAN_IOCTL_BSS:
+ if (sub_command == MLAN_OID_BSS_STOP ||
+#ifdef UAP_SUPPORT
+ sub_command == MLAN_OID_UAP_BSS_CONFIG ||
+#endif
+ sub_command == MLAN_OID_BSS_CHANNEL
+ /* sub_command == MLAN_OID_BSS_ROLE */ ) {
+ ret = MTRUE;
+ }
+ break;
+ case MLAN_IOCTL_RADIO_CFG:
+ if (sub_command == MLAN_OID_BAND_CFG) {
+ ret = MTRUE;
+ }
+ break;
+#if defined(UAP_SUPPORT)
+ case MLAN_IOCTL_SNMP_MIB:
+ if (sub_command == MLAN_OID_SNMP_MIB_DOT11D ||
+ sub_command == MLAN_OID_SNMP_MIB_DOT11H) {
+ ret = MTRUE;
+ }
+ break;
+#endif
+ case MLAN_IOCTL_11D_CFG:
+#ifdef STA_SUPPORT
+ if (sub_command == MLAN_OID_11D_CFG_ENABLE) {
+ ret = MTRUE;
+ }
+#endif
+ if (sub_command == MLAN_OID_11D_DOMAIN_INFO) {
+ ret = MTRUE;
+ }
+ break;
+ case MLAN_IOCTL_MISC_CFG:
+ if (sub_command == MLAN_OID_MISC_REGION) {
+ ret = MTRUE;
+ }
+ if (sub_command == MLAN_OID_MISC_HOST_CMD) {
+ phostcmd_header phostcmd;
+ t_u8 *ptlv_buf;
+ t_u16 tag, length;
+
+ phostcmd =
+ (phostcmd_header) ((pmlan_ds_misc_cfg) req->pbuf)->param.
+ hostcmd.cmd;
+ ptlv_buf = (t_u8 *) phostcmd + sizeof(hostcmd_header);
+ if (phostcmd->action == MLAN_ACT_SET) {
+ while (ptlv_buf < (t_u8 *) phostcmd + phostcmd->size) {
+ tag = *(t_u16 *) ptlv_buf;
+ length = *(t_u16 *) (ptlv_buf + 2);
+ /* Check Blocking TLV here, should add more... */
+ if (tag == MRVL_CHANNELCONFIG_TLV_ID) {
+ ret = MTRUE;
+ break;
+ }
+ ptlv_buf += (length + MRVL_TLV_HEADER_SIZE);
+ }
+ }
+ }
+ break;
+ case MLAN_IOCTL_11H_CFG:
+ /* Prevent execute more than once */
+ if (sub_command == MLAN_OID_11H_CHANNEL_CHECK) {
+ ret = MTRUE;
+ }
+ break;
+ default:
+ ret = MFALSE;
+ break;
+ }
+
+ done:
+ LEAVE();
+ return ret;
+}
+
+/********************************************************
+ Global Functions
+********************************************************/
+
+/**
+ * @brief Send ioctl request to MLAN
+ *
+ * @param priv A pointer to moal_private structure
+ * @param req A pointer to mlan_ioctl_req buffer
+ * @param wait_option Wait option (MOAL_WAIT or MOAL_NO_WAIT)
+ *
+ * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING -- success, otherwise fail
+ */
+mlan_status
+woal_request_ioctl(moal_private * priv, mlan_ioctl_req * req, t_u8 wait_option)
+{
+ wait_queue *wait;
+ mlan_status status;
+
+ ENTER();
+
+ if (priv->phandle->surprise_removed == MTRUE) {
+ PRINTM(MERROR,
+ "IOCTL is not allowed while the device is not present\n");
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+#if defined(SDIO_SUSPEND_RESUME)
+ if (priv->phandle->is_suspended == MTRUE) {
+ PRINTM(MERROR, "IOCTL is not allowed while suspended\n");
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+#endif
+
+ /* For MLAN_OID_MISC_HOST_CMD, action is 0, "action set" is checked later */
+ if ((req->action == MLAN_ACT_SET || req->action == 0) &&
+ priv->phandle->cac_period == MTRUE) {
+ t_u32 sub_command;
+ /* CAC checking period left to complete jiffies */
+ unsigned long cac_left_jiffies;
+
+ sub_command = *(t_u32 *) req->pbuf;
+
+ /* cac_left_jiffies will be negative if and only if * event
+ MLAN_EVENT_ID_DRV_MEAS_REPORT recieved from FW * after CAC measure
+ period ends, * usually this could be considered as a FW bug */
+ cac_left_jiffies = MEAS_REPORT_TIME -
+ (jiffies - priv->phandle->meas_start_jiffies);
+#ifdef DFS_TESTING_SUPPORT
+ if (priv->phandle->cac_period_jiffies) {
+ cac_left_jiffies = priv->phandle->cac_period_jiffies -
+ (jiffies - priv->phandle->meas_start_jiffies);
+ }
+#endif
+ if (cac_left_jiffies < 0) {
+ /* Avoid driver hang in FW died during CAC measure period */
+ priv->phandle->cac_period = MFALSE;
+ PRINTM(MERROR,
+ "CAC measure period spends longer than scheduled time "
+ "or meas done event never received\n");
+ status = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ /* Check BSS START first */
+ if (sub_command == MLAN_OID_BSS_START) {
+ mlan_ds_bss *bss;
+ bss = (mlan_ds_bss *) req->pbuf;
+ /*
+ * Bss delay start after channel report received,
+ * not block the driver by delay executing. This is
+ * because a BSS_START cmd is always executed right
+ * after channel check issued.
+ */
+ if (priv->phandle->delay_bss_start == MFALSE) {
+ PRINTM(MMSG, "Received BSS Start command during CAC period, "
+ "delay executing %ld seconds\n", cac_left_jiffies / HZ);
+ priv->phandle->delay_bss_start = MTRUE;
+ memcpy(&priv->phandle->delay_ssid_bssid,
+ &bss->param.ssid_bssid, sizeof(mlan_ssid_bssid));
+ /* TODO: return success to allow the half below of routines of
+ which calling BSS start to execute */
+ status = MLAN_STATUS_SUCCESS;
+ goto done;
+ } else {
+ /* TODO: not blocking it, just return failure */
+ PRINTM(MMSG, "Only one BSS Start command allowed for delay "
+ "executing!\n");
+ status = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ }
+ if (woal_cac_period_block_cmd(priv, req)) {
+ priv->phandle->meas_wait_q_woken = MFALSE;
+ PRINTM(MMSG, "CAC check is on going... Blocking Command"
+ " %ld seconds\n", cac_left_jiffies / HZ);
+ /* blocking timeout set to 1.5 * CAC checking period left time */
+ wait_event_interruptible_timeout(priv->phandle->meas_wait_q,
+ priv->phandle->meas_wait_q_woken,
+ cac_left_jiffies * 3 / 2);
+ }
+ } else if (priv->phandle->cac_period) {
+ PRINTM(MINFO, "Operation during CAC check period.\n");
+ }
+ wait = (wait_queue *) req->reserved_1;
+ req->bss_index = priv->bss_index;
+ if (wait_option)
+ woal_fill_wait_queue(priv, wait, wait_option);
+ else
+ req->reserved_1 = 0;
+
+ /* Call MLAN ioctl handle */
+ status = mlan_ioctl(priv->phandle->pmlan_adapter, req);
+ switch (status) {
+ case MLAN_STATUS_PENDING:
+ PRINTM(MIOCTL,
+ "IOCTL pending: %p id=0x%x, sub_id=0x%x wait_option=%d, action=%d\n",
+ req, req->req_id, (*(t_u32 *) req->pbuf), wait_option,
+ (int) req->action);
+ atomic_inc(&priv->phandle->ioctl_pending);
+ /* Status pending, wake up main process */
+ queue_work(priv->phandle->workqueue, &priv->phandle->main_work);
+
+ /* Wait for completion */
+ if (wait_option) {
+ woal_wait_ioctl_complete(priv, req, wait_option);
+ status = wait->status;
+ }
+ break;
+ case MLAN_STATUS_SUCCESS:
+ case MLAN_STATUS_FAILURE:
+ case MLAN_STATUS_RESOURCE:
+ PRINTM(MIOCTL,
+ "IOCTL: %p id=0x%x, sub_id=0x%x wait_option=%d, action=%d status=%d\n",
+ req, req->req_id, (*(t_u32 *) req->pbuf), wait_option,
+ (int) req->action, status);
+ default:
+ break;
+ }
+ done:
+ LEAVE();
+ return status;
+}
+
+/**
+ * @brief Send set MAC address request to MLAN
+ *
+ * @param priv A pointer to moal_private structure
+ *
+ * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING -- success, otherwise fail
+ */
+mlan_status
+woal_request_set_mac_address(moal_private * priv)
+{
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_bss *bss = NULL;
+ mlan_status status;
+ ENTER();
+
+ /* Allocate an IOCTL request buffer */
+ req = (mlan_ioctl_req *) woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_bss));
+ if (req == NULL) {
+ status = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ /* Fill request buffer */
+ bss = (mlan_ds_bss *) req->pbuf;
+ bss->sub_command = MLAN_OID_BSS_MAC_ADDR;
+ memcpy(&bss->param.mac_addr, priv->current_addr,
+ sizeof(mlan_802_11_mac_addr));
+ req->req_id = MLAN_IOCTL_BSS;
+ req->action = MLAN_ACT_SET;
+
+ /* Send IOCTL request to MLAN */
+ status = woal_request_ioctl(priv, req, MOAL_CMD_WAIT);
+ if (status == MLAN_STATUS_SUCCESS) {
+ memcpy(priv->netdev->dev_addr, priv->current_addr, ETH_ALEN);
+#if defined(STA_CFG80211) || defined(UAP_CFG80211)
+ if (IS_STA_OR_UAP_CFG80211(cfg80211_wext) && priv->wdev &&
+ priv->wdev->wiphy)
+ memcpy(priv->wdev->wiphy->perm_addr, priv->current_addr, ETH_ALEN);
+#endif
+ HEXDUMP("priv->MacAddr:", priv->current_addr, ETH_ALEN);
+ } else {
+ PRINTM(MERROR, "set mac address failed! status=%d, error_code=0x%x\n",
+ status, req->status_code);
+ }
+ done:
+ if (req)
+ kfree(req);
+ LEAVE();
+ return status;
+}
+
+/**
+ * @brief Send multicast list request to MLAN
+ *
+ * @param priv A pointer to moal_private structure
+ * @param dev A pointer to net_device structure
+ *
+ * @return N/A
+ */
+void
+woal_request_set_multicast_list(moal_private * priv, struct net_device *dev)
+{
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_bss *bss = NULL;
+ mlan_status status;
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,35)
+ int mc_count = dev->mc_count;
+#else
+ int mc_count = netdev_mc_count(dev);
+#endif
+
+ ENTER();
+
+ /* Allocate an IOCTL request buffer */
+ req = (mlan_ioctl_req *) woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_bss));
+ if (req == NULL) {
+ PRINTM(MERROR, "%s:Fail to allocate ioctl req buffer\n", __FUNCTION__);
+ goto done;
+ }
+
+ /* Fill request buffer */
+ bss = (mlan_ds_bss *) req->pbuf;
+ bss->sub_command = MLAN_OID_BSS_MULTICAST_LIST;
+ req->req_id = MLAN_IOCTL_BSS;
+ req->action = MLAN_ACT_SET;
+ if (dev->flags & IFF_PROMISC) {
+ bss->param.multicast_list.mode = MLAN_PROMISC_MODE;
+ } else if (dev->flags & IFF_ALLMULTI ||
+ mc_count > MLAN_MAX_MULTICAST_LIST_SIZE) {
+ bss->param.multicast_list.mode = MLAN_ALL_MULTI_MODE;
+ } else {
+ bss->param.multicast_list.mode = MLAN_MULTICAST_MODE;
+ if (mc_count)
+ bss->param.multicast_list.num_multicast_addr =
+ woal_copy_mcast_addr(&bss->param.multicast_list, dev);
+ }
+
+ /* Send IOCTL request to MLAN */
+ status = woal_request_ioctl(priv, req, MOAL_NO_WAIT);
+ if (status != MLAN_STATUS_PENDING)
+ kfree(req);
+ done:
+ LEAVE();
+ return;
+}
+
+/**
+ * @brief Send deauth command to MLAN
+ *
+ * @param priv A pointer to moal_private structure
+ * @param wait_option Wait option
+ * @param mac MAC address to deauthenticate
+ *
+ * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING -- success, otherwise fail
+ */
+mlan_status
+woal_disconnect(moal_private * priv, t_u8 wait_option, t_u8 * mac)
+{
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_bss *bss = NULL;
+ mlan_status status;
+
+ ENTER();
+
+ /* Allocate an IOCTL request buffer */
+ req = (mlan_ioctl_req *) woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_bss));
+ if (req == NULL) {
+ status = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ /* Fill request buffer */
+ bss = (mlan_ds_bss *) req->pbuf;
+ bss->sub_command = MLAN_OID_BSS_STOP;
+ if (mac)
+ memcpy((t_u8 *) & bss->param.bssid, mac, sizeof(mlan_802_11_mac_addr));
+ req->req_id = MLAN_IOCTL_BSS;
+ req->action = MLAN_ACT_SET;
+
+ /* Send IOCTL request to MLAN */
+ status = woal_request_ioctl(priv, req, wait_option);
+
+ done:
+ if (req)
+ kfree(req);
+#ifdef REASSOCIATION
+ priv->reassoc_required = MFALSE;
+#endif /* REASSOCIATION */
+ LEAVE();
+ return status;
+}
+
+/**
+ * @brief Send bss_start command to MLAN
+ *
+ * @param priv A pointer to moal_private structure
+ * @param wait_option Wait option
+ * @param ssid_bssid A point to mlan_ssid_bssid structure
+ *
+ * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING -- success, otherwise fail
+ */
+mlan_status
+woal_bss_start(moal_private * priv, t_u8 wait_option,
+ mlan_ssid_bssid * ssid_bssid)
+{
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_bss *bss = NULL;
+ mlan_status status;
+
+ ENTER();
+
+ /* Stop the O.S. TX queue if needed */
+ woal_stop_queue(priv->netdev);
+
+ /* Allocate an IOCTL request buffer */
+ req = (mlan_ioctl_req *) woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_bss));
+ if (req == NULL) {
+ status = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ /* Fill request buffer */
+ bss = (mlan_ds_bss *) req->pbuf;
+ bss->sub_command = MLAN_OID_BSS_START;
+ if (ssid_bssid)
+ memcpy(&bss->param.ssid_bssid, ssid_bssid, sizeof(mlan_ssid_bssid));
+ req->req_id = MLAN_IOCTL_BSS;
+ req->action = MLAN_ACT_SET;
+
+ /* Send IOCTL request to MLAN */
+ status = woal_request_ioctl(priv, req, wait_option);
+
+ done:
+ if (req)
+ kfree(req);
+ LEAVE();
+ return status;
+}
+
+/**
+ * @brief Get BSS info
+ *
+ * @param priv A pointer to moal_private structure
+ * @param wait_option Wait option
+ * @param bss_info A pointer to mlan_bss_info structure
+ *
+ * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING -- success, otherwise fail
+ */
+mlan_status
+woal_get_bss_info(moal_private * priv, t_u8 wait_option,
+ mlan_bss_info * bss_info)
+{
+ int ret = 0;
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_get_info *info = NULL;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+ ENTER();
+
+ /* Allocate an IOCTL request buffer */
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_get_info));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ /* Fill request buffer */
+ info = (mlan_ds_get_info *) req->pbuf;
+ info->sub_command = MLAN_OID_GET_BSS_INFO;
+ req->req_id = MLAN_IOCTL_GET_INFO;
+ req->action = MLAN_ACT_GET;
+
+ /* Send IOCTL request to MLAN */
+ status = woal_request_ioctl(priv, req, wait_option);
+ if (status == MLAN_STATUS_SUCCESS) {
+ if (bss_info) {
+ memcpy(bss_info, &info->param.bss_info, sizeof(mlan_bss_info));
+ }
+ }
+ done:
+ if (req && (status != MLAN_STATUS_PENDING))
+ kfree(req);
+ LEAVE();
+ return status;
+}
+
+#ifdef STA_SUPPORT
+/**
+ * @brief Set/Get retry count
+ *
+ * @param priv A pointer to moal_private structure
+ * @param action Action set or get
+ * @param wait_option Wait option
+ * @param value Retry value
+ *
+ * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING -- success, otherwise fail
+ */
+mlan_status
+woal_set_get_retry(moal_private * priv, t_u32 action,
+ t_u8 wait_option, int *value)
+{
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_snmp_mib *mib = NULL;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ ENTER();
+
+ /* Allocate an IOCTL request buffer */
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_snmp_mib));
+ if (req == NULL) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ /* Fill request buffer */
+ mib = (mlan_ds_snmp_mib *) req->pbuf;
+ mib->sub_command = MLAN_OID_SNMP_MIB_RETRY_COUNT;
+ req->req_id = MLAN_IOCTL_SNMP_MIB;
+ req->action = action;
+
+ if (action == MLAN_ACT_SET) {
+ if (*value < MLAN_TX_RETRY_MIN || *value > MLAN_TX_RETRY_MAX) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ mib->param.retry_count = *value;
+ }
+
+ /* Send IOCTL request to MLAN */
+ ret = woal_request_ioctl(priv, req, wait_option);
+ if (ret == MLAN_STATUS_SUCCESS && action == MLAN_ACT_GET) {
+ *value = mib->param.retry_count;
+ }
+#ifdef STA_CFG80211
+ /* If set is invoked from other than iw i.e iwconfig, wiphy retry count
+ should be updated as well */
+ if (IS_STA_CFG80211(cfg80211_wext) &&
+ (GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_STA) && (action == MLAN_ACT_SET)) {
+ priv->wdev->wiphy->retry_long = (t_u8) * value;
+ priv->wdev->wiphy->retry_short = (t_u8) * value;
+ }
+#endif
+
+ done:
+ if (req && (ret != MLAN_STATUS_PENDING))
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set/Get RTS threshold
+ *
+ * @param priv A pointer to moal_private structure
+ * @param action Action set or get
+ * @param wait_option Wait option
+ * @param value RTS threshold value
+ *
+ * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING -- success, otherwise fail
+ */
+mlan_status
+woal_set_get_rts(moal_private * priv, t_u32 action,
+ t_u8 wait_option, int *value)
+{
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_snmp_mib *mib = NULL;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ ENTER();
+
+ /* Allocate an IOCTL request buffer */
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_snmp_mib));
+ if (req == NULL) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ /* Fill request buffer */
+ mib = (mlan_ds_snmp_mib *) req->pbuf;
+ mib->sub_command = MLAN_OID_SNMP_MIB_RTS_THRESHOLD;
+ req->req_id = MLAN_IOCTL_SNMP_MIB;
+ req->action = action;
+
+ if (action == MLAN_ACT_SET) {
+ if (*value < MLAN_RTS_MIN_VALUE || *value > MLAN_RTS_MAX_VALUE) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ mib->param.rts_threshold = *value;
+ }
+
+ /* Send IOCTL request to MLAN */
+ ret = woal_request_ioctl(priv, req, wait_option);
+ if (ret == MLAN_STATUS_SUCCESS && action == MLAN_ACT_GET) {
+ *value = mib->param.rts_threshold;
+ }
+#ifdef STA_CFG80211
+ /* If set is invoked from other than iw i.e iwconfig, wiphy RTS threshold
+ should be updated as well */
+ if (IS_STA_CFG80211(cfg80211_wext) &&
+ (GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_STA) && (action == MLAN_ACT_SET))
+ priv->wdev->wiphy->rts_threshold = *value;
+#endif
+
+ done:
+ if (req && (ret != MLAN_STATUS_PENDING))
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set/Get Fragment threshold
+ *
+ * @param priv A pointer to moal_private structure
+ * @param action Action set or get
+ * @param wait_option Wait option
+ * @param value Fragment threshold value
+ *
+ * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING -- success, otherwise fail
+ */
+mlan_status
+woal_set_get_frag(moal_private * priv, t_u32 action,
+ t_u8 wait_option, int *value)
+{
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_snmp_mib *mib = NULL;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ ENTER();
+
+ /* Allocate an IOCTL request buffer */
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_snmp_mib));
+ if (req == NULL) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ /* Fill request buffer */
+ mib = (mlan_ds_snmp_mib *) req->pbuf;
+ mib->sub_command = MLAN_OID_SNMP_MIB_FRAG_THRESHOLD;
+ req->req_id = MLAN_IOCTL_SNMP_MIB;
+ req->action = action;
+
+ if (action == MLAN_ACT_SET) {
+ if (*value < MLAN_FRAG_MIN_VALUE || *value > MLAN_FRAG_MAX_VALUE) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ mib->param.frag_threshold = *value;
+ }
+
+ /* Send IOCTL request to MLAN */
+ ret = woal_request_ioctl(priv, req, wait_option);
+ if (ret == MLAN_STATUS_SUCCESS && action == MLAN_ACT_GET) {
+ *value = mib->param.frag_threshold;
+ }
+#ifdef STA_CFG80211
+ /* If set is invoked from other than iw i.e iwconfig, wiphy fragment
+ threshold should be updated as well */
+ if (IS_STA_CFG80211(cfg80211_wext) &&
+ (GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_STA) && (action == MLAN_ACT_SET))
+ priv->wdev->wiphy->frag_threshold = *value;
+#endif
+
+ done:
+ if (req && (ret != MLAN_STATUS_PENDING))
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set/Get generic IE
+ *
+ * @param priv A pointer to moal_private structure
+ * @param action Action set or get
+ * @param ie Information element
+ * @param ie_len Length of the IE
+ *
+ * @return MLAN_STATUS_SUCCESS -- success, otherwise fail
+ */
+mlan_status
+woal_set_get_gen_ie(moal_private * priv, t_u32 action, t_u8 * ie, int *ie_len)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_ds_misc_cfg *misc = NULL;
+ mlan_ioctl_req *req = NULL;
+
+ ENTER();
+
+ if ((action == MLAN_ACT_GET) && (ie == NULL || ie_len == NULL)) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ if (action == MLAN_ACT_SET && *ie_len > MAX_IE_SIZE) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
+ if (req == NULL) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ misc = (mlan_ds_misc_cfg *) req->pbuf;
+ misc->sub_command = MLAN_OID_MISC_GEN_IE;
+ req->req_id = MLAN_IOCTL_MISC_CFG;
+ req->action = action;
+ misc->param.gen_ie.type = MLAN_IE_TYPE_GEN_IE;
+
+ if (action == MLAN_ACT_SET) {
+ misc->param.gen_ie.len = *ie_len;
+ if (*ie_len)
+ memcpy(misc->param.gen_ie.ie_data, ie, *ie_len);
+ }
+
+ if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ if (action == MLAN_ACT_GET) {
+ *ie_len = misc->param.gen_ie.len;
+ if (*ie_len)
+ memcpy(ie, misc->param.gen_ie.ie_data, *ie_len);
+ }
+
+ done:
+ if (req)
+ kfree(req);
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set/Get TX power
+ *
+ * @param priv A pointer to moal_private structure
+ * @param action Action set or get
+ * @param power_cfg A pinter to mlan_power_cfg_t structure
+ *
+ * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING -- success, otherwise fail
+ */
+mlan_status
+woal_set_get_tx_power(moal_private * priv,
+ t_u32 action, mlan_power_cfg_t * power_cfg)
+{
+ mlan_ds_power_cfg *pcfg = NULL;
+ mlan_ioctl_req *req = NULL;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ ENTER();
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_power_cfg));
+ if (req == NULL) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ pcfg = (mlan_ds_power_cfg *) req->pbuf;
+ pcfg->sub_command = MLAN_OID_POWER_CFG;
+ req->req_id = MLAN_IOCTL_POWER_CFG;
+ req->action = action;
+ if (action == MLAN_ACT_SET && power_cfg)
+ memcpy(&pcfg->param.power_cfg, power_cfg, sizeof(mlan_power_cfg_t));
+
+ if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT))
+ ret = MLAN_STATUS_FAILURE;
+
+ if (ret == MLAN_STATUS_SUCCESS && power_cfg)
+ memcpy(power_cfg, &pcfg->param.power_cfg, sizeof(mlan_power_cfg_t));
+
+ done:
+ if (req && (ret != MLAN_STATUS_PENDING))
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set/Get IEEE power management
+ *
+ * @param priv A pointer to moal_private structure
+ * @param action Action set or get
+ * @param disabled A pointer to disabled flag
+ * @param power_type IEEE power type
+ *
+ * @return MLAN_STATUS_SUCCESS -- success, otherwise fail
+ */
+mlan_status
+woal_set_get_power_mgmt(moal_private * priv,
+ t_u32 action, int *disabled, int power_type)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_pm_cfg *pm_cfg = NULL;
+
+ ENTER();
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_pm_cfg));
+ if (req == NULL) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ pm_cfg = (mlan_ds_pm_cfg *) req->pbuf;
+ pm_cfg->sub_command = MLAN_OID_PM_CFG_IEEE_PS;
+ req->req_id = MLAN_IOCTL_PM_CFG;
+ req->action = action;
+
+ if (action == MLAN_ACT_SET) {
+ PRINTM(MINFO, "PS_MODE set power disabled=%d power type=%#x\n",
+ *disabled, power_type);
+ if (*disabled)
+ pm_cfg->param.ps_mode = 0;
+ else {
+ /* Check not support case only (vwrq->disabled == FALSE) */
+ if ((power_type & IW_POWER_TYPE) == IW_POWER_TIMEOUT) {
+ PRINTM(MERROR, "Setting power timeout is not supported\n");
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ } else if ((power_type & IW_POWER_TYPE) == IW_POWER_PERIOD) {
+ PRINTM(MERROR, "Setting power period is not supported\n");
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ pm_cfg->param.ps_mode = 1;
+ }
+ }
+
+ if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ if (ret == MLAN_STATUS_SUCCESS && action == MLAN_ACT_GET)
+ *disabled = pm_cfg->param.ps_mode;
+
+#ifdef STA_CFG80211
+ /* If set is invoked from other than iw i.e iwconfig, wiphy IEEE power save
+ mode should be updated */
+ if (IS_STA_CFG80211(cfg80211_wext) &&
+ (GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_STA) && (action == MLAN_ACT_SET)) {
+ if (*disabled)
+ priv->wdev->ps = MFALSE;
+ else
+ priv->wdev->ps = MTRUE;
+ }
+#endif
+
+ done:
+ if (req)
+ kfree(req);
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set region code
+ *
+ * @param priv A pointer to moal_private structure
+ * @param region A pointer to region string
+ *
+ * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING --success, otherwise fail
+ */
+mlan_status
+woal_set_region_code(moal_private * priv, char *region)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_ds_misc_cfg *cfg = NULL;
+ mlan_ioctl_req *req = NULL;
+
+ ENTER();
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
+ if (req == NULL) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ cfg = (mlan_ds_misc_cfg *) req->pbuf;
+ cfg->sub_command = MLAN_OID_MISC_REGION;
+ req->req_id = MLAN_IOCTL_MISC_CFG;
+ req->action = MLAN_ACT_SET;
+ cfg->param.region_code = region_string_2_region_code(region);
+ ret = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
+
+ done:
+ if (req)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set/Get data rate
+ *
+ * @param priv A pointer to moal_private structure
+ * @param action Action set or get
+ * @param datarate A pointer to mlan_rate_cfg_t structure
+ *
+ * @return MLAN_STATUS_SUCCESS -- success, otherwise fail
+ */
+mlan_status
+woal_set_get_data_rate(moal_private * priv,
+ t_u8 action, mlan_rate_cfg_t * datarate)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_ds_rate *rate = NULL;
+ mlan_ioctl_req *req = NULL;
+
+ ENTER();
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_rate));
+ if (req == NULL) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ rate = (mlan_ds_rate *) req->pbuf;
+ rate->param.rate_cfg.rate_type = MLAN_RATE_VALUE;
+ rate->sub_command = MLAN_OID_RATE_CFG;
+ req->req_id = MLAN_IOCTL_RATE;
+ req->action = action;
+
+ if (datarate && (action == MLAN_ACT_SET))
+ memcpy(&rate->param.rate_cfg, datarate, sizeof(mlan_rate_cfg_t));
+
+ if (MLAN_STATUS_SUCCESS == woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) {
+ if (datarate && (action == MLAN_ACT_GET))
+ memcpy(datarate, &rate->param.rate_cfg, sizeof(mlan_rate_cfg_t));
+ } else {
+ ret = MLAN_STATUS_FAILURE;
+ }
+
+ done:
+ if (req)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+#endif
+
+/**
+ * @brief Send get FW info request to MLAN
+ *
+ * @param priv A pointer to moal_private structure
+ * @param wait_option Wait option
+ * @param fw_info FW information
+ *
+ * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING -- success, otherwise fail
+ */
+mlan_status
+woal_request_get_fw_info(moal_private * priv, t_u8 wait_option,
+ mlan_fw_info * fw_info)
+{
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_get_info *info;
+ mlan_status status;
+ ENTER();
+ memset(priv->current_addr, 0xff, ETH_ALEN);
+
+ /* Allocate an IOCTL request buffer */
+ req = (mlan_ioctl_req *) woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_bss));
+ if (req == NULL) {
+ status = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ /* Fill request buffer */
+ info = (mlan_ds_get_info *) req->pbuf;
+ req->req_id = MLAN_IOCTL_GET_INFO;
+ req->action = MLAN_ACT_GET;
+ info->sub_command = MLAN_OID_GET_FW_INFO;
+
+ /* Send IOCTL request to MLAN */
+ status = woal_request_ioctl(priv, req, wait_option);
+ if (status == MLAN_STATUS_SUCCESS) {
+ priv->phandle->fw_release_number = info->param.fw_info.fw_ver;
+ if (priv->current_addr[0] == 0xff)
+ memcpy(priv->current_addr, &info->param.fw_info.mac_addr,
+ sizeof(mlan_802_11_mac_addr));
+ memcpy(priv->netdev->dev_addr, priv->current_addr, ETH_ALEN);
+#if defined(STA_CFG80211) || defined(UAP_CFG80211)
+ if (IS_STA_OR_UAP_CFG80211(cfg80211_wext) && priv->wdev &&
+ priv->wdev->wiphy)
+ memcpy(priv->wdev->wiphy->perm_addr, priv->current_addr, ETH_ALEN);
+#endif
+ if (fw_info)
+ memcpy(fw_info, &info->param.fw_info, sizeof(mlan_fw_info));
+ DBG_HEXDUMP(MCMD_D, "mac", priv->current_addr, 6);
+ } else
+ PRINTM(MERROR, "get fw info failed! status=%d, error_code=0x%x\n",
+ status, req->status_code);
+ done:
+ if (req)
+ kfree(req);
+ LEAVE();
+ return status;
+}
+
+#ifdef PROC_DEBUG
+/**
+ * @brief Get debug info
+ *
+ * @param priv A pointer to moal_private structure
+ * @param wait_option Wait option
+ * @param debug_info A pointer to mlan_debug_info structure
+ *
+ * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING -- success, otherwise fail
+ */
+mlan_status
+woal_get_debug_info(moal_private * priv, t_u8 wait_option,
+ mlan_debug_info * debug_info)
+{
+ int ret = 0;
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_get_info *info = NULL;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+ ENTER();
+
+ /* Allocate an IOCTL request buffer */
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_get_info));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ /* Fill request buffer */
+ info = (mlan_ds_get_info *) req->pbuf;
+ info->sub_command = MLAN_OID_GET_DEBUG_INFO;
+ req->req_id = MLAN_IOCTL_GET_INFO;
+ req->action = MLAN_ACT_GET;
+
+ /* Send IOCTL request to MLAN */
+ status = woal_request_ioctl(priv, req, wait_option);
+ if (status == MLAN_STATUS_SUCCESS) {
+ if (debug_info) {
+ memcpy(debug_info, &info->param.debug_info,
+ sizeof(mlan_debug_info));
+ }
+ }
+ done:
+ if (req && (status != MLAN_STATUS_PENDING))
+ kfree(req);
+ LEAVE();
+ return status;
+}
+
+/**
+ * @brief Set debug info
+ *
+ * @param priv A pointer to moal_private structure
+ * @param wait_option Wait option
+ * @param debug_info A pointer to mlan_debug_info structure
+ *
+ * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING -- success, otherwise fail
+ */
+mlan_status
+woal_set_debug_info(moal_private * priv, t_u8 wait_option,
+ mlan_debug_info * debug_info)
+{
+ int ret = 0;
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_get_info *info = NULL;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ if (!debug_info) {
+ ret = -EINVAL;
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+
+ /* Allocate an IOCTL request buffer */
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_get_info));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ /* Fill request buffer */
+ info = (mlan_ds_get_info *) req->pbuf;
+ info->sub_command = MLAN_OID_GET_DEBUG_INFO;
+ memcpy(&info->param.debug_info, debug_info, sizeof(mlan_debug_info));
+ req->req_id = MLAN_IOCTL_GET_INFO;
+ req->action = MLAN_ACT_SET;
+
+ /* Send IOCTL request to MLAN */
+ status = woal_request_ioctl(priv, req, wait_option);
+ done:
+ if (req && (status != MLAN_STATUS_PENDING))
+ kfree(req);
+ LEAVE();
+ return status;
+}
+#endif /* PROC_DEBUG */
+
+#if defined(STA_WEXT) || defined(UAP_WEXT)
+/**
+ * @brief host command ioctl function
+ *
+ * @param priv A pointer to moal_private structure
+ * @param wrq A pointer to iwreq structure
+ * @return 0 --success, otherwise fail
+ */
+int
+woal_host_command(moal_private * priv, struct iwreq *wrq)
+{
+ HostCmd_Header cmd_header;
+ int ret = 0;
+ mlan_ds_misc_cfg *misc = NULL;
+ mlan_ioctl_req *req = NULL;
+
+ ENTER();
+
+ /* Sanity check */
+ if (wrq->u.data.pointer == NULL) {
+ PRINTM(MERROR, "hostcmd IOCTL corrupt data\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+ misc = (mlan_ds_misc_cfg *) req->pbuf;
+ memset(&cmd_header, 0, sizeof(cmd_header));
+
+ /* get command header */
+ if (copy_from_user
+ (&cmd_header, wrq->u.data.pointer, sizeof(HostCmd_Header))) {
+ PRINTM(MERROR, "copy from user failed: Host command header\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ misc->param.hostcmd.len = woal_le16_to_cpu(cmd_header.size);
+
+ PRINTM(MINFO, "Host command len = %u\n", misc->param.hostcmd.len);
+
+ if (!misc->param.hostcmd.len ||
+ misc->param.hostcmd.len > MLAN_SIZE_OF_CMD_BUFFER) {
+ PRINTM(MERROR, "Invalid data buffer length\n");
+ ret = -EINVAL;
+ goto done;
+ }
+
+ /* get the whole command from user */
+ if (copy_from_user
+ (misc->param.hostcmd.cmd, wrq->u.data.pointer,
+ woal_le16_to_cpu(cmd_header.size))) {
+ PRINTM(MERROR, "copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ misc->sub_command = MLAN_OID_MISC_HOST_CMD;
+ req->req_id = MLAN_IOCTL_MISC_CFG;
+
+ if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ if (copy_to_user
+ (wrq->u.data.pointer, (t_u8 *) misc->param.hostcmd.cmd,
+ misc->param.hostcmd.len)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ wrq->u.data.length = misc->param.hostcmd.len;
+ done:
+ if (req)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+#endif
+
+#if defined(WIFI_DIRECT_SUPPORT) || defined(UAP_SUPPORT)
+/**
+ * @brief host command ioctl function
+ *
+ * @param dev A pointer to net_device structure
+ * @param req A pointer to ifreq structure
+ * @return 0 --success, otherwise fail
+ */
+/********* format of ifr_data *************/
+/* buf_len + Hostcmd_body */
+/* buf_len: 4 bytes */
+/* the length of the buf which */
+/* can be used to return data */
+/* to application */
+/* Hostcmd_body */
+/*******************************************/
+int
+woal_hostcmd_ioctl(struct net_device *dev, struct ifreq *req)
+{
+ moal_private *priv = (moal_private *) netdev_priv(dev);
+ t_u32 buf_len = 0;
+ HostCmd_Header cmd_header;
+ int ret = 0;
+ mlan_ds_misc_cfg *misc = NULL;
+ mlan_ioctl_req *ioctl_req = NULL;
+
+ ENTER();
+
+ /* Sanity check */
+ if (req->ifr_data == NULL) {
+ PRINTM(MERROR, "uap_hostcmd_ioctl() corrupt data\n");
+ ret = -EFAULT;
+ goto done;
+ }
+
+ if (copy_from_user(&buf_len, req->ifr_data, sizeof(buf_len))) {
+ PRINTM(MERROR, "Copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+
+ memset(&cmd_header, 0, sizeof(cmd_header));
+
+ /* get command header */
+ if (copy_from_user
+ (&cmd_header, req->ifr_data + sizeof(buf_len),
+ sizeof(HostCmd_Header))) {
+ PRINTM(MERROR, "Copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+
+ PRINTM(MINFO, "Host command len = %d\n", woal_le16_to_cpu(cmd_header.size));
+
+ if (woal_le16_to_cpu(cmd_header.size) > MLAN_SIZE_OF_CMD_BUFFER) {
+ ret = -EINVAL;
+ goto done;
+ }
+
+ ioctl_req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
+ if (ioctl_req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+ misc = (mlan_ds_misc_cfg *) ioctl_req->pbuf;
+
+ misc->param.hostcmd.len = woal_le16_to_cpu(cmd_header.size);
+
+ /* get the whole command from user */
+ if (copy_from_user
+ (misc->param.hostcmd.cmd, req->ifr_data + sizeof(buf_len),
+ misc->param.hostcmd.len)) {
+ PRINTM(MERROR, "copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ misc->sub_command = MLAN_OID_MISC_HOST_CMD;
+ ioctl_req->req_id = MLAN_IOCTL_MISC_CFG;
+
+ if (MLAN_STATUS_SUCCESS !=
+ woal_request_ioctl(priv, ioctl_req, MOAL_IOCTL_WAIT)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ if (misc->param.hostcmd.len > buf_len) {
+ PRINTM(MERROR, "buf_len is too small, resp_len=%d, buf_len=%d\n",
+ (int) misc->param.hostcmd.len, (int) buf_len);
+ ret = -EFAULT;
+ goto done;
+ }
+ if (copy_to_user
+ (req->ifr_data + sizeof(buf_len), (t_u8 *) misc->param.hostcmd.cmd,
+ misc->param.hostcmd.len)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ done:
+ if (ioctl_req)
+ kfree(ioctl_req);
+ LEAVE();
+ return ret;
+}
+#endif
+
+/**
+ * @brief CUSTOM_IE ioctl handler
+ *
+ * @param dev A pointer to net_device structure
+ * @param req A pointer to ifreq structure
+ * @return 0 --success, otherwise fail
+ */
+int
+woal_custom_ie_ioctl(struct net_device *dev, struct ifreq *req)
+{
+ moal_private *priv = (moal_private *) netdev_priv(dev);
+ mlan_ioctl_req *ioctl_req = NULL;
+ mlan_ds_misc_cfg *misc = NULL;
+ mlan_ds_misc_custom_ie *custom_ie = NULL;
+ int ret = 0;
+
+ ENTER();
+
+ /* Sanity check */
+ if (req->ifr_data == NULL) {
+ PRINTM(MERROR, "woal_custom_ie_ioctl() corrupt data\n");
+ ret = -EFAULT;
+ goto done;
+ }
+
+ if (!(custom_ie = kmalloc(sizeof(mlan_ds_misc_custom_ie), GFP_KERNEL))) {
+ ret = -ENOMEM;
+ goto done;
+ }
+ memset(custom_ie, 0, sizeof(mlan_ds_misc_custom_ie));
+
+ if (copy_from_user
+ (custom_ie, req->ifr_data, sizeof(mlan_ds_misc_custom_ie))) {
+ PRINTM(MERROR, "Copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+
+ ioctl_req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
+ if (ioctl_req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ misc = (mlan_ds_misc_cfg *) ioctl_req->pbuf;
+ misc->sub_command = MLAN_OID_MISC_CUSTOM_IE;
+ ioctl_req->req_id = MLAN_IOCTL_MISC_CFG;
+ if ((custom_ie->len == 0) ||
+ (custom_ie->len == sizeof(custom_ie->ie_data_list[0].ie_index)))
+ ioctl_req->action = MLAN_ACT_GET;
+ else
+ ioctl_req->action = MLAN_ACT_SET;
+
+ memcpy(&misc->param.cust_ie, custom_ie, sizeof(mlan_ds_misc_custom_ie));
+
+ if (MLAN_STATUS_SUCCESS !=
+ woal_request_ioctl(priv, ioctl_req, MOAL_IOCTL_WAIT)) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ if (ioctl_req->action == MLAN_ACT_GET) {
+ if (copy_to_user
+ (req->ifr_data, &misc->param.cust_ie,
+ sizeof(mlan_ds_misc_custom_ie))) {
+ PRINTM(MERROR, "Copy to user failed!\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ } else if (ioctl_req->status_code == MLAN_ERROR_IOCTL_FAIL) {
+ /* send a separate error code to indicate error from driver */
+ ret = EFAULT;
+ }
+
+ done:
+ if (ioctl_req)
+ kfree(ioctl_req);
+ if (custom_ie)
+ kfree(custom_ie);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief send raw data packet ioctl function
+ *
+ * @param dev A pointer to net_device structure
+ * @param req A pointer to ifreq structure
+ * @return 0 --success, otherwise fail
+ */
+int
+woal_send_host_packet(struct net_device *dev, struct ifreq *req)
+{
+ moal_private *priv = (moal_private *) netdev_priv(dev);
+ t_u32 packet_len = 0;
+ int ret = 0;
+ pmlan_buffer pmbuf = NULL;
+ mlan_status status;
+
+ ENTER();
+
+ /* Sanity check */
+ if (req->ifr_data == NULL) {
+ PRINTM(MERROR, "woal_send_host_packet() corrupt data\n");
+ ret = -EFAULT;
+ goto done;
+ }
+
+ if (copy_from_user(&packet_len, req->ifr_data, sizeof(packet_len))) {
+ PRINTM(MERROR, "Copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+#define PACKET_HEADER_LEN 8
+ pmbuf =
+ woal_alloc_mlan_buffer(priv->phandle,
+ MLAN_MIN_DATA_HEADER_LEN + packet_len +
+ PACKET_HEADER_LEN);
+ if (!pmbuf) {
+ PRINTM(MERROR, "Fail to allocate mlan_buffer\n");
+ ret = -ENOMEM;
+ goto done;
+ }
+ pmbuf->data_offset = MLAN_MIN_DATA_HEADER_LEN;
+
+ /* get whole packet and header */
+ if (copy_from_user
+ (pmbuf->pbuf + pmbuf->data_offset, req->ifr_data + sizeof(packet_len),
+ PACKET_HEADER_LEN + packet_len)) {
+ PRINTM(MERROR, "Copy from user failed\n");
+ ret = -EFAULT;
+ woal_free_mlan_buffer(priv->phandle, pmbuf);
+ goto done;
+ }
+ pmbuf->data_len = PACKET_HEADER_LEN + packet_len;
+ pmbuf->buf_type = MLAN_BUF_TYPE_RAW_DATA;
+ pmbuf->bss_index = priv->bss_index;
+ status = mlan_send_packet(priv->phandle->pmlan_adapter, pmbuf);
+ switch (status) {
+ case MLAN_STATUS_PENDING:
+ atomic_inc(&priv->phandle->tx_pending);
+ queue_work(priv->phandle->workqueue, &priv->phandle->main_work);
+ break;
+ case MLAN_STATUS_SUCCESS:
+ woal_free_mlan_buffer(priv->phandle, pmbuf);
+ break;
+ case MLAN_STATUS_FAILURE:
+ default:
+ woal_free_mlan_buffer(priv->phandle, pmbuf);
+ ret = -EFAULT;
+ break;
+ }
+ done:
+ LEAVE();
+ return ret;
+}
+
+#if defined(UAP_WEXT)
+/**
+ * @brief Set/Get CUSTOM_IE ioctl handler
+ *
+ * @param mask Mask to set or clear from caller
+ * @param ie IE buffer to set for beacon
+ * @param ie_len Length of the IE
+ *
+ * @return 0 --success, otherwise fail
+ */
+int
+woal_set_get_custom_ie(moal_private * priv, t_u16 mask, t_u8 * ie, int ie_len)
+{
+ mlan_ioctl_req *ioctl_req = NULL;
+ mlan_ds_misc_cfg *misc = NULL;
+ mlan_ds_misc_custom_ie *misc_ie = NULL;
+ int ret = 0;
+ custom_ie *pcust_bcn_ie = NULL;
+
+ ENTER();
+
+ ioctl_req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
+ if (ioctl_req == NULL) {
+ LEAVE();
+ return -ENOMEM;
+ }
+
+ misc = (mlan_ds_misc_cfg *) ioctl_req->pbuf;
+ misc->sub_command = MLAN_OID_MISC_CUSTOM_IE;
+ ioctl_req->req_id = MLAN_IOCTL_MISC_CFG;
+ ioctl_req->action = MLAN_ACT_SET;
+ misc_ie = &misc->param.cust_ie;
+
+#ifndef TLV_TYPE_MGMT_IE
+#define TLV_TYPE_MGMT_IE (0x169)
+#endif
+ misc_ie->type = TLV_TYPE_MGMT_IE;
+ misc_ie->len = (sizeof(custom_ie) - MAX_IE_SIZE) + ie_len;
+ pcust_bcn_ie = misc_ie->ie_data_list;
+ pcust_bcn_ie->ie_index = 0xffff;
+ pcust_bcn_ie->mgmt_subtype_mask = mask;
+ pcust_bcn_ie->ie_length = ie_len;
+ memcpy(pcust_bcn_ie->ie_buffer, ie, ie_len);
+
+ if (MLAN_STATUS_SUCCESS !=
+ woal_request_ioctl(priv, ioctl_req, MOAL_IOCTL_WAIT)) {
+ ret = -EFAULT;
+ }
+
+ if (ioctl_req)
+ kfree(ioctl_req);
+ LEAVE();
+ return ret;
+}
+#endif /* defined(HOST_TXRX_MGMT_FRAME) && defined(UAP_WEXT) */
+
+/**
+ * @brief ioctl function get BSS type
+ *
+ * @param dev A pointer to net_device structure
+ * @param req A pointer to ifreq structure
+ * @return 0 --success, otherwise fail
+ */
+int
+woal_get_bss_type(struct net_device *dev, struct ifreq *req)
+{
+ int ret = 0;
+ moal_private *priv = (moal_private *) netdev_priv(dev);
+ int bss_type;
+
+ ENTER();
+
+ bss_type = (int) priv->bss_type;
+ if (copy_to_user(req->ifr_data, &bss_type, sizeof(int))) {
+ PRINTM(MINFO, "Copy to user failed!\n");
+ ret = -EFAULT;
+ }
+
+ LEAVE();
+ return ret;
+}
+
+#if defined(WIFI_DIRECT_SUPPORT)
+#if defined(STA_SUPPORT) && defined(UAP_SUPPORT)
+#if defined(STA_WEXT) || defined(UAP_WEXT)
+/**
+ * @brief Set/Get BSS role
+ *
+ * @param priv A pointer to moal_private structure
+ * @param wrq A pointer to iwreq structure
+ *
+ * @return 0 --success, otherwise fail
+ */
+int
+woal_set_get_bss_role(moal_private * priv, struct iwreq *wrq)
+{
+ int ret = 0;
+ mlan_ds_bss *bss = NULL;
+ mlan_ioctl_req *req = NULL;
+ int bss_role = 0;
+ struct net_device *dev = priv->netdev;
+
+ ENTER();
+
+ if (priv->bss_type != MLAN_BSS_TYPE_WIFIDIRECT) {
+ PRINTM(MWARN, "Command is not allowed for this interface\n");
+ ret = -EPERM;
+ goto done;
+ }
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_bss));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+ bss = (mlan_ds_bss *) req->pbuf;
+ bss->sub_command = MLAN_OID_BSS_ROLE;
+ req->req_id = MLAN_IOCTL_BSS;
+ if (wrq->u.data.length) {
+ if (copy_from_user(&bss_role, wrq->u.data.pointer, sizeof(int))) {
+ PRINTM(MERROR, "Copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ if (bss_role != MLAN_BSS_ROLE_STA && bss_role != MLAN_BSS_ROLE_UAP) {
+ PRINTM(MWARN, "Invalid BSS role\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ if (bss_role == GET_BSS_ROLE(priv)) {
+ PRINTM(MWARN, "Already BSS is in desired role\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ req->action = MLAN_ACT_SET;
+ bss->param.bss_role = (t_u8) bss_role;
+ } else {
+ req->action = MLAN_ACT_GET;
+ }
+
+ if (req->action == MLAN_ACT_SET) {
+ /* Reset interface */
+ woal_reset_intf(priv, MOAL_IOCTL_WAIT, MFALSE);
+ }
+ if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ if (!wrq->u.data.length) {
+ bss_role = (int) bss->param.bss_role;
+ if (copy_to_user(wrq->u.data.pointer, &bss_role, sizeof(int))) {
+ ret = -EFAULT;
+ goto done;
+ }
+ wrq->u.data.length = 1;
+ } else {
+ /* Update moal_private */
+ priv->bss_role = bss_role;
+ if (priv->bss_type == MLAN_BSS_TYPE_UAP)
+ priv->bss_type = MLAN_BSS_TYPE_STA;
+ else if (priv->bss_type == MLAN_BSS_TYPE_STA)
+ priv->bss_type = MLAN_BSS_TYPE_UAP;
+
+ /* Initialize private structures */
+ woal_init_priv(priv, MOAL_IOCTL_WAIT);
+
+ if (bss_role == MLAN_BSS_ROLE_UAP) {
+ /* Switch: STA -> uAP */
+ /* Setup the OS Interface to our functions */
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,29)
+ dev->do_ioctl = woal_uap_do_ioctl;
+ dev->set_multicast_list = woal_uap_set_multicast_list;
+#else
+ dev->netdev_ops = &woal_uap_netdev_ops;
+#endif
+#ifdef UAP_WEXT
+ if (IS_UAP_WEXT(cfg80211_wext)) {
+#ifdef WIRELESS_EXT
+#if WIRELESS_EXT < 21
+ dev->get_wireless_stats = woal_get_uap_wireless_stats;
+#endif
+ dev->wireless_handlers =
+ (struct iw_handler_def *) &woal_uap_handler_def;
+#endif /* WIRELESS_EXT */
+ init_waitqueue_head(&priv->w_stats_wait_q);
+ }
+#endif /* UAP_WEXT */
+ } else if (bss_role == MLAN_BSS_ROLE_STA) {
+ /* Switch: uAP -> STA */
+ /* Setup the OS Interface to our functions */
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,29)
+ dev->do_ioctl = woal_do_ioctl;
+ dev->set_multicast_list = woal_set_multicast_list;
+#else
+ dev->netdev_ops = &woal_netdev_ops;
+#endif
+#ifdef STA_WEXT
+ if (IS_STA_WEXT(cfg80211_wext)) {
+#ifdef WIRELESS_EXT
+#if WIRELESS_EXT < 21
+ dev->get_wireless_stats = woal_get_wireless_stats;
+#endif
+ dev->wireless_handlers =
+ (struct iw_handler_def *) &woal_handler_def;
+#endif
+ init_waitqueue_head(&priv->w_stats_wait_q);
+ }
+#endif /* STA_WEXT */
+ }
+ /* Enable interfaces */
+ netif_device_attach(dev);
+ woal_start_queue(dev);
+ }
+
+ done:
+ if (req)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+#endif
+#endif
+#endif /* WIFI_DIRECT_SUPPORT && V14_FEATURE */
+
+/**
+ * @brief Get Host Sleep parameters
+ *
+ * @param priv A pointer to moal_private structure
+ * @param action Action: set or get
+ * @param wait_option Wait option (MOAL_WAIT or MOAL_NO_WAIT)
+ * @param hscfg A pointer to mlan_ds_hs_cfg structure
+ *
+ * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING -- success, otherwise fail
+ */
+mlan_status
+woal_set_get_hs_params(moal_private * priv, t_u16 action, t_u8 wait_option,
+ mlan_ds_hs_cfg * hscfg)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_ds_pm_cfg *pmcfg = NULL;
+ mlan_ioctl_req *req = NULL;
+
+ ENTER();
+
+ /* Allocate an IOCTL request buffer */
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_pm_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ /* Fill request buffer */
+ pmcfg = (mlan_ds_pm_cfg *) req->pbuf;
+ pmcfg->sub_command = MLAN_OID_PM_CFG_HS_CFG;
+ req->req_id = MLAN_IOCTL_PM_CFG;
+ req->action = action;
+ if (action == MLAN_ACT_SET)
+ memcpy(&pmcfg->param.hs_cfg, hscfg, sizeof(mlan_ds_hs_cfg));
+
+ /* Send IOCTL request to MLAN */
+ ret = woal_request_ioctl(priv, req, wait_option);
+ if (ret == MLAN_STATUS_SUCCESS) {
+ if (hscfg && action == MLAN_ACT_GET) {
+ memcpy(hscfg, &pmcfg->param.hs_cfg, sizeof(mlan_ds_hs_cfg));
+ }
+ }
+ done:
+ if (req && (ret != MLAN_STATUS_PENDING))
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Cancel Host Sleep configuration
+ *
+ * @param priv A pointer to moal_private structure
+ * @param wait_option wait option
+ *
+ * @return MLAN_STATUS_SUCCESS, MLAN_STATUS_PENDING,
+ * or MLAN_STATUS_FAILURE
+ */
+mlan_status
+woal_cancel_hs(moal_private * priv, t_u8 wait_option)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_ds_hs_cfg hscfg;
+
+ ENTER();
+
+ /* Cancel Host Sleep */
+ hscfg.conditions = HOST_SLEEP_CFG_CANCEL;
+ hscfg.is_invoke_hostcmd = MTRUE;
+ ret = woal_set_get_hs_params(priv, MLAN_ACT_SET, wait_option, &hscfg);
+
+ LEAVE();
+ return ret;
+}
+
+/** @brief This function enables the host sleep
+ *
+ * @param priv A Pointer to the moal_private structure
+ * @return MTRUE or MFALSE
+ */
+int
+woal_enable_hs(moal_private * priv)
+{
+ mlan_ds_hs_cfg hscfg;
+ moal_handle *handle = NULL;
+ int hs_actived = MFALSE;
+ int timeout = 0;
+#ifdef SDIO_SUSPEND_RESUME
+ mlan_ds_ps_info pm_info;
+#endif
+
+ ENTER();
+
+ if (priv == NULL) {
+ PRINTM(MERROR, "Invalid priv\n");
+ goto done;
+ }
+ handle = priv->phandle;
+ if (handle->hs_activated == MTRUE) {
+ PRINTM(MIOCTL, "HS Already actived\n");
+ hs_actived = MTRUE;
+ goto done;
+ }
+#ifdef STA_SUPPORT
+ woal_reconfig_bgscan(priv->phandle);
+#endif
+ /* Enable Host Sleep */
+ handle->hs_activate_wait_q_woken = MFALSE;
+ memset(&hscfg, 0, sizeof(mlan_ds_hs_cfg));
+ hscfg.is_invoke_hostcmd = MTRUE;
+ if (woal_set_get_hs_params(priv, MLAN_ACT_SET, MOAL_NO_WAIT, &hscfg) ==
+ MLAN_STATUS_FAILURE) {
+ PRINTM(MIOCTL, "IOCTL request HS enable failed\n");
+ goto done;
+ }
+ timeout = wait_event_interruptible_timeout(handle->hs_activate_wait_q,
+ handle->hs_activate_wait_q_woken,
+ HS_ACTIVE_TIMEOUT);
+ sdio_claim_host(((struct sdio_mmc_card *) handle->card)->func);
+ if ((handle->hs_activated == MTRUE) || (handle->is_suspended == MTRUE)) {
+ PRINTM(MCMND, "suspend success! force=%u skip=%u\n",
+ handle->hs_force_count, handle->hs_skip_count);
+ hs_actived = MTRUE;
+ }
+#ifdef SDIO_SUSPEND_RESUME
+ else {
+ handle->suspend_fail = MTRUE;
+ woal_get_pm_info(priv, &pm_info);
+ if (pm_info.is_suspend_allowed == MTRUE) {
+#ifdef MMC_PM_FUNC_SUSPENDED
+ woal_wlan_is_suspended(priv->phandle);
+#endif
+ handle->hs_force_count++;
+ PRINTM(MCMND, "suspend allowed! force=%u skip=%u\n",
+ handle->hs_force_count, handle->hs_skip_count);
+ hs_actived = MTRUE;
+ }
+ }
+#endif /* SDIO_SUSPEND_RESUME */
+ sdio_release_host(((struct sdio_mmc_card *) handle->card)->func);
+ if (hs_actived != MTRUE) {
+ handle->hs_skip_count++;
+#ifdef SDIO_SUSPEND_RESUME
+ PRINTM(MCMND, "suspend skipped! timeout=%d allow=%d force=%u skip=%u\n",
+ timeout, (int) pm_info.is_suspend_allowed,
+ handle->hs_force_count, handle->hs_skip_count);
+#else
+ PRINTM(MCMND, "suspend skipped! timeout=%d skip=%u\n",
+ timeout, handle->hs_skip_count);
+#endif
+ woal_cancel_hs(priv, MOAL_NO_WAIT);
+ }
+ done:
+ LEAVE();
+ return hs_actived;
+}
+
+/**
+ * @brief This function send soft_reset command to firmware
+ *
+ * @param handle A pointer to moal_handle structure
+ * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING on success, otherwise failure code
+ */
+mlan_status
+woal_request_soft_reset(moal_handle * handle)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_misc_cfg *misc = NULL;
+
+ ENTER();
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
+ if (req) {
+ misc = (mlan_ds_misc_cfg *) req->pbuf;
+ misc->sub_command = MLAN_OID_MISC_SOFT_RESET;
+ req->req_id = MLAN_IOCTL_MISC_CFG;
+ req->action = MLAN_ACT_SET;
+ ret =
+ woal_request_ioctl(woal_get_priv(handle, MLAN_BSS_ROLE_ANY), req,
+ MOAL_PROC_WAIT);
+ }
+
+ handle->surprise_removed = MTRUE;
+ woal_sched_timeout(5);
+ if (req)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set wapi enable
+ *
+ * @param priv A pointer to moal_private structure
+ * @param wait_option Wait option
+ * @param enable MTRUE or MFALSE
+ *
+ * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING -- success, otherwise fail
+ */
+mlan_status
+woal_set_wapi_enable(moal_private * priv, t_u8 wait_option, t_u32 enable)
+{
+ int ret = 0;
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_sec_cfg *sec = NULL;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+ ENTER();
+
+ /* Allocate an IOCTL request buffer */
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_sec_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ /* Fill request buffer */
+ sec = (mlan_ds_sec_cfg *) req->pbuf;
+ sec->sub_command = MLAN_OID_SEC_CFG_WAPI_ENABLED;
+ req->req_id = MLAN_IOCTL_SEC_CFG;
+ req->action = MLAN_ACT_SET;
+ sec->param.wapi_enabled = enable;
+
+ /* Send IOCTL request to MLAN */
+ status = woal_request_ioctl(priv, req, wait_option);
+ done:
+ if (req && (status != MLAN_STATUS_PENDING))
+ kfree(req);
+ LEAVE();
+ return status;
+}
+
+/**
+ * @brief Get version
+ *
+ * @param handle A pointer to moal_handle structure
+ * @param version A pointer to version buffer
+ * @param max_len max length of version buffer
+ *
+ * @return N/A
+ */
+void
+woal_get_version(moal_handle * handle, char *version, int max_len)
+{
+ union
+ {
+ t_u32 l;
+ t_u8 c[4];
+ } ver;
+ char fw_ver[32];
+
+ ENTER();
+
+ ver.l = handle->fw_release_number;
+ snprintf(fw_ver, sizeof(fw_ver), "%u.%u.%u.p%u",
+ ver.c[2], ver.c[1], ver.c[0], ver.c[3]);
+
+ snprintf(version, max_len, driver_version, fw_ver);
+
+ LEAVE();
+}
+
+#if defined(STA_WEXT) || defined(UAP_WEXT)
+/**
+ * @brief Get Driver Version
+ *
+ * @param priv A pointer to moal_private structure
+ * @param req A pointer to ifreq structure
+ *
+ * @return 0 --success, otherwise fail
+ */
+int
+woal_get_driver_version(moal_private * priv, struct ifreq *req)
+{
+ struct iwreq *wrq = (struct iwreq *) req;
+ int len;
+ char buf[MLAN_MAX_VER_STR_LEN];
+ ENTER();
+
+ woal_get_version(priv->phandle, buf, sizeof(buf) - 1);
+
+ len = strlen(buf);
+ if (wrq->u.data.pointer) {
+ if (copy_to_user(wrq->u.data.pointer, buf, len)) {
+ PRINTM(MERROR, "Copy to user failed\n");
+ LEAVE();
+ return -EFAULT;
+ }
+ wrq->u.data.length = len;
+ }
+ PRINTM(MINFO, "MOAL VERSION: %s\n", buf);
+ LEAVE();
+ return 0;
+}
+
+/**
+ * @brief Get extended driver version
+ *
+ * @param priv A pointer to moal_private structure
+ * @param ireq A pointer to ifreq structure
+ *
+ * @return 0 --success, otherwise fail
+ */
+int
+woal_get_driver_verext(moal_private * priv, struct ifreq *ireq)
+{
+ struct iwreq *wrq = (struct iwreq *) ireq;
+ mlan_ds_get_info *info = NULL;
+ mlan_ioctl_req *req = NULL;
+ int ret = 0;
+
+ ENTER();
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_get_info));
+ if (req == NULL) {
+ LEAVE();
+ return -ENOMEM;
+ }
+
+ info = (mlan_ds_get_info *) req->pbuf;
+ info->sub_command = MLAN_OID_GET_VER_EXT;
+ req->req_id = MLAN_IOCTL_GET_INFO;
+ req->action = MLAN_ACT_GET;
+
+ if (!wrq->u.data.flags) {
+ info->param.ver_ext.version_str_sel =
+ *((int *) (wrq->u.name + SUBCMD_OFFSET));
+ } else {
+ if (copy_from_user
+ (&info->param.ver_ext.version_str_sel, wrq->u.data.pointer,
+ sizeof(info->param.ver_ext.version_str_sel))) {
+ PRINTM(MERROR, "Copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ } else {
+ if (((t_s32) (info->param.ver_ext.version_str_sel)) < 0) {
+ PRINTM(MERROR, "Invalid arguments!\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ }
+ }
+
+ if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ if (wrq->u.data.pointer) {
+ if (copy_to_user(wrq->u.data.pointer, info->param.ver_ext.version_str,
+ strlen(info->param.ver_ext.version_str))) {
+ PRINTM(MERROR, "Copy to user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ wrq->u.data.length = strlen(info->param.ver_ext.version_str);
+ }
+
+ PRINTM(MINFO, "MOAL EXTENDED VERSION: %s\n",
+ info->param.ver_ext.version_str);
+ done:
+ if (req)
+ kfree(req);
+
+ LEAVE();
+ return ret;
+}
+#endif
+
+#ifdef DEBUG_LEVEL1
+/**
+ * @brief Set driver debug bit masks to mlan in order to enhance performance
+ *
+ * @param priv A pointer to moal_private structure
+ * @param drvdbg Driver debug level
+ *
+ * @return 0 --success, otherwise fail
+ */
+int
+woal_set_drvdbg(moal_private * priv, t_u32 drvdbg)
+{
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_misc_cfg *misc = NULL;
+ int ret = 0;
+
+ ENTER();
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
+ if (req == NULL) {
+ LEAVE();
+ return -ENOMEM;
+ }
+
+ misc = (mlan_ds_misc_cfg *) req->pbuf;
+ misc->sub_command = MLAN_OID_MISC_DRVDBG;
+ req->req_id = MLAN_IOCTL_MISC_CFG;
+ req->action = MLAN_ACT_SET;
+ misc->param.drvdbg = drvdbg;
+
+ ret = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
+
+ if (req && (ret != MLAN_STATUS_PENDING))
+ kfree(req);
+
+ LEAVE();
+ return ret;
+}
+#endif
+
+/**
+ * @brief Mgmt frame forward registration
+ *
+ * @param priv A pointer to moal_private structure
+ * @param action Action: set or get
+ * @param pmgmt_subtype_mask A Pointer to mgmt frame subtype mask
+ * @param wait_option wait option (MOAL_WAIT or MOAL_NO_WAIT)
+ *
+ * @return 0 --success, otherwise fail
+ */
+int
+woal_reg_rx_mgmt_ind(moal_private * priv, t_u16 action,
+ t_u32 * pmgmt_subtype_mask, t_u8 wait_option)
+{
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_misc_cfg *misc = NULL;
+ int ret = 0;
+
+ ENTER();
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
+ if (req == NULL) {
+ LEAVE();
+ return -ENOMEM;
+ }
+
+ misc = (mlan_ds_misc_cfg *) req->pbuf;
+ misc->sub_command = MLAN_OID_MISC_RX_MGMT_IND;
+ req->req_id = MLAN_IOCTL_MISC_CFG;
+ req->action = action;
+ misc->param.mgmt_subtype_mask = *pmgmt_subtype_mask;
+ if (req->action == MLAN_ACT_SET)
+ memcpy(&misc->param.mgmt_subtype_mask,
+ pmgmt_subtype_mask, sizeof(misc->param.mgmt_subtype_mask));
+
+ ret = woal_request_ioctl(priv, req, wait_option);
+
+ if (req->action == MLAN_ACT_GET)
+ memcpy(pmgmt_subtype_mask, &misc->param.mgmt_subtype_mask,
+ sizeof(misc->param.mgmt_subtype_mask));
+
+ if (req && (ret != MLAN_STATUS_PENDING))
+ kfree(req);
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set/Get Transmit beamforming configuration
+ *
+ * @param priv A pointer to moal_private structure
+ * @param action Action: set or get
+ * @param tx_bf_cfg A pointer to tx_bf_cfg structure
+ *
+ * @return MLAN_STATUS_SUCCESS -- success, otherwise fail
+ */
+mlan_status
+woal_set_get_tx_bf_cfg(moal_private * priv, t_u16 action,
+ mlan_ds_11n_tx_bf_cfg * tx_bf_cfg)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_11n_cfg *bf_cfg = NULL;
+
+ ENTER();
+
+ /* Sanity test */
+ if (tx_bf_cfg == NULL) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ /* Allocate an IOCTL request buffer */
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_11n_cfg));
+ if (req == NULL) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ /* Fill request buffer */
+ bf_cfg = (mlan_ds_11n_cfg *) req->pbuf;
+ req->req_id = MLAN_IOCTL_11N_CFG;
+ bf_cfg->sub_command = MLAN_OID_11N_CFG_TX_BF_CFG;
+
+ req->action = action;
+ memcpy(&bf_cfg->param.tx_bf, tx_bf_cfg, sizeof(mlan_ds_11n_tx_bf_cfg));
+
+ /* Send IOCTL request to MLAN */
+ if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ if (action == MLAN_ACT_GET)
+ memcpy(tx_bf_cfg, &bf_cfg->param.tx_bf, sizeof(mlan_ds_11n_tx_bf_cfg));
+
+ done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Handle ioctl resp
+ *
+ * @param priv Pointer to moal_private structure
+ * @param req Pointer to mlan_ioctl_req structure
+ *
+ * @return N/A
+ */
+void
+woal_process_ioctl_resp(moal_private * priv, mlan_ioctl_req * req)
+{
+ ENTER();
+
+ if (priv == NULL) {
+ LEAVE();
+ return;
+ }
+ switch (req->req_id) {
+ case MLAN_IOCTL_GET_INFO:
+#ifdef STA_WEXT
+#ifdef STA_SUPPORT
+ if (IS_STA_WEXT(cfg80211_wext) &&
+ GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_STA)
+ woal_ioctl_get_info_resp(priv, (mlan_ds_get_info *) req->pbuf);
+#endif
+#endif
+#ifdef UAP_WEXT
+#ifdef UAP_SUPPORT
+ if (IS_UAP_WEXT(cfg80211_wext) &&
+ GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_UAP)
+ woal_ioctl_get_uap_info_resp(priv, (mlan_ds_get_info *) req->pbuf);
+#endif
+#endif
+ break;
+#ifdef STA_WEXT
+#ifdef STA_SUPPORT
+ case MLAN_IOCTL_BSS:
+ if (IS_STA_WEXT(cfg80211_wext) &&
+ GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_STA)
+ woal_ioctl_get_bss_resp(priv, (mlan_ds_bss *) req->pbuf);
+ break;
+#endif
+#endif
+ default:
+ break;
+ }
+
+ LEAVE();
+ return;
+}
+
+/**
+ * @brief Get PM info
+ *
+ * @param priv A pointer to moal_private structure
+ * @param pm_info A pointer to mlan_ds_ps_info structure
+ *
+ * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING -- success, otherwise fail
+ */
+mlan_status
+woal_get_pm_info(moal_private * priv, mlan_ds_ps_info * pm_info)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_ds_pm_cfg *pmcfg = NULL;
+ mlan_ioctl_req *req = NULL;
+
+ ENTER();
+
+ /* Allocate an IOCTL request buffer */
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_pm_cfg));
+ if (req == NULL) {
+ PRINTM(MERROR, "Fail to alloc mlan_ds_pm_cfg buffer\n");
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ /* Fill request buffer */
+ pmcfg = (mlan_ds_pm_cfg *) req->pbuf;
+ pmcfg->sub_command = MLAN_OID_PM_INFO;
+ req->req_id = MLAN_IOCTL_PM_CFG;
+ req->action = MLAN_ACT_GET;
+
+ /* Send IOCTL request to MLAN */
+ ret = woal_request_ioctl(priv, req, MOAL_CMD_WAIT);
+ if (ret == MLAN_STATUS_SUCCESS) {
+ if (pm_info) {
+ memcpy(pm_info, &pmcfg->param.ps_info, sizeof(mlan_ds_ps_info));
+ }
+ }
+ done:
+ if (req && (ret != MLAN_STATUS_PENDING))
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set Deep Sleep
+ *
+ * @param priv Pointer to the moal_private driver data struct
+ * @param wait_option wait option
+ * @param bdeep_sleep TRUE--enalbe deepsleep, FALSE--disable deepsleep
+ * @param idletime Idle time for optimized PS API
+ *
+ * @return 0 --success, otherwise fail
+ */
+int
+woal_set_deep_sleep(moal_private * priv, t_u8 wait_option, BOOLEAN bdeep_sleep,
+ t_u16 idletime)
+{
+ int ret = 0;
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_pm_cfg *pm = NULL;
+
+ ENTER();
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_pm_cfg));
+ if (req == NULL) {
+ LEAVE();
+ return -ENOMEM;
+ }
+ pm = (mlan_ds_pm_cfg *) req->pbuf;
+ pm->sub_command = MLAN_OID_PM_CFG_DEEP_SLEEP;
+ req->req_id = MLAN_IOCTL_PM_CFG;
+
+ req->action = MLAN_ACT_SET;
+ if (bdeep_sleep == MTRUE) {
+ PRINTM(MIOCTL, "Deep Sleep: sleep\n");
+ pm->param.auto_deep_sleep.auto_ds = DEEP_SLEEP_ON;
+ if (idletime) {
+ pm->param.auto_deep_sleep.idletime = idletime;
+ }
+ ret = woal_request_ioctl(priv, req, wait_option);
+ if (ret != MLAN_STATUS_SUCCESS && ret != MLAN_STATUS_PENDING) {
+ ret = -EFAULT;
+ goto done;
+ }
+ } else {
+ PRINTM(MIOCTL, "%lu : Deep Sleep: wakeup\n", jiffies);
+ pm->param.auto_deep_sleep.auto_ds = DEEP_SLEEP_OFF;
+ ret = woal_request_ioctl(priv, req, wait_option);
+ if (ret != MLAN_STATUS_SUCCESS && ret != MLAN_STATUS_PENDING) {
+ ret = -EFAULT;
+ goto done;
+ }
+ }
+ done:
+ if (req && (ret != MLAN_STATUS_PENDING))
+ kfree(req);
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Cancel CAC period block
+ *
+ * @param priv A pointer to moal_private structure
+ *
+ * @return N/A
+ */
+void
+woal_cancel_cac_block(moal_private * priv)
+{
+ ENTER();
+ /* if during CAC period, wake up wait queue */
+ if (priv->phandle->cac_period == MTRUE) {
+ priv->phandle->cac_period = MFALSE;
+ priv->phandle->meas_start_jiffies = 0;
+ if (priv->phandle->delay_bss_start == MTRUE) {
+ priv->phandle->delay_bss_start = MFALSE;
+ }
+ if (priv->phandle->meas_wait_q_woken == MFALSE) {
+ priv->phandle->meas_wait_q_woken = MTRUE;
+ wake_up_interruptible(&priv->phandle->meas_wait_q);
+ }
+ }
+ LEAVE();
+}
+
+/** MEAS report timeout value in seconds */
+
+/**
+ * @brief Issue MLAN_OID_11H_CHANNEL_CHECK ioctl
+ *
+ * @param priv Pointer to the moal_private driver data struct
+ *
+ * @return 0 --success, otherwise fail
+ */
+int
+woal_11h_channel_check_ioctl(moal_private * priv)
+{
+ int ret = 0;
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_11h_cfg *ds_11hcfg = NULL;
+
+ ENTER();
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_11h_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+ ds_11hcfg = (mlan_ds_11h_cfg *) req->pbuf;
+
+ ds_11hcfg->sub_command = MLAN_OID_11H_CHANNEL_CHECK;
+ req->req_id = MLAN_IOCTL_11H_CFG;
+ req->action = MLAN_ACT_SET;
+ /* Send Channel Check command and wait until the report is ready */
+ if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ /* set flag from here */
+ priv->phandle->cac_period = MTRUE;
+ priv->phandle->meas_start_jiffies = jiffies;
+
+ done:
+ if (req)
+ kfree(req);
+
+ LEAVE();
+ return ret;
+}
+
+#if defined(WIFI_DIRECT_SUPPORT)
+/**
+ * @brief set/get wifi direct mode
+ *
+ * @param priv A pointer to moal_private structure
+ * @param action set or get
+ * @param mode A pointer to wifi direct mode
+ *
+ * @return MLAN_STATUS_SUCCESS -- success, otherwise fail
+ */
+mlan_status
+woal_cfg80211_wifi_direct_mode_cfg(moal_private * priv, t_u16 action,
+ t_u16 * mode)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_bss *bss = NULL;
+
+ ENTER();
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_bss));
+ if (req == NULL) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ bss = (mlan_ds_bss *) req->pbuf;
+ bss->sub_command = MLAN_OID_WIFI_DIRECT_MODE;
+ req->req_id = MLAN_IOCTL_BSS;
+
+ req->action = action;
+ if (action == MLAN_ACT_SET)
+ bss->param.wfd_mode = *mode;
+ ret = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
+ if (ret == MLAN_STATUS_SUCCESS) {
+ *mode = bss->param.wfd_mode;
+ PRINTM(MIOCTL, "ACT=%d, wifi_direct_mode=%d\n", action, *mode);
+ }
+ done:
+ if (req)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief set remain channel
+ *
+ * @param priv A pointer to moal_private structure
+ * @param wait_option Wait option
+ * @param pchan A pointer to mlan_ds_remain_chan structure
+ *
+ * @return MLAN_STATUS_SUCCESS -- success, otherwise fail
+ */
+mlan_status
+woal_set_remain_channel_ioctl(moal_private * priv, t_u8 wait_option,
+ mlan_ds_remain_chan * pchan)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_radio_cfg *radio_cfg = NULL;
+
+ ENTER();
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_radio_cfg));
+ if (req == NULL) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ radio_cfg = (mlan_ds_radio_cfg *) req->pbuf;
+ radio_cfg->sub_command = MLAN_OID_REMAIN_CHAN_CFG;
+ req->req_id = MLAN_IOCTL_RADIO_CFG;
+
+ req->action = MLAN_ACT_SET;
+ memcpy(&radio_cfg->param.remain_chan, pchan, sizeof(mlan_ds_remain_chan));
+ ret = woal_request_ioctl(priv, req, wait_option);
+ if (ret == MLAN_STATUS_SUCCESS) {
+ memcpy(pchan, &radio_cfg->param.remain_chan,
+ sizeof(mlan_ds_remain_chan));
+ }
+ done:
+ if (req)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+#endif /* WIFI_DIRECT_SUPPORT */
+
+#ifdef STA_SUPPORT
+/**
+ * @brief Get RSSI info
+ *
+ * @param priv A pointer to moal_private structure
+ * @param wait_option Wait option
+ * @param signal A pointer tp mlan_ds_get_signal structure
+ *
+ * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING -- success, otherwise fail
+ */
+mlan_status
+woal_get_signal_info(moal_private * priv, t_u8 wait_option,
+ mlan_ds_get_signal * signal)
+{
+ int ret = 0;
+ mlan_ds_get_info *info = NULL;
+ mlan_ioctl_req *req = NULL;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+ ENTER();
+
+ /* Allocate an IOCTL request buffer */
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_get_info));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ /* Fill request buffer */
+ info = (mlan_ds_get_info *) req->pbuf;
+ info->sub_command = MLAN_OID_GET_SIGNAL;
+ info->param.signal.selector = ALL_RSSI_INFO_MASK;
+ req->req_id = MLAN_IOCTL_GET_INFO;
+ req->action = MLAN_ACT_GET;
+
+ /* Send IOCTL request to MLAN */
+ status = woal_request_ioctl(priv, req, wait_option);
+ if (status == MLAN_STATUS_SUCCESS) {
+ if (signal)
+ memcpy(signal, &info->param.signal, sizeof(mlan_ds_get_signal));
+#ifdef STA_WEXT
+ if (IS_STA_WEXT(cfg80211_wext)) {
+ if (info->param.signal.selector & BCN_RSSI_AVG_MASK)
+ priv->w_stats.qual.level = info->param.signal.bcn_rssi_avg;
+ if (info->param.signal.selector & BCN_NF_AVG_MASK)
+ priv->w_stats.qual.noise = info->param.signal.bcn_nf_avg;
+ }
+#endif
+ }
+ done:
+ if (req && (status != MLAN_STATUS_PENDING))
+ kfree(req);
+ LEAVE();
+ return status;
+}
+
+/**
+ * @brief Get scan table
+ *
+ * @param priv A pointer to moal_private structure
+ * @param wait_option Wait option
+ * @param scan_resp A pointer to mlan_scan_resp structure
+ *
+ * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING -- success, otherwise fail
+ */
+mlan_status
+woal_get_scan_table(moal_private * priv, t_u8 wait_option,
+ mlan_scan_resp * scan_resp)
+{
+ int ret = 0;
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_scan *scan = NULL;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+ ENTER();
+
+ /* Allocate an IOCTL request buffer */
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_scan));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ /* Fill request buffer */
+ scan = (mlan_ds_scan *) req->pbuf;
+ scan->sub_command = MLAN_OID_SCAN_NORMAL;
+ req->req_id = MLAN_IOCTL_SCAN;
+ req->action = MLAN_ACT_GET;
+ memcpy((void *) &scan->param.scan_resp, (void *) scan_resp,
+ sizeof(mlan_scan_resp));
+
+ /* Send IOCTL request to MLAN */
+ status = woal_request_ioctl(priv, req, wait_option);
+ if (status == MLAN_STATUS_SUCCESS) {
+ if (scan_resp) {
+ memcpy(scan_resp, &scan->param.scan_resp, sizeof(mlan_scan_resp));
+ }
+ }
+
+ done:
+ if (req && (status != MLAN_STATUS_PENDING))
+ kfree(req);
+ LEAVE();
+ return status;
+}
+
+/**
+ * @brief Request a scan
+ *
+ * @param priv A pointer to moal_private structure
+ * @param wait_option Wait option
+ * @param req_ssid A pointer to mlan_802_11_ssid structure
+ *
+ * @return MLAN_STATUS_SUCCESS -- success, otherwise fail
+ */
+mlan_status
+woal_request_scan(moal_private * priv,
+ t_u8 wait_option, mlan_802_11_ssid * req_ssid)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ moal_handle *handle = priv->phandle;
+ mlan_ioctl_req *ioctl_req = NULL;
+ mlan_ds_scan *scan = NULL;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+ ENTER();
+
+ if (MOAL_ACQ_SEMAPHORE_BLOCK(&handle->async_sem)) {
+ PRINTM(MERROR, "Acquire semaphore error, request_scan\n");
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+ handle->scan_pending_on_block = MTRUE;
+
+ /* Allocate an IOCTL request buffer */
+ ioctl_req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_scan));
+ if (ioctl_req == NULL) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ scan = (mlan_ds_scan *) ioctl_req->pbuf;
+
+ if (req_ssid && req_ssid->ssid_len != 0) {
+ /* Specific SSID scan */
+ ioctl_req->req_id = MLAN_IOCTL_SCAN;
+ ioctl_req->action = MLAN_ACT_SET;
+
+ scan->sub_command = MLAN_OID_SCAN_SPECIFIC_SSID;
+
+ memcpy(scan->param.scan_req.scan_ssid.ssid,
+ req_ssid->ssid, MIN(MLAN_MAX_SSID_LENGTH, req_ssid->ssid_len));
+ scan->param.scan_req.scan_ssid.ssid_len =
+ MIN(MLAN_MAX_SSID_LENGTH, req_ssid->ssid_len);
+ } else {
+ /* Normal scan */
+ ioctl_req->req_id = MLAN_IOCTL_SCAN;
+ ioctl_req->action = MLAN_ACT_SET;
+
+ scan->sub_command = MLAN_OID_SCAN_NORMAL;
+ }
+ /* Send IOCTL request to MLAN */
+ status = woal_request_ioctl(priv, ioctl_req, wait_option);
+
+ if (status == MLAN_STATUS_FAILURE) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ done:
+ if ((ioctl_req) && (status != MLAN_STATUS_PENDING))
+ kfree(ioctl_req);
+
+ if (ret == MLAN_STATUS_FAILURE) {
+ handle->scan_pending_on_block = MFALSE;
+ MOAL_REL_SEMAPHORE(&handle->async_sem);
+ }
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Change Adhoc Channel
+ *
+ * @param priv A pointer to moal_private structure
+ * @param channel The channel to be set.
+ *
+ * @return MLAN_STATUS_SUCCESS--success, MLAN_STATUS_FAILURE--fail
+ */
+mlan_status
+woal_change_adhoc_chan(moal_private * priv, int channel)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_bss_info bss_info;
+ mlan_ds_bss *bss = NULL;
+ mlan_ioctl_req *req = NULL;
+
+ ENTER();
+
+ memset(&bss_info, 0, sizeof(bss_info));
+
+ /* Get BSS information */
+ if (MLAN_STATUS_SUCCESS !=
+ woal_get_bss_info(priv, MOAL_IOCTL_WAIT, &bss_info)) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ if (bss_info.bss_mode == MLAN_BSS_MODE_INFRA) {
+ ret = MLAN_STATUS_SUCCESS;
+ goto done;
+ }
+
+ /* Allocate an IOCTL request buffer */
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_bss));
+ if (req == NULL) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ /* Get current channel */
+ bss = (mlan_ds_bss *) req->pbuf;
+ bss->sub_command = MLAN_OID_IBSS_CHANNEL;
+ req->req_id = MLAN_IOCTL_BSS;
+ req->action = MLAN_ACT_GET;
+
+ /* Send IOCTL request to MLAN */
+ if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ if (bss->param.bss_chan.channel == (unsigned int) channel) {
+ ret = MLAN_STATUS_SUCCESS;
+ goto done;
+ }
+ PRINTM(MINFO, "Updating Channel from %d to %d\n",
+ (int) bss->param.bss_chan.channel, channel);
+
+ if (bss_info.media_connected != MTRUE) {
+ ret = MLAN_STATUS_SUCCESS;
+ goto done;
+ }
+
+ /* Do disonnect */
+ bss->sub_command = MLAN_OID_BSS_STOP;
+ memset((t_u8 *) & bss->param.bssid, 0, ETH_ALEN);
+
+ /* Send IOCTL request to MLAN */
+ if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ /* Do specific SSID scanning */
+ if (MLAN_STATUS_SUCCESS !=
+ woal_request_scan(priv, MOAL_IOCTL_WAIT, &bss_info.ssid)) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ /* Start/Join Adhoc network */
+ bss->sub_command = MLAN_OID_BSS_START;
+ memset(&bss->param.ssid_bssid, 0, sizeof(mlan_ssid_bssid));
+ memcpy(&bss->param.ssid_bssid.ssid, &bss_info.ssid,
+ sizeof(mlan_802_11_ssid));
+
+ /* Send IOCTL request to MLAN */
+ if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) {
+ ret = MLAN_STATUS_FAILURE;
+ }
+
+ done:
+ if (req)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Find the best network to associate
+ *
+ * @param priv A pointer to moal_private structure
+ * @param wait_option Wait option
+ * @param ssid_bssid A pointer to mlan_ssid_bssid structure
+ *
+ * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING -- success, otherwise fail
+ */
+mlan_status
+woal_find_best_network(moal_private * priv, t_u8 wait_option,
+ mlan_ssid_bssid * ssid_bssid)
+{
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_bss *bss = NULL;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ t_u8 *mac = 0;
+
+ ENTER();
+
+ if (!ssid_bssid) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ /* Allocate an IOCTL request buffer */
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_bss));
+ if (req == NULL) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ /* Fill request buffer */
+ bss = (mlan_ds_bss *) req->pbuf;
+ req->req_id = MLAN_IOCTL_BSS;
+ req->action = MLAN_ACT_GET;
+ bss->sub_command = MLAN_OID_BSS_FIND_BSS;
+
+ memcpy(&bss->param.ssid_bssid, ssid_bssid, sizeof(mlan_ssid_bssid));
+
+ /* Send IOCTL request to MLAN */
+ ret = woal_request_ioctl(priv, req, wait_option);
+ if (ret == MLAN_STATUS_SUCCESS) {
+ memcpy(ssid_bssid, &bss->param.ssid_bssid, sizeof(mlan_ssid_bssid));
+ mac = (t_u8 *) & ssid_bssid->bssid;
+ PRINTM(MINFO,
+ "Find network: ssid=%s, %02x:%02x:%02x:%02x:%02x:%02x, idx=%d\n",
+ ssid_bssid->ssid.ssid, mac[0], mac[1], mac[2], mac[3], mac[4],
+ mac[5], (int) ssid_bssid->idx);
+ }
+
+ done:
+ if (req)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Get authentication mode
+ *
+ * @param priv A pointer to moal_private structure
+ * @param wait_option Wait option
+ * @param auth_mode A pointer to authentication mode
+ *
+ * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING -- success, otherwise fail
+ */
+mlan_status
+woal_get_auth_mode(moal_private * priv, t_u8 wait_option, t_u32 * auth_mode)
+{
+ int ret = 0;
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_sec_cfg *sec = NULL;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+ ENTER();
+
+ /* Allocate an IOCTL request buffer */
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_sec_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ /* Fill request buffer */
+ sec = (mlan_ds_sec_cfg *) req->pbuf;
+ sec->sub_command = MLAN_OID_SEC_CFG_AUTH_MODE;
+ req->req_id = MLAN_IOCTL_SEC_CFG;
+ req->action = MLAN_ACT_GET;
+
+ /* Send IOCTL request to MLAN */
+ status = woal_request_ioctl(priv, req, wait_option);
+ if (status == MLAN_STATUS_SUCCESS && auth_mode) {
+ *auth_mode = sec->param.auth_mode;
+ }
+ done:
+ if (req && (status != MLAN_STATUS_PENDING))
+ kfree(req);
+ LEAVE();
+ return status;
+}
+
+/**
+ * @brief Get encrypt mode
+ *
+ * @param priv A pointer to moal_private structure
+ * @param wait_option Wait option
+ * @param encrypt_mode A pointer to encrypt mode
+ *
+ * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING -- success, otherwise fail
+ */
+mlan_status
+woal_get_encrypt_mode(moal_private * priv, t_u8 wait_option,
+ t_u32 * encrypt_mode)
+{
+ int ret = 0;
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_sec_cfg *sec = NULL;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ /* Allocate an IOCTL request buffer */
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_sec_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ /* Fill request buffer */
+ sec = (mlan_ds_sec_cfg *) req->pbuf;
+ sec->sub_command = MLAN_OID_SEC_CFG_ENCRYPT_MODE;
+ req->req_id = MLAN_IOCTL_SEC_CFG;
+ req->action = MLAN_ACT_GET;
+
+ /* Send IOCTL request to MLAN */
+ status = woal_request_ioctl(priv, req, wait_option);
+ if (status == MLAN_STATUS_SUCCESS && encrypt_mode) {
+ *encrypt_mode = sec->param.encrypt_mode;
+ }
+ done:
+ if (req && (status != MLAN_STATUS_PENDING))
+ kfree(req);
+ LEAVE();
+ return status;
+}
+
+/**
+ * @brief Get WPA enable
+ *
+ * @param priv A pointer to moal_private structure
+ * @param wait_option Wait option
+ * @param enable A pointer to wpa enable status
+ *
+ * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING -- success, otherwise fail
+ */
+mlan_status
+woal_get_wpa_enable(moal_private * priv, t_u8 wait_option, t_u32 * enable)
+{
+ int ret = 0;
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_sec_cfg *sec = NULL;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ /* Allocate an IOCTL request buffer */
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_sec_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ /* Fill request buffer */
+ sec = (mlan_ds_sec_cfg *) req->pbuf;
+ sec->sub_command = MLAN_OID_SEC_CFG_WPA_ENABLED;
+ req->req_id = MLAN_IOCTL_SEC_CFG;
+ req->action = MLAN_ACT_GET;
+
+ /* Send IOCTL request to MLAN */
+ status = woal_request_ioctl(priv, req, wait_option);
+ if (status == MLAN_STATUS_SUCCESS && enable) {
+ *enable = sec->param.wpa_enabled;
+ }
+ done:
+ if (req && (status != MLAN_STATUS_PENDING))
+ kfree(req);
+ LEAVE();
+ return status;
+}
+
+/**
+ * @brief Set authentication mode
+ *
+ * @param priv A pointer to moal_private structure
+ * @param wait_option Wait option
+ * @param auth_mode Authentication mode
+ *
+ * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING -- success, otherwise fail
+ */
+mlan_status
+woal_set_auth_mode(moal_private * priv, t_u8 wait_option, t_u32 auth_mode)
+{
+ int ret = 0;
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_sec_cfg *sec = NULL;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+ ENTER();
+
+ /* Allocate an IOCTL request buffer */
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_sec_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ /* Fill request buffer */
+ sec = (mlan_ds_sec_cfg *) req->pbuf;
+ sec->sub_command = MLAN_OID_SEC_CFG_AUTH_MODE;
+ req->req_id = MLAN_IOCTL_SEC_CFG;
+ req->action = MLAN_ACT_SET;
+ sec->param.auth_mode = auth_mode;
+
+ /* Send IOCTL request to MLAN */
+ status = woal_request_ioctl(priv, req, wait_option);
+ done:
+ if (req && (status != MLAN_STATUS_PENDING))
+ kfree(req);
+ LEAVE();
+ return status;
+}
+
+/**
+ * @brief Set encrypt mode
+ *
+ * @param priv A pointer to moal_private structure
+ * @param wait_option Wait option
+ * @param encrypt_mode Encryption mode
+ *
+ * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING -- success, otherwise fail
+ */
+mlan_status
+woal_set_encrypt_mode(moal_private * priv, t_u8 wait_option, t_u32 encrypt_mode)
+{
+ int ret = 0;
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_sec_cfg *sec = NULL;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+ ENTER();
+
+ /* Allocate an IOCTL request buffer */
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_sec_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ /* Fill request buffer */
+ sec = (mlan_ds_sec_cfg *) req->pbuf;
+ sec->sub_command = MLAN_OID_SEC_CFG_ENCRYPT_MODE;
+ req->req_id = MLAN_IOCTL_SEC_CFG;
+ req->action = MLAN_ACT_SET;
+ sec->param.encrypt_mode = encrypt_mode;
+
+ /* Send IOCTL request to MLAN */
+ status = woal_request_ioctl(priv, req, wait_option);
+ done:
+ if (req && (status != MLAN_STATUS_PENDING))
+ kfree(req);
+ LEAVE();
+ return status;
+}
+
+/**
+ * @brief Set wpa enable
+ *
+ * @param priv A pointer to moal_private structure
+ * @param wait_option Wait option
+ * @param enable MTRUE or MFALSE
+ *
+ * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING -- success, otherwise fail
+ */
+mlan_status
+woal_set_wpa_enable(moal_private * priv, t_u8 wait_option, t_u32 enable)
+{
+ int ret = 0;
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_sec_cfg *sec = NULL;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+ ENTER();
+
+ /* Allocate an IOCTL request buffer */
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_sec_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ /* Fill request buffer */
+ sec = (mlan_ds_sec_cfg *) req->pbuf;
+ sec->sub_command = MLAN_OID_SEC_CFG_WPA_ENABLED;
+ req->req_id = MLAN_IOCTL_SEC_CFG;
+ req->action = MLAN_ACT_SET;
+ sec->param.wpa_enabled = enable;
+
+ /* Send IOCTL request to MLAN */
+ status = woal_request_ioctl(priv, req, wait_option);
+ done:
+ if (req && (status != MLAN_STATUS_PENDING))
+ kfree(req);
+ LEAVE();
+ return status;
+}
+
+/**
+ * @brief enable wep key
+ *
+ * @param priv A pointer to moal_private structure
+ * @param wait_option Wait option
+ *
+ * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING -- success, otherwise fail
+ */
+mlan_status
+woal_enable_wep_key(moal_private * priv, t_u8 wait_option)
+{
+ int ret = 0;
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_sec_cfg *sec = NULL;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+ ENTER();
+
+ /* Allocate an IOCTL request buffer */
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_sec_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ /* Fill request buffer */
+ sec = (mlan_ds_sec_cfg *) req->pbuf;
+ sec->sub_command = MLAN_OID_SEC_CFG_ENCRYPT_KEY;
+ req->req_id = MLAN_IOCTL_SEC_CFG;
+ req->action = MLAN_ACT_SET;
+ sec->param.encrypt_key.key_disable = MFALSE;
+ sec->param.encrypt_key.key_index = MLAN_KEY_INDEX_DEFAULT;
+ sec->param.encrypt_key.is_current_wep_key = MTRUE;
+
+ /* Send IOCTL request to MLAN */
+ status = woal_request_ioctl(priv, req, wait_option);
+ done:
+ if (req && (status != MLAN_STATUS_PENDING))
+ kfree(req);
+ LEAVE();
+ return status;
+}
+
+/**
+ * @brief Request user scan
+ *
+ * @param priv A pointer to moal_private structure
+ * @param wait_option Wait option
+ * @param scan_cfg A pointer to wlan_user_scan_config structure
+ *
+ * @return MLAN_STATUS_SUCCESS -- success, otherwise fail
+ */
+mlan_status
+woal_request_userscan(moal_private * priv,
+ t_u8 wait_option, wlan_user_scan_cfg * scan_cfg)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_ioctl_req *ioctl_req = NULL;
+ mlan_ds_scan *scan = NULL;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+ moal_handle *handle = priv->phandle;
+ ENTER();
+
+ if (MOAL_ACQ_SEMAPHORE_BLOCK(&handle->async_sem)) {
+ PRINTM(MERROR, "Acquire semaphore error, request_scan\n");
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+ handle->scan_pending_on_block = MTRUE;
+
+ /* Allocate an IOCTL request buffer */
+ ioctl_req =
+ woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_scan) +
+ sizeof(wlan_user_scan_cfg));
+ if (ioctl_req == NULL) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ scan = (mlan_ds_scan *) ioctl_req->pbuf;
+ scan->sub_command = MLAN_OID_SCAN_USER_CONFIG;
+ ioctl_req->req_id = MLAN_IOCTL_SCAN;
+ ioctl_req->action = MLAN_ACT_SET;
+ memcpy(scan->param.user_scan.scan_cfg_buf, scan_cfg,
+ sizeof(wlan_user_scan_cfg));
+ /* Send IOCTL request to MLAN */
+ status = woal_request_ioctl(priv, ioctl_req, wait_option);
+ if (status == MLAN_STATUS_FAILURE) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ done:
+ if ((ioctl_req) && (status != MLAN_STATUS_PENDING))
+ kfree(ioctl_req);
+
+ if (ret == MLAN_STATUS_FAILURE) {
+ handle->scan_pending_on_block = MFALSE;
+ MOAL_REL_SEMAPHORE(&handle->async_sem);
+ }
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief set scan time
+ *
+ * @param priv A pointer to moal_private structure
+ * @param passive_scan_time passive scan time
+ * @param specific_scan_time specific scan time
+ *
+ * @return MLAN_STATUS_SUCCESS -- success, otherwise fail
+ */
+static mlan_status
+woal_set_scan_time(moal_private * priv, t_u16 passive_scan_time,
+ t_u16 specific_scan_time)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_ds_scan *scan = NULL;
+ mlan_ioctl_req *req = NULL;
+
+ ENTER();
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_scan));
+ if (req == NULL) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ scan = (mlan_ds_scan *) req->pbuf;
+ scan->sub_command = MLAN_OID_SCAN_CONFIG;
+ req->req_id = MLAN_IOCTL_SCAN;
+ req->action = MLAN_ACT_SET;
+ memset(&scan->param.scan_cfg, 0, sizeof(mlan_scan_cfg));
+ scan->param.scan_cfg.scan_time.specific_scan_time = specific_scan_time;
+ scan->param.scan_cfg.scan_time.passive_scan_time = passive_scan_time;
+ if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT))
+ ret = MLAN_STATUS_FAILURE;
+ done:
+ if (req)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief request scan
+ *
+ * @param priv A pointer to moal_private structure
+ * @param scan_cfg A pointer to wlan_user_scan_cfg structure
+ *
+ * @return MLAN_STATUS_SUCCESS -- success, otherwise fail
+ */
+mlan_status
+woal_do_scan(moal_private * priv, wlan_user_scan_cfg * scan_cfg)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ moal_handle *handle = priv->phandle;
+
+ ENTER();
+ if (handle->scan_pending_on_block == MTRUE) {
+ PRINTM(MINFO, "scan already in processing...\n");
+ LEAVE();
+ return ret;
+ }
+#ifdef REASSOCIATION
+ if (MOAL_ACQ_SEMAPHORE_BLOCK(&handle->reassoc_sem)) {
+ PRINTM(MERROR, "Acquire semaphore error, woal_do_combo_scan\n");
+ LEAVE();
+ return -EBUSY;
+ }
+#endif /* REASSOCIATION */
+ priv->report_scan_result = MTRUE;
+ if (!scan_cfg) {
+ ret = woal_request_scan(priv, MOAL_NO_WAIT, NULL);
+ } else {
+ ret = woal_request_userscan(priv, MOAL_NO_WAIT, scan_cfg);
+ }
+#ifdef REASSOCIATION
+ MOAL_REL_SEMAPHORE(&handle->reassoc_sem);
+#endif
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief find ssid in scan_table
+ *
+ * @param priv A pointer to moal_private
+ * @ssid_bssid A pointer to mlan_ssid_bssid structure
+ * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_FAILURE
+ */
+int
+woal_find_essid(moal_private * priv, mlan_ssid_bssid * ssid_bssid)
+{
+ int ret = 0;
+ mlan_scan_resp scan_resp;
+ struct timeval t;
+ ENTER();
+
+ if (MLAN_STATUS_SUCCESS !=
+ woal_get_scan_table(priv, MOAL_IOCTL_WAIT, &scan_resp)) {
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+ do_gettimeofday(&t);
+/** scan result timeout value */
+#define SCAN_RESULT_AGEOUT 10
+ if (t.tv_sec > (scan_resp.age_in_secs + SCAN_RESULT_AGEOUT)) {
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+ ret = woal_find_best_network(priv, MOAL_IOCTL_WAIT, ssid_bssid);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Request user scan
+ *
+ * @param priv A pointer to moal_private structure
+ * @param wait_option Wait option
+ * @param scan_cfg A pointer to wlan_bgscan_cfg structure
+ *
+ * @return MLAN_STATUS_SUCCESS -- success, otherwise fail
+ */
+mlan_status
+woal_request_bgscan(moal_private * priv,
+ t_u8 wait_option, wlan_bgscan_cfg * scan_cfg)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_ioctl_req *ioctl_req = NULL;
+ mlan_ds_scan *scan = NULL;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+ ENTER();
+
+ /* Allocate an IOCTL request buffer */
+ ioctl_req =
+ woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_scan) +
+ sizeof(wlan_bgscan_cfg));
+ if (ioctl_req == NULL) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ scan = (mlan_ds_scan *) ioctl_req->pbuf;
+ scan->sub_command = MLAN_OID_SCAN_BGSCAN_CONFIG;
+ ioctl_req->req_id = MLAN_IOCTL_SCAN;
+ ioctl_req->action = MLAN_ACT_SET;
+ memcpy(scan->param.user_scan.scan_cfg_buf, scan_cfg,
+ sizeof(wlan_bgscan_cfg));
+
+ /* Send IOCTL request to MLAN */
+ status = woal_request_ioctl(priv, ioctl_req, wait_option);
+ if (status == MLAN_STATUS_FAILURE) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ done:
+ if ((ioctl_req) && (status != MLAN_STATUS_PENDING))
+ kfree(ioctl_req);
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief set bgscan config
+ *
+ * @param priv A pointer to moal_private structure
+ * @param buf A pointer to scan command buf
+ * @param length buf length
+ *
+ * @return MLAN_STATUS_SUCCESS -- success, otherwise fail
+ */
+mlan_status
+woal_set_bg_scan(moal_private * priv, char *buf, int length)
+{
+ t_u8 *ptr = buf + strlen("BGSCAN-CONFIG") + 1;
+ int buf_left = length - (strlen("BGSCAN-CONFIG") + 1);
+ int band = 0;
+ int num_ssid = 0;
+ int ssid_len = 0;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+ memset(&priv->scan_cfg, 0, sizeof(priv->scan_cfg));
+ priv->scan_cfg.report_condition = BG_SCAN_SSID_MATCH;
+ while (buf_left >= 2) {
+ switch (*ptr) {
+ case WEXT_CSCAN_SSID_SECTION:
+ ssid_len = *(ptr + 1);
+ if ((buf_left < (ssid_len + 2)) ||
+ (ssid_len > MLAN_MAX_SSID_LENGTH)) {
+ PRINTM(MERROR, "Invalid ssid, buf_left=%d, ssid_len=%d\n",
+ buf_left, ssid_len);
+ buf_left = 0;
+ break;
+ }
+ if (ssid_len && (num_ssid < (MRVDRV_MAX_SSID_LIST_LENGTH - 1))) {
+ strncpy(priv->scan_cfg.ssid_list[num_ssid].ssid, ptr + 2,
+ ssid_len);
+ priv->scan_cfg.ssid_list[num_ssid].max_len = 0;
+ PRINTM(MIOCTL, "BG scan: ssid=%s\n",
+ priv->scan_cfg.ssid_list[num_ssid].ssid);
+ num_ssid++;
+ }
+ buf_left -= ssid_len + 2;
+ ptr += ssid_len + 2;
+ break;
+ case WEXT_BGSCAN_RSSI_SECTION:
+ priv->scan_cfg.report_condition = BG_SCAN_SSID_RSSI_MATCH;
+ priv->scan_cfg.rssi_threshold = ptr[1];
+ PRINTM(MIOCTL, "BG scan: rssi_threshold=%d\n",
+ (int) priv->scan_cfg.rssi_threshold);
+ ptr += 2;
+ buf_left -= 2;
+ break;
+ case WEXT_BGSCAN_INTERVAL_SECTION:
+ priv->scan_cfg.scan_interval = (ptr[2] << 8 | ptr[1]) * 1000;
+ PRINTM(MIOCTL, "BG scan: scan_interval=%d\n",
+ (int) priv->scan_cfg.scan_interval);
+ ptr += 3;
+ buf_left -= 3;
+ break;
+ default:
+ buf_left = 0;
+ break;
+ }
+ }
+ /** set bgscan when ssid_num > 0 */
+ if (num_ssid) {
+ if (MLAN_STATUS_SUCCESS != woal_get_band(priv, &band)) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ switch (band) {
+ case WIFI_FREQUENCY_BAND_2GHZ:
+ priv->scan_cfg.chan_list[0].radio_type = 0 | BAND_SPECIFIED;
+ break;
+ case WIFI_FREQUENCY_BAND_5GHZ:
+ priv->scan_cfg.chan_list[0].radio_type = 1 | BAND_SPECIFIED;
+ break;
+ default:
+ break;
+ }
+ priv->scan_cfg.bss_type = MLAN_BSS_MODE_INFRA;
+ priv->scan_cfg.action = BG_SCAN_ACT_SET;
+ priv->scan_cfg.enable = MTRUE;
+ ret = woal_request_bgscan(priv, MOAL_IOCTL_WAIT, &priv->scan_cfg);
+ }
+ done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief stop bg scan
+ *
+ * @param priv A pointer to moal_private structure
+ *
+ * @return MLAN_STATUS_SUCCESS -- success, otherwise fail
+ */
+mlan_status
+woal_stop_bg_scan(moal_private * priv)
+{
+ wlan_bgscan_cfg scan_cfg;
+ ENTER();
+
+ memset(&scan_cfg, 0, sizeof(scan_cfg));
+ scan_cfg.action = BG_SCAN_ACT_SET;
+ scan_cfg.enable = MFALSE;
+ return woal_request_bgscan(priv, MOAL_IOCTL_WAIT, &scan_cfg);
+
+ LEAVE();
+}
+
+/**
+ * @brief set bgscan config
+ *
+ * @param handle A pointer to moal_handle structure
+ *
+ * @return MLAN_STATUS_SUCCESS -- success, otherwise fail
+ */
+void
+woal_reconfig_bgscan(moal_handle * handle)
+{
+ int i;
+ for (i = 0; i < MIN(handle->priv_num, MLAN_MAX_BSS_NUM); i++) {
+ if (handle->priv[i] &&
+ (GET_BSS_ROLE(handle->priv[i]) == MLAN_BSS_ROLE_STA)) {
+ if (handle->priv[i]->bg_scan_start &&
+ handle->priv[i]->bg_scan_reported) {
+ PRINTM(MIOCTL, "Reconfig BGSCAN\n");
+ woal_request_bgscan(handle->priv[i], MOAL_NO_WAIT,
+ &handle->priv[i]->scan_cfg);
+ handle->priv[i]->bg_scan_reported = MFALSE;
+ }
+ }
+ }
+}
+
+/**
+ * @brief set rssi low threshold
+ *
+ * @param priv A pointer to moal_private structure
+ * @param scan_type MLAN_SCAN_TYPE_ACTIVE/MLAN_SCAN_TYPE_PASSIVE
+ *
+ * @return MLAN_STATUS_SUCCESS -- success, otherwise fail
+ */
+mlan_status
+woal_set_rssi_low_threshold(moal_private * priv, char *rssi)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_misc_cfg *misc = NULL;
+ int low_rssi = 0;
+
+ ENTER();
+ if (priv->media_connected == MFALSE)
+ goto done;
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+ misc = (mlan_ds_misc_cfg *) req->pbuf;
+ req->req_id = MLAN_IOCTL_MISC_CFG;
+ misc->sub_command = MLAN_OID_MISC_SUBSCRIBE_EVENT;
+ req->action = MLAN_ACT_SET;
+ misc->param.subscribe_event.evt_bitmap = SUBSCRIBE_EVT_RSSI_LOW;
+ if (MLAN_STATUS_SUCCESS != woal_atoi(&low_rssi, rssi)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ misc->param.subscribe_event.low_rssi = low_rssi;
+ misc->param.subscribe_event.low_rssi_freq = 0;
+ if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ done:
+ if (req)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Get power mode
+ *
+ * @param priv A pointer to moal_private structure
+ * @param powermode A pointer to powermode buf
+ *
+ * @return MLAN_STATUS_SUCCESS -- success, otherwise fail
+ */
+mlan_status
+woal_get_powermode(moal_private * priv, int *powermode)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ int ps_mode;
+
+ ENTER();
+
+ if (MLAN_STATUS_SUCCESS !=
+ woal_set_get_power_mgmt(priv, MLAN_ACT_GET, &ps_mode, 0)) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ if (ps_mode)
+ *powermode = MFALSE;
+ else
+ *powermode = MTRUE;
+
+ done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief set scan type
+ *
+ * @param priv A pointer to moal_private structure
+ * @param scan_type MLAN_SCAN_TYPE_ACTIVE/MLAN_SCAN_TYPE_PASSIVE
+ *
+ * @return MLAN_STATUS_SUCCESS -- success, otherwise fail
+ */
+mlan_status
+woal_set_scan_type(moal_private * priv, t_u32 scan_type)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_ds_scan *scan = NULL;
+ mlan_ioctl_req *req = NULL;
+
+ ENTER();
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_scan));
+ if (req == NULL) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ scan = (mlan_ds_scan *) req->pbuf;
+ scan->sub_command = MLAN_OID_SCAN_CONFIG;
+ req->req_id = MLAN_IOCTL_SCAN;
+ req->action = MLAN_ACT_SET;
+ memset(&scan->param.scan_cfg, 0, sizeof(mlan_scan_cfg));
+ scan->param.scan_cfg.scan_type = scan_type;
+
+ if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT))
+ ret = MLAN_STATUS_FAILURE;
+ done:
+ if (req)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief set power mode
+ *
+ * @param priv A pointer to moal_private structure
+ * @param powermode A pointer to powermode string.
+ *
+ * @return MLAN_STATUS_SUCCESS -- success, otherwise fail
+ */
+mlan_status
+woal_set_powermode(moal_private * priv, char *powermode)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ int disabled;
+
+ ENTER();
+
+ if (*powermode == '1') {
+ PRINTM(MIOCTL, "Disable power save\n");
+ disabled = 1;
+ } else if (*powermode == '0') {
+ PRINTM(MIOCTL, "Enable power save\n");
+ disabled = 0;
+ } else {
+ PRINTM(MERROR, "unsupported power mode\n");
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ if (MLAN_STATUS_SUCCESS !=
+ woal_set_get_power_mgmt(priv, MLAN_ACT_SET, &disabled, 0))
+ ret = MLAN_STATUS_FAILURE;
+
+ done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief set combo scan
+ *
+ * @param priv A pointer to moal_private structure
+ * @param buf A pointer to scan command buf
+ * @param length buf length
+ *
+ * @return 0 -- success, otherwise fail
+ */
+int
+woal_set_combo_scan(moal_private * priv, char *buf, int length)
+{
+ int ret = 0;
+ wlan_user_scan_cfg scan_cfg;
+ t_u8 *ptr = buf + WEXT_CSCAN_HEADER_SIZE;
+ int buf_left = length - WEXT_CSCAN_HEADER_SIZE;
+ int num_ssid = 0;
+ int num_chan = 0;
+ int ssid_len = 0;
+ int i = 0;
+ t_u16 passive_scan_time = 0;
+ t_u16 specific_scan_time = 0;
+
+ ENTER();
+ memset(&scan_cfg, 0, sizeof(scan_cfg));
+ while (buf_left >= 2) {
+ switch (*ptr) {
+ case WEXT_CSCAN_SSID_SECTION:
+ ssid_len = *(ptr + 1);
+ if ((buf_left < (ssid_len + 2)) ||
+ (ssid_len > MLAN_MAX_SSID_LENGTH)) {
+ PRINTM(MERROR, "Invalid ssid, buf_left=%d, ssid_len=%d\n",
+ buf_left, ssid_len);
+ buf_left = 0;
+ break;
+ }
+ if (ssid_len && (num_ssid < (MRVDRV_MAX_SSID_LIST_LENGTH - 1))) {
+ strncpy(scan_cfg.ssid_list[num_ssid].ssid, ptr + 2, ssid_len);
+ scan_cfg.ssid_list[num_ssid].max_len = 0;
+ PRINTM(MIOCTL, "Combo scan: ssid=%s\n",
+ scan_cfg.ssid_list[num_ssid].ssid);
+ num_ssid++;
+ }
+ buf_left -= ssid_len + 2;
+ ptr += ssid_len + 2;
+ break;
+ case WEXT_CSCAN_CHANNEL_SECTION:
+ num_chan = ptr[1];
+ if ((buf_left < (num_chan + 2)) ||
+ (num_chan > WLAN_USER_SCAN_CHAN_MAX)) {
+ PRINTM(MERROR,
+ "Invalid channel list, buf_left=%d, num_chan=%d\n",
+ buf_left, num_chan);
+ buf_left = 0;
+ break;
+ }
+ for (i = 0; i < num_chan; i++) {
+ scan_cfg.chan_list[i].chan_number = ptr[2 + i];
+ PRINTM(MIOCTL, "Combo scan: chan=%d\n",
+ scan_cfg.chan_list[i].chan_number);
+ }
+ buf_left -= 2 + num_chan;
+ ptr += 2 + num_chan;
+ break;
+ case WEXT_CSCAN_PASV_DWELL_SECTION:
+ if (buf_left < 3) {
+ PRINTM(MERROR, "Invalid PASV_DWELL_SECTION, buf_left=%d\n",
+ buf_left);
+ buf_left = 0;
+ break;
+ }
+ passive_scan_time = ptr[2] << 8 | ptr[1];
+ ptr += 3;
+ buf_left -= 3;
+ break;
+ case WEXT_CSCAN_HOME_DWELL_SECTION:
+ if (buf_left < 3) {
+ PRINTM(MERROR, "Invalid HOME_DWELL_SECTION, buf_left=%d\n",
+ buf_left);
+ buf_left = 0;
+ break;
+ }
+ specific_scan_time = ptr[2] << 8 | ptr[1];
+ ptr += 3;
+ buf_left -= 3;
+ break;
+ default:
+ buf_left = 0;
+ break;
+ }
+ }
+ if (passive_scan_time || specific_scan_time) {
+ PRINTM(MIOCTL, "Set passive_scan_time=%d specific_scan_time=%d\n",
+ passive_scan_time, specific_scan_time);
+ if (MLAN_STATUS_FAILURE ==
+ woal_set_scan_time(priv, passive_scan_time, specific_scan_time)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ }
+ if (num_ssid || num_chan) {
+ if (num_ssid) {
+ /* Add broadcast scan to ssid_list */
+ scan_cfg.ssid_list[num_ssid].max_len = 0xff;
+ if (priv->scan_type == MLAN_SCAN_TYPE_PASSIVE)
+ woal_set_scan_type(priv, MLAN_SCAN_TYPE_ACTIVE);
+ }
+ if (MLAN_STATUS_FAILURE == woal_do_scan(priv, &scan_cfg))
+ ret = -EFAULT;
+ if (num_ssid && (priv->scan_type == MLAN_SCAN_TYPE_PASSIVE))
+ woal_set_scan_type(priv, MLAN_SCAN_TYPE_PASSIVE);
+ } else {
+ /* request broadcast scan */
+ if (MLAN_STATUS_FAILURE == woal_do_scan(priv, NULL))
+ ret = -EFAULT;
+ }
+ done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Get band
+ *
+ * @param priv A pointer to moal_private structure
+ * @param band A pointer to band buf
+ *
+ * @return MLAN_STATUS_SUCCESS -- success, otherwise fail
+ */
+mlan_status
+woal_get_band(moal_private * priv, int *band)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_radio_cfg *radio_cfg = NULL;
+ int support_band = 0;
+
+ ENTER();
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_radio_cfg));
+ if (req == NULL) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ radio_cfg = (mlan_ds_radio_cfg *) req->pbuf;
+ radio_cfg->sub_command = MLAN_OID_BAND_CFG;
+ req->req_id = MLAN_IOCTL_RADIO_CFG;
+ /* Get config_bands, adhoc_start_band and adhoc_channel values from MLAN */
+ req->action = MLAN_ACT_GET;
+ if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ if (radio_cfg->param.band_cfg.config_bands & (BAND_B | BAND_G | BAND_GN))
+ support_band |= WIFI_FREQUENCY_BAND_2GHZ;
+ if (radio_cfg->param.band_cfg.config_bands & (BAND_A | BAND_AN))
+ support_band |= WIFI_FREQUENCY_BAND_5GHZ;
+ *band = support_band;
+ if (support_band == WIFI_FREQUENCY_ALL_BAND)
+ *band = WIFI_FREQUENCY_BAND_AUTO;
+ done:
+ if (req)
+ kfree(req);
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief set band
+ *
+ * @param priv A pointer to moal_private structure
+ * @param pband A pointer to band string.
+ *
+ * @return MLAN_STATUS_SUCCESS -- success, otherwise fail
+ */
+mlan_status
+woal_set_band(moal_private * priv, char *pband)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ int band = 0;
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_radio_cfg *radio_cfg = NULL;
+
+ ENTER();
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_radio_cfg));
+ if (req == NULL) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ radio_cfg = (mlan_ds_radio_cfg *) req->pbuf;
+ radio_cfg->sub_command = MLAN_OID_BAND_CFG;
+ req->req_id = MLAN_IOCTL_RADIO_CFG;
+
+ /* Get fw supported values from MLAN */
+ req->action = MLAN_ACT_GET;
+ if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ if (*pband == '0') {
+ PRINTM(MIOCTL, "Set band to AUTO\n");
+ band = radio_cfg->param.band_cfg.fw_bands;
+#if defined(STA_CFG80211) || defined(UAP_CFG80211)
+ if (IS_STA_OR_UAP_CFG80211(cfg80211_wext) && priv->wdev &&
+ priv->wdev->wiphy) {
+ if (radio_cfg->param.band_cfg.fw_bands & BAND_A)
+ priv->wdev->wiphy->bands[IEEE80211_BAND_5GHZ] =
+ &cfg80211_band_5ghz;
+ priv->wdev->wiphy->bands[IEEE80211_BAND_2GHZ] = &cfg80211_band_2ghz;
+ }
+#endif
+ } else if (*pband == '1') {
+ PRINTM(MIOCTL, "Set band to 5G\n");
+ if (!(radio_cfg->param.band_cfg.fw_bands & BAND_A)) {
+ PRINTM(MERROR, "Don't support 5G band\n");
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ band = BAND_A;
+ band |= BAND_AN;
+#if defined(STA_CFG80211) || defined(UAP_CFG80211)
+ if (IS_STA_OR_UAP_CFG80211(cfg80211_wext) && priv->wdev &&
+ priv->wdev->wiphy) {
+ priv->wdev->wiphy->bands[IEEE80211_BAND_5GHZ] = &cfg80211_band_5ghz;
+ priv->wdev->wiphy->bands[IEEE80211_BAND_2GHZ] = NULL;
+ }
+#endif
+ } else if (*pband == '2') {
+ PRINTM(MIOCTL, "Set band to 2G\n");
+ band = BAND_B | BAND_G;
+ band |= BAND_GN;
+#if defined(STA_CFG80211) || defined(UAP_CFG80211)
+ if (IS_STA_OR_UAP_CFG80211(cfg80211_wext) && priv->wdev &&
+ priv->wdev->wiphy) {
+ priv->wdev->wiphy->bands[IEEE80211_BAND_5GHZ] = NULL;
+ priv->wdev->wiphy->bands[IEEE80211_BAND_2GHZ] = &cfg80211_band_2ghz;
+ }
+#endif
+ } else {
+ PRINTM(MERROR, "unsupported band\n");
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ /* Set config_bands to MLAN */
+ req->action = MLAN_ACT_SET;
+ memset(&radio_cfg->param.band_cfg, 0, sizeof(mlan_ds_band_cfg));
+ radio_cfg->param.band_cfg.config_bands = band;
+ radio_cfg->param.band_cfg.adhoc_start_band = band;
+ if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ done:
+ if (req)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Add RX Filter
+ *
+ * @param priv A pointer to moal_private structure
+ * @param rxfilter A pointer to rxfilter string.
+ *
+ * @return MLAN_STATUS_SUCCESS -- success, otherwise fail
+ */
+mlan_status
+woal_add_rxfilter(moal_private * priv, char *rxfilter)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ ENTER();
+ /* Android command: "DRIVER RXFILTER-ADD 0" "DRIVER RXFILTER-ADD 1" "DRIVER
+ RXFILTER-ADD 3" */
+ if (*rxfilter == '0') {
+ PRINTM(MIOCTL, "Add IPV4 multicast filter\n");
+ priv->rx_filter |= RX_FILTER_IPV4_MULTICAST;
+ } else if (*rxfilter == '1') {
+ PRINTM(MIOCTL, "Add broadcast filter\n");
+ priv->rx_filter |= RX_FILTER_BROADCAST;
+ } else if (*rxfilter == '2') {
+ PRINTM(MIOCTL, "Add unicast filter\n");
+ priv->rx_filter |= RX_FILTER_UNICAST;
+ } else if (*rxfilter == '3') {
+ PRINTM(MIOCTL, "Add IPV6 multicast fitler\n");
+ priv->rx_filter |= RX_FILTER_IPV6_MULTICAST;
+ } else {
+ PRINTM(MERROR, "unsupported rx fitler\n");
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Remove RX Filter
+ *
+ * @param priv A pointer to moal_private structure
+ * @param rxfilter A pointer to rxfilter string.
+ *
+ * @return MLAN_STATUS_SUCCESS -- success, otherwise fail
+ */
+mlan_status
+woal_remove_rxfilter(moal_private * priv, char *rxfilter)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ ENTER();
+ if (*rxfilter == '0') {
+ PRINTM(MIOCTL, "Remove IPV4 multicast filter\n");
+ priv->rx_filter &= ~RX_FILTER_IPV4_MULTICAST;
+ } else if (*rxfilter == '1') {
+ PRINTM(MIOCTL, "Remove broadcast filter\n");
+ priv->rx_filter &= ~RX_FILTER_BROADCAST;
+ } else if (*rxfilter == '2') {
+ PRINTM(MIOCTL, "Remove unicast filter\n");
+ priv->rx_filter &= ~RX_FILTER_UNICAST;
+ } else if (*rxfilter == '3') {
+ PRINTM(MIOCTL, "Remove IPV6 multicast fitler\n");
+ priv->rx_filter &= ~RX_FILTER_IPV6_MULTICAST;
+ } else {
+ PRINTM(MERROR, "unsupported rx fitler\n");
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set QoS configuration
+ *
+ * @param priv A pointer to moal_private structure
+ * @param qos_cfg A pointer to QoS configuration structure
+ *
+ * @return MLAN_STATUS_SUCCESS -- success, otherwise fail
+ */
+mlan_status
+woal_set_qos_cfg(moal_private * priv, char *qos_cfg)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_ds_wmm_cfg *cfg = NULL;
+ mlan_ioctl_req *req = NULL;
+ int qosinfo = 0;
+
+ ENTER();
+ if (MLAN_STATUS_SUCCESS != woal_atoi(&qosinfo, qos_cfg)) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ PRINTM(MIOCTL, "set qosinfo=%d\n", qosinfo);
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_wmm_cfg));
+ if (req == NULL) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ cfg = (mlan_ds_wmm_cfg *) req->pbuf;
+ cfg->sub_command = MLAN_OID_WMM_CFG_QOS;
+ req->req_id = MLAN_IOCTL_WMM_CFG;
+ req->action = MLAN_ACT_SET;
+ cfg->param.qos_cfg = (t_u8) qosinfo;
+ if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT))
+ ret = MLAN_STATUS_FAILURE;
+ done:
+ if (req)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set sleep period
+ *
+ * @param priv A pointer to moal_private structure
+ * @param psleeppd A pointer to sleep period configuration structure
+ *
+ * @return MLAN_STATUS_SUCCESS -- success, otherwise fail
+ */
+int
+woal_set_sleeppd(moal_private * priv, char *psleeppd)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_ds_pm_cfg *pm_cfg = NULL;
+ mlan_ioctl_req *req = NULL;
+ int sleeppd = 0;
+
+ ENTER();
+
+ if (MLAN_STATUS_SUCCESS != woal_atoi(&sleeppd, psleeppd)) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ PRINTM(MIOCTL, "set sleeppd=%d\n", sleeppd);
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_pm_cfg));
+ if (req == NULL) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ pm_cfg = (mlan_ds_pm_cfg *) req->pbuf;
+ pm_cfg->sub_command = MLAN_OID_PM_CFG_SLEEP_PD;
+ req->req_id = MLAN_IOCTL_PM_CFG;
+ if ((sleeppd <= MAX_SLEEP_PERIOD && sleeppd >= MIN_SLEEP_PERIOD) ||
+ (sleeppd == 0)
+ || (sleeppd == SLEEP_PERIOD_RESERVED_FF)
+ ) {
+ req->action = MLAN_ACT_SET;
+ pm_cfg->param.sleep_period = sleeppd;
+ } else {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ done:
+ if (req)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+#endif /* STA_SUPPORT */
diff --git a/drivers/net/wireless/sd8797/mlinux/moal_main.c b/drivers/net/wireless/sd8797/mlinux/moal_main.c
new file mode 100644
index 000000000000..820c1267cc78
--- /dev/null
+++ b/drivers/net/wireless/sd8797/mlinux/moal_main.c
@@ -0,0 +1,3773 @@
+/** @file moal_main.c
+ *
+ * @brief This file contains the major functions in WLAN
+ * driver.
+ *
+ * Copyright (C) 2008-2012, Marvell International Ltd.
+ *
+ * This software file (the "File") is distributed by Marvell International
+ * Ltd. under the terms of the GNU General Public License Version 2, June 1991
+ * (the "License"). You may use, redistribute and/or modify this File in
+ * accordance with the terms and conditions of the License, a copy of which
+ * is available by writing to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
+ * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
+ *
+ * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
+ * ARE EXPRESSLY DISCLAIMED. The License provides additional details about
+ * this warranty disclaimer.
+ *
+ */
+
+/********************************************************
+Change log:
+ 10/21/2008: initial version
+********************************************************/
+
+#include "moal_main.h"
+#include "moal_sdio.h"
+#ifdef UAP_SUPPORT
+#include "moal_uap.h"
+#endif
+#if defined(STA_CFG80211) || defined(UAP_CFG80211)
+#include "moal_cfg80211.h"
+#endif
+#ifdef STA_CFG80211
+#ifdef STA_SUPPORT
+#include "moal_sta_cfg80211.h"
+#endif
+#endif
+#ifdef UAP_CFG80211
+#ifdef UAP_SUPPORT
+#include "moal_uap_cfg80211.h"
+#endif
+#endif
+#include <linux/platform_device.h>
+#include <linux/wlan_plat.h>
+#include "moal_eth_ioctl.h"
+
+/********************************************************
+ Local Variables
+********************************************************/
+
+#define KERN_VERSION "26"
+
+/** Driver version */
+char driver_version[] =
+ "SD8797-%s-M2614" MLAN_RELEASE_VERSION "-GPL" "-(" "FP" FPNUM ")"
+#ifdef DEBUG_LEVEL2
+ "-dbg"
+#endif
+ " ";
+
+/** Firmware name */
+char *fw_name = NULL;
+int req_fw_nowait = 0;
+
+/** MAC address */
+char *mac_addr = NULL;
+
+#ifdef MFG_CMD_SUPPORT
+/** Mfg mode */
+int mfg_mode = 0;
+#endif
+
+/** SDIO interrupt mode (0: INT_MODE_SDIO, 1: INT_MODE_GPIO) */
+int intmode = INT_MODE_SDIO;
+/** GPIO interrupt pin number */
+int gpiopin = 0;
+
+/** Auto deep sleep */
+int auto_ds = 0;
+
+/** IEEE PS mode */
+int ps_mode = 0;
+
+/** Max Tx buffer size */
+int max_tx_buf = 0;
+
+#ifdef STA_SUPPORT
+/** Max STA interfaces */
+int max_sta_bss = DEF_STA_BSS;
+#endif
+
+#ifdef UAP_SUPPORT
+/** Max uAP interfaces */
+int max_uap_bss = DEF_UAP_BSS;
+#endif
+
+#if defined(WIFI_DIRECT_SUPPORT)
+/** Max WIFIDIRECT interfaces */
+int max_wfd_bss = DEF_WIFIDIRECT_BSS;
+#endif
+
+#ifdef SDIO_SUSPEND_RESUME
+/** PM keep power */
+int pm_keep_power = 1;
+#endif
+
+#if defined(STA_SUPPORT)
+/** 802.11d configuration */
+int cfg_11d = 0;
+#endif
+
+/** CAL data config file */
+char *cal_data_cfg = NULL;
+/** Init config file (MAC address, register etc.) */
+char *init_cfg = NULL;
+
+/** Enable minicard power-up/down */
+int minicard_pwrup = 1;
+/** Pointer to struct with control hooks */
+struct wifi_platform_data *wifi_control_data = NULL;
+
+int cfg80211_wext = STA_WEXT_MASK | UAP_WEXT_MASK;
+
+/** woal_callbacks */
+static mlan_callbacks woal_callbacks = {
+ .moal_get_fw_data = moal_get_fw_data,
+ .moal_init_fw_complete = moal_init_fw_complete,
+ .moal_shutdown_fw_complete = moal_shutdown_fw_complete,
+ .moal_send_packet_complete = moal_send_packet_complete,
+ .moal_recv_packet = moal_recv_packet,
+ .moal_recv_event = moal_recv_event,
+ .moal_ioctl_complete = moal_ioctl_complete,
+ .moal_alloc_mlan_buffer = moal_alloc_mlan_buffer,
+ .moal_free_mlan_buffer = moal_free_mlan_buffer,
+ .moal_write_reg = moal_write_reg,
+ .moal_read_reg = moal_read_reg,
+ .moal_write_data_sync = moal_write_data_sync,
+ .moal_read_data_sync = moal_read_data_sync,
+ .moal_malloc = moal_malloc,
+ .moal_mfree = moal_mfree,
+ .moal_memset = moal_memset,
+ .moal_memcpy = moal_memcpy,
+ .moal_memmove = moal_memmove,
+ .moal_memcmp = moal_memcmp,
+ .moal_udelay = moal_udelay,
+ .moal_get_system_time = moal_get_system_time,
+ .moal_init_timer = moal_init_timer,
+ .moal_free_timer = moal_free_timer,
+ .moal_start_timer = moal_start_timer,
+ .moal_stop_timer = moal_stop_timer,
+ .moal_init_lock = moal_init_lock,
+ .moal_free_lock = moal_free_lock,
+ .moal_spin_lock = moal_spin_lock,
+ .moal_spin_unlock = moal_spin_unlock,
+ .moal_print = moal_print,
+ .moal_print_netintf = moal_print_netintf,
+ .moal_assert = moal_assert,
+};
+
+/** Default Driver mode */
+#if defined(STA_SUPPORT) && defined(UAP_SUPPORT)
+#if defined(WIFI_DIRECT_SUPPORT)
+int drv_mode = (DRV_MODE_STA | DRV_MODE_UAP | DRV_MODE_WIFIDIRECT);
+#else
+int drv_mode = (DRV_MODE_STA | DRV_MODE_UAP);
+#endif
+#else
+#ifdef STA_SUPPORT
+int drv_mode = DRV_MODE_STA;
+#else
+int drv_mode = DRV_MODE_UAP;
+#endif /* STA_SUPPORT */
+#endif /* STA_SUPPORT & UAP_SUPPORT */
+
+/********************************************************
+ Global Variables
+********************************************************/
+
+/** Semaphore for add/remove card */
+struct semaphore AddRemoveCardSem;
+/**
+ * the maximum number of adapter supported
+ **/
+#define MAX_MLAN_ADAPTER 2
+/**
+ * The global variable of a pointer to moal_handle
+ * structure variable
+ **/
+moal_handle *m_handle[MAX_MLAN_ADAPTER];
+
+#ifdef DEBUG_LEVEL1
+#ifdef DEBUG_LEVEL2
+#define DEFAULT_DEBUG_MASK (0xffffffff)
+#else
+#define DEFAULT_DEBUG_MASK (MMSG | MFATAL | MERROR)
+#endif /* DEBUG_LEVEL2 */
+t_u32 drvdbg = DEFAULT_DEBUG_MASK;
+#endif /* DEBUG_LEVEL1 */
+
+int woal_open(struct net_device *dev);
+int woal_close(struct net_device *dev);
+int woal_set_mac_address(struct net_device *dev, void *addr);
+void woal_tx_timeout(struct net_device *dev);
+struct net_device_stats *woal_get_stats(struct net_device *dev);
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,34)
+u16 woal_select_queue(struct net_device *dev, struct sk_buff *skb);
+#endif
+
+mlan_debug_info info;
+
+/********************************************************
+ Local Functions
+********************************************************/
+
+/**
+ * @brief This function dynamically populates the driver mode table
+ *
+ * @param handle A pointer to moal_handle structure
+ * @param drv_mode_local Driver mode
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+static mlan_status
+woal_update_drv_tbl(moal_handle * handle, int drv_mode_local)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ unsigned int intf_num = 0;
+ int i = 0, j = 0;
+ mlan_bss_attr *bss_tbl = NULL;
+
+ ENTER();
+
+ /* Calculate number of interfaces */
+#ifdef STA_SUPPORT
+ if (drv_mode_local & DRV_MODE_STA) {
+ if ((max_sta_bss < 1) || (max_sta_bss > MAX_STA_BSS)) {
+ PRINTM(MWARN, "Unsupported max_sta_bss (%d), setting to default\n",
+ max_sta_bss);
+ max_sta_bss = DEF_STA_BSS;
+ }
+ intf_num += max_sta_bss;
+ }
+#endif /* STA_SUPPORT */
+
+#ifdef UAP_SUPPORT
+ if (drv_mode_local & DRV_MODE_UAP) {
+ if ((max_uap_bss < 1) || (max_uap_bss > MAX_UAP_BSS)) {
+ PRINTM(MWARN, "Unsupported max_uap_bss (%d), setting to default\n",
+ max_uap_bss);
+ max_uap_bss = DEF_UAP_BSS;
+ }
+ intf_num += max_uap_bss;
+ }
+#endif /* UAP_SUPPORT */
+
+#if defined(WIFI_DIRECT_SUPPORT)
+ if (drv_mode_local & DRV_MODE_WIFIDIRECT) {
+ if ((max_wfd_bss < 1) || (max_wfd_bss > MAX_WIFIDIRECT_BSS)) {
+ PRINTM(MWARN, "Unsupported max_wfd_bss (%d), setting to default\n",
+ max_wfd_bss);
+ max_wfd_bss = DEF_WIFIDIRECT_BSS;
+ }
+ intf_num += max_wfd_bss;
+ }
+#endif /* WIFI_DIRECT_SUPPORT && V14_FEATURE */
+
+ /* Create BSS attribute table */
+ if ((intf_num == 0) || (intf_num > MLAN_MAX_BSS_NUM)) {
+ PRINTM(MERROR, "Unsupported number of BSS %d\n", intf_num);
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ } else {
+ /* Create new table */
+ if (!
+ (bss_tbl =
+ (mlan_bss_attr *) kmalloc(sizeof(mlan_bss_attr) * intf_num,
+ GFP_KERNEL))) {
+ PRINTM(MERROR, "Could not create BSS attribute table\n");
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ }
+
+ /* Populate BSS attribute table */
+#ifdef STA_SUPPORT
+ if (drv_mode_local & DRV_MODE_STA) {
+ for (j = 0; j < max_sta_bss; j++) {
+ if (i >= intf_num)
+ break;
+ bss_tbl[i].bss_type = MLAN_BSS_TYPE_STA;
+ bss_tbl[i].frame_type = MLAN_DATA_FRAME_TYPE_ETH_II;
+ bss_tbl[i].active = MTRUE;
+ bss_tbl[i].bss_priority = 0;
+ bss_tbl[i].bss_num = j;
+ i++;
+ }
+ }
+#endif /* STA_SUPPORT */
+
+#ifdef UAP_SUPPORT
+ if (drv_mode_local & DRV_MODE_UAP) {
+ for (j = 0; j < max_uap_bss; j++) {
+ if (i >= intf_num)
+ break;
+ bss_tbl[i].bss_type = MLAN_BSS_TYPE_UAP;
+ bss_tbl[i].frame_type = MLAN_DATA_FRAME_TYPE_ETH_II;
+ bss_tbl[i].active = MTRUE;
+ bss_tbl[i].bss_priority = 0;
+ bss_tbl[i].bss_num = j;
+ i++;
+ }
+ }
+#endif /* UAP_SUPPORT */
+
+#if defined(WIFI_DIRECT_SUPPORT)
+ if (drv_mode_local & DRV_MODE_WIFIDIRECT) {
+ for (j = 0; j < max_wfd_bss; j++) {
+ if (i >= intf_num)
+ break;
+ bss_tbl[i].bss_type = MLAN_BSS_TYPE_WIFIDIRECT;
+ bss_tbl[i].frame_type = MLAN_DATA_FRAME_TYPE_ETH_II;
+ bss_tbl[i].active = MTRUE;
+ bss_tbl[i].bss_priority = 0;
+ bss_tbl[i].bss_num = j;
+ i++;
+ }
+ }
+#endif /* WIFI_DIRECT_SUPPORT && V14_FEATURE */
+
+ /* Clear existing table, if any */
+ if (handle->drv_mode.bss_attr != NULL) {
+ kfree(handle->drv_mode.bss_attr);
+ handle->drv_mode.bss_attr = NULL;
+ }
+
+ /* Create moal_drv_mode entry */
+ handle->drv_mode.drv_mode = drv_mode;
+ handle->drv_mode.intf_num = intf_num;
+ handle->drv_mode.bss_attr = bss_tbl;
+ if (fw_name) {
+ handle->drv_mode.fw_name = fw_name;
+ } else {
+#if defined(UAP_SUPPORT) && defined(STA_SUPPORT)
+ handle->drv_mode.fw_name = DEFAULT_AP_STA_FW_NAME;
+#else
+#ifdef UAP_SUPPORT
+ handle->drv_mode.fw_name = DEFAULT_AP_FW_NAME;
+#else
+ handle->drv_mode.fw_name = DEFAULT_FW_NAME;
+#endif /* UAP_SUPPORT */
+#endif /* UAP_SUPPORT && STA_SUPPORT */
+ }
+
+ done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function initializes software
+ *
+ * @param handle A pointer to moal_handle structure
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+static mlan_status
+woal_init_sw(moal_handle * handle)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ unsigned int i;
+ mlan_device device;
+ t_void *pmlan;
+
+ ENTER();
+
+ /* Initialize moal_handle structure */
+ handle->hardware_status = HardwareStatusInitializing;
+ handle->main_state = MOAL_STATE_IDLE;
+
+#ifdef STA_SUPPORT
+ if (MTRUE
+#ifdef STA_WEXT
+ && !IS_STA_WEXT(cfg80211_wext)
+#endif
+#ifdef STA_CFG80211
+ && !IS_STA_CFG80211(cfg80211_wext)
+#endif
+ ) {
+ PRINTM(MERROR, "STA without WEXT or CFG80211 bit definition!\n");
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+#endif /* STA_SUPPORT */
+
+ if (woal_update_drv_tbl(handle, drv_mode) != MLAN_STATUS_SUCCESS) {
+ PRINTM(MERROR, "Could not update driver mode table\n");
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+
+ /* PnP and power profile */
+ handle->surprise_removed = MFALSE;
+ init_waitqueue_head(&handle->init_wait_q);
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,34)
+ spin_lock_init(&handle->queue_lock);
+#endif
+
+#if defined(SDIO_SUSPEND_RESUME)
+ handle->is_suspended = MFALSE;
+ handle->hs_activated = MFALSE;
+ handle->suspend_fail = MFALSE;
+#ifdef SDIO_SUSPEND_RESUME
+ handle->suspend_notify_req = MFALSE;
+#endif
+ handle->hs_skip_count = 0;
+ handle->hs_force_count = 0;
+ handle->cmd52_func = 0;
+ handle->cmd52_reg = 0;
+ handle->cmd52_val = 0;
+ init_waitqueue_head(&handle->hs_activate_wait_q);
+#endif
+
+ /* Initialize measurement wait queue */
+ handle->meas_wait_q_woken = MFALSE;
+ handle->meas_start_jiffies = 0;
+ handle->cac_period = MFALSE;
+ handle->delay_bss_start = MFALSE;
+ init_waitqueue_head(&handle->meas_wait_q);
+#ifdef DFS_TESTING_SUPPORT
+ handle->cac_period_jiffies = 0;
+#endif
+
+#ifdef REASSOCIATION
+ MOAL_INIT_SEMAPHORE(&handle->reassoc_sem);
+ handle->reassoc_on = 0;
+
+ /* Initialize the timer for the reassociation */
+ woal_initialize_timer(&handle->reassoc_timer,
+ woal_reassoc_timer_func, handle);
+
+ handle->is_reassoc_timer_set = MFALSE;
+#endif /* REASSOCIATION */
+
+ /* Register to MLAN */
+ memset(&device, 0, sizeof(mlan_device));
+ device.pmoal_handle = handle;
+
+#ifdef MFG_CMD_SUPPORT
+ device.mfg_mode = (t_u32) mfg_mode;
+#endif
+ device.int_mode = (t_u32) intmode;
+ device.gpio_pin = (t_u32) gpiopin;
+#ifdef DEBUG_LEVEL1
+ device.drvdbg = drvdbg;
+#endif
+ device.auto_ds = (t_u32) auto_ds;
+ device.ps_mode = (t_u32) ps_mode;
+ device.max_tx_buf = (t_u32) max_tx_buf;
+#if defined(STA_SUPPORT)
+ device.cfg_11d = (t_u32) cfg_11d;
+#endif
+#ifdef SDIO_MULTI_PORT_TX_AGGR
+#ifdef MMC_QUIRK_BLKSZ_FOR_BYTE_MODE
+ device.mpa_tx_cfg = MLAN_INIT_PARA_ENABLED;
+#else
+ device.mpa_tx_cfg = MLAN_INIT_PARA_DISABLED;
+#endif
+#endif
+#ifdef SDIO_MULTI_PORT_RX_AGGR
+#ifdef MMC_QUIRK_BLKSZ_FOR_BYTE_MODE
+ device.mpa_rx_cfg = MLAN_INIT_PARA_ENABLED;
+#else
+ device.mpa_rx_cfg = MLAN_INIT_PARA_DISABLED;
+#endif
+#endif
+
+ for (i = 0; i < handle->drv_mode.intf_num; i++) {
+ device.bss_attr[i].bss_type = handle->drv_mode.bss_attr[i].bss_type;
+ device.bss_attr[i].frame_type = handle->drv_mode.bss_attr[i].frame_type;
+ device.bss_attr[i].active = handle->drv_mode.bss_attr[i].active;
+ device.bss_attr[i].bss_priority =
+ handle->drv_mode.bss_attr[i].bss_priority;
+ device.bss_attr[i].bss_num = handle->drv_mode.bss_attr[i].bss_num;
+ }
+ memcpy(&device.callbacks, &woal_callbacks, sizeof(mlan_callbacks));
+
+ sdio_claim_host(((struct sdio_mmc_card *) handle->card)->func);
+ if (MLAN_STATUS_SUCCESS == mlan_register(&device, &pmlan))
+ handle->pmlan_adapter = pmlan;
+ else
+ ret = MLAN_STATUS_FAILURE;
+ sdio_release_host(((struct sdio_mmc_card *) handle->card)->func);
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function frees the structure of moal_handle
+ *
+ * @param handle A pointer to moal_handle structure
+ *
+ * @return N/A
+ */
+static void
+woal_free_moal_handle(moal_handle * handle)
+{
+ ENTER();
+ if (!handle) {
+ PRINTM(MERROR, "The handle is NULL\n");
+ LEAVE();
+ return;
+ }
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,25)
+ if ((handle->nl_sk) && ((handle->nl_sk)->sk_socket)) {
+ sock_release((handle->nl_sk)->sk_socket);
+ handle->nl_sk = NULL;
+ }
+#else
+ netlink_kernel_release(handle->nl_sk);
+#endif
+
+ if (handle->pmlan_adapter)
+ mlan_unregister(handle->pmlan_adapter);
+
+ /* Free BSS attribute table */
+ if (handle->drv_mode.bss_attr != NULL) {
+ kfree(handle->drv_mode.bss_attr);
+ handle->drv_mode.bss_attr = NULL;
+ }
+ PRINTM(MINFO, "Free Adapter\n");
+ if (handle->malloc_count || handle->lock_count || handle->mbufalloc_count) {
+ PRINTM(MERROR,
+ "mlan has memory leak: malloc_count=%u lock_count=%u mbufalloc_count=%u\n",
+ handle->malloc_count, handle->lock_count,
+ handle->mbufalloc_count);
+ }
+ /* Free the moal handle itself */
+ kfree(handle);
+ LEAVE();
+}
+
+/**
+ * @brief WOAL get one line data from ASCII format data
+ *
+ * @param data Source data
+ * @param size Source data length
+ * @param line_pos Destination data
+ * @return routnine status
+ */
+static t_size
+parse_cfg_get_line(t_u8 * data, t_size size, t_u8 * line_pos)
+{
+ t_u8 *src, *dest;
+ static t_s32 pos = 0;
+
+ ENTER();
+
+ if (pos >= size) { /* reach the end */
+ pos = 0; /* Reset position for rfkill */
+ LEAVE();
+ return -1;
+ }
+ memset(line_pos, 0, MAX_LINE_LEN);
+ src = data + pos;
+ dest = line_pos;
+
+ while (*src != '\x0A' && *src != '\0') {
+ if (*src != ' ' && *src != '\t') /* parse space */
+ *dest++ = *src++;
+ else
+ src++;
+ pos++;
+ }
+ /* parse new line */
+ pos++;
+ *dest = '\0';
+ LEAVE();
+ return strlen(line_pos);
+}
+
+/**
+ * @brief Process register access request
+ * @param type_string String format Register type
+ * @param offset_string String format Register offset
+ * @param value_string String format Pointer to value
+ * @return MLAN_STATUS_SUCCESS--success, otherwise--fail
+ */
+static t_u32
+woal_process_regrdwr(moal_handle * handle, t_u8 * type_string,
+ t_u8 * offset_string, t_u8 * value_string)
+{
+ mlan_status ret = MLAN_STATUS_FAILURE;
+ int type, offset, value;
+ pmlan_ioctl_req ioctl_req = NULL;
+ mlan_ds_reg_mem *reg = NULL;
+
+ ENTER();
+
+ /* Alloc ioctl_req */
+ ioctl_req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_reg_mem));
+
+ if (ioctl_req == NULL) {
+ PRINTM(MERROR, "Can't alloc memory\n");
+ goto done;
+ }
+
+ if (MLAN_STATUS_SUCCESS != woal_atoi(&type, type_string)) {
+ goto done;
+ }
+ if (MLAN_STATUS_SUCCESS != woal_atoi(&offset, offset_string)) {
+ goto done;
+ }
+ if (MLAN_STATUS_SUCCESS != woal_atoi(&value, value_string)) {
+ goto done;
+ }
+
+ ioctl_req->req_id = MLAN_IOCTL_REG_MEM;
+ ioctl_req->action = MLAN_ACT_SET;
+
+ reg = (mlan_ds_reg_mem *) ioctl_req->pbuf;
+ reg->sub_command = MLAN_OID_REG_RW;
+ if (type < 5) {
+ reg->param.reg_rw.type = type;
+ } else {
+ PRINTM(MERROR, "Unsupported Type\n");
+ goto done;
+ }
+ reg->param.reg_rw.offset = offset;
+ reg->param.reg_rw.value = value;
+
+ /* request ioctl for STA */
+ if (MLAN_STATUS_SUCCESS !=
+ woal_request_ioctl(handle->priv[0], ioctl_req, MOAL_IOCTL_WAIT)) {
+ goto done;
+ }
+ PRINTM(MINFO, "Register type: %d, offset: 0x%x, value: 0x%x\n", type,
+ offset, value);
+ ret = MLAN_STATUS_SUCCESS;
+
+ done:
+ if (ioctl_req)
+ kfree(ioctl_req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief WOAL parse ASCII format data to MAC address
+ *
+ * @param handle MOAL handle
+ * @param data Source data
+ * @param size data length
+ * @return MLAN_STATUS_SUCCESS--success, otherwise--fail
+ */
+static t_u32
+woal_process_init_cfg(moal_handle * handle, t_u8 * data, t_size size)
+{
+ mlan_status ret = MLAN_STATUS_FAILURE;
+ t_u8 *pos;
+ t_u8 *intf_s, *intf_e;
+ t_u8 s[MAX_LINE_LEN]; /* 1 line data */
+ t_size line_len;
+ t_u8 index = 0;
+ t_u32 i;
+ t_u8 bss_mac_addr[MAX_MAC_ADDR_LEN];
+ t_u8 bss_mac_name[MAX_PARAM_LEN];
+ t_u8 type[MAX_PARAM_LEN];
+ t_u8 offset[MAX_PARAM_LEN];
+ t_u8 value[MAX_PARAM_LEN];
+
+ ENTER();
+
+ while ((line_len = parse_cfg_get_line(data, size, s)) != -1) {
+
+ pos = s;
+ while (*pos == ' ' || *pos == '\t')
+ pos++;
+
+ if (*pos == '#' || (*pos == '\r' && *(pos + 1) == '\n') ||
+ *pos == '\n' || *pos == '\0')
+ continue; /* Needn't process this line */
+
+ /* Process MAC addr */
+ if (strncmp(pos, "mac_addr", 8) == 0) {
+ intf_s = strchr(pos, '=');
+ if (intf_s != NULL)
+ intf_e = strchr(intf_s, ':');
+ else
+ intf_e = NULL;
+ if (intf_s != NULL && intf_e != NULL) {
+ strncpy(bss_mac_addr, intf_e + 1, MAX_MAC_ADDR_LEN - 1);
+ bss_mac_addr[MAX_MAC_ADDR_LEN - 1] = '\0';
+ if ((intf_e - intf_s) > MAX_PARAM_LEN) {
+ PRINTM(MERROR, "Too long interface name %d\n", __LINE__);
+ goto done;
+ }
+ strncpy(bss_mac_name, intf_s + 1, intf_e - intf_s - 1);
+ bss_mac_name[intf_e - intf_s - 1] = '\0';
+ for (i = 0; i < handle->priv_num; i++) {
+ if (strcmp(bss_mac_name, handle->priv[i]->netdev->name) ==
+ 0) {
+ memset(handle->priv[i]->current_addr, 0, ETH_ALEN);
+ PRINTM(MINFO, "Interface name: %s mac: %s\n",
+ bss_mac_name, bss_mac_addr);
+ woal_mac2u8(handle->priv[i]->current_addr,
+ bss_mac_addr);
+ /* Set WLAN MAC addresses */
+ if (MLAN_STATUS_SUCCESS !=
+ woal_request_set_mac_address(handle->priv[i])) {
+ PRINTM(MERROR, "Set MAC address failed\n");
+ goto done;
+ }
+ memcpy(handle->priv[i]->netdev->dev_addr,
+ handle->priv[i]->current_addr, ETH_ALEN);
+ index++; /* Mark found one interface matching */
+ }
+ }
+ } else {
+ PRINTM(MERROR, "Wrong config file format %d\n", __LINE__);
+ goto done;
+ }
+ }
+ /* Process REG value */
+ else if (strncmp(pos, "wlan_reg", 8) == 0) {
+ intf_s = strchr(pos, '=');
+ if (intf_s != NULL)
+ intf_e = strchr(intf_s, ',');
+ else
+ intf_e = NULL;
+ if (intf_s != NULL && intf_e != NULL) {
+ /* Copy type */
+ strncpy(type, intf_s + 1, 1);
+ type[1] = '\0';
+ } else {
+ PRINTM(MERROR, "Wrong config file format %d\n", __LINE__);
+ goto done;
+ }
+ intf_s = intf_e + 1;
+ if (intf_s != NULL)
+ intf_e = strchr(intf_s, ',');
+ else
+ intf_e = NULL;
+ if (intf_s != NULL && intf_e != NULL) {
+ if ((intf_e - intf_s) >= MAX_PARAM_LEN) {
+ PRINTM(MERROR, "Regsier offset is too long %d\n", __LINE__);
+ goto done;
+ }
+ /* Copy offset */
+ strncpy(offset, intf_s, intf_e - intf_s);
+ offset[intf_e - intf_s] = '\0';
+ } else {
+ PRINTM(MERROR, "Wrong config file format %d\n", __LINE__);
+ goto done;
+ }
+ intf_s = intf_e + 1;
+ if (intf_s != NULL) {
+ if ((strlen(intf_s) >= MAX_PARAM_LEN)) {
+ PRINTM(MERROR, "Regsier value is too long %d\n", __LINE__);
+ goto done;
+ }
+ /* Copy value */
+ strncpy(value, intf_s, sizeof(value));
+ } else {
+ PRINTM(MERROR, "Wrong config file format %d\n", __LINE__);
+ goto done;
+ }
+
+ if (MLAN_STATUS_SUCCESS !=
+ woal_process_regrdwr(handle, type, offset, value)) {
+ PRINTM(MERROR, "Access Reg failed\n");
+ goto done;
+ }
+ PRINTM(MINFO, "Reg type: %s, offset: %s, value: %s\n", type, offset,
+ value);
+ }
+ }
+
+ if (index == 0) {
+ PRINTM(MINFO, "Can't find any matching MAC Address");
+ }
+ ret = MLAN_STATUS_SUCCESS;
+
+ done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief WOAL set user defined init data and param
+ *
+ * @param handle MOAL handle structure
+ * @return MLAN_STATUS_SUCCESS--success, otherwise--fail
+ */
+static t_u32
+woal_set_user_init_data(moal_handle * handle)
+{
+ mlan_status ret = MLAN_STATUS_FAILURE;
+ t_u8 *cfg_data = NULL;
+ t_size len;
+
+ ENTER();
+
+ if ((request_firmware(&handle->user_data, init_cfg, handle->hotplug_device))
+ < 0) {
+ PRINTM(MERROR, "Init config file request_firmware() failed\n");
+ goto done;
+ }
+
+ if (handle->user_data) {
+ cfg_data = (t_u8 *) (handle->user_data)->data;
+ len = (handle->user_data)->size;
+ if (MLAN_STATUS_SUCCESS != woal_process_init_cfg(handle, cfg_data, len)) {
+ PRINTM(MERROR, "Can't process init config file\n");
+ goto done;
+ }
+ ret = MLAN_STATUS_SUCCESS;
+ }
+
+ done:
+ if (handle->user_data)
+ release_firmware(handle->user_data);
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Add interfaces DPC
+ *
+ * @param handle A pointer to moal_handle structure
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+static mlan_status
+woal_add_card_dpc(moal_handle * handle)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ int i;
+
+ ENTER();
+
+#ifdef CONFIG_PROC_FS
+ /* Initialize proc fs */
+ woal_proc_init(handle);
+#endif /* CONFIG_PROC_FS */
+
+ /* Add interfaces */
+ for (i = 0; i < handle->drv_mode.intf_num; i++) {
+ if (!woal_add_interface
+ (handle, handle->priv_num, handle->drv_mode.bss_attr[i].bss_type)) {
+ ret = MLAN_STATUS_FAILURE;
+ goto err;
+ }
+ handle->priv_num++;
+ }
+ if (init_cfg) {
+ if (MLAN_STATUS_SUCCESS != woal_set_user_init_data(handle)) {
+ PRINTM(MFATAL, "Set user init data and param failed\n");
+ ret = MLAN_STATUS_FAILURE;
+ goto err;
+ }
+ }
+
+ err:
+ if (ret != MLAN_STATUS_SUCCESS) {
+ PRINTM(MERROR, "Failed to add interface\n");
+ for (i = 0; i < handle->priv_num; i++)
+ woal_remove_interface(handle, i);
+ handle->priv_num = 0;
+#ifdef CONFIG_PROC_FS
+ woal_proc_exit(handle);
+#endif
+ }
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Download and Initialize firmware DPC
+ *
+ * @param handle A pointer to moal_handle structure
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+static mlan_status
+woal_init_fw_dpc(moal_handle * handle)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_fw_image fw;
+
+ mlan_init_param param;
+
+ ENTER();
+
+ if (handle->firmware) {
+ memset(&fw, 0, sizeof(mlan_fw_image));
+ fw.pfw_buf = (t_u8 *) handle->firmware->data;
+ fw.fw_len = handle->firmware->size;
+ sdio_claim_host(((struct sdio_mmc_card *) handle->card)->func);
+ ret = mlan_dnld_fw(handle->pmlan_adapter, &fw);
+ sdio_release_host(((struct sdio_mmc_card *) handle->card)->func);
+ if (ret == MLAN_STATUS_FAILURE) {
+ PRINTM(MERROR, "WLAN: Download FW with nowwait: %d\n",
+ req_fw_nowait);
+ goto done;
+ }
+ PRINTM(MMSG, "WLAN FW is active\n");
+ }
+
+ /** Cal data request */
+ memset(&param, 0, sizeof(mlan_init_param));
+ if (cal_data_cfg) {
+ if ((request_firmware
+ (&handle->user_data, cal_data_cfg, handle->hotplug_device)) < 0) {
+ PRINTM(MERROR, "Cal data request_firmware() failed\n");
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ }
+
+ if (handle->user_data) {
+ param.pcal_data_buf = (t_u8 *) handle->user_data->data;
+ param.cal_data_len = handle->user_data->size;
+ }
+
+ handle->hardware_status = HardwareStatusFwReady;
+ if (ret != MLAN_STATUS_SUCCESS)
+ goto done;
+
+ handle->init_wait_q_woken = MFALSE;
+
+ ret = mlan_set_init_param(handle->pmlan_adapter, &param);
+
+ sdio_claim_host(((struct sdio_mmc_card *) handle->card)->func);
+ ret = mlan_init_fw(handle->pmlan_adapter);
+ sdio_release_host(((struct sdio_mmc_card *) handle->card)->func);
+ if (ret == MLAN_STATUS_FAILURE) {
+ goto done;
+ } else if (ret == MLAN_STATUS_SUCCESS) {
+ handle->hardware_status = HardwareStatusReady;
+ goto done;
+ }
+ /* Wait for mlan_init to complete */
+ wait_event_interruptible(handle->init_wait_q, handle->init_wait_q_woken);
+ if (handle->hardware_status != HardwareStatusReady) {
+ woal_moal_debug_info(woal_get_priv(handle, MLAN_BSS_ROLE_ANY), handle,
+ MTRUE);
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ ret = MLAN_STATUS_SUCCESS;
+ done:
+ if (handle->user_data)
+ release_firmware(handle->user_data);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Request firmware DPC
+ *
+ * @param handle A pointer to moal_handle structure
+ * @param firmware A pointer to firmware image
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+static mlan_status
+woal_request_fw_dpc(moal_handle * handle, const struct firmware *firmware)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ struct timeval tstamp;
+
+ ENTER();
+
+ if (!firmware) {
+ do_gettimeofday(&tstamp);
+ if (tstamp.tv_sec > (handle->req_fw_time.tv_sec + REQUEST_FW_TIMEOUT)) {
+ PRINTM(MERROR, "No firmware image found. Skipping download\n");
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ PRINTM(MERROR, "request_firmware_nowait failed for %s. Retrying..\n",
+ handle->drv_mode.fw_name);
+ woal_sched_timeout(MOAL_TIMER_1S);
+ woal_request_fw(handle);
+ LEAVE();
+ return ret;
+ }
+ handle->firmware = firmware;
+
+ if ((ret = woal_init_fw_dpc(handle)))
+ goto done;
+ if ((ret = woal_add_card_dpc(handle)))
+ goto done;
+
+ done:
+ /* We should hold the semaphore until callback finishes execution */
+ MOAL_REL_SEMAPHORE(&AddRemoveCardSem);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Request firmware callback
+ * This function is invoked by request_firmware_nowait system call
+ *
+ * @param firmware A pointer to firmware image
+ * @param context A pointer to moal_handle structure
+ *
+ * @return N/A
+ */
+static void
+woal_request_fw_callback(const struct firmware *firmware, void *context)
+{
+ ENTER();
+ woal_request_fw_dpc((moal_handle *) context, firmware);
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,32)
+ if (firmware)
+ release_firmware(firmware);
+#endif
+ LEAVE();
+ return;
+}
+
+/**
+ * @brief Download firmware using helper
+ *
+ * @param handle A pointer to moal_handle structure
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status
+woal_request_fw(moal_handle * handle)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ int err;
+ t_u32 revision_id = 0;
+
+ ENTER();
+
+ if (!fw_name) {
+/** Revision ID register */
+#define REV_ID_REG 0x5c
+ sdio_claim_host(((struct sdio_mmc_card *) handle->card)->func);
+ woal_read_reg(handle, REV_ID_REG, &revision_id);
+ sdio_release_host(((struct sdio_mmc_card *) handle->card)->func);
+ /* Check revision ID */
+ switch (revision_id) {
+ case SD8797_A0:
+ handle->drv_mode.fw_name = SD8797_A0_FW_NAME;
+ break;
+ case SD8797_B0:
+ handle->drv_mode.fw_name = SD8797_B0_FW_NAME;
+ break;
+ default:
+ break;
+ }
+ }
+
+ if (req_fw_nowait) {
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,32)
+ if ((err = request_firmware_nowait(THIS_MODULE, FW_ACTION_HOTPLUG,
+ handle->drv_mode.fw_name,
+ handle->hotplug_device, GFP_KERNEL,
+ handle,
+ woal_request_fw_callback)) < 0) {
+#else
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,13)
+ if ((err = request_firmware_nowait(THIS_MODULE, FW_ACTION_HOTPLUG,
+ handle->drv_mode.fw_name,
+ handle->hotplug_device, handle,
+ woal_request_fw_callback)) < 0) {
+#else
+ if ((err = request_firmware_nowait(THIS_MODULE,
+ handle->drv_mode.fw_name,
+ handle->hotplug_device, handle,
+ woal_request_fw_callback)) < 0) {
+#endif
+#endif
+ PRINTM(MFATAL,
+ "WLAN: request_firmware_nowait() failed, error code = %d\n",
+ err);
+ ret = MLAN_STATUS_FAILURE;
+ }
+ } else {
+ if ((err =
+ request_firmware(&handle->firmware, handle->drv_mode.fw_name,
+ handle->hotplug_device)) < 0) {
+ PRINTM(MFATAL, "WLAN: request_firmware() failed, error code = %d\n",
+ err);
+ ret = MLAN_STATUS_FAILURE;
+ } else {
+ ret = woal_request_fw_dpc(handle, handle->firmware);
+ release_firmware(handle->firmware);
+ }
+ }
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function initializes firmware
+ *
+ * @param handle A pointer to moal_handle structure
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+static mlan_status
+woal_init_fw(moal_handle * handle)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ do_gettimeofday(&handle->req_fw_time);
+ if ((ret = woal_request_fw(handle)) < 0) {
+ PRINTM(MFATAL, "woal_request_fw failed\n");
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function will fill in the mlan_buffer
+ *
+ * @param pmbuf A pointer to mlan_buffer
+ * @param skb A pointer to struct sk_buff
+ *
+ * @return N/A
+ */
+static void
+woal_fill_mlan_buffer(moal_private * priv,
+ mlan_buffer * pmbuf, struct sk_buff *skb)
+{
+ struct timeval tstamp;
+ struct ethhdr *eth;
+ t_u8 tid;
+
+ ENTER();
+
+ eth = (struct ethhdr *) skb->data;
+
+ switch (eth->h_proto) {
+
+ case __constant_htons(ETH_P_IP):
+ tid = (IPTOS_PREC(SKB_TOS(skb)) >> IPTOS_OFFSET);
+ PRINTM(MDAT_D, "packet type ETH_P_IP: %04x, tid=%#x prio=%#x\n",
+ eth->h_proto, tid, skb->priority);
+ break;
+
+ case __constant_htons(ETH_P_ARP):
+ PRINTM(MDATA, "ARP packet %04x\n", eth->h_proto);
+ tid = 0;
+ break;
+ default:
+ tid = 0;
+ break;
+ }
+
+ skb->priority = tid;
+
+ /* Record the current time the packet was queued; used to determine the
+ amount of time the packet was queued in the driver before it was sent to
+ the firmware. The delay is then sent along with the packet to the
+ firmware for aggregate delay calculation for stats and MSDU lifetime
+ expiry. */
+ do_gettimeofday(&tstamp);
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22)
+ skb->tstamp = timeval_to_ktime(tstamp);
+#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,14)
+ skb_set_timestamp(skb, &tstamp);
+#else
+ memcpy(&skb->stamp, &tstamp, sizeof(skb->stamp));
+#endif
+
+ pmbuf->pdesc = skb;
+ pmbuf->pbuf = skb->head + sizeof(mlan_buffer);
+ pmbuf->data_offset = skb->data - (skb->head + sizeof(mlan_buffer));
+ pmbuf->data_len = skb->len;
+ pmbuf->priority = skb->priority;
+ pmbuf->buf_type = 0;
+ pmbuf->in_ts_sec = (t_u32) tstamp.tv_sec;
+ pmbuf->in_ts_usec = (t_u32) tstamp.tv_usec;
+
+ LEAVE();
+ return;
+}
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,33)
+static struct device_type wlan_type = {.name = "wlan", };
+#endif
+
+#ifdef STA_SUPPORT
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,29)
+/** Network device handlers */
+const struct net_device_ops woal_netdev_ops = {
+ .ndo_open = woal_open,
+ .ndo_start_xmit = woal_hard_start_xmit,
+ .ndo_stop = woal_close,
+ .ndo_do_ioctl = woal_do_ioctl,
+ .ndo_set_mac_address = woal_set_mac_address,
+ .ndo_tx_timeout = woal_tx_timeout,
+ .ndo_get_stats = woal_get_stats,
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,2,0)
+ .ndo_set_rx_mode = woal_set_multicast_list,
+#else
+ .ndo_set_multicast_list = woal_set_multicast_list,
+#endif
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,34)
+ .ndo_select_queue = woal_select_queue,
+#endif
+};
+#endif
+
+/**
+ * @brief This function initializes the private structure
+ * and dev structure for station mode
+ *
+ * @param dev A pointer to net_device structure
+ * @param priv A pointer to moal_private structure
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+static mlan_status
+woal_init_sta_dev(struct net_device *dev, moal_private * priv)
+{
+ ENTER();
+
+ /* Setup the OS Interface to our functions */
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,29)
+ dev->open = woal_open;
+ dev->hard_start_xmit = woal_hard_start_xmit;
+ dev->stop = woal_close;
+ dev->do_ioctl = woal_do_ioctl;
+ dev->set_mac_address = woal_set_mac_address;
+ dev->tx_timeout = woal_tx_timeout;
+ dev->get_stats = woal_get_stats;
+ dev->set_multicast_list = woal_set_multicast_list;
+#else
+ dev->netdev_ops = &woal_netdev_ops;
+#endif
+ dev->watchdog_timeo = MRVDRV_DEFAULT_WATCHDOG_TIMEOUT;
+ dev->hard_header_len += MLAN_MIN_DATA_HEADER_LEN + sizeof(mlan_buffer);
+#ifdef WIRELESS_EXT
+#ifdef STA_WEXT
+ if (IS_STA_WEXT(cfg80211_wext)) {
+#if WIRELESS_EXT < 21
+ dev->get_wireless_stats = woal_get_wireless_stats;
+#endif
+ dev->wireless_handlers = (struct iw_handler_def *) &woal_handler_def;
+ }
+#endif
+#endif
+ dev->flags |= IFF_BROADCAST | IFF_MULTICAST;
+
+ /* Initialize private structure */
+ init_waitqueue_head(&priv->ioctl_wait_q);
+ init_waitqueue_head(&priv->cmd_wait_q);
+ init_waitqueue_head(&priv->proc_wait_q);
+#ifdef STA_WEXT
+ if (IS_STA_WEXT(cfg80211_wext))
+ init_waitqueue_head(&priv->w_stats_wait_q);
+#endif
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+#endif /* STA_SUPPORT */
+
+#ifdef UAP_SUPPORT
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,29)
+/** Network device handlers */
+const struct net_device_ops woal_uap_netdev_ops = {
+ .ndo_open = woal_open,
+ .ndo_start_xmit = woal_hard_start_xmit,
+ .ndo_stop = woal_close,
+ .ndo_do_ioctl = woal_uap_do_ioctl,
+ .ndo_set_mac_address = woal_set_mac_address,
+ .ndo_tx_timeout = woal_tx_timeout,
+ .ndo_get_stats = woal_get_stats,
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,2,0)
+ .ndo_set_rx_mode = woal_uap_set_multicast_list,
+#else
+ .ndo_set_multicast_list = woal_uap_set_multicast_list,
+#endif
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,34)
+ .ndo_select_queue = woal_select_queue,
+#endif
+};
+#endif
+
+/**
+ * @brief This function initializes the private structure
+ * and dev structure for uap mode
+ *
+ * @param dev A pointer to net_device structure
+ * @param priv A pointer to moal_private structure
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+static mlan_status
+woal_init_uap_dev(struct net_device *dev, moal_private * priv)
+{
+ mlan_status status = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ /* Setup the OS Interface to our functions */
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,29)
+ dev->open = woal_open;
+ dev->hard_start_xmit = woal_hard_start_xmit;
+ dev->stop = woal_close;
+ dev->set_mac_address = woal_set_mac_address;
+ dev->tx_timeout = woal_tx_timeout;
+ dev->get_stats = woal_get_stats;
+ dev->do_ioctl = woal_uap_do_ioctl;
+ dev->set_multicast_list = woal_uap_set_multicast_list;
+#else
+ dev->netdev_ops = &woal_uap_netdev_ops;
+#endif
+ dev->watchdog_timeo = MRVDRV_DEFAULT_UAP_WATCHDOG_TIMEOUT;
+ dev->hard_header_len += MLAN_MIN_DATA_HEADER_LEN + sizeof(mlan_buffer);
+#ifdef UAP_WEXT
+#ifdef WIRELESS_EXT
+ if (IS_UAP_WEXT(cfg80211_wext)) {
+#if WIRELESS_EXT < 21
+ dev->get_wireless_stats = woal_get_uap_wireless_stats;
+#endif
+ dev->wireless_handlers =
+ (struct iw_handler_def *) &woal_uap_handler_def;
+ }
+#endif /* WIRELESS_EXT */
+#endif /* UAP_WEXT */
+ dev->flags |= IFF_BROADCAST | IFF_MULTICAST;
+
+ /* Initialize private structure */
+ init_waitqueue_head(&priv->ioctl_wait_q);
+ init_waitqueue_head(&priv->cmd_wait_q);
+ init_waitqueue_head(&priv->proc_wait_q);
+#ifdef UAP_WEXT
+ if (IS_UAP_WEXT(cfg80211_wext))
+ init_waitqueue_head(&priv->w_stats_wait_q);
+#endif
+
+ LEAVE();
+ return status;
+}
+#endif /* UAP_SUPPORT */
+
+/**
+ * @brief This function adds a new interface. It will
+ * allocate, initialize and register the device.
+ *
+ * @param handle A pointer to moal_handle structure
+ * @param bss_index BSS index number
+ * @param bss_type BSS type
+ *
+ * @return A pointer to the new priv structure
+ */
+moal_private *
+woal_add_interface(moal_handle * handle, t_u8 bss_index, t_u8 bss_type)
+{
+ struct net_device *dev = NULL;
+ moal_private *priv = NULL;
+
+ ENTER();
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,34)
+#define MAX_WMM_QUEUE 4
+ /* Allocate an Ethernet device */
+ if (!(dev = alloc_etherdev_mq(sizeof(moal_private), MAX_WMM_QUEUE))) {
+#else
+ if (!(dev = alloc_etherdev(sizeof(moal_private)))) {
+#endif
+ PRINTM(MFATAL, "Init virtual ethernet device failed\n");
+ goto error;
+ }
+#ifdef STA_SUPPORT
+ /* Allocate device name */
+ if ((bss_type == MLAN_BSS_TYPE_STA) && (dev_alloc_name(dev, "mlan%d") < 0)) {
+ PRINTM(MERROR, "Could not allocate mlan device name\n");
+ goto error;
+ }
+#endif
+#ifdef UAP_SUPPORT
+ if ((bss_type == MLAN_BSS_TYPE_UAP) && (dev_alloc_name(dev, "uap%d") < 0)) {
+ PRINTM(MERROR, "Could not allocate uap device name\n");
+ goto error;
+ }
+#endif
+#if defined(WIFI_DIRECT_SUPPORT)
+ if ((bss_type == MLAN_BSS_TYPE_WIFIDIRECT) &&
+ (dev_alloc_name(dev, "wfd%d") < 0)) {
+ PRINTM(MERROR, "Could not allocate wifidirect device name\n");
+ goto error;
+ }
+#endif
+ priv = (moal_private *) netdev_priv(dev);
+ /* Save the priv to handle */
+ handle->priv[bss_index] = priv;
+
+ /* Use the same handle structure */
+ priv->phandle = handle;
+ priv->netdev = dev;
+ priv->bss_index = bss_index;
+ priv->bss_type = bss_type;
+ if (bss_type == MLAN_BSS_TYPE_STA)
+ priv->bss_role = MLAN_BSS_ROLE_STA;
+ else if (bss_type == MLAN_BSS_TYPE_UAP)
+ priv->bss_role = MLAN_BSS_ROLE_UAP;
+#if defined(WIFI_DIRECT_SUPPORT)
+ else if (bss_type == MLAN_BSS_TYPE_WIFIDIRECT)
+ priv->bss_role = MLAN_BSS_ROLE_STA;
+#endif
+#if defined(STA_CFG80211) || defined(UAP_CFG80211)
+ priv->probereq_index = MLAN_CUSTOM_IE_AUTO_IDX_MASK;
+#endif
+#ifdef STA_SUPPORT
+#endif
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24)
+ SET_MODULE_OWNER(dev);
+#endif
+#ifdef STA_SUPPORT
+ if (bss_type == MLAN_BSS_TYPE_STA
+#if defined(WIFI_DIRECT_SUPPORT)
+ || bss_type == MLAN_BSS_TYPE_WIFIDIRECT
+#endif
+ )
+ woal_init_sta_dev(dev, priv);
+#endif
+#ifdef UAP_SUPPORT
+ if (bss_type == MLAN_BSS_TYPE_UAP) {
+ if (MLAN_STATUS_SUCCESS != woal_init_uap_dev(dev, priv))
+ goto error;
+ }
+#endif
+#ifdef STA_CFG80211
+#ifdef STA_SUPPORT
+ if ((priv->bss_role == MLAN_BSS_ROLE_STA) && IS_STA_CFG80211(cfg80211_wext)) {
+ if (bss_type == MLAN_BSS_TYPE_STA
+#if defined(WIFI_DIRECT_SUPPORT)
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,0,0) || defined(COMPAT_WIRELESS)
+ || bss_type == MLAN_BSS_TYPE_WIFIDIRECT
+#endif
+#endif
+ )
+ /* Register cfg80211 for STA or Wifi direct */
+ if (woal_register_sta_cfg80211(dev, bss_type)) {
+ PRINTM(MERROR, "Cannot register STA with cfg80211\n");
+ goto error;
+ }
+ }
+#endif /* STA_SUPPORT */
+#endif /* STA_CFG80211 */
+#ifdef UAP_CFG80211
+#ifdef UAP_SUPPORT
+ if ((priv->bss_role == MLAN_BSS_ROLE_UAP) && IS_UAP_CFG80211(cfg80211_wext)) {
+ /* Register cfg80211 for UAP */
+ if (woal_register_uap_cfg80211(dev, bss_type)) {
+ PRINTM(MERROR, "Cannot register UAP with cfg80211\n");
+ goto error;
+ }
+ }
+#endif
+#endif /* UAP_CFG80211 */
+
+ /* Initialize priv structure */
+ woal_init_priv(priv, MOAL_CMD_WAIT);
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,29)
+ SET_NETDEV_DEV(dev, handle->hotplug_device);
+#endif
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,33)
+ SET_NETDEV_DEVTYPE(dev, &wlan_type);
+#endif
+
+ /* Register network device */
+ if (register_netdev(dev)) {
+ PRINTM(MERROR, "Cannot register virtual network device\n");
+ goto error;
+ }
+ netif_carrier_off(dev);
+ woal_stop_queue(dev);
+
+ PRINTM(MINFO, "%s: Marvell 802.11 Adapter\n", dev->name);
+
+ /* Set MAC address from the insmod command line */
+ if (handle->set_mac_addr) {
+ memset(priv->current_addr, 0, ETH_ALEN);
+ memcpy(priv->current_addr, handle->mac_addr, ETH_ALEN);
+ if (MLAN_STATUS_SUCCESS != woal_request_set_mac_address(priv)) {
+ PRINTM(MERROR, "Set MAC address failed\n");
+ goto error;
+ }
+ memcpy(dev->dev_addr, priv->current_addr, ETH_ALEN);
+ }
+#ifdef CONFIG_PROC_FS
+ woal_create_proc_entry(priv);
+#ifdef PROC_DEBUG
+ woal_debug_entry(priv);
+#endif /* PROC_DEBUG */
+#endif /* CONFIG_PROC_FS */
+
+ LEAVE();
+ return priv;
+ error:
+ if (dev && dev->reg_state == NETREG_REGISTERED)
+ unregister_netdev(dev);
+#if defined(STA_CFG80211) || defined(UAP_CFG80211)
+ /* Unregister wiphy device and free */
+ if (priv->wdev && IS_STA_OR_UAP_CFG80211(cfg80211_wext)) {
+ wiphy_unregister(priv->wdev->wiphy);
+ wiphy_free(priv->wdev->wiphy);
+ /* Free wireless device */
+ kfree(priv->wdev);
+ priv->wdev = NULL;
+ }
+#endif
+ if (dev)
+ free_netdev(dev);
+ LEAVE();
+ return NULL;
+}
+
+/**
+ * @brief This function removes an interface.
+ *
+ * @param handle A pointer to the moal_handle structure
+ * @param bss_index BSS index number
+ *
+ * @return N/A
+ */
+void
+woal_remove_interface(moal_handle * handle, t_u8 bss_index)
+{
+ struct net_device *dev = NULL;
+ moal_private *priv = handle->priv[bss_index];
+#if defined(STA_WEXT) || defined(UAP_WEXT)
+ union iwreq_data wrqu;
+#endif
+
+ ENTER();
+ if (!priv)
+ goto error;
+ dev = priv->netdev;
+
+ if (priv->media_connected == MTRUE) {
+ priv->media_connected = MFALSE;
+#if defined(STA_WEXT) || defined(UAP_WEXT)
+ if (IS_STA_OR_UAP_WEXT(cfg80211_wext) &&
+ GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_STA) {
+ memset(wrqu.ap_addr.sa_data, 0x00, ETH_ALEN);
+ wrqu.ap_addr.sa_family = ARPHRD_ETHER;
+ wireless_send_event(priv->netdev, SIOCGIWAP, &wrqu, NULL);
+ }
+#endif
+ }
+#ifdef CONFIG_PROC_FS
+#ifdef PROC_DEBUG
+ /* Remove proc debug */
+ woal_debug_remove(priv);
+#endif /* PROC_DEBUG */
+ woal_proc_remove(priv);
+#endif /* CONFIG_PROC_FS */
+ /* Last reference is our one */
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,37)
+ PRINTM(MINFO, "refcnt = %d\n", atomic_read(&dev->refcnt));
+#else
+ PRINTM(MINFO, "refcnt = %d\n", netdev_refcnt_read(dev));
+#endif
+
+ PRINTM(MINFO, "netdev_finish_unregister: %s\n", dev->name);
+
+ if (dev->reg_state == NETREG_REGISTERED)
+ unregister_netdev(dev);
+
+#if defined(STA_CFG80211) || defined(UAP_CFG80211)
+ /* Unregister wiphy device and free */
+ if (priv->wdev && IS_STA_OR_UAP_CFG80211(cfg80211_wext)) {
+ wiphy_unregister(priv->wdev->wiphy);
+ wiphy_free(priv->wdev->wiphy);
+ /* Free wireless device */
+ kfree(priv->wdev);
+ priv->wdev = NULL;
+ }
+#endif
+
+ /* Clear the priv in handle */
+ priv->phandle->priv[priv->bss_index] = NULL;
+ priv->phandle = NULL;
+ priv->netdev = NULL;
+ free_netdev(dev);
+ error:
+ LEAVE();
+ return;
+}
+
+/**
+ * @brief Send FW shutdown command to MLAN
+ *
+ * @param priv A pointer to moal_private structure
+ * @param wait_option Wait option
+ *
+ * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING -- success, otherwise fail
+ */
+static mlan_status
+woal_shutdown_fw(moal_private * priv, t_u8 wait_option)
+{
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_misc_cfg *misc = NULL;
+ mlan_status status;
+
+ ENTER();
+
+ /* Allocate an IOCTL request buffer */
+ req =
+ (mlan_ioctl_req *) woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
+ if (req == NULL) {
+ status = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ /* Fill request buffer */
+ misc = (mlan_ds_misc_cfg *) req->pbuf;
+ misc->sub_command = MLAN_OID_MISC_INIT_SHUTDOWN;
+ misc->param.func_init_shutdown = MLAN_FUNC_SHUTDOWN;
+ req->req_id = MLAN_IOCTL_MISC_CFG;
+ req->action = MLAN_ACT_SET;
+
+ /* Send IOCTL request to MLAN */
+ status = woal_request_ioctl(priv, req, wait_option);
+
+ done:
+ if (req)
+ kfree(req);
+ LEAVE();
+ return status;
+}
+
+/**
+ * @brief Return hex value of a give character
+ *
+ * @param chr Character to be converted
+ *
+ * @return The converted character if chr is a valid hex, else 0
+ */
+static int
+woal_hexval(char chr)
+{
+ if (chr >= '0' && chr <= '9')
+ return chr - '0';
+ if (chr >= 'A' && chr <= 'F')
+ return chr - 'A' + 10;
+ if (chr >= 'a' && chr <= 'f')
+ return chr - 'a' + 10;
+
+ return 0;
+}
+
+#ifdef STA_WEXT
+#endif
+
+/**
+ * @brief This function cancel all works in the queue
+ * and destroy the main workqueue.
+ *
+ * @param handle A pointer to moal_handle
+ *
+ * @return N/A
+ */
+static void
+woal_terminate_workqueue(moal_handle * handle)
+{
+ ENTER();
+
+ /* Terminate main workqueue */
+ if (handle->workqueue) {
+ flush_workqueue(handle->workqueue);
+ destroy_workqueue(handle->workqueue);
+ handle->workqueue = NULL;
+ }
+
+ LEAVE();
+}
+
+/* Support for Cardhu wifi gpio toggling */
+/**
+ * @brief Sets the card detect state
+ *
+ * @param on 0: Card will be made undetected
+ * 1: Card will be detected
+ *
+ * @return 0
+ */
+static int
+wifi_set_carddetect(int on)
+{
+ ENTER();
+ PRINTM(MMSG, "%s = %d\n", __FUNCTION__, on);
+ if (wifi_control_data && wifi_control_data->set_carddetect) {
+ wifi_control_data->set_carddetect(on);
+ }
+ LEAVE();
+ return 0;
+}
+
+/**
+ * @brief Sets the power state to On or Off after 'msec' millisecond
+ *
+ * @param on 0: Card will be powered on
+ * 1: Card will be powered off
+ * @param msec Delay in millisecond
+ *
+ * @return 0
+ */
+static int
+wifi_set_power(int on, unsigned long msec)
+{
+ ENTER();
+ PRINTM(MMSG, "%s = %d\n", __FUNCTION__, on);
+ if (wifi_control_data && wifi_control_data->set_power) {
+ wifi_control_data->set_power(on);
+ }
+ if (msec)
+ mdelay(msec);
+ LEAVE();
+ return 0;
+}
+
+/**
+ * @brief Probes an wifi device
+ *
+ * @param pdev A pointer to the platform_device structure
+ *
+ * @return 0
+ */
+static int
+wifi_probe(struct platform_device *pdev)
+{
+ struct wifi_platform_data *wifi_ctrl =
+ (struct wifi_platform_data *) (pdev->dev.platform_data);
+
+ ENTER();
+
+ wifi_control_data = wifi_ctrl;
+ wifi_set_power(1, 0); /* Power On */
+ wifi_set_carddetect(1); /* CardDetect (0->1) */
+
+ LEAVE();
+ return 0;
+}
+
+/**
+ * @brief Removes an wifi device
+ *
+ * @param pdev A pointer to the platform_device structure
+ *
+ * @return 0
+ */
+static int
+wifi_remove(struct platform_device *pdev)
+{
+ struct wifi_platform_data *wifi_ctrl =
+ (struct wifi_platform_data *) (pdev->dev.platform_data);
+
+ ENTER();
+
+ wifi_control_data = wifi_ctrl;
+ wifi_set_power(0, 0); /* Power Off */
+ wifi_set_carddetect(0); /* CardDetect (1->0) */
+
+ LEAVE();
+ return 0;
+}
+
+static struct platform_driver wifi_device = {
+ .probe = wifi_probe,
+ .remove = wifi_remove,
+ .driver = {
+ .name = "mrvl8797_wlan",
+ }
+};
+
+/**
+ * @brief Adds an wifi device
+ * @return 0 --success, otherwise fail
+ */
+static int
+wifi_add_dev(void)
+{
+ int ret = 0;
+
+ ENTER();
+
+ if (minicard_pwrup)
+ ret = platform_driver_register(&wifi_device);
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Removes an wifi device
+ *
+ * @return N/A
+ */
+static void
+wifi_del_dev(void)
+{
+ ENTER();
+
+ if (minicard_pwrup)
+ platform_driver_unregister(&wifi_device);
+
+ LEAVE();
+}
+
+/********************************************************
+ Global Functions
+********************************************************/
+
+/**
+ * @brief This function opens the network device
+ *
+ * @param dev A pointer to net_device structure
+ *
+ * @return 0 --success, otherwise fail
+ */
+int
+woal_open(struct net_device *dev)
+{
+ moal_private *priv = (moal_private *) netdev_priv(dev);
+ t_u8 carrier_on = MFALSE;
+
+ ENTER();
+
+ if (!MODULE_GET) {
+ LEAVE();
+ return -EFAULT;
+ }
+#ifdef UAP_SUPPORT
+ if ((GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_UAP) && (priv->media_connected))
+ carrier_on = MTRUE;
+#endif
+#ifdef STA_SUPPORT
+ if ((GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_STA) &&
+ (priv->media_connected || priv->is_adhoc_link_sensed))
+ carrier_on = MTRUE;
+#endif
+ if (carrier_on == MTRUE) {
+ if (!netif_carrier_ok(priv->netdev))
+ netif_carrier_on(priv->netdev);
+ woal_wake_queue(priv->netdev);
+ } else {
+ if (netif_carrier_ok(priv->netdev))
+ netif_carrier_off(priv->netdev);
+ }
+
+ LEAVE();
+ return 0;
+}
+
+/**
+ * @brief This function closes the network device
+ *
+ * @param dev A pointer to net_device structure
+ *
+ * @return 0
+ */
+int
+woal_close(struct net_device *dev)
+{
+ moal_private *priv = (moal_private *) netdev_priv(dev);
+
+ ENTER();
+
+ woal_stop_queue(priv->netdev);
+
+ MODULE_PUT;
+
+ LEAVE();
+ return 0;
+}
+
+/**
+ * @brief This function sets the MAC address to firmware.
+ *
+ * @param dev A pointer to mlan_private structure
+ * @param addr MAC address to set
+ *
+ * @return 0 --success, otherwise fail
+ */
+int
+woal_set_mac_address(struct net_device *dev, void *addr)
+{
+ int ret = 0;
+ moal_private *priv = (moal_private *) netdev_priv(dev);
+ struct sockaddr *phw_addr = (struct sockaddr *) addr;
+ t_u8 prev_addr[ETH_ALEN];
+
+ ENTER();
+
+ memcpy(prev_addr, priv->current_addr, ETH_ALEN);
+ memset(priv->current_addr, 0, ETH_ALEN);
+ /* dev->dev_addr is 6 bytes */
+ HEXDUMP("dev->dev_addr:", dev->dev_addr, ETH_ALEN);
+
+ HEXDUMP("addr:", (t_u8 *) phw_addr->sa_data, ETH_ALEN);
+ memcpy(priv->current_addr, phw_addr->sa_data, ETH_ALEN);
+ if (MLAN_STATUS_SUCCESS != woal_request_set_mac_address(priv)) {
+ PRINTM(MERROR, "Set MAC address failed\n");
+ /* For failure restore the MAC address */
+ memcpy(priv->current_addr, prev_addr, ETH_ALEN);
+ ret = -EFAULT;
+ goto done;
+ }
+ HEXDUMP("priv->MacAddr:", priv->current_addr, ETH_ALEN);
+ memcpy(dev->dev_addr, priv->current_addr, ETH_ALEN);
+ done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Display MLAN debug information
+ *
+ * @param priv A pointer to moal_private
+ *
+ * @return N/A
+ */
+void
+woal_mlan_debug_info(moal_private * priv)
+{
+ int i;
+
+ ENTER();
+
+ if (!priv || woal_get_debug_info(priv, MOAL_CMD_WAIT, &info)) {
+ PRINTM(MERROR, "Could not retrieve debug information from MLAN\n");
+ LEAVE();
+ return;
+ }
+
+ PRINTM(MERROR, "num_cmd_timeout = %d\n", info.num_cmd_timeout);
+ PRINTM(MERROR, "Timeout cmd id = 0x%x, act = 0x%x \n",
+ info.timeout_cmd_id, info.timeout_cmd_act);
+
+ PRINTM(MERROR, "last_cmd_index = %d\n", info.last_cmd_index);
+ PRINTM(MERROR, "last_cmd_id = ");
+ for (i = 0; i < DBG_CMD_NUM; i++) {
+ PRINTM(MERROR, "0x%x ", info.last_cmd_id[i]);
+ }
+ PRINTM(MERROR, "\n");
+ PRINTM(MERROR, "last_cmd_act = ");
+ for (i = 0; i < DBG_CMD_NUM; i++) {
+ PRINTM(MERROR, "0x%x ", info.last_cmd_act[i]);
+ }
+ PRINTM(MERROR, "\n");
+ PRINTM(MERROR, "last_cmd_resp_index = %d\n", info.last_cmd_resp_index);
+ PRINTM(MERROR, "last_cmd_resp_id = ");
+ for (i = 0; i < DBG_CMD_NUM; i++) {
+ PRINTM(MERROR, "0x%x ", info.last_cmd_resp_id[i]);
+ }
+ PRINTM(MERROR, "\n");
+ PRINTM(MERROR, "last_event_index = %d\n", info.last_event_index);
+ PRINTM(MERROR, "last_event = ");
+ for (i = 0; i < DBG_CMD_NUM; i++) {
+ PRINTM(MERROR, "0x%x ", info.last_event[i]);
+ }
+ PRINTM(MERROR, "\n");
+
+ PRINTM(MERROR, "num_data_h2c_failure = %d\n",
+ info.num_tx_host_to_card_failure);
+ PRINTM(MERROR, "num_cmd_h2c_failure = %d\n",
+ info.num_cmd_host_to_card_failure);
+ PRINTM(MERROR, "num_data_c2h_failure = %d\n",
+ info.num_rx_card_to_host_failure);
+ PRINTM(MERROR, "num_cmdevt_c2h_failure = %d\n",
+ info.num_cmdevt_card_to_host_failure);
+ PRINTM(MERROR, "num_int_read_failure = %d\n", info.num_int_read_failure);
+ PRINTM(MERROR, "last_int_status = %d\n", info.last_int_status);
+
+ PRINTM(MERROR, "num_event_deauth = %d\n", info.num_event_deauth);
+ PRINTM(MERROR, "num_event_disassoc = %d\n", info.num_event_disassoc);
+ PRINTM(MERROR, "num_event_link_lost = %d\n", info.num_event_link_lost);
+ PRINTM(MERROR, "num_cmd_deauth = %d\n", info.num_cmd_deauth);
+ PRINTM(MERROR, "num_cmd_assoc_success = %d\n", info.num_cmd_assoc_success);
+ PRINTM(MERROR, "num_cmd_assoc_failure = %d\n", info.num_cmd_assoc_failure);
+ PRINTM(MERROR, "cmd_resp_received = %d\n", info.cmd_resp_received);
+ PRINTM(MERROR, "event_received = %d\n", info.event_received);
+
+ PRINTM(MERROR, "max_tx_buf_size = %d\n", info.max_tx_buf_size);
+ PRINTM(MERROR, "tx_buf_size = %d\n", info.tx_buf_size);
+ PRINTM(MERROR, "curr_tx_buf_size = %d\n", info.curr_tx_buf_size);
+
+ PRINTM(MERROR, "data_sent=%d cmd_sent=%d\n", info.data_sent, info.cmd_sent);
+
+ PRINTM(MERROR, "ps_mode=%d ps_state=%d\n", info.ps_mode, info.ps_state);
+ PRINTM(MERROR, "wakeup_dev_req=%d wakeup_tries=%d\n",
+ info.pm_wakeup_card_req, info.pm_wakeup_fw_try);
+ PRINTM(MERROR, "hs_configured=%d hs_activated=%d\n",
+ info.is_hs_configured, info.hs_activated);
+ PRINTM(MERROR, "pps_uapsd_mode=%d sleep_pd=%d\n",
+ info.pps_uapsd_mode, info.sleep_pd);
+ PRINTM(MERROR, "tx_lock_flag = %d\n", info.tx_lock_flag);
+ PRINTM(MERROR, "port_open = %d\n", info.port_open);
+ PRINTM(MERROR, "scan_processing = %d\n", info.scan_processing);
+
+ PRINTM(MERROR, "mp_rd_bitmap=0x%x curr_rd_port=0x%x\n",
+ (unsigned int) info.mp_rd_bitmap, info.curr_rd_port);
+ PRINTM(MERROR, "mp_wr_bitmap=0x%x curr_wr_port=0x%x\n",
+ (unsigned int) info.mp_wr_bitmap, info.curr_wr_port);
+
+ LEAVE();
+}
+
+/**
+ * @brief This function handles the timeout of packet
+ * transmission
+ *
+ * @param dev A pointer to net_device structure
+ *
+ * @return N/A
+ */
+void
+woal_tx_timeout(struct net_device *dev)
+{
+ moal_private *priv = (moal_private *) netdev_priv(dev);
+
+ ENTER();
+
+ priv->num_tx_timeout++;
+ PRINTM(MERROR, "%lu : Tx timeout (%d), bss_index=%d\n",
+ jiffies, priv->num_tx_timeout, priv->bss_index);
+ woal_set_trans_start(dev);
+
+ if (priv->num_tx_timeout == NUM_TX_TIMEOUT_THRESHOLD) {
+ woal_mlan_debug_info(priv);
+ woal_moal_debug_info(priv, NULL, MFALSE);
+ }
+
+ LEAVE();
+}
+
+/**
+ * @brief This function returns the network statistics
+ *
+ * @param dev A pointer to net_device structure
+ *
+ * @return A pointer to net_device_stats structure
+ */
+struct net_device_stats *
+woal_get_stats(struct net_device *dev)
+{
+ moal_private *priv = (moal_private *) netdev_priv(dev);
+ return &priv->stats;
+}
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,34)
+/**
+ * @brief This function handles wmm queue select
+ *
+ * @param dev A pointer to net_device structure
+ * @param skb A pointer to sk_buff structure
+ *
+ * @return tx_queue index (0-3)
+ */
+u16
+woal_select_queue(struct net_device * dev, struct sk_buff * skb)
+{
+ moal_private *priv = (moal_private *) netdev_priv(dev);
+ struct ethhdr *eth = NULL;
+ struct iphdr *iph;
+ t_u8 tid = 0;
+ t_u8 index = 0;
+
+ ENTER();
+
+ eth = (struct ethhdr *) skb->data;
+ switch (eth->h_proto) {
+ case __constant_htons(ETH_P_IP):
+ iph = ip_hdr(skb);
+ tid = IPTOS_PREC(iph->tos);
+ break;
+ case __constant_htons(ETH_P_ARP):
+ default:
+ break;
+ }
+/** Offset for TOS field in the IP header */
+#define IPTOS_OFFSET 5
+ tid = (tid >> IPTOS_OFFSET);
+ index =
+ mlan_select_wmm_queue(priv->phandle->pmlan_adapter, priv->bss_index,
+ tid);
+ PRINTM(MDATA, "select queue: tid=%d, index=%d\n", tid, index);
+ LEAVE();
+ return index;
+}
+#endif
+
+/**
+ * @brief This function handles packet transmission
+ *
+ * @param skb A pointer to sk_buff structure
+ * @param dev A pointer to net_device structure
+ *
+ * @return 0 --success
+ */
+int
+woal_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+ moal_private *priv = (moal_private *) netdev_priv(dev);
+ mlan_buffer *pmbuf = NULL;
+ mlan_status status;
+ struct sk_buff *new_skb = NULL;
+
+ ENTER();
+
+ PRINTM(MDATA, "%lu BSS(%d): Data <= kernel\n", jiffies, priv->bss_index);
+
+ if (priv->phandle->surprise_removed == MTRUE) {
+ dev_kfree_skb_any(skb);
+ priv->stats.tx_dropped++;
+ goto done;
+ }
+ priv->num_tx_timeout = 0;
+ if (!skb->len || (skb->len > ETH_FRAME_LEN)) {
+ PRINTM(MERROR, "Tx Error: Bad skb length %d : %d\n",
+ skb->len, ETH_FRAME_LEN);
+ dev_kfree_skb_any(skb);
+ priv->stats.tx_dropped++;
+ goto done;
+ }
+ if (skb->cloned ||
+ (skb_headroom(skb) <
+ (MLAN_MIN_DATA_HEADER_LEN + sizeof(mlan_buffer)))) {
+ PRINTM(MWARN, "Tx: Insufficient skb headroom %d\n", skb_headroom(skb));
+ /* Insufficient skb headroom - allocate a new skb */
+ new_skb =
+ skb_realloc_headroom(skb,
+ MLAN_MIN_DATA_HEADER_LEN +
+ sizeof(mlan_buffer));
+ if (unlikely(!new_skb)) {
+ PRINTM(MERROR, "Tx: Cannot allocate skb\n");
+ dev_kfree_skb_any(skb);
+ priv->stats.tx_dropped++;
+ goto done;
+ }
+ if (new_skb != skb)
+ dev_kfree_skb_any(skb);
+ skb = new_skb;
+ PRINTM(MINFO, "new skb headroom %d\n", skb_headroom(skb));
+ }
+ pmbuf = (mlan_buffer *) skb->head;
+ memset((t_u8 *) pmbuf, 0, sizeof(mlan_buffer));
+ pmbuf->bss_index = priv->bss_index;
+ woal_fill_mlan_buffer(priv, pmbuf, skb);
+ status = mlan_send_packet(priv->phandle->pmlan_adapter, pmbuf);
+ switch (status) {
+ case MLAN_STATUS_PENDING:
+ atomic_inc(&priv->phandle->tx_pending);
+ if (atomic_read(&priv->phandle->tx_pending) >= MAX_TX_PENDING)
+ woal_stop_queue(priv->netdev);
+ queue_work(priv->phandle->workqueue, &priv->phandle->main_work);
+ break;
+ case MLAN_STATUS_SUCCESS:
+ priv->stats.tx_packets++;
+ priv->stats.tx_bytes += skb->len;
+ dev_kfree_skb_any(skb);
+ break;
+ case MLAN_STATUS_FAILURE:
+ default:
+ priv->stats.tx_dropped++;
+ dev_kfree_skb_any(skb);
+ break;
+ }
+ done:
+ LEAVE();
+ return 0;
+}
+
+/**
+ * @brief Convert ascii string to Hex integer
+ *
+ * @param d A pointer to integer buf
+ * @param s A pointer to ascii string
+ * @param dlen The byte number of ascii string in hex
+ *
+ * @return Number of integer
+ */
+int
+woal_ascii2hex(t_u8 * d, char *s, t_u32 dlen)
+{
+ unsigned int i;
+ t_u8 n;
+
+ ENTER();
+
+ memset(d, 0x00, dlen);
+
+ for (i = 0; i < dlen * 2; i++) {
+ if ((s[i] >= 48) && (s[i] <= 57))
+ n = s[i] - 48;
+ else if ((s[i] >= 65) && (s[i] <= 70))
+ n = s[i] - 55;
+ else if ((s[i] >= 97) && (s[i] <= 102))
+ n = s[i] - 87;
+ else
+ break;
+ if (!(i % 2))
+ n = n * 16;
+ d[i / 2] += n;
+ }
+
+ LEAVE();
+ return i;
+}
+
+/**
+ * @brief Return integer value of a given ascii string
+ *
+ * @param data Converted data to be returned
+ * @param a String to be converted
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status
+woal_atoi(int *data, char *a)
+{
+ int i, val = 0, len;
+
+ ENTER();
+
+ len = strlen(a);
+ if (!strncmp(a, "0x", 2)) {
+ a = a + 2;
+ len -= 2;
+ *data = woal_atox(a);
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+ }
+ for (i = 0; i < len; i++) {
+ if (isdigit(a[i])) {
+ val = val * 10 + (a[i] - '0');
+ } else {
+ PRINTM(MERROR, "Invalid char %c in string %s\n", a[i], a);
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+ }
+ *data = val;
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief Return hex value of a given ascii string
+ *
+ * @param a String to be converted to ascii
+ *
+ * @return The converted character if a is a valid hex, else 0
+ */
+int
+woal_atox(char *a)
+{
+ int i = 0;
+
+ ENTER();
+
+ while (isxdigit(*a))
+ i = i * 16 + woal_hexval(*a++);
+
+ LEAVE();
+ return i;
+}
+
+/**
+ * @brief Extension of strsep lib command. This function will also take care
+ * escape character
+ *
+ * @param s A pointer to array of chars to process
+ * @param delim The delimiter character to end the string
+ * @param esc The escape character to ignore for delimiter
+ *
+ * @return Pointer to the separated string if delim found, else NULL
+ */
+char *
+woal_strsep(char **s, char delim, char esc)
+{
+ char *se = *s, *sb;
+
+ ENTER();
+
+ if (!(*s) || (*se == '\0')) {
+ LEAVE();
+ return NULL;
+ }
+
+ for (sb = *s; *sb != '\0'; ++sb) {
+ if (*sb == esc && *(sb + 1) == esc) {
+ /*
+ * We get a esc + esc seq then keep the one esc
+ * and chop off the other esc character
+ */
+ memmove(sb, sb + 1, strlen(sb));
+ continue;
+ }
+ if (*sb == esc && *(sb + 1) == delim) {
+ /*
+ * We get a delim + esc seq then keep the delim
+ * and chop off the esc character
+ */
+ memmove(sb, sb + 1, strlen(sb));
+ continue;
+ }
+ if (*sb == delim)
+ break;
+ }
+
+ if (*sb == '\0')
+ sb = NULL;
+ else
+ *sb++ = '\0';
+
+ *s = sb;
+
+ LEAVE();
+ return se;
+}
+
+/**
+ * @brief Convert mac address from string to t_u8 buffer.
+ *
+ * @param mac_addr The buffer to store the mac address in.
+ * @param buf The source of mac address which is a string.
+ *
+ * @return N/A
+ */
+void
+woal_mac2u8(t_u8 * mac_addr, char *buf)
+{
+ char *begin = buf, *end;
+ int i;
+
+ ENTER();
+
+ for (i = 0; i < ETH_ALEN; ++i) {
+ end = woal_strsep(&begin, ':', '/');
+ if (end)
+ mac_addr[i] = woal_atox(end);
+ }
+
+ LEAVE();
+}
+
+#ifdef STA_SUPPORT
+/**
+ * @brief This function sets multicast addresses to firmware
+ *
+ * @param dev A pointer to net_device structure
+ *
+ * @return N/A
+ */
+void
+woal_set_multicast_list(struct net_device *dev)
+{
+ moal_private *priv = (moal_private *) netdev_priv(dev);
+ ENTER();
+ woal_request_set_multicast_list(priv, dev);
+ LEAVE();
+}
+#endif
+
+/**
+ * @brief This function initializes the private structure
+ * and set default value to the member of moal_private.
+ *
+ * @param priv A pointer to moal_private structure
+ * @param wait_option Wait option
+ *
+ * @return N/A
+ */
+void
+woal_init_priv(moal_private * priv, t_u8 wait_option)
+{
+ ENTER();
+#ifdef STA_SUPPORT
+ if (GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_STA) {
+ priv->current_key_index = 0;
+ priv->rate_index = AUTO_RATE;
+ priv->is_adhoc_link_sensed = MFALSE;
+ priv->scan_type = MLAN_SCAN_TYPE_ACTIVE;
+ priv->bg_scan_start = MFALSE;
+ priv->bg_scan_reported = MFALSE;
+ memset(&priv->nick_name, 0, sizeof(priv->nick_name));
+ priv->num_tx_timeout = 0;
+ priv->rx_filter = 0;
+
+#ifdef REASSOCIATION
+ priv->reassoc_on = MFALSE;
+#endif
+#ifdef STA_CFG80211
+ if (IS_STA_CFG80211(cfg80211_wext)) {
+ if (priv->bss_type == MLAN_BSS_TYPE_STA
+#if defined(WIFI_DIRECT_SUPPORT)
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,0,0) || defined(COMPAT_WIRELESS)
+ || priv->bss_type == MLAN_BSS_TYPE_WIFIDIRECT
+#endif
+#endif
+ )
+ woal_cfg80211_sta_init_wiphy(priv, wait_option);
+ }
+#endif
+ }
+#endif /* STA_SUPPORT */
+#ifdef UAP_SUPPORT
+ if (GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_UAP) {
+ priv->bss_started = MFALSE;
+#ifdef UAP_CFG80211
+ if (IS_UAP_CFG80211(cfg80211_wext))
+ woal_cfg80211_uap_init_wiphy(priv, wait_option);
+#endif
+ }
+#endif
+ priv->media_connected = MFALSE;
+ woal_request_get_fw_info(priv, wait_option, NULL);
+
+ LEAVE();
+}
+
+/**
+ * @brief Reset all interfaces if all_intf flag is TRUE,
+ * otherwise specified interface only
+ *
+ * @param priv A pointer to moal_private structure
+ * @param wait_option Wait option
+ * @param all_intf TRUE : all interfaces
+ * FALSE : current interface only
+ *
+ * @return MLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+int
+woal_reset_intf(moal_private * priv, t_u8 wait_option, int all_intf)
+{
+ int ret = MLAN_STATUS_SUCCESS;
+ int intf_num;
+ moal_handle *handle = priv->phandle;
+ mlan_bss_info bss_info;
+
+ ENTER();
+
+ /* Stop queue and detach device */
+ if (!all_intf) {
+ woal_stop_queue(priv->netdev);
+ netif_device_detach(priv->netdev);
+ } else {
+ for (intf_num = 0; intf_num < handle->priv_num; intf_num++) {
+ woal_stop_queue(handle->priv[intf_num]->netdev);
+ netif_device_detach(handle->priv[intf_num]->netdev);
+ }
+ }
+
+ /* Get BSS info */
+ memset(&bss_info, 0, sizeof(bss_info));
+ woal_get_bss_info(priv, wait_option, &bss_info);
+
+#ifdef STA_SUPPORT
+ /* If scan is in process, cancel the scan command */
+ if (handle->scan_pending_on_block == MTRUE) {
+ mlan_ioctl_req *req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_scan));
+ if (req == NULL) {
+ ret = -EFAULT;
+ goto err_cancel_scan;
+ }
+ req->req_id = MLAN_IOCTL_SCAN;
+ req->action = MLAN_ACT_SET;
+ ((mlan_ds_scan *) req->pbuf)->sub_command = MLAN_OID_SCAN_CANCEL;
+ if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, wait_option)) {
+ ret = -EFAULT;
+ goto err_cancel_scan;
+ }
+ err_cancel_scan:
+ handle->scan_pending_on_block = MFALSE;
+ MOAL_REL_SEMAPHORE(&handle->async_sem);
+ if (req)
+ kfree(req);
+ }
+#endif
+
+ /* Cancel host sleep */
+ if (bss_info.is_hs_configured) {
+ if (MLAN_STATUS_SUCCESS != woal_cancel_hs(priv, wait_option)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ }
+
+ /* Disconnect from network */
+ if (!all_intf) {
+ /* Disconnect specified interface only */
+ if ((priv->media_connected == MTRUE)
+#ifdef UAP_SUPPORT
+ || (GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_UAP)
+#endif
+ ) {
+ woal_disconnect(priv, wait_option, NULL);
+ priv->media_connected = MFALSE;
+ }
+ } else {
+ /* Disconnect all interfaces */
+ for (intf_num = 0; intf_num < handle->priv_num; intf_num++) {
+ if (handle->priv[intf_num]->media_connected == MTRUE
+#ifdef UAP_SUPPORT
+ || (GET_BSS_ROLE(handle->priv[intf_num]) == MLAN_BSS_ROLE_UAP)
+#endif
+ ) {
+ woal_disconnect(handle->priv[intf_num], wait_option, NULL);
+ handle->priv[intf_num]->media_connected = MFALSE;
+ }
+ }
+ }
+
+#ifdef REASSOCIATION
+ /* Reset the reassoc timer and status */
+ if (!all_intf) {
+ handle->reassoc_on &= ~MBIT(priv->bss_index);
+ priv->reassoc_on = MFALSE;
+ } else {
+ handle->reassoc_on = 0;
+ for (intf_num = 0; intf_num < handle->priv_num; intf_num++) {
+ handle->priv[intf_num]->reassoc_on = MFALSE;
+ }
+ }
+ if (!handle->reassoc_on && handle->is_reassoc_timer_set) {
+ woal_cancel_timer(&handle->reassoc_timer);
+ handle->is_reassoc_timer_set = MFALSE;
+ }
+#endif /* REASSOCIATION */
+
+ done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function return the point to structure moal_private
+ *
+ * @param handle Pointer to structure moal_handle
+ * @param bss_index BSS index number
+ *
+ * @return moal_private pointer or NULL
+ */
+moal_private *
+woal_bss_index_to_priv(moal_handle * handle, t_u8 bss_index)
+{
+ int i;
+
+ ENTER();
+ if (!handle) {
+ LEAVE();
+ return NULL;
+ }
+ for (i = 0; i < MLAN_MAX_BSS_NUM; i++) {
+ if (handle->priv[i] && (handle->priv[i]->bss_index == bss_index)) {
+ LEAVE();
+ return handle->priv[i];
+ }
+ }
+
+ LEAVE();
+ return NULL;
+}
+
+/**
+ * @brief This function alloc mlan_buffer.
+ * @param handle A pointer to moal_handle structure
+ * @param size buffer size to allocate
+ *
+ * @return mlan_buffer pointer or NULL
+ */
+pmlan_buffer
+woal_alloc_mlan_buffer(moal_handle * handle, int size)
+{
+ mlan_buffer *pmbuf = NULL;
+ struct sk_buff *skb;
+
+ ENTER();
+ if (!(pmbuf = kmalloc(sizeof(mlan_buffer), GFP_ATOMIC))) {
+ PRINTM(MERROR, "%s: Fail to alloc mlan buffer\n", __FUNCTION__);
+ LEAVE();
+ return NULL;
+ }
+ memset((t_u8 *) pmbuf, 0, sizeof(mlan_buffer));
+ if (!(skb = dev_alloc_skb(size))) {
+ PRINTM(MERROR, "%s: No free skb\n", __FUNCTION__);
+ kfree(pmbuf);
+ LEAVE();
+ return NULL;
+ }
+ pmbuf->pdesc = (t_void *) skb;
+ pmbuf->pbuf = (t_u8 *) skb->data;
+ handle->mbufalloc_count++;
+ LEAVE();
+ return pmbuf;
+}
+
+/**
+ * @brief This function alloc mlan_ioctl_req.
+ *
+ * @param size buffer size to allocate
+ *
+ * @return mlan_ioctl_req pointer or NULL
+ */
+pmlan_ioctl_req
+woal_alloc_mlan_ioctl_req(int size)
+{
+ mlan_ioctl_req *req = NULL;
+
+ ENTER();
+
+ if (!
+ (req =
+ (mlan_ioctl_req *)
+ kmalloc((sizeof(mlan_ioctl_req) + size + sizeof(int) +
+ sizeof(wait_queue)), GFP_ATOMIC))) {
+ PRINTM(MERROR, "%s: Fail to alloc ioctl buffer\n", __FUNCTION__);
+ LEAVE();
+ return NULL;
+ }
+ memset((t_u8 *) req, 0, (sizeof(mlan_ioctl_req) + size +
+ sizeof(int) + sizeof(wait_queue)));
+ req->pbuf = (t_u8 *) req + sizeof(mlan_ioctl_req) + sizeof(wait_queue);
+ req->buf_len = (t_u32) size;
+ req->reserved_1 = (t_ptr) ((t_u8 *) req + sizeof(mlan_ioctl_req));
+
+ LEAVE();
+ return req;
+}
+
+/**
+ * @brief This function frees mlan_buffer.
+ * @param handle A pointer to moal_handle structure
+ * @param pmbuf Pointer to mlan_buffer
+ *
+ * @return N/A
+ */
+void
+woal_free_mlan_buffer(moal_handle * handle, pmlan_buffer pmbuf)
+{
+ ENTER();
+ if (!pmbuf) {
+ LEAVE();
+ return;
+ }
+ if (pmbuf->pdesc)
+ dev_kfree_skb_any((struct sk_buff *) pmbuf->pdesc);
+ kfree(pmbuf);
+ handle->mbufalloc_count--;
+ LEAVE();
+ return;
+}
+
+#ifdef STA_WEXT
+#endif
+
+/**
+ * @brief This function handles events generated by firmware
+ *
+ * @param priv A pointer to moal_private structure
+ * @param payload A pointer to payload buffer
+ * @param len Length of the payload
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status
+woal_broadcast_event(moal_private * priv, t_u8 * payload, t_u32 len)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ struct sk_buff *skb = NULL;
+ struct nlmsghdr *nlh = NULL;
+ moal_handle *handle = priv->phandle;
+ struct sock *sk = handle->nl_sk;
+
+ ENTER();
+ /* interface name to be prepended to event */
+ if ((len + IFNAMSIZ) > NL_MAX_PAYLOAD) {
+ PRINTM(MERROR, "event size is too big, len=%d\n", (int) len);
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ if (sk) {
+ /* Allocate skb */
+ if (!(skb = alloc_skb(NLMSG_SPACE(NL_MAX_PAYLOAD), GFP_ATOMIC))) {
+ PRINTM(MERROR, "Could not allocate skb for netlink\n");
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ nlh = (struct nlmsghdr *) skb->data;
+ nlh->nlmsg_len = NLMSG_SPACE(len + IFNAMSIZ);
+
+ /* From kernel */
+ nlh->nlmsg_pid = 0;
+ nlh->nlmsg_flags = 0;
+
+ /* Data */
+ skb_put(skb, nlh->nlmsg_len);
+ memcpy(NLMSG_DATA(nlh), priv->netdev->name, IFNAMSIZ);
+ memcpy(((t_u8 *) (NLMSG_DATA(nlh))) + IFNAMSIZ, payload, len);
+
+ /* From Kernel */
+ NETLINK_CB(skb).pid = 0;
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20)
+ /* Multicast message */
+ NETLINK_CB(skb).dst_pid = 0;
+#endif
+
+ /* Multicast group number */
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,14)
+ NETLINK_CB(skb).dst_groups = NL_MULTICAST_GROUP;
+#else
+ NETLINK_CB(skb).dst_group = NL_MULTICAST_GROUP;
+#endif
+
+ /* Send message */
+ netlink_broadcast(sk, skb, 0, NL_MULTICAST_GROUP, GFP_ATOMIC);
+
+ ret = MLAN_STATUS_SUCCESS;
+ } else {
+ PRINTM(MERROR, "Could not send event through NETLINK. Link down.\n");
+ ret = MLAN_STATUS_FAILURE;
+ }
+ done:
+ LEAVE();
+ return ret;
+}
+
+#ifdef REASSOCIATION
+/**
+ * @brief This function handles re-association. it is triggered
+ * by re-assoc timer.
+ *
+ * @param data A pointer to wlan_thread structure
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+int
+woal_reassociation_thread(void *data)
+{
+ moal_thread *pmoal_thread = data;
+ moal_private *priv = NULL;
+ moal_handle *handle = (moal_handle *) pmoal_thread->handle;
+ wait_queue_t wait;
+ int i;
+ BOOLEAN reassoc_timer_req;
+ mlan_802_11_ssid req_ssid;
+ mlan_ssid_bssid ssid_bssid;
+ mlan_status status;
+ mlan_bss_info bss_info;
+ t_u32 timer_val = MOAL_TIMER_10S;
+
+ ENTER();
+
+ woal_activate_thread(pmoal_thread);
+ init_waitqueue_entry(&wait, current);
+
+ current->flags |= PF_NOFREEZE;
+
+ for (;;) {
+ add_wait_queue(&pmoal_thread->wait_q, &wait);
+ set_current_state(TASK_INTERRUPTIBLE);
+
+ schedule();
+
+ set_current_state(TASK_RUNNING);
+ remove_wait_queue(&pmoal_thread->wait_q, &wait);
+
+ /* Cancel re-association timer */
+ if (handle->is_reassoc_timer_set == MTRUE) {
+ woal_cancel_timer(&handle->reassoc_timer);
+ handle->is_reassoc_timer_set = MFALSE;
+ }
+
+ if (handle->surprise_removed)
+ break;
+ if (kthread_should_stop())
+ break;
+
+ if (handle->hardware_status != HardwareStatusReady) {
+ PRINTM(MINFO, "Reassoc: Hardware status is not correct\n");
+ continue;
+ }
+
+ PRINTM(MEVENT, "Reassoc: Thread waking up...\n");
+ reassoc_timer_req = MFALSE;
+
+ for (i = 0; i < handle->priv_num && (priv = handle->priv[i]); i++) {
+
+ if (priv->reassoc_required == MFALSE)
+ continue;
+
+ memset(&bss_info, 0x00, sizeof(bss_info));
+
+ if (MLAN_STATUS_SUCCESS != woal_get_bss_info(priv,
+ MOAL_CMD_WAIT,
+ &bss_info)) {
+ PRINTM(MINFO, "Ressoc: Fail to get bss info\n");
+ priv->reassoc_required = MFALSE;
+ continue;
+ }
+
+ if (bss_info.bss_mode != MLAN_BSS_MODE_INFRA ||
+ priv->media_connected != MFALSE) {
+ PRINTM(MINFO, "Reassoc: ad-hoc mode or media connected\n");
+ priv->reassoc_required = MFALSE;
+ continue;
+ }
+
+ /* The semaphore is used to avoid reassociation thread and
+ wlan_set_scan/wlan_set_essid interrupting each other.
+ Reassociation should be disabled completely by application if
+ wlan_set_user_scan_ioctl/wlan_set_wap is used. */
+ if (MOAL_ACQ_SEMAPHORE_BLOCK(&handle->reassoc_sem)) {
+ PRINTM(MERROR,
+ "Acquire semaphore error, reassociation thread\n");
+ reassoc_timer_req = MTRUE;
+ break;
+ }
+
+ PRINTM(MINFO, "Reassoc: Required ESSID: %s\n",
+ priv->prev_ssid_bssid.ssid.ssid);
+ PRINTM(MINFO, "Reassoc: Performing Active Scan\n");
+
+ memset(&req_ssid, 0x00, sizeof(mlan_802_11_ssid));
+ memcpy(&req_ssid,
+ &priv->prev_ssid_bssid.ssid, sizeof(mlan_802_11_ssid));
+
+ /* Do specific SSID scanning */
+ if (MLAN_STATUS_SUCCESS !=
+ woal_request_scan(priv, MOAL_CMD_WAIT, &req_ssid)) {
+ PRINTM(MERROR, "Reassoc: Fail to do specific scan\n");
+ reassoc_timer_req = MTRUE;
+ MOAL_REL_SEMAPHORE(&handle->reassoc_sem);
+ break;
+ }
+
+ if (handle->surprise_removed) {
+ MOAL_REL_SEMAPHORE(&handle->reassoc_sem);
+ break;
+ }
+
+ /* Search AP by BSSID first */
+ PRINTM(MINFO, "Reassoc: Search AP by BSSID first\n");
+ memset(&ssid_bssid, 0, sizeof(mlan_ssid_bssid));
+ memcpy(&ssid_bssid.bssid,
+ &priv->prev_ssid_bssid.bssid, MLAN_MAC_ADDR_LENGTH);
+ status = woal_find_best_network(priv, MOAL_CMD_WAIT, &ssid_bssid);
+
+ if (MLAN_STATUS_SUCCESS != status) {
+ PRINTM(MINFO, "Reassoc: AP not found in scan list\n");
+ PRINTM(MINFO, "Reassoc: Search AP by SSID\n");
+ /* Search AP by SSID */
+ memset(&ssid_bssid, 0, sizeof(mlan_ssid_bssid));
+ memcpy(&ssid_bssid.ssid,
+ &priv->prev_ssid_bssid.ssid, sizeof(mlan_802_11_ssid));
+ status = woal_find_best_network(priv,
+ MOAL_CMD_WAIT, &ssid_bssid);
+ }
+
+ if (status == MLAN_STATUS_SUCCESS) {
+ /* set the wep key */
+ if (bss_info.wep_status)
+ woal_enable_wep_key(priv, MOAL_CMD_WAIT);
+ /* Zero SSID implies use BSSID to connect */
+ memset(&ssid_bssid.ssid, 0, sizeof(mlan_802_11_ssid));
+ status = woal_bss_start(priv, MOAL_CMD_WAIT, &ssid_bssid);
+ }
+
+ if (priv->media_connected == MFALSE)
+ reassoc_timer_req = MTRUE;
+ else {
+ mlan_ds_rate *rate = NULL;
+ mlan_ioctl_req *req = NULL;
+
+ reassoc_timer_req = MFALSE;
+
+ if (priv->rate_index != AUTO_RATE) {
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_rate));
+
+ if (req == NULL) {
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+
+ rate = (mlan_ds_rate *) req->pbuf;
+ rate->param.rate_cfg.rate_type = MLAN_RATE_INDEX;
+ rate->sub_command = MLAN_OID_RATE_CFG;
+ req->req_id = MLAN_IOCTL_RATE;
+
+ req->action = MLAN_ACT_SET;
+
+ rate->param.rate_cfg.rate = priv->rate_index;
+
+ if (MLAN_STATUS_SUCCESS
+ != woal_request_ioctl(priv, req, MOAL_CMD_WAIT)) {
+ kfree(req);
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+ if (req)
+ kfree(req);
+ }
+ }
+
+ MOAL_REL_SEMAPHORE(&handle->reassoc_sem);
+ }
+
+ if (handle->surprise_removed)
+ break;
+
+ if (reassoc_timer_req == MTRUE) {
+ PRINTM(MEVENT,
+ "Reassoc: No AP found or assoc failed. "
+ "Restarting re-assoc Timer: %d\n", (int) timer_val);
+ handle->is_reassoc_timer_set = MTRUE;
+ woal_mod_timer(&handle->reassoc_timer, timer_val);
+ }
+ }
+ woal_deactivate_thread(pmoal_thread);
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function triggers re-association by waking up
+ * re-assoc thread.
+ *
+ * @param context A pointer to context
+ * @return N/A
+ */
+void
+woal_reassoc_timer_func(void *context)
+{
+ moal_handle *handle = (moal_handle *) context;
+
+ ENTER();
+
+ PRINTM(MINFO, "reassoc_timer fired.\n");
+ handle->is_reassoc_timer_set = MFALSE;
+
+ PRINTM(MINFO, "Waking Up the Reassoc Thread\n");
+ wake_up_interruptible(&handle->reassoc_thread.wait_q);
+
+ LEAVE();
+ return;
+}
+#endif /* REASSOCIATION */
+
+#ifdef STA_SUPPORT
+/**
+ * @brief Sends disconnect event
+ *
+ * @param priv A pointer to moal_private struct
+ * @return N/A
+ */
+t_void
+woal_send_disconnect_to_system(moal_private * priv)
+{
+#ifdef STA_WEXT
+ union iwreq_data wrqu;
+#endif
+
+ ENTER();
+ priv->media_connected = MFALSE;
+ woal_stop_queue(priv->netdev);
+ if (netif_carrier_ok(priv->netdev))
+ netif_carrier_off(priv->netdev);
+#ifdef STA_WEXT
+ if (IS_STA_WEXT(cfg80211_wext)) {
+ memset(wrqu.ap_addr.sa_data, 0x00, ETH_ALEN);
+ wrqu.ap_addr.sa_family = ARPHRD_ETHER;
+ wireless_send_event(priv->netdev, SIOCGIWAP, &wrqu, NULL);
+ }
+#endif
+ LEAVE();
+}
+#endif /* STA_SUPPORT */
+
+/**
+ * @brief This function reads and displays SDIO registers for debugging
+ *
+ * @param phandle A pointer to moal_handle
+ *
+ * @return N/A
+ */
+void
+woal_sdio_reg_dbg(moal_handle * phandle)
+{
+ int ret = 0;
+ t_u8 loop, index = 0, func, data;
+ unsigned int reg, reg_start, reg_end;
+ unsigned int reg_table[] = { 0x28, 0x30, 0x34, 0x38, 0x3c };
+ char buf[128], *ptr;
+
+ sdio_claim_host(((struct sdio_mmc_card *) phandle->card)->func);
+ for (loop = 0; loop < 5; loop++) {
+ memset(buf, 0, sizeof(buf));
+ ptr = buf;
+ if (loop < 2) {
+ /* Read the registers of SDIO function0 and function1 */
+ func = loop;
+ reg_start = 0;
+ reg_end = 9;
+ } else if (loop == 2) {
+ /* Read specific registers of SDIO function1 */
+ index = 0;
+ func = 1;
+ reg_start = reg_table[index++];
+ reg_end = reg_table[sizeof(reg_table) / sizeof(int) - 1];
+ } else {
+ /* Read the scratch registers of SDIO function1 */
+ if (loop == 4)
+ mdelay(100);
+ func = 1;
+#define SDIO_SCRATCH_REG 0x60
+ reg_start = SDIO_SCRATCH_REG;
+ reg_end = SDIO_SCRATCH_REG + 10;
+ }
+ if (loop != 2)
+ ptr +=
+ sprintf(ptr, "SDIO Func%d (%#x-%#x): ", func, reg_start,
+ reg_end);
+ else
+ ptr += sprintf(ptr, "SDIO Func%d: ", func);
+ for (reg = reg_start; reg <= reg_end;) {
+ if (func == 0)
+ data =
+ sdio_f0_readb(((struct sdio_mmc_card *) phandle->card)->
+ func, reg, &ret);
+ else
+ data =
+ sdio_readb(((struct sdio_mmc_card *) phandle->card)->func,
+ reg, &ret);
+ if (loop == 2)
+ ptr += sprintf(ptr, "(%#x) ", reg);
+ if (!ret)
+ ptr += sprintf(ptr, "%02x ", data);
+ else {
+ ptr += sprintf(ptr, "ERR");
+ break;
+ }
+ if (loop == 2 && reg < reg_end)
+ reg = reg_table[index++];
+ else
+ reg++;
+ }
+ PRINTM(MMSG, "%s\n", buf);
+ }
+ sdio_release_host(((struct sdio_mmc_card *) phandle->card)->func);
+}
+
+/**
+ * @brief This function displays extra MOAL debug information
+ *
+ * @param priv A pointer to moal_private
+ * @param handle A pointer to moal_handle
+ * @param flag Indicates whether register read can be done directly
+ *
+ * @return N/A
+ */
+void
+woal_moal_debug_info(moal_private * priv, moal_handle * handle, u8 flag)
+{
+ moal_handle *phandle = NULL;
+ char buf[MLAN_MAX_VER_STR_LEN];
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,34)
+ int i = 0;
+#endif
+
+ ENTER();
+
+ if (!priv) {
+ if (handle) {
+ phandle = handle;
+ } else {
+ PRINTM(MERROR, "Could not retrieve debug information from MOAL\n");
+ LEAVE();
+ return;
+ }
+ } else {
+ phandle = priv->phandle;
+ }
+
+ woal_get_version(phandle, buf, sizeof(buf) - 1);
+ PRINTM(MERROR, "Driver version = %s\n", buf);
+ PRINTM(MERROR, "main_state = %d\n", phandle->main_state);
+ PRINTM(MERROR, "ioctl_pending = %d\n",
+ atomic_read(&phandle->ioctl_pending));
+ PRINTM(MERROR, "tx_pending = %d\n", atomic_read(&phandle->tx_pending));
+ PRINTM(MERROR, "rx_pending = %d\n", atomic_read(&phandle->rx_pending));
+ PRINTM(MERROR, "malloc_count = %u\n", phandle->malloc_count);
+ PRINTM(MERROR, "lock_count = %u\n", phandle->lock_count);
+ PRINTM(MERROR, "mbufalloc_count = %u\n", phandle->mbufalloc_count);
+#if defined(SDIO_SUSPEND_RESUME)
+ PRINTM(MERROR, "hs_skip_count = %u\n", phandle->hs_skip_count);
+ PRINTM(MERROR, "hs_force_count = %u\n", phandle->hs_force_count);
+#endif
+
+ if (priv) {
+ PRINTM(MERROR, "Media state = \"%s\"\n",
+ ((priv->media_connected ==
+ MFALSE) ? "Disconnected" : "Connected"));
+ PRINTM(MERROR, "carrier %s\n",
+ ((netif_carrier_ok(priv->netdev)) ? "on" : "off"));
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,34)
+ for (i = 0; i < (priv->netdev->num_tx_queues); i++) {
+ PRINTM(MERROR, "tx queue %d: %s\n", i,
+ ((netif_tx_queue_stopped
+ (netdev_get_tx_queue(priv->netdev, 0))) ? "stopped" :
+ "started"));
+ }
+#else
+ PRINTM(MERROR, "tx queue %s\n",
+ ((netif_queue_stopped(priv->netdev)) ? "stopped" : "started"));
+#endif
+ }
+
+ /* Display SDIO registers */
+ if (flag && phandle->main_state == MOAL_END_MAIN_PROCESS) {
+ woal_sdio_reg_dbg(phandle);
+ } else {
+ phandle->sdio_reg_dbg = MTRUE;
+ queue_work(phandle->workqueue, &phandle->main_work);
+ }
+
+ LEAVE();
+ return;
+}
+
+/**
+ * @brief This workqueue function handles main_process
+ *
+ * @param work A pointer to work_struct
+ *
+ * @return N/A
+ */
+t_void
+woal_main_work_queue(struct work_struct * work)
+{
+ moal_handle *handle = container_of(work, moal_handle, main_work);
+
+ ENTER();
+
+ if (handle->surprise_removed == MTRUE) {
+ LEAVE();
+ return;
+ }
+
+ if (handle->sdio_reg_dbg == MTRUE) {
+ handle->sdio_reg_dbg = MFALSE;
+ woal_sdio_reg_dbg(handle);
+ LEAVE();
+ return;
+ }
+
+ handle->main_state = MOAL_ENTER_WORK_QUEUE;
+ sdio_claim_host(((struct sdio_mmc_card *) handle->card)->func);
+ handle->main_state = MOAL_START_MAIN_PROCESS;
+ /* Call MLAN main process */
+ mlan_main_process(handle->pmlan_adapter);
+ handle->main_state = MOAL_END_MAIN_PROCESS;
+ sdio_release_host(((struct sdio_mmc_card *) handle->card)->func);
+
+ LEAVE();
+}
+
+/**
+ * @brief Handles interrupt
+ *
+ * @param handle A pointer to moal_handle struct
+ *
+ * @return N/A
+ */
+void
+woal_interrupt(moal_handle * handle)
+{
+ ENTER();
+ handle->main_state = MOAL_RECV_INT;
+ PRINTM(MINTR, "*\n");
+ if (handle->surprise_removed == MTRUE) {
+ LEAVE();
+ return;
+ }
+ /* call mlan_interrupt to read int status */
+ mlan_interrupt(handle->pmlan_adapter);
+ handle->main_state = MOAL_START_MAIN_PROCESS;
+ /* Call MLAN main process */
+ mlan_main_process(handle->pmlan_adapter);
+ handle->main_state = MOAL_END_MAIN_PROCESS;
+ LEAVE();
+}
+
+/**
+ * @brief This function adds the card. it will probe the
+ * card, allocate the mlan_private and initialize the device.
+ *
+ * @param card A pointer to card
+ *
+ * @return A pointer to moal_handle structure
+ */
+moal_handle *
+woal_add_card(void *card)
+{
+ moal_handle *handle = NULL;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+ int netlink_num = NETLINK_MARVELL;
+ int index = 0;
+
+ ENTER();
+
+ if (MOAL_ACQ_SEMAPHORE_BLOCK(&AddRemoveCardSem))
+ goto exit_sem_err;
+
+ /* Allocate buffer for moal_handle */
+ if (!(handle = kmalloc(sizeof(moal_handle), GFP_KERNEL))) {
+ PRINTM(MERROR, "Allocate buffer for moal_handle failed!\n");
+ goto err_handle;
+ }
+
+ /* Init moal_handle */
+ memset(handle, 0, sizeof(moal_handle));
+ handle->card = card;
+ /* Save the handle */
+ for (index = 0; index < MAX_MLAN_ADAPTER; index++) {
+ if (m_handle[index] == NULL)
+ break;
+ }
+ if (index < MAX_MLAN_ADAPTER) {
+ m_handle[index] = handle;
+ handle->handle_idx = index;
+ } else {
+ PRINTM(MERROR, "Exceeded maximum cards supported!\n");
+ goto err_kmalloc;
+ }
+
+ if (mac_addr) {
+ t_u8 temp[20];
+ t_u8 len = strlen(mac_addr) + 1;
+ if (len < sizeof(temp)) {
+ memcpy(temp, mac_addr, len);
+ handle->set_mac_addr = 1;
+ /* note: the following function overwrites the temp buffer */
+ woal_mac2u8(handle->mac_addr, temp);
+ }
+ }
+
+ ((struct sdio_mmc_card *) card)->handle = handle;
+#ifdef STA_SUPPORT
+ handle->scan_pending_on_block = MFALSE;
+ MOAL_INIT_SEMAPHORE(&handle->async_sem);
+#endif
+
+ /* Init SW */
+ if (MLAN_STATUS_SUCCESS != woal_init_sw(handle)) {
+ PRINTM(MFATAL, "Software Init Failed\n");
+ goto err_kmalloc;
+ }
+
+ do {
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,14)
+ handle->nl_sk = netlink_kernel_create(netlink_num, NULL);
+#else
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,22)
+ handle->nl_sk =
+ netlink_kernel_create(netlink_num, NL_MULTICAST_GROUP, NULL,
+ THIS_MODULE);
+#else
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24)
+ handle->nl_sk =
+ netlink_kernel_create(netlink_num, NL_MULTICAST_GROUP, NULL, NULL,
+ THIS_MODULE);
+#else
+ handle->nl_sk =
+ netlink_kernel_create(&init_net, netlink_num, NL_MULTICAST_GROUP,
+ NULL, NULL, THIS_MODULE);
+#endif
+#endif
+#endif
+ if (handle->nl_sk) {
+ PRINTM(MINFO, "Netlink number = %d\n", netlink_num);
+ handle->netlink_num = netlink_num;
+ break;
+ }
+ netlink_num--;
+ } while (netlink_num > 0);
+
+ if (handle->nl_sk == NULL) {
+ PRINTM(MERROR,
+ "Could not initialize netlink event passing mechanism!\n");
+ goto err_kmalloc;
+ }
+
+ /* Create workqueue for main process */
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,14)
+ /* For kernel less than 2.6.14 name can not be greater than 10 characters */
+ handle->workqueue = create_workqueue("MOAL_WORKQ");
+#else
+ handle->workqueue = create_workqueue("MOAL_WORK_QUEUE");
+#endif
+ if (!handle->workqueue)
+ goto err_kmalloc;
+
+ MLAN_INIT_WORK(&handle->main_work, woal_main_work_queue);
+
+#ifdef REASSOCIATION
+ PRINTM(MINFO, "Starting re-association thread...\n");
+ handle->reassoc_thread.handle = handle;
+ woal_create_thread(woal_reassociation_thread,
+ &handle->reassoc_thread, "woal_reassoc_service");
+
+ while (!handle->reassoc_thread.pid) {
+ woal_sched_timeout(2);
+ }
+#endif /* REASSOCIATION */
+
+ /* Register the device. Fill up the private data structure with relevant
+ information from the card and request for the required IRQ. */
+ if (woal_register_dev(handle) != MLAN_STATUS_SUCCESS) {
+ PRINTM(MFATAL, "Failed to register wlan device!\n");
+ goto err_registerdev;
+ }
+
+ /* Init FW and HW */
+ if (MLAN_STATUS_SUCCESS != woal_init_fw(handle)) {
+ PRINTM(MFATAL, "Firmware Init Failed\n");
+ goto err_init_fw;
+ }
+
+ LEAVE();
+ return handle;
+
+ err_init_fw:
+ /* Unregister device */
+ PRINTM(MINFO, "unregister device\n");
+ woal_unregister_dev(handle);
+ err_registerdev:
+ handle->surprise_removed = MTRUE;
+#ifdef REASSOCIATION
+ if (handle->reassoc_thread.pid) {
+ wake_up_interruptible(&handle->reassoc_thread.wait_q);
+ }
+ /* waiting for main thread quit */
+ while (handle->reassoc_thread.pid) {
+ woal_sched_timeout(2);
+ }
+#endif /* REASSOCIATION */
+ woal_terminate_workqueue(handle);
+ err_kmalloc:
+ if ((handle->hardware_status == HardwareStatusFwReady) ||
+ (handle->hardware_status == HardwareStatusReady)) {
+ PRINTM(MINFO, "shutdown mlan\n");
+ handle->init_wait_q_woken = MFALSE;
+ status = mlan_shutdown_fw(handle->pmlan_adapter);
+ if (status == MLAN_STATUS_PENDING)
+ wait_event_interruptible(handle->init_wait_q,
+ handle->init_wait_q_woken);
+ }
+ woal_free_moal_handle(handle);
+ if (index < MAX_MLAN_ADAPTER) {
+ m_handle[index] = NULL;
+ }
+ ((struct sdio_mmc_card *) card)->handle = NULL;
+ err_handle:
+ MOAL_REL_SEMAPHORE(&AddRemoveCardSem);
+ exit_sem_err:
+ LEAVE();
+ return NULL;
+}
+
+/**
+ * @brief This function removes the card.
+ *
+ * @param card A pointer to card
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+mlan_status
+woal_remove_card(void *card)
+{
+ moal_handle *handle = NULL;
+ moal_private *priv = NULL;
+ mlan_status status;
+ int i;
+ int index = 0;
+
+ ENTER();
+
+ if (MOAL_ACQ_SEMAPHORE_BLOCK(&AddRemoveCardSem))
+ goto exit_sem_err;
+ /* Find the correct handle */
+ for (index = 0; index < MAX_MLAN_ADAPTER; index++) {
+ if (m_handle[index] && (m_handle[index]->card == card)) {
+ handle = m_handle[index];
+ break;
+ }
+ }
+ if (!handle)
+ goto exit_remove;
+ handle->surprise_removed = MTRUE;
+
+ /* Stop data */
+ for (i = 0; i < MIN(handle->priv_num, MLAN_MAX_BSS_NUM); i++) {
+ if ((priv = handle->priv[i])) {
+ woal_stop_queue(priv->netdev);
+ if (netif_carrier_ok(priv->netdev))
+ netif_carrier_off(priv->netdev);
+ }
+ }
+
+ if ((handle->hardware_status == HardwareStatusFwReady) ||
+ (handle->hardware_status == HardwareStatusReady)) {
+ /* Shutdown firmware */
+ PRINTM(MIOCTL, "mlan_shutdown_fw.....\n");
+ handle->init_wait_q_woken = MFALSE;
+
+ status = mlan_shutdown_fw(handle->pmlan_adapter);
+ if (status == MLAN_STATUS_PENDING)
+ wait_event_interruptible(handle->init_wait_q,
+ handle->init_wait_q_woken);
+ PRINTM(MIOCTL, "mlan_shutdown_fw done!\n");
+ }
+ if (atomic_read(&handle->rx_pending) || atomic_read(&handle->tx_pending) ||
+ atomic_read(&handle->ioctl_pending)) {
+ PRINTM(MERROR, "ERR: rx_pending=%d,tx_pending=%d,ioctl_pending=%d\n",
+ atomic_read(&handle->rx_pending),
+ atomic_read(&handle->tx_pending),
+ atomic_read(&handle->ioctl_pending));
+ }
+
+ /* Remove interface */
+ for (i = 0; i < handle->priv_num; i++)
+ woal_remove_interface(handle, i);
+
+ woal_terminate_workqueue(handle);
+
+#ifdef REASSOCIATION
+ PRINTM(MINFO, "Free reassoc_timer\n");
+ if (handle->is_reassoc_timer_set) {
+ woal_cancel_timer(&handle->reassoc_timer);
+ handle->is_reassoc_timer_set = MFALSE;
+ }
+ if (handle->reassoc_thread.pid)
+ wake_up_interruptible(&handle->reassoc_thread.wait_q);
+
+ /* waiting for main thread quit */
+ while (handle->reassoc_thread.pid) {
+ woal_sched_timeout(2);
+ }
+#endif /* REASSOCIATION */
+
+#ifdef CONFIG_PROC_FS
+ woal_proc_exit(handle);
+#endif
+ /* Unregister device */
+ PRINTM(MINFO, "unregister device\n");
+ woal_unregister_dev(handle);
+ /* Free adapter structure */
+ PRINTM(MINFO, "Free Adapter\n");
+ woal_free_moal_handle(handle);
+
+ for (index = 0; index < MAX_MLAN_ADAPTER; index++) {
+ if (m_handle[index] == handle) {
+ m_handle[index] = NULL;
+ break;
+ }
+ }
+ exit_remove:
+ MOAL_REL_SEMAPHORE(&AddRemoveCardSem);
+ exit_sem_err:
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function switch the drv_mode
+ *
+ * @param handle A pointer to moal_handle structure
+ * @param mode new drv_mode to switch.
+ *
+ * @return MLAN_STATUS_SUCCESS /MLAN_STATUS_FAILURE /MLAN_STATUS_PENDING
+ */
+mlan_status
+woal_switch_drv_mode(moal_handle * handle, t_u32 mode)
+{
+ unsigned int i;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+ moal_private *priv = NULL;
+
+ ENTER();
+
+ if (MOAL_ACQ_SEMAPHORE_BLOCK(&AddRemoveCardSem))
+ goto exit_sem_err;
+
+ if (woal_update_drv_tbl(handle, mode) != MLAN_STATUS_SUCCESS) {
+ PRINTM(MERROR, "Could not update driver mode table!\n");
+ status = MLAN_STATUS_FAILURE;
+ goto exit;
+ }
+
+ /* Reset all interfaces */
+ priv = woal_get_priv(handle, MLAN_BSS_ROLE_ANY);
+ woal_reset_intf(priv, MOAL_PROC_WAIT, MTRUE);
+
+ status = woal_shutdown_fw(priv, MOAL_CMD_WAIT);
+ if (status != MLAN_STATUS_SUCCESS) {
+ PRINTM(MERROR, "func shutdown failed!\n");
+ goto exit;
+ }
+
+ /* Shutdown firmware */
+ PRINTM(MIOCTL, "mlan_shutdown_fw.....\n");
+ handle->init_wait_q_woken = MFALSE;
+ status = mlan_shutdown_fw(handle->pmlan_adapter);
+ if (status == MLAN_STATUS_PENDING)
+ wait_event_interruptible(handle->init_wait_q,
+ handle->init_wait_q_woken);
+ PRINTM(MIOCTL, "mlan_shutdown_fw done!\n");
+ if (atomic_read(&handle->rx_pending) || atomic_read(&handle->tx_pending) ||
+ atomic_read(&handle->ioctl_pending)) {
+ PRINTM(MERROR, "ERR: rx_pending=%d,tx_pending=%d,ioctl_pending=%d\n",
+ atomic_read(&handle->rx_pending),
+ atomic_read(&handle->tx_pending),
+ atomic_read(&handle->ioctl_pending));
+ }
+
+ /* Remove interface */
+ for (i = 0; i < handle->priv_num; i++)
+ woal_remove_interface(handle, i);
+
+ /* Unregister mlan */
+ if (handle->pmlan_adapter) {
+ mlan_unregister(handle->pmlan_adapter);
+ if (handle->malloc_count || handle->lock_count) {
+ PRINTM(MERROR,
+ "mlan has memory leak: malloc_count=%u lock_count=%u\n",
+ handle->malloc_count, handle->lock_count);
+ }
+ handle->pmlan_adapter = NULL;
+ }
+
+ handle->priv_num = 0;
+ drv_mode = mode;
+ /* Init SW */
+ if (woal_init_sw(handle)) {
+ PRINTM(MFATAL, "Software Init Failed\n");
+ goto exit;
+ }
+ /* Init FW and HW */
+ if (woal_init_fw(handle)) {
+ PRINTM(MFATAL, "Firmware Init Failed\n");
+ goto exit;
+ }
+ LEAVE();
+ return status;
+ exit:
+ MOAL_REL_SEMAPHORE(&AddRemoveCardSem);
+ exit_sem_err:
+ LEAVE();
+ return status;
+}
+
+/**
+ * @brief This function initializes module.
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+static int
+woal_init_module(void)
+{
+ int ret = (int) MLAN_STATUS_SUCCESS;
+ int index = 0;
+
+ ENTER();
+
+ /* Init the wlan_private pointer array first */
+ for (index = 0; index < MAX_MLAN_ADAPTER; index++) {
+ m_handle[index] = NULL;
+ }
+ /* Init mutex */
+ MOAL_INIT_SEMAPHORE(&AddRemoveCardSem);
+
+ /* Register with bus */
+ ret = woal_bus_register();
+
+ wifi_add_dev();
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function cleans module
+ *
+ * @return N/A
+ */
+static void
+woal_cleanup_module(void)
+{
+ moal_handle *handle = NULL;
+ int index = 0;
+ int i;
+
+ ENTER();
+
+ if (MOAL_ACQ_SEMAPHORE_BLOCK(&AddRemoveCardSem))
+ goto exit_sem_err;
+ for (index = 0; index < MAX_MLAN_ADAPTER; index++) {
+ handle = m_handle[index];
+ if (!handle)
+ continue;
+ if (!handle->priv_num)
+ goto exit;
+#ifdef SDIO_SUSPEND_RESUME
+#ifdef MMC_PM_KEEP_POWER
+ if (handle->is_suspended == MTRUE) {
+ woal_sdio_resume(&(((struct sdio_mmc_card *) handle->card)->func)->
+ dev);
+ }
+#endif
+#endif /* SDIO_SUSPEND_RESUME */
+
+ for (i = 0; i < handle->priv_num; i++) {
+#ifdef STA_SUPPORT
+ if (GET_BSS_ROLE(handle->priv[i]) == MLAN_BSS_ROLE_STA) {
+ if (handle->priv[i]->media_connected == MTRUE)
+ woal_disconnect(handle->priv[i], MOAL_CMD_WAIT, NULL);
+#ifdef STA_CFG80211
+ if (handle->priv[i]->scan_request) {
+ cfg80211_scan_done(handle->priv[i]->scan_request, MTRUE);
+ handle->priv[i]->scan_request = NULL;
+ }
+#endif
+ }
+#endif
+#ifdef UAP_SUPPORT
+ if (GET_BSS_ROLE(handle->priv[i]) == MLAN_BSS_ROLE_UAP) {
+#ifdef MFG_CMD_SUPPORT
+ if (mfg_mode != MLAN_INIT_PARA_ENABLED)
+#endif
+ woal_disconnect(handle->priv[i], MOAL_CMD_WAIT, NULL);
+ }
+#endif
+#if defined(STA_CFG80211) || defined(UAP_CFG80211)
+ if (handle->priv[i]->probereq_index != MLAN_CUSTOM_IE_AUTO_IDX_MASK)
+ woal_cfg80211_mgmt_frame_ie(handle->priv[i], NULL, 0, NULL, 0,
+ NULL, 0, NULL, 0,
+ MGMT_MASK_PROBE_REQ);
+#endif
+ }
+
+#ifdef MFG_CMD_SUPPORT
+ if (mfg_mode != MLAN_INIT_PARA_ENABLED)
+#endif
+ woal_set_deep_sleep(woal_get_priv(handle, MLAN_BSS_ROLE_ANY),
+ MOAL_CMD_WAIT, MFALSE, 0);
+
+#ifdef MFG_CMD_SUPPORT
+ if (mfg_mode != MLAN_INIT_PARA_ENABLED)
+#endif
+ woal_shutdown_fw(woal_get_priv(handle, MLAN_BSS_ROLE_ANY),
+ MOAL_CMD_WAIT);
+ }
+
+ wifi_del_dev();
+
+ exit:
+ MOAL_REL_SEMAPHORE(&AddRemoveCardSem);
+ exit_sem_err:
+ /* Unregister from bus */
+ woal_bus_unregister();
+ LEAVE();
+}
+
+module_init(woal_init_module);
+module_exit(woal_cleanup_module);
+
+module_param(fw_name, charp, 0);
+MODULE_PARM_DESC(fw_name, "Firmware name");
+module_param(req_fw_nowait, int, 0);
+MODULE_PARM_DESC(req_fw_nowait,
+ "0: Use request_firmware API; 1: Use request_firmware_nowait API");
+module_param(mac_addr, charp, 0);
+MODULE_PARM_DESC(mac_addr, "MAC address");
+#ifdef MFG_CMD_SUPPORT
+module_param(mfg_mode, int, 0);
+MODULE_PARM_DESC(mfg_mode,
+ "0: Download normal firmware; 1: Download MFG firmware");
+#endif /* MFG_CMD_SUPPORT */
+module_param(drv_mode, int, 0);
+#if defined(WIFI_DIRECT_SUPPORT)
+MODULE_PARM_DESC(drv_mode, "Bit 0: STA; Bit 1: uAP; Bit 2: WIFIDIRECT");
+#else
+MODULE_PARM_DESC(drv_mode, "Bit 0: STA; Bit 1: uAP");
+#endif /* WIFI_DIRECT_SUPPORT && V14_FEATURE */
+#ifdef STA_SUPPORT
+module_param(max_sta_bss, int, 0);
+MODULE_PARM_DESC(max_sta_bss, "Number of STA interfaces (1)");
+#endif /* STA_SUPPORT */
+#ifdef UAP_SUPPORT
+module_param(max_uap_bss, int, 0);
+MODULE_PARM_DESC(max_uap_bss, "Number of uAP interfaces (1)");
+#endif /* UAP_SUPPORT */
+#if defined(WIFI_DIRECT_SUPPORT)
+module_param(max_wfd_bss, int, 0);
+MODULE_PARM_DESC(max_wfd_bss, "Number of WIFIDIRECT interfaces (1)");
+#endif /* WIFI_DIRECT_SUPPORT && V14_FEATURE */
+#ifdef DEBUG_LEVEL1
+module_param(drvdbg, uint, 0);
+MODULE_PARM_DESC(drvdbg, "Driver debug");
+#endif /* DEBUG_LEVEL1 */
+module_param(auto_ds, int, 0);
+MODULE_PARM_DESC(auto_ds,
+ "0: MLAN default; 1: Enable auto deep sleep; 2: Disable auto deep sleep");
+module_param(ps_mode, int, 0);
+MODULE_PARM_DESC(ps_mode,
+ "0: MLAN default; 1: Enable IEEE PS mode; 2: Disable IEEE PS mode");
+module_param(max_tx_buf, int, 0);
+MODULE_PARM_DESC(max_tx_buf, "Maximum Tx buffer size (2048/4096/8192)");
+#ifdef SDIO_SUSPEND_RESUME
+module_param(pm_keep_power, int, 1);
+MODULE_PARM_DESC(pm_keep_power, "1: PM keep power; 0: PM no power");
+#endif
+#if defined(STA_SUPPORT)
+module_param(cfg_11d, int, 0);
+MODULE_PARM_DESC(cfg_11d,
+ "0: MLAN default; 1: Enable 802.11d; 2: Disable 802.11d");
+#endif
+module_param(init_cfg, charp, 0);
+MODULE_PARM_DESC(init_cfg, "Init config file name");
+module_param(cal_data_cfg, charp, 0);
+MODULE_PARM_DESC(cal_data_cfg, "Calibration data file name");
+module_param(minicard_pwrup, int, 0);
+MODULE_PARM_DESC(minicard_pwrup,
+ "1: Driver load clears PDn/Rst, unload sets (default); 0: Don't do this.");
+module_param(cfg80211_wext, int, 0);
+MODULE_PARM_DESC(cfg80211_wext,
+#ifdef STA_WEXT
+ "Bit 0: STA WEXT; "
+#endif
+#ifdef UAP_WEXT
+ "Bit 1: UAP WEXT; "
+#endif
+#ifdef STA_CFG80211
+ "Bit 2: STA CFG80211; "
+#endif
+#ifdef UAP_CFG80211
+ "Bit 3: UAP CFG80211;"
+#endif
+ );
+MODULE_DESCRIPTION("M-WLAN Driver");
+MODULE_AUTHOR("Marvell International Ltd.");
+MODULE_VERSION(MLAN_RELEASE_VERSION);
+MODULE_LICENSE("GPL");
diff --git a/drivers/net/wireless/sd8797/mlinux/moal_main.h b/drivers/net/wireless/sd8797/mlinux/moal_main.h
new file mode 100644
index 000000000000..0a753dabe488
--- /dev/null
+++ b/drivers/net/wireless/sd8797/mlinux/moal_main.h
@@ -0,0 +1,1510 @@
+/** @file moal_main.h
+ *
+ * @brief This file contains wlan driver specific defines etc.
+ *
+ * Copyright (C) 2008-2011, Marvell International Ltd.
+ *
+ * This software file (the "File") is distributed by Marvell International
+ * Ltd. under the terms of the GNU General Public License Version 2, June 1991
+ * (the "License"). You may use, redistribute and/or modify this File in
+ * accordance with the terms and conditions of the License, a copy of which
+ * is available by writing to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
+ * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
+ *
+ * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
+ * ARE EXPRESSLY DISCLAIMED. The License provides additional details about
+ * this warranty disclaimer.
+ *
+ */
+
+/********************************************************
+Change log:
+ 10/21/2008: initial version
+********************************************************/
+
+#ifndef _MOAL_MAIN_H
+#define _MOAL_MAIN_H
+
+/* warnfix for FS redefination if any? */
+#ifdef FS
+#undef FS
+#endif
+
+/* Linux header files */
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/version.h>
+#include <linux/param.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/mm.h>
+#include <linux/types.h>
+#include <linux/sched.h>
+#include <linux/timer.h>
+#include <linux/ioport.h>
+#include <linux/pci.h>
+#include <linux/ctype.h>
+#include <linux/proc_fs.h>
+#include <linux/vmalloc.h>
+#include <linux/ptrace.h>
+#include <linux/string.h>
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,18)
+#include <linux/config.h>
+#endif
+
+/* ASM files */
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27)
+#include <linux/semaphore.h>
+#else
+#include <asm/semaphore.h>
+#endif
+#include <asm/byteorder.h>
+#include <asm/irq.h>
+#include <asm/uaccess.h>
+#include <asm/io.h>
+#include <asm/system.h>
+
+/* Net header files */
+#include <linux/netdevice.h>
+#include <linux/net.h>
+#include <linux/inet.h>
+#include <linux/ip.h>
+#include <linux/skbuff.h>
+#include <linux/if_arp.h>
+#include <linux/if_ether.h>
+#include <linux/etherdevice.h>
+#include <net/sock.h>
+#include <net/arp.h>
+#include <linux/rtnetlink.h>
+
+#include <linux/firmware.h>
+
+#include "mlan.h"
+#include "moal_shim.h"
+/* Wireless header */
+#include <linux/wireless.h>
+#if defined(STA_CFG80211) || defined(UAP_CFG80211)
+#include <net/lib80211.h>
+#include <net/cfg80211.h>
+#include <net/ieee80211_radiotap.h>
+#endif
+#if defined(STA_WEXT) || defined(UAP_WEXT)
+#include <net/iw_handler.h>
+#include "moal_wext.h"
+#endif
+#ifdef STA_WEXT
+#include "moal_priv.h"
+#endif
+
+/** Define BOOLEAN */
+typedef t_u8 BOOLEAN;
+
+/** Driver version */
+extern char driver_version[];
+
+/** Private structure for MOAL */
+typedef struct _moal_private moal_private;
+/** Handle data structure for MOAL */
+typedef struct _moal_handle moal_handle;
+
+/** Hardware status codes */
+typedef enum _MOAL_HARDWARE_STATUS
+{
+ HardwareStatusReady,
+ HardwareStatusInitializing,
+ HardwareStatusFwReady,
+ HardwareStatusReset,
+ HardwareStatusClosing,
+ HardwareStatusNotReady
+} MOAL_HARDWARE_STATUS;
+
+/** moal_wait_option */
+enum
+{
+ MOAL_NO_WAIT,
+ MOAL_IOCTL_WAIT,
+ MOAL_CMD_WAIT,
+ MOAL_PROC_WAIT,
+ MOAL_WSTATS_WAIT
+};
+
+/** moal_main_state */
+enum
+{
+ MOAL_STATE_IDLE,
+ MOAL_RECV_INT,
+ MOAL_ENTER_WORK_QUEUE,
+ MOAL_START_MAIN_PROCESS,
+ MOAL_END_MAIN_PROCESS
+};
+
+/** HostCmd_Header */
+typedef struct _HostCmd_Header
+{
+ /** Command */
+ t_u16 command;
+ /** Size */
+ t_u16 size;
+} HostCmd_Header;
+
+#ifndef MIN
+/** Find minimum */
+#define MIN(a,b) ((a) < (b) ? (a) : (b))
+#endif
+
+/*
+ * OS timer specific
+ */
+
+/** Timer structure */
+typedef struct _moal_drv_timer
+{
+ /** Timer list */
+ struct timer_list tl;
+ /** Timer function */
+ void (*timer_function) (void *context);
+ /** Timer function context */
+ void *function_context;
+ /** Time period */
+ t_u32 time_period;
+ /** Is timer periodic ? */
+ t_u32 timer_is_periodic;
+ /** Is timer cancelled ? */
+ t_u32 timer_is_canceled;
+} moal_drv_timer, *pmoal_drv_timer;
+
+/**
+ * @brief Timer handler
+ *
+ * @param fcontext Timer context
+ *
+ * @return N/A
+ */
+static inline void
+woal_timer_handler(unsigned long fcontext)
+{
+ pmoal_drv_timer timer = (pmoal_drv_timer) fcontext;
+
+ timer->timer_function(timer->function_context);
+
+ if (timer->timer_is_periodic == MTRUE) {
+ mod_timer(&timer->tl, jiffies + ((timer->time_period * HZ) / 1000));
+ } else {
+ timer->timer_is_canceled = MTRUE;
+ timer->time_period = 0;
+ }
+}
+
+/**
+ * @brief Initialize timer
+ *
+ * @param timer Timer structure
+ * @param TimerFunction Timer function
+ * @param FunctionContext Timer function context
+ *
+ * @return N/A
+ */
+static inline void
+woal_initialize_timer(pmoal_drv_timer timer,
+ void (*TimerFunction) (void *context),
+ void *FunctionContext)
+{
+ /* First, setup the timer to trigger the wlan_timer_handler proxy */
+ init_timer(&timer->tl);
+ timer->tl.function = woal_timer_handler;
+ timer->tl.data = (t_ptr) timer;
+
+ /* Then tell the proxy which function to call and what to pass it */
+ timer->timer_function = TimerFunction;
+ timer->function_context = FunctionContext;
+ timer->timer_is_canceled = MTRUE;
+ timer->time_period = 0;
+ timer->timer_is_periodic = MFALSE;
+}
+
+/**
+ * @brief Modify timer
+ *
+ * @param timer Timer structure
+ * @param MillisecondPeriod Time period in millisecond
+ *
+ * @return N/A
+ */
+static inline void
+woal_mod_timer(pmoal_drv_timer timer, t_u32 MillisecondPeriod)
+{
+ timer->time_period = MillisecondPeriod;
+ mod_timer(&timer->tl, jiffies + (MillisecondPeriod * HZ) / 1000);
+ timer->timer_is_canceled = MFALSE;
+}
+
+/**
+ * @brief Cancel timer
+ *
+ * @param timer Timer structure
+ *
+ * @return N/A
+ */
+static inline void
+woal_cancel_timer(moal_drv_timer * timer)
+{
+ del_timer(&timer->tl);
+ timer->timer_is_canceled = MTRUE;
+ timer->time_period = 0;
+}
+
+#ifdef REASSOCIATION
+/*
+ * OS Thread Specific
+ */
+
+#include <linux/kthread.h>
+
+/** Kernel thread structure */
+typedef struct _moal_thread
+{
+ /** Task control structrue */
+ struct task_struct *task;
+ /** Pointer to wait_queue_head */
+ wait_queue_head_t wait_q;
+ /** PID */
+ pid_t pid;
+ /** Pointer to moal_handle */
+ void *handle;
+} moal_thread;
+
+/**
+ * @brief Activate thread
+ *
+ * @param thr Thread structure
+ * @return N/A
+ */
+static inline void
+woal_activate_thread(moal_thread * thr)
+{
+ /** Initialize the wait queue */
+ init_waitqueue_head(&thr->wait_q);
+
+ /** Record the thread pid */
+ thr->pid = current->pid;
+}
+
+/**
+ * @brief De-activate thread
+ *
+ * @param thr Thread structure
+ * @return N/A
+ */
+static inline void
+woal_deactivate_thread(moal_thread * thr)
+{
+ /* Reset the pid */
+ thr->pid = 0;
+}
+
+/**
+ * @brief Create and run the thread
+ *
+ * @param threadfunc Thread function
+ * @param thr Thread structure
+ * @param name Thread name
+ * @return N/A
+ */
+static inline void
+woal_create_thread(int (*threadfunc) (void *), moal_thread * thr, char *name)
+{
+ /* Create and run the thread */
+ thr->task = kthread_run(threadfunc, thr, "%s", name);
+}
+#endif /* REASSOCIATION */
+
+/* The following macros are neccessary to retain compatibility
+ * around the workqueue chenges happened in kernels >= 2.6.20:
+ * - INIT_WORK changed to take 2 arguments and let the work function
+ * get its own data through the container_of macro
+ * - delayed works have been split from normal works to save some
+ * memory usage in struct work_struct
+ */
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20)
+/** Work_queue work initialization */
+#define MLAN_INIT_WORK(_work, _fun) INIT_WORK(_work, ((void (*)(void *))_fun), _work)
+/** Work_queue delayed work initialization */
+#define MLAN_INIT_DELAYED_WORK(_work, _fun) INIT_WORK(_work, ((void (*)(void *))_fun), _work)
+/** Work_queue container parameter */
+#define MLAN_DELAYED_CONTAINER_OF(_ptr, _type, _m) container_of(_ptr, _type, _m)
+#else /* LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20) */
+/** Work_queue work initialization */
+#define MLAN_INIT_WORK INIT_WORK
+/** Work_queue delayed work initialization */
+#define MLAN_INIT_DELAYED_WORK INIT_DELAYED_WORK
+/** Work_queue container parameter */
+#define MLAN_DELAYED_CONTAINER_OF(_ptr, _type, _m) container_of(_ptr, _type, _m.work)
+#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20) */
+
+/**
+ * @brief Schedule timeout
+ *
+ * @param millisec Timeout duration in milli second
+ *
+ * @return N/A
+ */
+static inline void
+woal_sched_timeout(t_u32 millisec)
+{
+ set_current_state(TASK_INTERRUPTIBLE);
+
+ schedule_timeout((millisec * HZ) / 1000);
+}
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19)
+#define IN6PTON_XDIGIT 0x00010000
+#define IN6PTON_DIGIT 0x00020000
+#define IN6PTON_COLON_MASK 0x00700000
+#define IN6PTON_COLON_1 0x00100000 /* single : requested */
+#define IN6PTON_COLON_2 0x00200000 /* second : requested */
+#define IN6PTON_COLON_1_2 0x00400000 /* :: requested */
+#define IN6PTON_DOT 0x00800000 /* . */
+#define IN6PTON_DELIM 0x10000000
+#define IN6PTON_NULL 0x20000000 /* first/tail */
+#define IN6PTON_UNKNOWN 0x40000000
+
+static inline int
+xdigit2bin(char c, int delim)
+{
+ if (c == delim || c == '\0')
+ return IN6PTON_DELIM;
+ if (c == ':')
+ return IN6PTON_COLON_MASK;
+ if (c == '.')
+ return IN6PTON_DOT;
+ if (c >= '0' && c <= '9')
+ return (IN6PTON_XDIGIT | IN6PTON_DIGIT | (c - '0'));
+ if (c >= 'a' && c <= 'f')
+ return (IN6PTON_XDIGIT | (c - 'a' + 10));
+ if (c >= 'A' && c <= 'F')
+ return (IN6PTON_XDIGIT | (c - 'A' + 10));
+ if (delim == -1)
+ return IN6PTON_DELIM;
+ return IN6PTON_UNKNOWN;
+}
+
+static inline int
+in4_pton(const char *src, int srclen, u8 * dst, int delim, const char **end)
+{
+ const char *s;
+ u8 *d;
+ u8 dbuf[4];
+ int ret = 0;
+ int i;
+ int w = 0;
+
+ if (srclen < 0)
+ srclen = strlen(src);
+ s = src;
+ d = dbuf;
+ i = 0;
+ while (1) {
+ int c;
+ c = xdigit2bin(srclen > 0 ? *s : '\0', delim);
+ if (!
+ (c &
+ (IN6PTON_DIGIT | IN6PTON_DOT | IN6PTON_DELIM |
+ IN6PTON_COLON_MASK))) {
+ goto out;
+ }
+ if (c & (IN6PTON_DOT | IN6PTON_DELIM | IN6PTON_COLON_MASK)) {
+ if (w == 0)
+ goto out;
+ *d++ = w & 0xff;
+ w = 0;
+ i++;
+ if (c & (IN6PTON_DELIM | IN6PTON_COLON_MASK)) {
+ if (i != 4)
+ goto out;
+ break;
+ }
+ goto cont;
+ }
+ w = (w * 10) + c;
+ if ((w & 0xffff) > 255) {
+ goto out;
+ }
+ cont:
+ if (i >= 4)
+ goto out;
+ s++;
+ srclen--;
+ }
+ ret = 1;
+ memcpy(dst, dbuf, sizeof(dbuf));
+ out:
+ if (end)
+ *end = s;
+ return ret;
+}
+#endif /* < 2.6.19 */
+
+#ifndef __ATTRIB_ALIGN__
+#define __ATTRIB_ALIGN__ __attribute__((aligned(4)))
+#endif
+
+#ifndef __ATTRIB_PACK__
+#define __ATTRIB_PACK__ __attribute__ ((packed))
+#endif
+
+/** Get module */
+#define MODULE_GET try_module_get(THIS_MODULE)
+/** Put module */
+#define MODULE_PUT module_put(THIS_MODULE)
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,37)
+/** Initialize semaphore */
+#define MOAL_INIT_SEMAPHORE(x) init_MUTEX(x)
+/** Initialize semaphore */
+#define MOAL_INIT_SEMAPHORE_LOCKED(x) init_MUTEX_LOCKED(x)
+#else
+/** Initialize semaphore */
+#define MOAL_INIT_SEMAPHORE(x) sema_init(x,1)
+/** Initialize semaphore */
+#define MOAL_INIT_SEMAPHORE_LOCKED(x) sema_init(x,0)
+#endif
+
+/** Acquire semaphore and with blocking */
+#define MOAL_ACQ_SEMAPHORE_BLOCK(x) down_interruptible(x)
+/** Acquire semaphore without blocking */
+#define MOAL_ACQ_SEMAPHORE_NOBLOCK(x) down_trylock(x)
+/** Release semaphore */
+#define MOAL_REL_SEMAPHORE(x) up(x)
+
+/** Request FW timeout in second */
+#define REQUEST_FW_TIMEOUT 30
+
+/** Default watchdog timeout */
+#define MRVDRV_DEFAULT_WATCHDOG_TIMEOUT (5 * HZ)
+
+#ifdef UAP_SUPPORT
+/** Default watchdog timeout
+ Increase the value to avoid kernel Tx timeout message in case
+ station in PS mode or left.
+ The default value of PS station ageout timer is 40 seconds.
+ Hence, the watchdog timer is set to a value higher than it.
+*/
+#define MRVDRV_DEFAULT_UAP_WATCHDOG_TIMEOUT (41 * HZ)
+#endif
+
+/** Threshold value of number of times the Tx timeout happened */
+#define NUM_TX_TIMEOUT_THRESHOLD 5
+
+/** 10 seconds */
+#define MOAL_TIMER_10S 10000
+/** 5 seconds */
+#define MOAL_TIMER_5S 5000
+/** 1 second */
+#define MOAL_TIMER_1S 1000
+
+/** Default value of re-assoc timer */
+#define REASSOC_TIMER_DEFAULT 500
+
+/** Netlink protocol number */
+#define NETLINK_MARVELL (MAX_LINKS - 1)
+/** Netlink maximum payload size */
+#define NL_MAX_PAYLOAD 1024
+/** Netlink multicast group number */
+#define NL_MULTICAST_GROUP 1
+
+/** MAX Tx Pending count */
+#define MAX_TX_PENDING 100
+
+/** LOW Tx Pending count */
+#define LOW_TX_PENDING 80
+
+/** Offset for subcommand */
+#define SUBCMD_OFFSET 4
+
+/** Macro to extract the TOS field from a skb */
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22)
+#define SKB_TOS(skb) (ip_hdr(skb)->tos)
+#else
+#define SKB_TOS(skb) (skb->nh.iph->tos)
+#endif
+
+/** Offset for TOS field in the IP header */
+#define IPTOS_OFFSET 5
+
+/** Offset for DSCP in the tos field */
+#define DSCP_OFFSET 2
+
+/** wait_queue structure */
+typedef struct _wait_queue
+{
+ /** Pointer to wait_queue_head */
+ wait_queue_head_t *wait;
+ /** Wait condition */
+ BOOLEAN condition;
+ /** Start time */
+ t_u32 start_time;
+ /** Status from MLAN */
+ mlan_status status;
+} wait_queue, *pwait_queue;
+
+/** Auto Rate */
+#define AUTO_RATE 0xFF
+
+#define STA_WEXT_MASK MBIT(0)
+#define UAP_WEXT_MASK MBIT(1)
+#define STA_CFG80211_MASK MBIT(2)
+#define UAP_CFG80211_MASK MBIT(3)
+#ifdef STA_CFG80211
+#ifdef STA_SUPPORT
+/** Is STA CFG80211 enabled in module param */
+#define IS_STA_CFG80211(x) (x & STA_CFG80211_MASK)
+#endif
+#endif
+#ifdef UAP_CFG80211
+#ifdef UAP_SUPPORT
+/** Is UAP CFG80211 enabled in module param */
+#define IS_UAP_CFG80211(x) (x & UAP_CFG80211_MASK)
+#endif
+#endif
+#if defined(STA_CFG80211) || defined(UAP_CFG80211)
+/** Is UAP or STA CFG80211 enabled in module param */
+#define IS_STA_OR_UAP_CFG80211(x) (x & (STA_CFG80211_MASK | UAP_CFG80211_MASK))
+#endif
+
+#ifdef STA_WEXT
+/** Is STA WEXT enabled in module param */
+#define IS_STA_WEXT(x) (x & STA_WEXT_MASK)
+#endif /* STA_WEXT */
+#ifdef UAP_WEXT
+/** Is UAP WEXT enabled in module param */
+#define IS_UAP_WEXT(x) (x & UAP_WEXT_MASK)
+#endif /* UAP_WEXT */
+#if defined(STA_WEXT) || defined(UAP_WEXT)
+/** Is UAP or STA WEXT enabled in module param */
+#define IS_STA_OR_UAP_WEXT(x) (x & (STA_WEXT_MASK | UAP_WEXT_MASK))
+#endif
+
+#ifdef STA_SUPPORT
+/** Driver mode STA bit */
+#define DRV_MODE_STA MBIT(0)
+/** Maximum STA BSS */
+#define MAX_STA_BSS 1
+/** Default STA BSS */
+#define DEF_STA_BSS 1
+#endif
+#ifdef UAP_SUPPORT
+/** Driver mode uAP bit */
+#define DRV_MODE_UAP MBIT(1)
+/** Maximum uAP BSS */
+#define MAX_UAP_BSS 2
+/** Default uAP BSS */
+#define DEF_UAP_BSS 1
+#endif
+#if defined(WIFI_DIRECT_SUPPORT)
+/** Driver mode WIFIDIRECT bit */
+#define DRV_MODE_WIFIDIRECT MBIT(2)
+/** Maximum WIFIDIRECT BSS */
+#define MAX_WIFIDIRECT_BSS 1
+/** Default WIFIDIRECT BSS */
+#define DEF_WIFIDIRECT_BSS 1
+#endif /* WIFI_DIRECT_SUPPORT && V14_FEATURE */
+
+typedef struct _moal_drv_mode
+{
+ /** driver mode */
+ t_u16 drv_mode;
+ /** total number of interfaces */
+ t_u16 intf_num;
+ /** attribute of bss */
+ mlan_bss_attr *bss_attr;
+ /** name of firmware image */
+ char *fw_name;
+} moal_drv_mode;
+
+#ifdef PROC_DEBUG
+/** Debug data */
+struct debug_data
+{
+ /** Name */
+ char name[32];
+ /** Size */
+ t_u32 size;
+ /** Address */
+ t_ptr addr;
+};
+
+/** Private debug data */
+struct debug_data_priv
+{
+ /** moal_private handle */
+ moal_private *priv;
+ /** Debug items */
+ struct debug_data *items;
+ /** numbre of item */
+ int num_of_items;
+};
+#endif
+
+/** Maximum IP address buffer length */
+#define IPADDR_MAX_BUF 20
+/** IP address operation: Remove */
+#define IPADDR_OP_REMOVE 0
+
+/** Private structure for MOAL */
+struct _moal_private
+{
+ /** Handle structure */
+ moal_handle *phandle;
+ /** Tx timeout count */
+ t_u32 num_tx_timeout;
+ /** BSS index */
+ t_u8 bss_index;
+ /** BSS type */
+ t_u8 bss_type;
+ /** BSS role */
+ t_u8 bss_role;
+ /** MAC address information */
+ t_u8 current_addr[ETH_ALEN];
+ /** Media connection status */
+ BOOLEAN media_connected;
+#ifdef UAP_SUPPORT
+ /** uAP started or not */
+ BOOLEAN bss_started;
+#endif
+#ifdef STA_SUPPORT
+ /** scan type */
+ t_u8 scan_type;
+ /** bg_scan_start */
+ t_u8 bg_scan_start;
+ /** bg_scan reported */
+ t_u8 bg_scan_reported;
+ /** bg_scan config */
+ wlan_bgscan_cfg scan_cfg;
+#endif
+ /** Net device pointer */
+ struct net_device *netdev;
+ /** Net device statistics structure */
+ struct net_device_stats stats;
+#if defined(STA_CFG80211) || defined(UAP_CFG80211)
+ /** Country code for regulatory domain */
+ t_u8 country_code[COUNTRY_CODE_LEN];
+ /** Wireless device pointer */
+ struct wireless_dev *wdev;
+ /** channel parameter for UAP/GO */
+ t_u16 channel;
+ /** cipher */
+ t_u32 cipher;
+ /** key index */
+ t_u8 key_index;
+ /** key len */
+ t_u16 key_len;
+ /** key data */
+ t_u8 key_material[MLAN_MAX_KEY_LENGTH];
+ /** probereq index for mgmt ie */
+ t_u16 probereq_index;
+#endif
+#ifdef STA_CFG80211
+#ifdef STA_SUPPORT
+ /** CFG80211 scan request description */
+ struct cfg80211_scan_request *scan_request;
+ /** CFG80211 association description */
+ t_u8 cfg_bssid[ETH_ALEN];
+ /** Disconnect request from CFG80211 */
+ bool cfg_disconnect;
+#endif /* STA_SUPPORT */
+#endif /* STA_CFG80211 */
+ /** IOCTL wait queue */
+ wait_queue_head_t ioctl_wait_q __ATTRIB_ALIGN__;
+ /** CMD wait queue */
+ wait_queue_head_t cmd_wait_q __ATTRIB_ALIGN__;
+#ifdef CONFIG_PROC_FS
+ /** Proc entry */
+ struct proc_dir_entry *proc_entry;
+ /** Proc entry name */
+ t_s8 proc_entry_name[IFNAMSIZ];
+ /** PROC wait queue */
+ wait_queue_head_t proc_wait_q __ATTRIB_ALIGN__;
+#endif /* CONFIG_PROC_FS */
+#ifdef STA_SUPPORT
+ /** Nickname */
+ t_u8 nick_name[16];
+ /** AdHoc link sensed flag */
+ BOOLEAN is_adhoc_link_sensed;
+ /** Current WEP key index */
+ t_u16 current_key_index;
+#ifdef REASSOCIATION
+ mlan_ssid_bssid prev_ssid_bssid;
+ /** Re-association required */
+ BOOLEAN reassoc_required;
+ /** Flag of re-association on/off */
+ BOOLEAN reassoc_on;
+#endif /* REASSOCIATION */
+ /** Report scan result */
+ t_u8 report_scan_result;
+ /** wpa_version */
+ t_u8 wpa_version;
+ /** key mgmt */
+ t_u8 key_mgmt;
+ /** rx_filter */
+ t_u8 rx_filter;
+#endif /* STA_SUPPORT */
+ /** Rate index */
+ t_u16 rate_index;
+#if defined(STA_WEXT) || defined(UAP_WEXT)
+ /** IW statistics */
+ struct iw_statistics w_stats;
+ /** w_stats wait queue */
+ wait_queue_head_t w_stats_wait_q __ATTRIB_ALIGN__;
+#endif
+#ifdef UAP_WEXT
+ /** Pairwise Cipher used for WPA/WPA2 mode */
+ t_u16 pairwise_cipher;
+ /** Group Cipher */
+ t_u16 group_cipher;
+ /** Protocol stored during uap wext configuratoin */
+ t_u16 uap_protocol;
+ /** Key Mgmt whether PSK or 1x */
+ t_u16 uap_key_mgmt;
+ /** Beacon IE length from hostapd */
+ t_u16 bcn_ie_len;
+ /** Beacon IE buffer from hostapd */
+ t_u8 bcn_ie_buf[MAX_IE_SIZE];
+#endif
+
+#ifdef PROC_DEBUG
+ /** MLAN debug info */
+ struct debug_data_priv items_priv;
+#endif
+};
+
+/** Handle data structure for MOAL */
+struct _moal_handle
+{
+ /** MLAN adapter structure */
+ t_void *pmlan_adapter;
+ /** Private pointer */
+ moal_private *priv[MLAN_MAX_BSS_NUM];
+ /** Priv number */
+ t_u8 priv_num;
+ /** Bss attr */
+ moal_drv_mode drv_mode;
+ /** set mac address flag */
+ t_u8 set_mac_addr;
+ /** MAC address */
+ t_u8 mac_addr[ETH_ALEN];
+#ifdef CONFIG_PROC_FS
+ /** Proc top level directory entry */
+ struct proc_dir_entry *proc_mwlan;
+#endif
+ /** Firmware */
+ const struct firmware *firmware;
+ /** Firmware request start time */
+ struct timeval req_fw_time;
+ /** Init config file */
+ const struct firmware *user_data;
+ /** Hotplug device */
+ struct device *hotplug_device;
+ /** STATUS variables */
+ MOAL_HARDWARE_STATUS hardware_status;
+ /** POWER MANAGEMENT AND PnP SUPPORT */
+ BOOLEAN surprise_removed;
+ /** Firmware release number */
+ t_u32 fw_release_number;
+ /** Init wait queue token */
+ t_u16 init_wait_q_woken;
+ /** Init wait queue */
+ wait_queue_head_t init_wait_q __ATTRIB_ALIGN__;
+ /** Device suspend flag */
+ BOOLEAN is_suspended;
+#ifdef SDIO_SUSPEND_RESUME
+ /** suspend notify flag */
+ BOOLEAN suspend_notify_req;
+#endif
+ /** Host Sleep activated flag */
+ t_u8 hs_activated;
+ /** Host Sleep activated event wait queue token */
+ t_u16 hs_activate_wait_q_woken;
+ /** Host Sleep activated event wait queue */
+ wait_queue_head_t hs_activate_wait_q __ATTRIB_ALIGN__;
+ /** Card pointer */
+ t_void *card;
+ /** Rx pending in MLAN */
+ atomic_t rx_pending;
+ /** Tx packet pending count in mlan */
+ atomic_t tx_pending;
+ /** IOCTL pending count in mlan */
+ atomic_t ioctl_pending;
+ /** Malloc count */
+ t_u32 malloc_count;
+ /** lock count */
+ t_u32 lock_count;
+ /** mlan buffer alloc count */
+ t_u32 mbufalloc_count;
+ /** hs skip count */
+ t_u32 hs_skip_count;
+ /** hs force count */
+ t_u32 hs_force_count;
+ /** suspend_fail flag */
+ BOOLEAN suspend_fail;
+#ifdef REASSOCIATION
+ /** Re-association thread */
+ moal_thread reassoc_thread;
+ /** Re-association timer set flag */
+ BOOLEAN is_reassoc_timer_set;
+ /** Re-association timer */
+ moal_drv_timer reassoc_timer __ATTRIB_ALIGN__;
+ /** */
+ struct semaphore reassoc_sem;
+ /** Bitmap for re-association on/off */
+ t_u8 reassoc_on;
+#endif /* REASSOCIATION */
+ /** Driver workqueue */
+ struct workqueue_struct *workqueue;
+ /** main work */
+ struct work_struct main_work;
+#if defined(STA_CFG80211) || defined(UAP_CFG80211)
+#ifdef WIFI_DIRECT_SUPPORT
+ /** remain on channel flag */
+ t_u8 remain_on_channel;
+ /** ieee802_11_channel */
+ struct ieee80211_channel chan;
+ /** channel type */
+ enum nl80211_channel_type channel_type;
+ /** cookie */
+ t_u64 cookie;
+#endif
+#endif
+ /** Read SDIO registers for debugging */
+ t_u32 sdio_reg_dbg;
+ /** Netlink kernel socket */
+ struct sock *nl_sk;
+ /** Netlink kernel socket number */
+ t_u32 netlink_num;
+ /** w_stats wait queue token */
+ BOOLEAN meas_wait_q_woken;
+ /** w_stats wait queue */
+ wait_queue_head_t meas_wait_q __ATTRIB_ALIGN__;
+ /** Measurement start jiffes */
+ t_u32 meas_start_jiffies;
+ /** CAC checking period flag */
+ BOOLEAN cac_period;
+ /** BSS START command delay executing flag */
+ BOOLEAN delay_bss_start;
+ /** SSID,BSSID parameter of delay executing */
+ mlan_ssid_bssid delay_ssid_bssid;
+#ifdef DFS_TESTING_SUPPORT
+ /** cac period length, valid only when dfs testing is enabled */
+ t_u32 cac_period_jiffies;
+#endif
+ /** handle index - for multiple card supports */
+ t_u8 handle_idx;
+#ifdef SDIO_MMC_DEBUG
+ /** cmd53 write state */
+ u8 cmd53w;
+ /** cmd53 read state */
+ u8 cmd53r;
+#endif
+#ifdef STA_SUPPORT
+ /** Scan pending on blocked flag */
+ t_u8 scan_pending_on_block;
+ /** Async scan semaphore */
+ struct semaphore async_sem;
+
+#endif
+ /** main state */
+ t_u8 main_state;
+ /** cmd52 function */
+ t_u8 cmd52_func;
+ /** cmd52 register */
+ t_u8 cmd52_reg;
+ /** cmd52 value */
+ t_u8 cmd52_val;
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,34)
+ /** spinlock to stop_queue/wake_queue*/
+ spinlock_t queue_lock;
+#endif
+};
+
+/**
+ * @brief set trans_start for each TX queue.
+ *
+ * @param dev A pointer to net_device structure
+ *
+ * @return N/A
+ */
+static inline void
+woal_set_trans_start(struct net_device *dev)
+{
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,34)
+ unsigned int i;
+ for (i = 0; i < dev->num_tx_queues; i++) {
+ netdev_get_tx_queue(dev, i)->trans_start = jiffies;
+ }
+#endif
+ dev->trans_start = jiffies;
+}
+
+/**
+ * @brief Start queue
+ *
+ * @param dev A pointer to net_device structure
+ *
+ * @return N/A
+ */
+static inline void
+woal_start_queue(struct net_device *dev)
+{
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,34)
+ netif_start_queue(dev);
+#else
+ netif_tx_start_all_queues(dev);
+#endif
+}
+
+/**
+ * @brief Stop queue
+ *
+ * @param dev A pointer to net_device structure
+ *
+ * @return N/A
+ */
+static inline void
+woal_stop_queue(struct net_device *dev)
+{
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,34)
+ unsigned long flags;
+ moal_private *priv = (moal_private *) netdev_priv(dev);
+ spin_lock_irqsave(&priv->phandle->queue_lock, flags);
+ woal_set_trans_start(dev);
+ if (!netif_queue_stopped(dev))
+ netif_tx_stop_all_queues(dev);
+ spin_unlock_irqrestore(&priv->phandle->queue_lock, flags);
+#else
+ woal_set_trans_start(dev);
+ if (!netif_queue_stopped(dev))
+ netif_stop_queue(dev);
+#endif
+}
+
+/**
+ * @brief wake queue
+ *
+ * @param dev A pointer to net_device structure
+ *
+ * @return N/A
+ */
+static inline void
+woal_wake_queue(struct net_device *dev)
+{
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,34)
+ unsigned long flags;
+ moal_private *priv = (moal_private *) netdev_priv(dev);
+ spin_lock_irqsave(&priv->phandle->queue_lock, flags);
+ if (netif_queue_stopped(dev))
+ netif_tx_wake_all_queues(dev);
+ spin_unlock_irqrestore(&priv->phandle->queue_lock, flags);
+#else
+ if (netif_queue_stopped(dev))
+ netif_wake_queue(dev);
+#endif
+}
+
+/** Max number of char in custom event - use multiple of them if needed */
+#define IW_CUSTOM_MAX 256 /* In bytes */
+
+/** Debug Macro definition*/
+#ifdef DEBUG_LEVEL1
+extern t_u32 drvdbg;
+
+#ifdef DEBUG_LEVEL2
+#define PRINTM_MINFO(msg...) do {if (drvdbg & MINFO) printk(KERN_DEBUG msg);} while(0)
+#define PRINTM_MWARN(msg...) do {if (drvdbg & MWARN) printk(KERN_DEBUG msg);} while(0)
+#define PRINTM_MENTRY(msg...) do {if (drvdbg & MENTRY) printk(KERN_DEBUG msg);} while(0)
+#else
+#define PRINTM_MINFO(msg...) do {} while (0)
+#define PRINTM_MWARN(msg...) do {} while (0)
+#define PRINTM_MENTRY(msg...) do {} while (0)
+#endif /* DEBUG_LEVEL2 */
+
+#define PRINTM_MFW_D(msg...) do {if (drvdbg & MFW_D) printk(KERN_DEBUG msg);} while(0)
+#define PRINTM_MCMD_D(msg...) do {if (drvdbg & MCMD_D) printk(KERN_DEBUG msg);} while(0)
+#define PRINTM_MDAT_D(msg...) do {if (drvdbg & MDAT_D) printk(KERN_DEBUG msg);} while(0)
+#define PRINTM_MIF_D(msg...) do {if (drvdbg & MIF_D) printk(KERN_DEBUG msg);} while(0)
+
+#define PRINTM_MIOCTL(msg...) do {if (drvdbg & MIOCTL) printk(KERN_DEBUG msg);} while(0)
+#define PRINTM_MINTR(msg...) do {if (drvdbg & MINTR) printk(KERN_DEBUG msg);} while(0)
+#define PRINTM_MEVENT(msg...) do {if (drvdbg & MEVENT) printk(msg);} while(0)
+#define PRINTM_MCMND(msg...) do {if (drvdbg & MCMND) printk(KERN_DEBUG msg);} while(0)
+#define PRINTM_MDATA(msg...) do {if (drvdbg & MDATA) printk(KERN_DEBUG msg);} while(0)
+#define PRINTM_MERROR(msg...) do {if (drvdbg & MERROR) printk(KERN_ERR msg);} while(0)
+#define PRINTM_MFATAL(msg...) do {if (drvdbg & MFATAL) printk(KERN_ERR msg);} while(0)
+#define PRINTM_MMSG(msg...) do {if (drvdbg & MMSG) printk(KERN_ALERT msg);} while(0)
+
+#define PRINTM(level,msg...) PRINTM_##level(msg)
+
+#else
+
+#define PRINTM(level,msg...) do {} while (0)
+
+#endif /* DEBUG_LEVEL1 */
+
+/** Wait until a condition becomes true */
+#define MASSERT(cond) \
+do { \
+ if (!(cond)) { \
+ PRINTM(MFATAL, "ASSERT: %s: %i\n", __FUNCTION__, __LINE__); \
+ panic("Assert failed: Panic!"); \
+ } \
+} while(0)
+
+/** Log entry point for debugging */
+#define ENTER() PRINTM(MENTRY, "Enter: %s\n", \
+ __FUNCTION__)
+/** Log exit point for debugging */
+#define LEAVE() PRINTM(MENTRY, "Leave: %s\n", \
+ __FUNCTION__)
+
+#ifdef DEBUG_LEVEL1
+#define DBG_DUMP_BUF_LEN 64
+#define MAX_DUMP_PER_LINE 16
+
+static inline void
+hexdump(char *prompt, t_u8 * buf, int len)
+{
+ int i;
+ char dbgdumpbuf[DBG_DUMP_BUF_LEN];
+ char *ptr = dbgdumpbuf;
+
+ printk(KERN_DEBUG "%s:\n", prompt);
+ for (i = 1; i <= len; i++) {
+ ptr += snprintf(ptr, 4, "%02x ", *buf);
+ buf++;
+ if (i % MAX_DUMP_PER_LINE == 0) {
+ *ptr = 0;
+ printk(KERN_DEBUG "%s\n", dbgdumpbuf);
+ ptr = dbgdumpbuf;
+ }
+ }
+ if (len % MAX_DUMP_PER_LINE) {
+ *ptr = 0;
+ printk(KERN_DEBUG "%s\n", dbgdumpbuf);
+ }
+}
+
+#define DBG_HEXDUMP_MERROR(x,y,z) do {if (drvdbg & MERROR) hexdump(x,y,z);} while(0)
+#define DBG_HEXDUMP_MCMD_D(x,y,z) do {if (drvdbg & MCMD_D) hexdump(x,y,z);} while(0)
+#define DBG_HEXDUMP_MDAT_D(x,y,z) do {if (drvdbg & MDAT_D) hexdump(x,y,z);} while(0)
+#define DBG_HEXDUMP_MIF_D(x,y,z) do {if (drvdbg & MIF_D) hexdump(x,y,z);} while(0)
+#define DBG_HEXDUMP_MEVT_D(x,y,z) do {if (drvdbg & MEVT_D) hexdump(x,y,z);} while(0)
+#define DBG_HEXDUMP_MFW_D(x,y,z) do {if (drvdbg & MFW_D) hexdump(x,y,z);} while(0)
+#define DBG_HEXDUMP(level,x,y,z) DBG_HEXDUMP_##level(x,y,z)
+
+#else
+/** Do nothing since debugging is not turned on */
+#define DBG_HEXDUMP(level,x,y,z) do {} while (0)
+#endif
+
+#ifdef DEBUG_LEVEL2
+#define HEXDUMP(x,y,z) do {if (drvdbg & MINFO) hexdump(x,y,z);} while(0)
+#else
+/** Do nothing since debugging is not turned on */
+#define HEXDUMP(x,y,z) do {} while (0)
+#endif
+
+#ifdef BIG_ENDIAN_SUPPORT
+/** Convert from 16 bit little endian format to CPU format */
+#define woal_le16_to_cpu(x) le16_to_cpu(x)
+/** Convert from 32 bit little endian format to CPU format */
+#define woal_le32_to_cpu(x) le32_to_cpu(x)
+/** Convert from 64 bit little endian format to CPU format */
+#define woal_le64_to_cpu(x) le64_to_cpu(x)
+/** Convert to 16 bit little endian format from CPU format */
+#define woal_cpu_to_le16(x) cpu_to_le16(x)
+/** Convert to 32 bit little endian format from CPU format */
+#define woal_cpu_to_le32(x) cpu_to_le32(x)
+/** Convert to 64 bit little endian format from CPU format */
+#define woal_cpu_to_le64(x) cpu_to_le64(x)
+#else
+/** Do nothing */
+#define woal_le16_to_cpu(x) x
+/** Do nothing */
+#define woal_le32_to_cpu(x) x
+/** Do nothing */
+#define woal_le64_to_cpu(x) x
+/** Do nothing */
+#define woal_cpu_to_le16(x) x
+/** Do nothing */
+#define woal_cpu_to_le32(x) x
+/** Do nothing */
+#define woal_cpu_to_le64(x) x
+#endif
+
+/**
+ * @brief This function returns first available priv
+ * based on the BSS role
+ *
+ * @param handle A pointer to moal_handle
+ * @param bss_role BSS role or MLAN_BSS_ROLE_ANY
+ *
+ * @return Pointer to moal_private
+ */
+static inline moal_private *
+woal_get_priv(moal_handle * handle, mlan_bss_role bss_role)
+{
+ int i;
+
+ for (i = 0; i < MIN(handle->priv_num, MLAN_MAX_BSS_NUM); i++) {
+ if (handle->priv[i]) {
+ if (bss_role == MLAN_BSS_ROLE_ANY ||
+ GET_BSS_ROLE(handle->priv[i]) == bss_role)
+ return (handle->priv[i]);
+ }
+ }
+ return NULL;
+}
+
+/** Max line length allowed in init config file */
+#define MAX_LINE_LEN 256
+/** Max MAC address string length allowed */
+#define MAX_MAC_ADDR_LEN 18
+/** Max register type/offset/value etc. parameter length allowed */
+#define MAX_PARAM_LEN 12
+
+/** HostCmd_CMD_CFG_DATA for CAL data */
+#define HostCmd_CMD_CFG_DATA 0x008f
+/** HostCmd action set */
+#define HostCmd_ACT_GEN_SET 0x0001
+/** HostCmd CAL data header length */
+#define CFG_DATA_HEADER_LEN 6
+
+typedef struct _HostCmd_DS_GEN
+{
+ t_u16 command;
+ t_u16 size;
+ t_u16 seq_num;
+ t_u16 result;
+} HostCmd_DS_GEN;
+
+typedef struct _HostCmd_DS_802_11_CFG_DATA
+{
+ /** Action */
+ t_u16 action;
+ /** Type */
+ t_u16 type;
+ /** Data length */
+ t_u16 data_len;
+ /** Data */
+ t_u8 data[1];
+} __ATTRIB_PACK__ HostCmd_DS_802_11_CFG_DATA;
+
+/** combo scan header */
+#define WEXT_CSCAN_HEADER "CSCAN S\x01\x00\x00S\x00"
+/** combo scan header size */
+#define WEXT_CSCAN_HEADER_SIZE 12
+/** combo scan ssid section */
+#define WEXT_CSCAN_SSID_SECTION 'S'
+/** commbo scan channel section */
+#define WEXT_CSCAN_CHANNEL_SECTION 'C'
+/** commbo scan passive dwell section */
+#define WEXT_CSCAN_PASV_DWELL_SECTION 'P'
+/** commbo scan home dwell section */
+#define WEXT_CSCAN_HOME_DWELL_SECTION 'H'
+/** BGSCAN RSSI section */
+#define WEXT_BGSCAN_RSSI_SECTION 'R'
+/** BGSCAN SCAN INTERVAL SECTION */
+#define WEXT_BGSCAN_INTERVAL_SECTION 'T'
+
+/** band AUTO */
+#define WIFI_FREQUENCY_BAND_AUTO 0
+/** band 5G */
+#define WIFI_FREQUENCY_BAND_5GHZ 1
+/** band 2G */
+#define WIFI_FREQUENCY_BAND_2GHZ 2
+/** All band */
+#define WIFI_FREQUENCY_ALL_BAND 3
+
+/** Rx filter: IPV4 multicast */
+#define RX_FILTER_IPV4_MULTICAST 1
+/** Rx filter: broadcast */
+#define RX_FILTER_BROADCAST 2
+/** Rx filter: unicast */
+#define RX_FILTER_UNICAST 4
+/** Rx filter: IPV6 multicast */
+#define RX_FILTER_IPV6_MULTICAST 8
+
+/** Convert ASCII string to hex value */
+int woal_ascii2hex(t_u8 * d, char *s, t_u32 dlen);
+/** Convert mac address from string to t_u8 buffer */
+void woal_mac2u8(t_u8 * mac_addr, char *buf);
+/** Extract token from string */
+char *woal_strsep(char **s, char delim, char esc);
+/** Return int value of a given ASCII string */
+mlan_status woal_atoi(int *data, char *a);
+/** Return hex value of a given ASCII string */
+int woal_atox(char *a);
+/** Allocate buffer */
+pmlan_buffer woal_alloc_mlan_buffer(moal_handle * handle, int size);
+/** Allocate IOCTL request buffer */
+pmlan_ioctl_req woal_alloc_mlan_ioctl_req(int size);
+/** Free buffer */
+void woal_free_mlan_buffer(moal_handle * handle, pmlan_buffer pmbuf);
+/** Get private structure of a BSS by index */
+moal_private *woal_bss_index_to_priv(moal_handle * handle, t_u8 bss_index);
+/* Functions in interface module */
+/** Add card */
+moal_handle *woal_add_card(void *card);
+/** Remove card */
+mlan_status woal_remove_card(void *card);
+/** broadcast event */
+mlan_status woal_broadcast_event(moal_private * priv, t_u8 * payload,
+ t_u32 len);
+/** switch driver mode */
+mlan_status woal_switch_drv_mode(moal_handle * handle, t_u32 mode);
+
+/** Interrupt handler */
+void woal_interrupt(moal_handle * handle);
+
+#ifdef STA_WEXT
+#endif
+/** Get version */
+void woal_get_version(moal_handle * handle, char *version, int maxlen);
+/** Get Driver Version */
+int woal_get_driver_version(moal_private * priv, struct ifreq *req);
+/** Get extended driver version */
+int woal_get_driver_verext(moal_private * priv, struct ifreq *ireq);
+/** Mgmt frame forward registration */
+int woal_reg_rx_mgmt_ind(moal_private * priv, t_u16 action,
+ t_u32 * pmgmt_subtype_mask, t_u8 wait_option);
+#ifdef DEBUG_LEVEL1
+/** Set driver debug bit masks */
+int woal_set_drvdbg(moal_private * priv, t_u32 drvdbg);
+#endif
+/** Set/Get TX beamforming configurations */
+mlan_status woal_set_get_tx_bf_cfg(moal_private * priv, t_u16 action,
+ mlan_ds_11n_tx_bf_cfg * bf_cfg);
+/** Request MAC address setting */
+mlan_status woal_request_set_mac_address(moal_private * priv);
+/** Request multicast list setting */
+void woal_request_set_multicast_list(moal_private * priv,
+ struct net_device *dev);
+/** Request IOCTL action */
+mlan_status woal_request_ioctl(moal_private * priv, mlan_ioctl_req * req,
+ t_u8 wait_option);
+mlan_status woal_request_soft_reset(moal_handle * handle);
+#ifdef PROC_DEBUG
+/** Get debug information */
+mlan_status woal_get_debug_info(moal_private * priv, t_u8 wait_option,
+ mlan_debug_info * debug_info);
+/** Set debug information */
+mlan_status woal_set_debug_info(moal_private * priv, t_u8 wait_option,
+ mlan_debug_info * debug_info);
+#endif
+/** Disconnect */
+mlan_status woal_disconnect(moal_private * priv, t_u8 wait_option, t_u8 * mac);
+/** associate */
+mlan_status woal_bss_start(moal_private * priv, t_u8 wait_option,
+ mlan_ssid_bssid * ssid_bssid);
+/** Request firmware information */
+mlan_status woal_request_get_fw_info(moal_private * priv, t_u8 wait_option,
+ mlan_fw_info * fw_info);
+/** Set/get Host Sleep parameters */
+mlan_status woal_set_get_hs_params(moal_private * priv, t_u16 action,
+ t_u8 wait_option, mlan_ds_hs_cfg * hscfg);
+/** Cancel Host Sleep configuration */
+mlan_status woal_cancel_hs(moal_private * priv, t_u8 wait_option);
+/** Enable Host Sleep configuration */
+int woal_enable_hs(moal_private * priv);
+/** hs active timeout 2 second */
+#define HS_ACTIVE_TIMEOUT (2 * HZ)
+
+/** set deep sleep */
+int woal_set_deep_sleep(moal_private * priv, t_u8 wait_option,
+ BOOLEAN bdeep_sleep, t_u16 idletime);
+
+/** Get BSS information */
+mlan_status woal_get_bss_info(moal_private * priv, t_u8 wait_option,
+ mlan_bss_info * bss_info);
+void woal_process_ioctl_resp(moal_private * priv, mlan_ioctl_req * req);
+#ifdef STA_SUPPORT
+void woal_send_disconnect_to_system(moal_private * priv);
+void woal_send_mic_error_event(moal_private * priv, t_u32 event);
+void woal_ioctl_get_bss_resp(moal_private * priv, mlan_ds_bss * bss);
+void woal_ioctl_get_info_resp(moal_private * priv, mlan_ds_get_info * info);
+/** Get signal information */
+mlan_status woal_get_signal_info(moal_private * priv, t_u8 wait_option,
+ mlan_ds_get_signal * signal);
+#ifdef STA_WEXT
+/** Get mode */
+t_u32 woal_get_mode(moal_private * priv, t_u8 wait_option);
+/** Get data rates */
+mlan_status woal_get_data_rates(moal_private * priv, t_u8 wait_option,
+ moal_802_11_rates * m_rates);
+void woal_send_iwevcustom_event(moal_private * priv, t_s8 * str);
+/** Get statistics information */
+mlan_status woal_get_stats_info(moal_private * priv, t_u8 wait_option,
+ mlan_ds_get_stats * stats);
+/** Get channel list */
+mlan_status woal_get_channel_list(moal_private * priv, t_u8 wait_option,
+ mlan_chan_list * chanlist);
+#endif
+/** Set/Get retry count */
+mlan_status woal_set_get_retry(moal_private * priv, t_u32 action,
+ t_u8 wait_option, int *value);
+/** Set/Get RTS threshold */
+mlan_status woal_set_get_rts(moal_private * priv, t_u32 action,
+ t_u8 wait_option, int *value);
+/** Set/Get fragment threshold */
+mlan_status woal_set_get_frag(moal_private * priv, t_u32 action,
+ t_u8 wait_option, int *value);
+/** Set/Get generic element */
+mlan_status woal_set_get_gen_ie(moal_private * priv, t_u32 action, t_u8 * ie,
+ int *ie_len);
+/** Set/Get TX power */
+mlan_status woal_set_get_tx_power(moal_private * priv, t_u32 action,
+ mlan_power_cfg_t * pwr);
+/** Set/Get power IEEE management */
+mlan_status woal_set_get_power_mgmt(moal_private * priv, t_u32 action,
+ int *disabled, int type);
+/** Get data rate */
+mlan_status woal_set_get_data_rate(moal_private * priv, t_u8 action,
+ mlan_rate_cfg_t * datarate);
+/** Request a network scan */
+mlan_status woal_request_scan(moal_private * priv, t_u8 wait_option,
+ mlan_802_11_ssid * req_ssid);
+/** Set radio on/off */
+int woal_set_radio(moal_private * priv, t_u8 option);
+/** Set region code */
+mlan_status woal_set_region_code(moal_private * priv, char *region);
+/** Set authentication mode */
+mlan_status woal_set_auth_mode(moal_private * priv, t_u8 wait_option,
+ t_u32 auth_mode);
+/** Set encryption mode */
+mlan_status woal_set_encrypt_mode(moal_private * priv, t_u8 wait_option,
+ t_u32 encrypt_mode);
+/** Enable wep key */
+mlan_status woal_enable_wep_key(moal_private * priv, t_u8 wait_option);
+/** Set WPA enable */
+mlan_status woal_set_wpa_enable(moal_private * priv, t_u8 wait_option,
+ t_u32 enable);
+
+/** Find best network to connect */
+mlan_status woal_find_best_network(moal_private * priv, t_u8 wait_option,
+ mlan_ssid_bssid * ssid_bssid);
+/** Set Ad-Hoc channel */
+mlan_status woal_change_adhoc_chan(moal_private * priv, int channel);
+
+/** Get scan table */
+mlan_status woal_get_scan_table(moal_private * priv, t_u8 wait_option,
+ mlan_scan_resp * scanresp);
+/** Get authentication mode */
+mlan_status woal_get_auth_mode(moal_private * priv, t_u8 wait_option,
+ t_u32 * auth_mode);
+/** Get encryption mode */
+mlan_status woal_get_encrypt_mode(moal_private * priv, t_u8 wait_option,
+ t_u32 * encrypt_mode);
+/** Get WPA state */
+mlan_status woal_get_wpa_enable(moal_private * priv, t_u8 wait_option,
+ t_u32 * enable);
+#endif /**STA_SUPPORT */
+
+mlan_status woal_set_wapi_enable(moal_private * priv, t_u8 wait_option,
+ t_u32 enable);
+
+/** Initialize priv */
+void woal_init_priv(moal_private * priv, t_u8 wait_option);
+/** Reset interface(s) */
+int woal_reset_intf(moal_private * priv, t_u8 wait_option, int all_intf);
+/** common ioctl for uap, station */
+int woal_custom_ie_ioctl(struct net_device *dev, struct ifreq *req);
+int woal_send_host_packet(struct net_device *dev, struct ifreq *req);
+/** Private command ID to pass mgmt frame */
+#define WOAL_MGMT_FRAME_TX_IOCTL (SIOCDEVPRIVATE + 12)
+
+int woal_get_bss_type(struct net_device *dev, struct ifreq *req);
+#if defined(STA_WEXT) || defined(UAP_WEXT)
+int woal_host_command(moal_private * priv, struct iwreq *wrq);
+#endif
+#if defined(WIFI_DIRECT_SUPPORT)
+#if defined(STA_SUPPORT) && defined(UAP_SUPPORT)
+#if defined(STA_WEXT) || defined(UAP_WEXT)
+int woal_set_get_bss_role(moal_private * priv, struct iwreq *wrq);
+#endif
+#endif
+#endif
+#if defined(WIFI_DIRECT_SUPPORT) || defined(UAP_SUPPORT)
+/** hostcmd ioctl for uap, wifidirect */
+int woal_hostcmd_ioctl(struct net_device *dev, struct ifreq *req);
+#endif
+
+#if defined(WIFI_DIRECT_SUPPORT)
+mlan_status woal_set_remain_channel_ioctl(moal_private * priv, t_u8 wait_option,
+ mlan_ds_remain_chan * pchan);
+mlan_status woal_cfg80211_wifi_direct_mode_cfg(moal_private * priv,
+ t_u16 action, t_u16 * mode);
+#endif /* WIFI_DIRECT_SUPPORT */
+
+#ifdef CONFIG_PROC_FS
+/** Initialize proc fs */
+void woal_proc_init(moal_handle * handle);
+/** Clean up proc fs */
+void woal_proc_exit(moal_handle * handle);
+/** Create proc entry */
+void woal_create_proc_entry(moal_private * priv);
+/** Remove proc entry */
+void woal_proc_remove(moal_private * priv);
+/** string to number */
+int woal_string_to_number(char *s);
+#endif
+
+#ifdef PROC_DEBUG
+/** Create debug proc fs */
+void woal_debug_entry(moal_private * priv);
+/** Remove debug proc fs */
+void woal_debug_remove(moal_private * priv);
+#endif /* PROC_DEBUG */
+
+/** check pm info */
+mlan_status woal_get_pm_info(moal_private * priv, mlan_ds_ps_info * pm_info);
+
+#ifdef REASSOCIATION
+int woal_reassociation_thread(void *data);
+void woal_reassoc_timer_func(void *context);
+#endif /* REASSOCIATION */
+
+t_void woal_main_work_queue(struct work_struct *work);
+
+int woal_hard_start_xmit(struct sk_buff *skb, struct net_device *dev);
+moal_private *woal_add_interface(moal_handle * handle, t_u8 bss_num,
+ t_u8 bss_type);
+void woal_remove_interface(moal_handle * handle, t_u8 bss_index);
+void woal_set_multicast_list(struct net_device *dev);
+mlan_status woal_request_fw(moal_handle * handle);
+
+int woal_11h_channel_check_ioctl(moal_private * priv);
+void woal_cancel_cac_block(moal_private * priv);
+void woal_moal_debug_info(moal_private * priv, moal_handle * handle, u8 flag);
+
+#ifdef STA_SUPPORT
+mlan_status woal_get_powermode(moal_private * priv, int *powermode);
+mlan_status woal_set_scan_type(moal_private * priv, t_u32 scan_type);
+mlan_status woal_set_powermode(moal_private * priv, char *powermode);
+int woal_find_essid(moal_private * priv, mlan_ssid_bssid * ssid_bssid);
+mlan_status woal_do_scan(moal_private * priv, wlan_user_scan_cfg * scan_cfg);
+int woal_set_combo_scan(moal_private * priv, char *buf, int length);
+mlan_status woal_get_band(moal_private * priv, int *band);
+mlan_status woal_set_band(moal_private * priv, char *pband);
+mlan_status woal_add_rxfilter(moal_private * priv, char *rxfilter);
+mlan_status woal_remove_rxfilter(moal_private * priv, char *rxfilter);
+mlan_status woal_set_qos_cfg(moal_private * priv, char *qos_cfg);
+int woal_set_sleeppd(moal_private * priv, char *psleeppd);
+mlan_status woal_set_rssi_low_threshold(moal_private * priv, char *rssi);
+mlan_status woal_set_bg_scan(moal_private * priv, char *buf, int length);
+mlan_status woal_stop_bg_scan(moal_private * priv);
+void woal_reconfig_bgscan(moal_handle * handle);
+#endif
+
+#endif /* _MOAL_MAIN_H */
diff --git a/drivers/net/wireless/sd8797/mlinux/moal_priv.c b/drivers/net/wireless/sd8797/mlinux/moal_priv.c
new file mode 100644
index 000000000000..dc5cd82b7f44
--- /dev/null
+++ b/drivers/net/wireless/sd8797/mlinux/moal_priv.c
@@ -0,0 +1,6596 @@
+/** @file moal_priv.c
+ *
+ * @brief This file contains standard ioctl functions
+ *
+ * Copyright (C) 2008-2011, Marvell International Ltd.
+ *
+ * This software file (the "File") is distributed by Marvell International
+ * Ltd. under the terms of the GNU General Public License Version 2, June 1991
+ * (the "License"). You may use, redistribute and/or modify this File in
+ * accordance with the terms and conditions of the License, a copy of which
+ * is available by writing to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
+ * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
+ *
+ * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
+ * ARE EXPRESSLY DISCLAIMED. The License provides additional details about
+ * this warranty disclaimer.
+ *
+ */
+
+/************************************************************************
+Change log:
+ 10/30/2008: initial version
+************************************************************************/
+
+#include "moal_main.h"
+#include "moal_sdio.h"
+
+#if defined(STA_CFG80211) && defined(UAP_CFG80211)
+#include "moal_cfg80211.h"
+#endif
+#include "moal_eth_ioctl.h"
+
+/********************************************************
+ Local Variables
+********************************************************/
+/** Bands supported in Infra mode */
+static t_u8 SupportedInfraBand[] = {
+ BAND_B,
+ BAND_B | BAND_G, BAND_G,
+ BAND_GN, BAND_B | BAND_G | BAND_GN, BAND_G | BAND_GN,
+ BAND_A, BAND_B | BAND_A, BAND_B | BAND_G | BAND_A, BAND_G | BAND_A,
+ BAND_A | BAND_B | BAND_G | BAND_AN | BAND_GN,
+ BAND_A | BAND_G | BAND_AN | BAND_GN, BAND_A | BAND_AN,
+};
+
+/** Bands supported in Ad-Hoc mode */
+static t_u8 SupportedAdhocBand[] = {
+ BAND_B, BAND_B | BAND_G, BAND_G,
+ BAND_GN, BAND_B | BAND_G | BAND_GN, BAND_G | BAND_GN,
+ BAND_A,
+ BAND_AN, BAND_A | BAND_AN,
+};
+
+/********************************************************
+ Global Variables
+********************************************************/
+
+extern int cfg80211_wext;
+
+/********************************************************
+ Local Functions
+********************************************************/
+
+/**
+ * @brief Copy Rates
+ *
+ * @param dest A pointer to destination buffer
+ * @param pos The position for copy
+ * @param src A pointer to source buffer
+ * @param len Length of the source buffer
+ *
+ * @return Number of rates copied
+ */
+static inline int
+woal_copy_rates(t_u8 * dest, int pos, t_u8 * src, int len)
+{
+ int i;
+
+ for (i = 0; i < len && src[i]; i++, pos++) {
+ if (pos >= MLAN_SUPPORTED_RATES)
+ break;
+ dest[pos] = src[i];
+ }
+ return pos;
+}
+
+/**
+ * @brief Performs warm reset
+ *
+ * @param priv A pointer to moal_private structure
+ *
+ * @return 0/MLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static int
+woal_warm_reset(moal_private * priv)
+{
+ int ret = 0;
+ int intf_num;
+ moal_handle *handle = priv->phandle;
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_misc_cfg *misc = NULL;
+
+ ENTER();
+
+ woal_cancel_cac_block(priv);
+
+ /* Reset all interfaces */
+ ret = woal_reset_intf(priv, MOAL_IOCTL_WAIT, MTRUE);
+
+ /* Initialize private structures */
+ for (intf_num = 0; intf_num < handle->priv_num; intf_num++)
+ woal_init_priv(handle->priv[intf_num], MOAL_IOCTL_WAIT);
+
+ /* Restart the firmware */
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
+ if (req) {
+ misc = (mlan_ds_misc_cfg *) req->pbuf;
+ misc->sub_command = MLAN_OID_MISC_WARM_RESET;
+ req->req_id = MLAN_IOCTL_MISC_CFG;
+ req->action = MLAN_ACT_SET;
+ if (MLAN_STATUS_SUCCESS !=
+ woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) {
+ ret = -EFAULT;
+ kfree(req);
+ goto done;
+ }
+ kfree(req);
+ }
+
+ /* Enable interfaces */
+ for (intf_num = 0; intf_num < handle->priv_num; intf_num++) {
+ netif_device_attach(handle->priv[intf_num]->netdev);
+ woal_start_queue(handle->priv[intf_num]->netdev);
+ }
+
+ done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Get signal
+ *
+ * @param priv A pointer to moal_private structure
+ * @param wrq A pointer to iwreq structure
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_get_signal(moal_private * priv, struct iwreq *wrq)
+{
+/** Input data size */
+#define IN_DATA_SIZE 2
+/** Output data size */
+#define OUT_DATA_SIZE 12
+ int ret = 0;
+ int in_data[IN_DATA_SIZE];
+ int out_data[OUT_DATA_SIZE];
+ mlan_ds_get_signal signal;
+ int data_length = 0;
+ int buflen = 0;
+
+ ENTER();
+
+ memset(in_data, 0, sizeof(in_data));
+ memset(out_data, 0, sizeof(out_data));
+ buflen = MIN(wrq->u.data.length, IN_DATA_SIZE);
+
+ if (priv->media_connected == MFALSE) {
+ PRINTM(MERROR, "Can not get RSSI in disconnected state\n");
+ ret = -ENOTSUPP;
+ goto done;
+ }
+
+ if (wrq->u.data.length) {
+ if (sizeof(int) * wrq->u.data.length > sizeof(in_data)) {
+ PRINTM(MERROR, "Too many arguments\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ if (copy_from_user(in_data, wrq->u.data.pointer, sizeof(int) * buflen)) {
+ PRINTM(MERROR, "Copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ }
+
+ switch (wrq->u.data.length) {
+ case 0: /* No checking, get everything */
+ break;
+ case 2: /* Check subtype range */
+ if (in_data[1] < 1 || in_data[1] > 4) {
+ ret = -EINVAL;
+ goto done;
+ }
+ /* Fall through */
+ case 1: /* Check type range */
+ if (in_data[0] < 1 || in_data[0] > 3) {
+ ret = -EINVAL;
+ goto done;
+ }
+ break;
+ default:
+ ret = -EINVAL;
+ goto done;
+ }
+
+ memset(&signal, 0, sizeof(mlan_ds_get_signal));
+ if (MLAN_STATUS_SUCCESS !=
+ woal_get_signal_info(priv, MOAL_IOCTL_WAIT, &signal)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ PRINTM(MINFO, "RSSI Beacon Last : %d\n", (int) signal.bcn_rssi_last);
+ PRINTM(MINFO, "RSSI Beacon Average: %d\n", (int) signal.bcn_rssi_avg);
+ PRINTM(MINFO, "RSSI Data Last : %d\n", (int) signal.data_rssi_last);
+ PRINTM(MINFO, "RSSI Data Average : %d\n", (int) signal.data_rssi_avg);
+ PRINTM(MINFO, "SNR Beacon Last : %d\n", (int) signal.bcn_snr_last);
+ PRINTM(MINFO, "SNR Beacon Average : %d\n", (int) signal.bcn_snr_avg);
+ PRINTM(MINFO, "SNR Data Last : %d\n", (int) signal.data_snr_last);
+ PRINTM(MINFO, "SNR Data Average : %d\n", (int) signal.data_snr_avg);
+ PRINTM(MINFO, "NF Beacon Last : %d\n", (int) signal.bcn_nf_last);
+ PRINTM(MINFO, "NF Beacon Average : %d\n", (int) signal.bcn_nf_avg);
+ PRINTM(MINFO, "NF Data Last : %d\n", (int) signal.data_nf_last);
+ PRINTM(MINFO, "NF Data Average : %d\n", (int) signal.data_nf_avg);
+
+ /* Check type */
+ switch (in_data[0]) {
+ case 0: /* Send everything */
+ out_data[data_length++] = signal.bcn_rssi_last;
+ out_data[data_length++] = signal.bcn_rssi_avg;
+ out_data[data_length++] = signal.data_rssi_last;
+ out_data[data_length++] = signal.data_rssi_avg;
+ out_data[data_length++] = signal.bcn_snr_last;
+ out_data[data_length++] = signal.bcn_snr_avg;
+ out_data[data_length++] = signal.data_snr_last;
+ out_data[data_length++] = signal.data_snr_avg;
+ out_data[data_length++] = signal.bcn_nf_last;
+ out_data[data_length++] = signal.bcn_nf_avg;
+ out_data[data_length++] = signal.data_nf_last;
+ out_data[data_length++] = signal.data_nf_avg;
+ break;
+ case 1: /* RSSI */
+ /* Check subtype */
+ switch (in_data[1]) {
+ case 0: /* Everything */
+ out_data[data_length++] = signal.bcn_rssi_last;
+ out_data[data_length++] = signal.bcn_rssi_avg;
+ out_data[data_length++] = signal.data_rssi_last;
+ out_data[data_length++] = signal.data_rssi_avg;
+ break;
+ case 1: /* bcn last */
+ out_data[data_length++] = signal.bcn_rssi_last;
+ break;
+ case 2: /* bcn avg */
+ out_data[data_length++] = signal.bcn_rssi_avg;
+ break;
+ case 3: /* data last */
+ out_data[data_length++] = signal.data_rssi_last;
+ break;
+ case 4: /* data avg */
+ out_data[data_length++] = signal.data_rssi_avg;
+ break;
+ default:
+ break;
+ }
+ break;
+ case 2: /* SNR */
+ /* Check subtype */
+ switch (in_data[1]) {
+ case 0: /* Everything */
+ out_data[data_length++] = signal.bcn_snr_last;
+ out_data[data_length++] = signal.bcn_snr_avg;
+ out_data[data_length++] = signal.data_snr_last;
+ out_data[data_length++] = signal.data_snr_avg;
+ break;
+ case 1: /* bcn last */
+ out_data[data_length++] = signal.bcn_snr_last;
+ break;
+ case 2: /* bcn avg */
+ out_data[data_length++] = signal.bcn_snr_avg;
+ break;
+ case 3: /* data last */
+ out_data[data_length++] = signal.data_snr_last;
+ break;
+ case 4: /* data avg */
+ out_data[data_length++] = signal.data_snr_avg;
+ break;
+ default:
+ break;
+ }
+ break;
+ case 3: /* NF */
+ /* Check subtype */
+ switch (in_data[1]) {
+ case 0: /* Everything */
+ out_data[data_length++] = signal.bcn_nf_last;
+ out_data[data_length++] = signal.bcn_nf_avg;
+ out_data[data_length++] = signal.data_nf_last;
+ out_data[data_length++] = signal.data_nf_avg;
+ break;
+ case 1: /* bcn last */
+ out_data[data_length++] = signal.bcn_nf_last;
+ break;
+ case 2: /* bcn avg */
+ out_data[data_length++] = signal.bcn_nf_avg;
+ break;
+ case 3: /* data last */
+ out_data[data_length++] = signal.data_nf_last;
+ break;
+ case 4: /* data avg */
+ out_data[data_length++] = signal.data_nf_avg;
+ break;
+ default:
+ break;
+ }
+ break;
+ default:
+ break;
+ }
+
+ wrq->u.data.length = data_length;
+ if (copy_to_user(wrq->u.data.pointer, out_data,
+ wrq->u.data.length * sizeof(out_data[0]))) {
+ PRINTM(MERROR, "Copy to user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Get Deep Sleep
+ *
+ * @param priv Pointer to the moal_private driver data struct
+ * @param deep_sleep Pointer to return deep_sleep setting
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_get_deep_sleep(moal_private * priv, t_u32 * data)
+{
+ int ret = 0;
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_pm_cfg *pm = NULL;
+
+ ENTER();
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_pm_cfg));
+ if (req == NULL) {
+ LEAVE();
+ return -ENOMEM;
+ }
+ pm = (mlan_ds_pm_cfg *) req->pbuf;
+ pm->sub_command = MLAN_OID_PM_CFG_DEEP_SLEEP;
+ req->req_id = MLAN_IOCTL_PM_CFG;
+
+ req->action = MLAN_ACT_GET;
+ if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ *data = pm->param.auto_deep_sleep.auto_ds;
+ *(data + 1) = pm->param.auto_deep_sleep.idletime;
+
+ done:
+ if (req)
+ kfree(req);
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Get/Set DeepSleep mode
+ *
+ * @param priv Pointer to the moal_private driver data struct
+ * @param wreq A pointer to iwreq structure
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_deep_sleep_ioctl(moal_private * priv, struct iwreq *wrq)
+{
+ int ret = 0;
+ t_u32 deep_sleep = DEEP_SLEEP_OFF;
+ t_u32 data[2];
+ t_u16 idletime = DEEP_SLEEP_IDLE_TIME;
+
+ ENTER();
+
+ if (wrq->u.data.length == 1 || wrq->u.data.length == 2) {
+ if (copy_from_user
+ (&data, wrq->u.data.pointer, wrq->u.data.length * sizeof(int))) {
+ PRINTM(MERROR, "Copy from user failed\n");
+ LEAVE();
+ return -EFAULT;
+ }
+ deep_sleep = data[0];
+ if (deep_sleep == DEEP_SLEEP_OFF) {
+ PRINTM(MINFO, "Exit Deep Sleep Mode\n");
+ ret = woal_set_deep_sleep(priv, MOAL_IOCTL_WAIT, MFALSE, 0);
+ if (ret != MLAN_STATUS_SUCCESS) {
+ LEAVE();
+ return -EINVAL;
+ }
+ } else if (deep_sleep == DEEP_SLEEP_ON) {
+ PRINTM(MINFO, "Enter Deep Sleep Mode\n");
+ if (wrq->u.data.length == 2)
+ idletime = data[1];
+ else
+ idletime = 0;
+ ret = woal_set_deep_sleep(priv, MOAL_IOCTL_WAIT, MTRUE, idletime);
+ if (ret != MLAN_STATUS_SUCCESS) {
+ LEAVE();
+ return -EINVAL;
+ }
+ } else {
+ PRINTM(MERROR, "Unknown option = %u\n", deep_sleep);
+ LEAVE();
+ return -EINVAL;
+ }
+ } else if (wrq->u.data.length > 2) {
+ PRINTM(MERROR, "Invalid number of arguments %d\n", wrq->u.data.length);
+ LEAVE();
+ return -EINVAL;
+ } else { /* Display Deep Sleep settings */
+ PRINTM(MINFO, "Get Deep Sleep Mode\n");
+ if (MLAN_STATUS_SUCCESS != woal_get_deep_sleep(priv, data)) {
+ LEAVE();
+ return -EFAULT;
+ }
+ if (data[0] == 0)
+ wrq->u.data.length = 1;
+ else
+ wrq->u.data.length = 2;
+ }
+
+ /* Copy the Deep Sleep setting to user */
+ if (copy_to_user
+ (wrq->u.data.pointer, data, wrq->u.data.length * sizeof(int))) {
+ PRINTM(MERROR, "Copy to user failed\n");
+ LEAVE();
+ return -EINVAL;
+ }
+
+ LEAVE();
+ return 0;
+}
+
+/**
+ * @brief Set/Get Usr 11n configuration request
+ *
+ * @param priv Pointer to the moal_private driver data struct
+ * @param wrq A pointer to iwreq structure
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_11n_htcap_cfg(moal_private * priv, struct iwreq *wrq)
+{
+ int data[2];
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_11n_cfg *cfg_11n = NULL;
+ int ret = 0;
+ int data_length = wrq->u.data.length;
+
+ ENTER();
+
+ if (data_length > 2) {
+ PRINTM(MERROR, "Invalid number of arguments\n");
+ ret = -EINVAL;
+ goto done;
+ }
+
+ if (((req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_11n_cfg))) == NULL)) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ cfg_11n = (mlan_ds_11n_cfg *) req->pbuf;
+ cfg_11n->sub_command = MLAN_OID_11N_HTCAP_CFG;
+ req->req_id = MLAN_IOCTL_11N_CFG;
+
+ if (data_length == 0) {
+ /* Get 11n tx parameters from MLAN */
+ req->action = MLAN_ACT_GET;
+ cfg_11n->param.htcap_cfg.misc_cfg = BAND_SELECT_BG;
+ } else {
+ if (copy_from_user
+ (data, wrq->u.data.pointer, data_length * sizeof(int))) {
+ PRINTM(MERROR, "Copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+
+ cfg_11n->param.htcap_cfg.htcap = data[0];
+ PRINTM(MINFO, "SET: htcapinfo:0x%x\n", data[0]);
+ cfg_11n->param.htcap_cfg.misc_cfg = BAND_SELECT_BOTH;
+ if (data_length == 2) {
+ if (data[1] != BAND_SELECT_BG &&
+ data[1] != BAND_SELECT_A && data[1] != BAND_SELECT_BOTH) {
+ PRINTM(MERROR, "Invalid band selection\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ cfg_11n->param.htcap_cfg.misc_cfg = data[1];
+ PRINTM(MINFO, "SET: htcapinfo band:0x%x\n", data[1]);
+ }
+ /* Update 11n tx parameters in MLAN */
+ req->action = MLAN_ACT_SET;
+ }
+
+ if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ data[0] = cfg_11n->param.htcap_cfg.htcap;
+
+ if (req->action == MLAN_ACT_GET) {
+ data_length = 1;
+ cfg_11n->param.htcap_cfg.htcap = 0;
+ cfg_11n->param.htcap_cfg.misc_cfg = BAND_SELECT_A;
+ if (MLAN_STATUS_SUCCESS !=
+ woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ if (cfg_11n->param.htcap_cfg.htcap != data[0]) {
+ data_length = 2;
+ data[1] = cfg_11n->param.htcap_cfg.htcap;
+ PRINTM(MINFO, "GET: htcapinfo for 2.4GHz:0x%x\n", data[0]);
+ PRINTM(MINFO, "GET: htcapinfo for 5GHz:0x%x\n", data[1]);
+ } else
+ PRINTM(MINFO, "GET: htcapinfo:0x%x\n", data[0]);
+ }
+
+ if (copy_to_user(wrq->u.data.pointer, data, sizeof(data))) {
+ PRINTM(MERROR, "Copy to user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+
+ wrq->u.data.length = data_length;
+
+ done:
+ if (req)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Enable/Disable amsdu_aggr_ctrl
+ *
+ * @param priv Pointer to the moal_private driver data struct
+ * @param wrq A pointer to iwreq structure
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_11n_amsdu_aggr_ctrl(moal_private * priv, struct iwreq *wrq)
+{
+ int data[2];
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_11n_cfg *cfg_11n = NULL;
+ int ret = 0;
+
+ ENTER();
+
+ if ((wrq->u.data.length != 0) && (wrq->u.data.length != 1)) {
+ PRINTM(MERROR, "Invalid number of arguments\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_11n_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ cfg_11n = (mlan_ds_11n_cfg *) req->pbuf;
+ cfg_11n->sub_command = MLAN_OID_11N_CFG_AMSDU_AGGR_CTRL;
+ req->req_id = MLAN_IOCTL_11N_CFG;
+
+ if (wrq->u.data.length == 0) {
+ /* Get 11n tx parameters from MLAN */
+ req->action = MLAN_ACT_GET;
+ } else if (wrq->u.data.length == 1) {
+ if (copy_from_user(data, wrq->u.data.pointer,
+ wrq->u.data.length * sizeof(int))) {
+ PRINTM(MERROR, "Copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ cfg_11n->param.amsdu_aggr_ctrl.enable = data[0];
+ /* Update 11n tx parameters in MLAN */
+ req->action = MLAN_ACT_SET;
+ }
+ if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ data[0] = cfg_11n->param.amsdu_aggr_ctrl.enable;
+ data[1] = cfg_11n->param.amsdu_aggr_ctrl.curr_buf_size;
+
+ if (copy_to_user(wrq->u.data.pointer, data, sizeof(data))) {
+ PRINTM(MERROR, "Copy to user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ wrq->u.data.length = 2;
+ done:
+ if (req)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set/Get 11n configuration request
+ *
+ * @param priv Pointer to the moal_private driver data struct
+ * @param wrq A pointer to iwreq structure
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_11n_tx_cfg(moal_private * priv, struct iwreq *wrq)
+{
+ int data[2];
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_11n_cfg *cfg_11n = NULL;
+ int ret = 0;
+ int data_length = wrq->u.data.length;
+
+ ENTER();
+
+ if (data_length > 2) {
+ PRINTM(MERROR, "Invalid number of arguments\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_11n_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ cfg_11n = (mlan_ds_11n_cfg *) req->pbuf;
+ cfg_11n->sub_command = MLAN_OID_11N_CFG_TX;
+ req->req_id = MLAN_IOCTL_11N_CFG;
+
+ if (wrq->u.data.length == 0) {
+ /* Get 11n tx parameters from MLAN */
+ req->action = MLAN_ACT_GET;
+ cfg_11n->param.tx_cfg.misc_cfg = BAND_SELECT_BG;
+ } else {
+ if (copy_from_user
+ (data, wrq->u.data.pointer, data_length * sizeof(int))) {
+ PRINTM(MERROR, "Copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+
+ cfg_11n->param.tx_cfg.httxcap = data[0];
+ PRINTM(MINFO, "SET: httxcap:0x%x\n", data[0]);
+ cfg_11n->param.tx_cfg.misc_cfg = BAND_SELECT_BOTH;
+ if (data_length == 2) {
+ if (data[1] != BAND_SELECT_BG &&
+ data[1] != BAND_SELECT_A && data[1] != BAND_SELECT_BOTH) {
+ PRINTM(MERROR, "Invalid band selection\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ cfg_11n->param.tx_cfg.misc_cfg = data[1];
+ PRINTM(MINFO, "SET: httxcap band:0x%x\n", data[1]);
+ }
+ /* Update 11n tx parameters in MLAN */
+ req->action = MLAN_ACT_SET;
+ }
+ if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ data[0] = cfg_11n->param.tx_cfg.httxcap;
+
+ if (req->action == MLAN_ACT_GET) {
+ data_length = 1;
+ cfg_11n->param.tx_cfg.httxcap = 0;
+ cfg_11n->param.tx_cfg.misc_cfg = BAND_SELECT_A;
+ if (MLAN_STATUS_SUCCESS !=
+ woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ if (cfg_11n->param.tx_cfg.httxcap != data[0]) {
+ data_length = 2;
+ data[1] = cfg_11n->param.tx_cfg.httxcap;
+ PRINTM(MINFO, "GET: httxcap for 2.4GHz:0x%x\n", data[0]);
+ PRINTM(MINFO, "GET: httxcap for 5GHz:0x%x\n", data[1]);
+ } else
+ PRINTM(MINFO, "GET: httxcap:0x%x\n", data[0]);
+ }
+
+ if (copy_to_user(wrq->u.data.pointer, data, sizeof(data))) {
+ PRINTM(MERROR, "Copy to user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ wrq->u.data.length = data_length;
+
+ done:
+ if (req)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Enable/Disable TX Aggregation
+ *
+ * @param priv Pointer to the moal_private driver data struct
+ * @param wrq A pointer to iwreq structure
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_11n_prio_tbl(moal_private * priv, struct iwreq *wrq)
+{
+ int data[MAX_NUM_TID * 2], i, j;
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_11n_cfg *cfg_11n = NULL;
+ int ret = 0;
+
+ ENTER();
+
+ if ((wrq->u.data.pointer == NULL)) {
+ LEAVE();
+ return -EINVAL;
+ }
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_11n_cfg));
+ if (req == NULL) {
+ LEAVE();
+ return -ENOMEM;
+ }
+ cfg_11n = (mlan_ds_11n_cfg *) req->pbuf;
+ cfg_11n->sub_command = MLAN_OID_11N_CFG_AGGR_PRIO_TBL;
+ req->req_id = MLAN_IOCTL_11N_CFG;
+
+ if (wrq->u.data.length == 0) {
+ /* Get aggr priority table from MLAN */
+ req->action = MLAN_ACT_GET;
+ if (MLAN_STATUS_SUCCESS !=
+ woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) {
+ ret = -EFAULT;
+ goto error;
+ }
+ wrq->u.data.length = MAX_NUM_TID * 2;
+ for (i = 0, j = 0; i < (wrq->u.data.length); i = i + 2, ++j) {
+ data[i] = cfg_11n->param.aggr_prio_tbl.ampdu[j];
+ data[i + 1] = cfg_11n->param.aggr_prio_tbl.amsdu[j];
+ }
+
+ if (copy_to_user(wrq->u.data.pointer, data,
+ sizeof(int) * wrq->u.data.length)) {
+ PRINTM(MERROR, "Copy to user failed\n");
+ ret = -EFAULT;
+ goto error;
+ }
+ } else if (wrq->u.data.length == 16) {
+ if (copy_from_user(data, wrq->u.data.pointer,
+ sizeof(int) * wrq->u.data.length)) {
+ PRINTM(MERROR, "Copy from user failed\n");
+ ret = -EFAULT;
+ goto error;
+ }
+ for (i = 0, j = 0; i < (wrq->u.data.length); i = i + 2, ++j) {
+ if ((data[i] > 7 && data[i] != 0xff) ||
+ (data[i + 1] > 7 && data[i + 1] != 0xff)) {
+ PRINTM(MERROR, "Invalid priority, valid value 0-7 or 0xff.\n");
+ ret = -EFAULT;
+ goto error;
+ }
+ cfg_11n->param.aggr_prio_tbl.ampdu[j] = data[i];
+ cfg_11n->param.aggr_prio_tbl.amsdu[j] = data[i + 1];
+ }
+
+ /* Update aggr priority table in MLAN */
+ req->action = MLAN_ACT_SET;
+ if (MLAN_STATUS_SUCCESS !=
+ woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) {
+ ret = -EFAULT;
+ goto error;
+ }
+ } else {
+ PRINTM(MERROR, "Invalid number of arguments\n");
+ ret = -EINVAL;
+ goto error;
+ }
+
+ error:
+ if (req)
+ kfree(req);
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set/Get add BA Reject parameters
+ *
+ * @param priv Pointer to the moal_private driver data struct
+ * @param wrq A pointer to iwreq structure
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_addba_reject(moal_private * priv, struct iwreq *wrq)
+{
+ int data[MAX_NUM_TID], ret = 0, i;
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_11n_cfg *cfg_11n = NULL;
+
+ ENTER();
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_11n_cfg));
+ if (req == NULL) {
+ LEAVE();
+ return -ENOMEM;
+ }
+ cfg_11n = (mlan_ds_11n_cfg *) req->pbuf;
+ cfg_11n->sub_command = MLAN_OID_11N_CFG_ADDBA_REJECT;
+ req->req_id = MLAN_IOCTL_11N_CFG;
+
+ if (wrq->u.data.length == 0) {
+ PRINTM(MERROR, "Addba reject moal\n");
+ /* Get aggr priority table from MLAN */
+ req->action = MLAN_ACT_GET;
+ if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req,
+ MOAL_IOCTL_WAIT)) {
+ ret = -EFAULT;
+ goto error;
+ }
+
+ wrq->u.data.length = MAX_NUM_TID;
+ for (i = 0; i < (wrq->u.data.length); ++i) {
+ data[i] = cfg_11n->param.addba_reject[i];
+ }
+
+ if (copy_to_user(wrq->u.data.pointer, data,
+ sizeof(int) * wrq->u.data.length)) {
+ PRINTM(MERROR, "Copy to user failed\n");
+ ret = -EFAULT;
+ goto error;
+ }
+ } else if (wrq->u.data.length == 8) {
+ if (copy_from_user(data, wrq->u.data.pointer,
+ sizeof(int) * wrq->u.data.length)) {
+ PRINTM(MERROR, "Copy from user failed\n");
+ ret = -EFAULT;
+ goto error;
+ }
+ for (i = 0; i < (wrq->u.data.length); ++i) {
+ if (data[i] != 0 && data[i] != 1) {
+ PRINTM(MERROR, "addba reject only takes argument as 0 or 1\n");
+ ret = -EFAULT;
+ goto error;
+ }
+ cfg_11n->param.addba_reject[i] = data[i];
+ }
+
+ /* Update aggr priority table in MLAN */
+ req->action = MLAN_ACT_SET;
+ if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req,
+ MOAL_IOCTL_WAIT)) {
+ ret = -EFAULT;
+ goto error;
+ }
+ } else {
+ PRINTM(MERROR, "Invalid number of arguments\n");
+ ret = -EINVAL;
+ goto error;
+ }
+ error:
+ if (req)
+ kfree(req);
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set/Get add BA parameters
+ *
+ * @param priv Pointer to the moal_private driver data struct
+ * @param wrq A pointer to iwreq structure
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_addba_para_updt(moal_private * priv, struct iwreq *wrq)
+{
+ int data[5], ret = 0;
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_11n_cfg *cfg_11n = NULL;
+
+ ENTER();
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_11n_cfg));
+ if (req == NULL) {
+ LEAVE();
+ return -ENOMEM;
+ }
+ cfg_11n = (mlan_ds_11n_cfg *) req->pbuf;
+ cfg_11n->sub_command = MLAN_OID_11N_CFG_ADDBA_PARAM;
+ req->req_id = MLAN_IOCTL_11N_CFG;
+
+ if (wrq->u.data.length == 0) {
+ /* Get Add BA parameters from MLAN */
+ req->action = MLAN_ACT_GET;
+ if (MLAN_STATUS_SUCCESS !=
+ woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) {
+ ret = -EFAULT;
+ goto error;
+ }
+ data[0] = cfg_11n->param.addba_param.timeout;
+ data[1] = cfg_11n->param.addba_param.txwinsize;
+ data[2] = cfg_11n->param.addba_param.rxwinsize;
+ data[3] = cfg_11n->param.addba_param.txamsdu;
+ data[4] = cfg_11n->param.addba_param.rxamsdu;
+ PRINTM(MINFO,
+ "GET: timeout:%d txwinsize:%d rxwinsize:%d txamsdu=%d, rxamsdu=%d\n",
+ data[0], data[1], data[2], data[3], data[4]);
+ wrq->u.data.length = 5;
+ if (copy_to_user(wrq->u.data.pointer, data,
+ wrq->u.data.length * sizeof(int))) {
+ PRINTM(MERROR, "Copy to user failed\n");
+ ret = -EFAULT;
+ goto error;
+ }
+ } else if (wrq->u.data.length == 5) {
+ if (copy_from_user
+ (data, wrq->u.data.pointer, wrq->u.data.length * sizeof(int))) {
+ PRINTM(MERROR, "Copy from user failed\n");
+ ret = -EFAULT;
+ goto error;
+ }
+ if (data[0] < 0 || data[0] > MLAN_DEFAULT_BLOCK_ACK_TIMEOUT) {
+ PRINTM(MERROR, "Incorrect addba timeout value.\n");
+ ret = -EFAULT;
+ goto error;
+ }
+ if (data[1] <= 0 || data[1] > MLAN_AMPDU_MAX_TXWINSIZE || data[2] <= 0
+ || data[2] > MLAN_AMPDU_MAX_RXWINSIZE) {
+ PRINTM(MERROR, "Incorrect Tx/Rx window size.\n");
+ ret = -EFAULT;
+ goto error;
+ }
+ cfg_11n->param.addba_param.timeout = data[0];
+ cfg_11n->param.addba_param.txwinsize = data[1];
+ cfg_11n->param.addba_param.rxwinsize = data[2];
+ if (data[3] < 0 || data[3] > 1 || data[4] < 0 || data[4] > 1) {
+ PRINTM(MERROR, "Incorrect Tx/Rx amsdu.\n");
+ ret = -EFAULT;
+ goto error;
+ }
+ cfg_11n->param.addba_param.txamsdu = data[3];
+ cfg_11n->param.addba_param.rxamsdu = data[4];
+ PRINTM(MINFO,
+ "SET: timeout:%d txwinsize:%d rxwinsize:%d txamsdu=%d rxamsdu=%d\n",
+ data[0], data[1], data[2], data[3], data[4]);
+ /* Update Add BA parameters in MLAN */
+ req->action = MLAN_ACT_SET;
+ if (MLAN_STATUS_SUCCESS !=
+ woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) {
+ ret = MLAN_STATUS_FAILURE;
+ goto error;
+ }
+ } else {
+ PRINTM(MERROR, "Invalid number of arguments\n");
+ ret = -EINVAL;
+ goto error;
+ }
+
+ error:
+ if (req)
+ kfree(req);
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set/Get Transmit buffer size
+ *
+ * @param priv Pointer to the moal_private driver data struct
+ * @param wrq A pointer to iwreq structure
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_txbuf_cfg(moal_private * priv, struct iwreq *wrq)
+{
+ int buf_size;
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_11n_cfg *cfg_11n = NULL;
+ int ret = 0;
+
+ ENTER();
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_11n_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+ cfg_11n = (mlan_ds_11n_cfg *) req->pbuf;
+ cfg_11n->sub_command = MLAN_OID_11N_CFG_MAX_TX_BUF_SIZE;
+ req->req_id = MLAN_IOCTL_11N_CFG;
+
+ if (wrq->u.data.length == 0) {
+ /* Get Tx buffer size from MLAN */
+ req->action = MLAN_ACT_GET;
+ } else {
+ ret = -EINVAL;
+ PRINTM(MERROR,
+ "Don't support set Tx buffer size after driver loaded!\n");
+ goto done;
+ }
+ if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ buf_size = cfg_11n->param.tx_buf_size;
+ if (copy_to_user(wrq->u.data.pointer, &buf_size, sizeof(buf_size))) {
+ PRINTM(MERROR, "Copy to user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ wrq->u.data.length = 1;
+ done:
+ if (req)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set/Get Host Sleep configuration
+ *
+ * @param priv A pointer to moal_private structure
+ * @param wrq A pointer to iwreq structure
+ * @param invoke_hostcmd MTRUE --invoke HostCmd, otherwise MFALSE
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_hs_cfg(moal_private * priv, struct iwreq *wrq, BOOLEAN invoke_hostcmd)
+{
+ int data[3];
+ int ret = 0;
+ mlan_ds_hs_cfg hscfg;
+ t_u16 action;
+ mlan_bss_info bss_info;
+ int data_length = wrq->u.data.length;
+
+ ENTER();
+
+ memset(data, 0, sizeof(data));
+ memset(&hscfg, 0, sizeof(mlan_ds_hs_cfg));
+
+ if (data_length == 0) {
+ action = MLAN_ACT_GET;
+ } else {
+ action = MLAN_ACT_SET;
+ if (data_length >= 1 && data_length <= 3) {
+ if (copy_from_user
+ (data, wrq->u.data.pointer, sizeof(int) * data_length)) {
+ PRINTM(MERROR, "Copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ } else {
+ PRINTM(MERROR, "Invalid arguments\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ }
+
+ /* HS config is blocked if HS is already activated */
+ if (data_length &&
+ (data[0] != HOST_SLEEP_CFG_CANCEL || invoke_hostcmd == MFALSE)) {
+ memset(&bss_info, 0, sizeof(bss_info));
+ woal_get_bss_info(priv, MOAL_IOCTL_WAIT, &bss_info);
+ if (bss_info.is_hs_configured) {
+ PRINTM(MERROR, "HS already configured\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ }
+
+ /* Do a GET first if some arguments are not provided */
+ if (data_length >= 1 && data_length < 3) {
+ woal_set_get_hs_params(priv, MLAN_ACT_GET, MOAL_IOCTL_WAIT, &hscfg);
+ }
+
+ if (data_length)
+ hscfg.conditions = data[0];
+ if (data_length >= 2)
+ hscfg.gpio = data[1];
+ if (data_length == 3)
+ hscfg.gap = data[2];
+
+ if ((invoke_hostcmd == MTRUE) && (action == MLAN_ACT_SET)) {
+ /* Need to issue an extra IOCTL first to set up parameters */
+ hscfg.is_invoke_hostcmd = MFALSE;
+ if (MLAN_STATUS_SUCCESS !=
+ woal_set_get_hs_params(priv, MLAN_ACT_SET, MOAL_IOCTL_WAIT,
+ &hscfg)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ }
+ hscfg.is_invoke_hostcmd = invoke_hostcmd;
+ if (MLAN_STATUS_SUCCESS !=
+ woal_set_get_hs_params(priv, action, MOAL_IOCTL_WAIT, &hscfg)) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ if (action == MLAN_ACT_GET) {
+ data[0] = hscfg.conditions;
+ data[1] = hscfg.gpio;
+ data[2] = hscfg.gap;
+ wrq->u.data.length = 3;
+ if (copy_to_user
+ (wrq->u.data.pointer, data, sizeof(int) * wrq->u.data.length)) {
+ PRINTM(MERROR, "Copy to user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ }
+ done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set Host Sleep parameters
+ *
+ * @param priv A pointer to moal_private structure
+ * @param wrq A pointer to iwreq structure
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_hs_setpara(moal_private * priv, struct iwreq *wrq)
+{
+ int ret = 0;
+ int data_length = wrq->u.data.length;
+
+ ENTER();
+
+ if (data_length >= 1 && data_length <= 3) {
+ ret = woal_hs_cfg(priv, wrq, MFALSE);
+ goto done;
+ } else {
+ PRINTM(MERROR, "Invalid arguments\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Get/Set inactivity timeout extend
+ *
+ * @param priv A pointer to moal_private structure
+ * @param wrq A pointer to iwreq structure
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_inactivity_timeout_ext(moal_private * priv, struct iwreq *wrq)
+{
+ int data[4];
+ int ret = 0;
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_pm_cfg *pmcfg = NULL;
+ pmlan_ds_inactivity_to inac_to = NULL;
+ int data_length = wrq->u.data.length;
+
+ ENTER();
+
+ memset(data, 0, sizeof(data));
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_pm_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ pmcfg = (mlan_ds_pm_cfg *) req->pbuf;
+ inac_to = &pmcfg->param.inactivity_to;
+ pmcfg->sub_command = MLAN_OID_PM_CFG_INACTIVITY_TO;
+ req->req_id = MLAN_IOCTL_PM_CFG;
+
+ if ((data_length != 0 && data_length != 3 && data_length != 4) ||
+ sizeof(int) * data_length > sizeof(data)) {
+ PRINTM(MERROR, "Invalid number of parameters\n");
+ ret = -EINVAL;
+ goto done;
+ }
+
+ req->action = MLAN_ACT_GET;
+ if (data_length) {
+ if (copy_from_user
+ (data, wrq->u.data.pointer, sizeof(int) * data_length)) {
+ PRINTM(MERROR, "Copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ req->action = MLAN_ACT_SET;
+ inac_to->timeout_unit = data[0];
+ inac_to->unicast_timeout = data[1];
+ inac_to->mcast_timeout = data[2];
+ inac_to->ps_entry_timeout = data[3];
+ }
+
+ if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ /* Copy back current values regardless of GET/SET */
+ data[0] = inac_to->timeout_unit;
+ data[1] = inac_to->unicast_timeout;
+ data[2] = inac_to->mcast_timeout;
+ data[3] = inac_to->ps_entry_timeout;
+
+ if (req->action == MLAN_ACT_GET) {
+ wrq->u.data.length = 4;
+ if (copy_to_user
+ (wrq->u.data.pointer, data, wrq->u.data.length * sizeof(int))) {
+ PRINTM(MERROR, "Copy to user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ }
+
+ done:
+ if (req)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set/Get system clock
+ *
+ * @param priv A pointer to moal_private structure
+ * @param wrq A pointer to iwreq structure
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_ecl_sys_clock(moal_private * priv, struct iwreq *wrq)
+{
+ int data[64];
+ int ret = 0;
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_misc_cfg *cfg = NULL;
+ int data_length = wrq->u.data.length;
+ int i = 0;
+
+ ENTER();
+
+ memset(data, 0, sizeof(data));
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ cfg = (mlan_ds_misc_cfg *) req->pbuf;
+ cfg->sub_command = MLAN_OID_MISC_SYS_CLOCK;
+ req->req_id = MLAN_IOCTL_MISC_CFG;
+
+ if (!data_length)
+ req->action = MLAN_ACT_GET;
+ else if (data_length <= MLAN_MAX_CLK_NUM) {
+ req->action = MLAN_ACT_SET;
+ if (copy_from_user
+ (data, wrq->u.data.pointer, sizeof(int) * data_length)) {
+ PRINTM(MERROR, "Copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ } else {
+ PRINTM(MERROR, "Invalid arguments\n");
+ ret = -EINVAL;
+ goto done;
+ }
+
+ if (req->action == MLAN_ACT_GET) {
+ /* Get configurable clocks */
+ cfg->param.sys_clock.sys_clk_type = MLAN_CLK_CONFIGURABLE;
+ if (MLAN_STATUS_SUCCESS !=
+ woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ /* Current system clock */
+ data[0] = (int) cfg->param.sys_clock.cur_sys_clk;
+ wrq->u.data.length = 1;
+
+ data_length = MIN(cfg->param.sys_clock.sys_clk_num, MLAN_MAX_CLK_NUM);
+
+ /* Configurable clocks */
+ for (i = 0; i < data_length; i++) {
+ data[i + wrq->u.data.length] =
+ (int) cfg->param.sys_clock.sys_clk[i];
+ }
+ wrq->u.data.length += data_length;
+
+ /* Get supported clocks */
+ cfg->param.sys_clock.sys_clk_type = MLAN_CLK_SUPPORTED;
+ if (MLAN_STATUS_SUCCESS !=
+ woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ data_length = MIN(cfg->param.sys_clock.sys_clk_num, MLAN_MAX_CLK_NUM);
+
+ /* Supported clocks */
+ for (i = 0; i < data_length; i++) {
+ data[i + wrq->u.data.length] =
+ (int) cfg->param.sys_clock.sys_clk[i];
+ }
+
+ wrq->u.data.length += data_length;
+
+ if (copy_to_user
+ (wrq->u.data.pointer, data, sizeof(int) * wrq->u.data.length)) {
+ PRINTM(MERROR, "Copy to user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ } else {
+ /* Set configurable clocks */
+ cfg->param.sys_clock.sys_clk_type = MLAN_CLK_CONFIGURABLE;
+ cfg->param.sys_clock.sys_clk_num = MIN(MLAN_MAX_CLK_NUM, data_length);
+ for (i = 0; i < cfg->param.sys_clock.sys_clk_num; i++) {
+ cfg->param.sys_clock.sys_clk[i] = (t_u16) data[i];
+ }
+
+ if (MLAN_STATUS_SUCCESS !=
+ woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ }
+ done:
+ if (req)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set/Get Band and Adhoc-band setting
+ *
+ * @param priv A pointer to moal_private structure
+ * @param wrq A pointer to iwreq structure
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_band_cfg(moal_private * priv, struct iwreq *wrq)
+{
+ int ret = 0;
+ unsigned int i;
+ int data[4];
+ int user_data_len = wrq->u.data.length;
+ t_u32 infra_band = 0;
+ t_u32 adhoc_band = 0;
+ t_u32 adhoc_channel = 0;
+ t_u32 adhoc_chan_bandwidth = 0;
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_radio_cfg *radio_cfg = NULL;
+
+ ENTER();
+
+ if (sizeof(int) * user_data_len > sizeof(data)) {
+ PRINTM(MERROR, "Too many arguments\n");
+ LEAVE();
+ return -EINVAL;
+ }
+
+ if (user_data_len > 0) {
+ if (priv->media_connected == MTRUE) {
+ LEAVE();
+ return -EOPNOTSUPP;
+ }
+ }
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_radio_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto error;
+ }
+ radio_cfg = (mlan_ds_radio_cfg *) req->pbuf;
+ radio_cfg->sub_command = MLAN_OID_BAND_CFG;
+ req->req_id = MLAN_IOCTL_RADIO_CFG;
+
+ if (wrq->u.data.length == 0) {
+ /* Get config_bands, adhoc_start_band and adhoc_channel values from
+ MLAN */
+ req->action = MLAN_ACT_GET;
+ if (MLAN_STATUS_SUCCESS !=
+ woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) {
+ ret = -EFAULT;
+ goto error;
+ }
+ data[0] = radio_cfg->param.band_cfg.config_bands; /* Infra Band */
+ data[1] = radio_cfg->param.band_cfg.adhoc_start_band; /* Adhoc Band */
+ data[2] = radio_cfg->param.band_cfg.adhoc_channel; /* Adhoc
+ Channel */
+ wrq->u.data.length = 3;
+ if (radio_cfg->param.band_cfg.adhoc_start_band & BAND_GN
+ || radio_cfg->param.band_cfg.adhoc_start_band & BAND_AN) {
+ data[3] = radio_cfg->param.band_cfg.sec_chan_offset;
+ wrq->u.data.length = 4;
+ }
+
+ if (copy_to_user
+ (wrq->u.data.pointer, data, sizeof(int) * wrq->u.data.length)) {
+ ret = -EFAULT;
+ goto error;
+ }
+ } else {
+ if (copy_from_user
+ (data, wrq->u.data.pointer, sizeof(int) * user_data_len)) {
+ PRINTM(MERROR, "Copy from user failed\n");
+ ret = -EFAULT;
+ goto error;
+ }
+
+ /* To support only <b/bg/bgn/n> */
+ infra_band = data[0];
+ for (i = 0; i < sizeof(SupportedInfraBand); i++)
+ if (infra_band == SupportedInfraBand[i])
+ break;
+ if (i == sizeof(SupportedInfraBand)) {
+ ret = -EINVAL;
+ goto error;
+ }
+
+ /* Set Adhoc band */
+ if (user_data_len >= 2) {
+ adhoc_band = data[1];
+ for (i = 0; i < sizeof(SupportedAdhocBand); i++)
+ if (adhoc_band == SupportedAdhocBand[i])
+ break;
+ if (i == sizeof(SupportedAdhocBand)) {
+ ret = -EINVAL;
+ goto error;
+ }
+ }
+
+ /* Set Adhoc channel */
+ if (user_data_len >= 3) {
+ adhoc_channel = data[2];
+ if (adhoc_channel == 0) {
+ /* Check if specified adhoc channel is non-zero */
+ ret = -EINVAL;
+ goto error;
+ }
+ }
+ if (user_data_len == 4) {
+ if (!(adhoc_band & (BAND_GN | BAND_AN))) {
+ PRINTM(MERROR,
+ "11n is not enabled for adhoc, can not set HT/VHT channel bandwidth\n");
+ ret = -EINVAL;
+ goto error;
+ }
+ adhoc_chan_bandwidth = data[3];
+ if ((adhoc_chan_bandwidth != CHANNEL_BW_20MHZ) &&
+ (adhoc_chan_bandwidth != CHANNEL_BW_40MHZ_ABOVE) &&
+ (adhoc_chan_bandwidth != CHANNEL_BW_40MHZ_BELOW)
+ ) {
+ PRINTM(MERROR,
+ "Invalid secondary channel bandwidth, only allowed 0, 1, 3 or 4\n");
+ ret = -EINVAL;
+ goto error;
+ }
+ }
+ /* Set config_bands and adhoc_start_band values to MLAN */
+ req->action = MLAN_ACT_SET;
+ radio_cfg->param.band_cfg.config_bands = infra_band;
+ radio_cfg->param.band_cfg.adhoc_start_band = adhoc_band;
+ radio_cfg->param.band_cfg.adhoc_channel = adhoc_channel;
+ radio_cfg->param.band_cfg.sec_chan_offset = adhoc_chan_bandwidth;
+ if (MLAN_STATUS_SUCCESS !=
+ woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) {
+ ret = -EFAULT;
+ goto error;
+ }
+ }
+
+ error:
+ if (req)
+ kfree(req);
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Read/Write adapter registers value
+ *
+ * @param priv A pointer to moal_private structure
+ * @param wrq A pointer to iwreq structure
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_reg_read_write(moal_private * priv, struct iwreq *wrq)
+{
+ int data[3];
+ int ret = 0;
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_reg_mem *reg = NULL;
+ int data_length = wrq->u.data.length;
+
+ ENTER();
+
+ memset(data, 0, sizeof(data));
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_reg_mem));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ reg = (mlan_ds_reg_mem *) req->pbuf;
+ reg->sub_command = MLAN_OID_REG_RW;
+ req->req_id = MLAN_IOCTL_REG_MEM;
+
+ if (data_length == 2) {
+ req->action = MLAN_ACT_GET;
+ } else if (data_length == 3) {
+ req->action = MLAN_ACT_SET;
+ } else {
+ ret = -EINVAL;
+ goto done;
+ }
+ if (copy_from_user(data, wrq->u.data.pointer, sizeof(int) * data_length)) {
+ PRINTM(MERROR, "Copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ reg->param.reg_rw.type = (t_u32) data[0];
+ reg->param.reg_rw.offset = (t_u32) data[1];
+ if (data_length == 3)
+ reg->param.reg_rw.value = (t_u32) data[2];
+
+ if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ if (req->action == MLAN_ACT_GET) {
+ if (copy_to_user
+ (wrq->u.data.pointer, &reg->param.reg_rw.value, sizeof(int))) {
+ PRINTM(MERROR, "Copy to user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ wrq->u.data.length = 1;
+ }
+
+ done:
+ if (req)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Read the EEPROM contents of the card
+ *
+ * @param priv A pointer to moal_private structure
+ * @param wrq A pointer to iwreq structure
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_read_eeprom(moal_private * priv, struct iwreq *wrq)
+{
+ int data[2];
+ int ret = 0;
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_reg_mem *reg = NULL;
+ int data_length = wrq->u.data.length;
+
+ ENTER();
+
+ memset(data, 0, sizeof(data));
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_reg_mem));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ reg = (mlan_ds_reg_mem *) req->pbuf;
+ reg->sub_command = MLAN_OID_EEPROM_RD;
+ req->req_id = MLAN_IOCTL_REG_MEM;
+
+ if (data_length == 2) {
+ req->action = MLAN_ACT_GET;
+ } else {
+ ret = -EINVAL;
+ goto done;
+ }
+ if (copy_from_user(data, wrq->u.data.pointer, sizeof(int) * data_length)) {
+ PRINTM(MERROR, "Copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+
+ reg->param.rd_eeprom.offset = (t_u16) data[0];
+ reg->param.rd_eeprom.byte_count = (t_u16) data[1];
+
+ if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ if (req->action == MLAN_ACT_GET) {
+ wrq->u.data.length = reg->param.rd_eeprom.byte_count;
+ if (copy_to_user
+ (wrq->u.data.pointer, reg->param.rd_eeprom.value,
+ MIN(wrq->u.data.length, MAX_EEPROM_DATA))) {
+ PRINTM(MERROR, "Copy to user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ }
+
+ done:
+ if (req)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Read/Write device memory value
+ *
+ * @param priv A pointer to moal_private structure
+ * @param wrq A pointer to iwreq structure
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_mem_read_write(moal_private * priv, struct iwreq *wrq)
+{
+ t_u32 data[2];
+ int ret = 0;
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_reg_mem *reg_mem = NULL;
+ int data_length = wrq->u.data.length;
+
+ ENTER();
+
+ memset(data, 0, sizeof(data));
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_reg_mem));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ reg_mem = (mlan_ds_reg_mem *) req->pbuf;
+ reg_mem->sub_command = MLAN_OID_MEM_RW;
+ req->req_id = MLAN_IOCTL_REG_MEM;
+
+ if (data_length == 1) {
+ PRINTM(MINFO, "MEM_RW: GET\n");
+ req->action = MLAN_ACT_GET;
+ } else if (data_length == 2) {
+ PRINTM(MINFO, "MEM_RW: SET\n");
+ req->action = MLAN_ACT_SET;
+ } else {
+ ret = -EINVAL;
+ goto done;
+ }
+ if (copy_from_user(data, wrq->u.data.pointer, sizeof(int) * data_length)) {
+ PRINTM(MERROR, "Copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+
+ reg_mem->param.mem_rw.addr = (t_u32) data[0];
+ if (data_length == 2)
+ reg_mem->param.mem_rw.value = (t_u32) data[1];
+
+ PRINTM(MINFO, "MEM_RW: Addr=0x%x, Value=0x%x\n",
+ (int) reg_mem->param.mem_rw.addr, (int) reg_mem->param.mem_rw.value);
+
+ if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ if (req->action == MLAN_ACT_GET) {
+ if (copy_to_user
+ (wrq->u.data.pointer, &reg_mem->param.mem_rw.value, sizeof(int))) {
+ PRINTM(MERROR, "Copy to user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ wrq->u.data.length = 1;
+ }
+
+ done:
+ if (req)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Get LOG
+ *
+ * @param priv A pointer to moal_private structure
+ * @param wrq A pointer to iwreq structure
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_get_log(moal_private * priv, struct iwreq *wrq)
+{
+ int ret = 0;
+ mlan_ds_get_stats stats;
+ char *buf = NULL;
+
+ ENTER();
+
+ PRINTM(MINFO, " GET STATS\n");
+ if (!(buf = kmalloc(GETLOG_BUFSIZE, GFP_KERNEL))) {
+ PRINTM(MERROR, "kmalloc failed!\n");
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ memset(&stats, 0, sizeof(mlan_ds_get_stats));
+ if (MLAN_STATUS_SUCCESS !=
+ woal_get_stats_info(priv, MOAL_IOCTL_WAIT, &stats)) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ if (wrq->u.data.pointer) {
+ sprintf(buf, "\n"
+ "mcasttxframe %u\n"
+ "failed %u\n"
+ "retry %u\n"
+ "multiretry %u\n"
+ "framedup %u\n"
+ "rtssuccess %u\n"
+ "rtsfailure %u\n"
+ "ackfailure %u\n"
+ "rxfrag %u\n"
+ "mcastrxframe %u\n"
+ "fcserror %u\n"
+ "txframe %u\n"
+ "wepicverrcnt-1 %u\n"
+ "wepicverrcnt-2 %u\n"
+ "wepicverrcnt-3 %u\n"
+ "wepicverrcnt-4 %u\n",
+ stats.mcast_tx_frame,
+ stats.failed,
+ stats.retry,
+ stats.multi_retry,
+ stats.frame_dup,
+ stats.rts_success,
+ stats.rts_failure,
+ stats.ack_failure,
+ stats.rx_frag,
+ stats.mcast_rx_frame,
+ stats.fcs_error,
+ stats.tx_frame,
+ stats.wep_icv_error[0],
+ stats.wep_icv_error[1],
+ stats.wep_icv_error[2], stats.wep_icv_error[3]);
+ wrq->u.data.length = strlen(buf) + 1;
+ if (copy_to_user(wrq->u.data.pointer, buf, wrq->u.data.length)) {
+ PRINTM(MERROR, "Copy to user failed\n");
+ ret = -EFAULT;
+ }
+ }
+ done:
+ if (buf)
+ kfree(buf);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Deauthenticate
+ *
+ * @param priv A pointer to moal_private structure
+ * @param wrq A pointer to iwreq structure
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_deauth(moal_private * priv, struct iwreq *wrq)
+{
+ int ret = 0;
+ struct sockaddr saddr;
+
+ ENTER();
+ if (wrq->u.data.length) {
+ /* Deauth mentioned BSSID */
+ if (copy_from_user(&saddr, wrq->u.data.pointer, sizeof(saddr))) {
+ PRINTM(MERROR, "Copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ if (MLAN_STATUS_SUCCESS !=
+ woal_disconnect(priv, MOAL_IOCTL_WAIT, (t_u8 *) saddr.sa_data)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ } else {
+ if (MLAN_STATUS_SUCCESS != woal_disconnect(priv, MOAL_IOCTL_WAIT, NULL))
+ ret = -EFAULT;
+ }
+ done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set/Get TX power configurations
+ *
+ * @param priv A pointer to moal_private structure
+ * @param wrq A pointer to iwreq structure
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_tx_power_cfg(moal_private * priv, struct iwreq *wrq)
+{
+ int data[5], user_data_len;
+ int ret = 0;
+ mlan_bss_info bss_info;
+ mlan_ds_power_cfg *pcfg = NULL;
+ mlan_ioctl_req *req = NULL;
+ ENTER();
+
+ memset(&bss_info, 0, sizeof(bss_info));
+ woal_get_bss_info(priv, MOAL_IOCTL_WAIT, &bss_info);
+
+ memset(data, 0, sizeof(data));
+ user_data_len = wrq->u.data.length;
+
+ if (user_data_len) {
+ if (sizeof(int) * user_data_len > sizeof(data)) {
+ PRINTM(MERROR, "Too many arguments\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ if (copy_from_user
+ (data, wrq->u.data.pointer, sizeof(int) * user_data_len)) {
+ PRINTM(MERROR, "Copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ switch (user_data_len) {
+ case 1:
+ if (data[0] != 0xFF)
+ ret = -EINVAL;
+ break;
+ case 2:
+ case 4:
+ if (data[0] == 0xFF) {
+ ret = -EINVAL;
+ break;
+ }
+ if ((unsigned int) data[1] < bss_info.min_power_level) {
+ PRINTM(MERROR,
+ "The set powercfg rate value %d dBm is out of range (%d dBm-%d dBm)!\n",
+ data[1], (int) bss_info.min_power_level,
+ (int) bss_info.max_power_level);
+ ret = -EINVAL;
+ break;
+ }
+ if (user_data_len == 4) {
+ if (data[1] > data[2]) {
+ PRINTM(MERROR, "Min power should be less than maximum!\n");
+ ret = -EINVAL;
+ break;
+ }
+ if (data[3] < 0) {
+ PRINTM(MERROR, "Step should not less than 0!\n");
+ ret = -EINVAL;
+ break;
+ }
+ if ((unsigned int) data[2] > bss_info.max_power_level) {
+ PRINTM(MERROR,
+ "The set powercfg rate value %d dBm is out of range (%d dBm-%d dBm)!\n",
+ data[2], (int) bss_info.min_power_level,
+ (int) bss_info.max_power_level);
+ ret = -EINVAL;
+ break;
+ }
+ if (data[3] > data[2] - data[1]) {
+ PRINTM(MERROR,
+ "Step should not greater than power difference!\n");
+ ret = -EINVAL;
+ break;
+ }
+ }
+ break;
+ default:
+ ret = -EINVAL;
+ break;
+ }
+ if (ret)
+ goto done;
+ }
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_power_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+ pcfg = (mlan_ds_power_cfg *) req->pbuf;
+ pcfg->sub_command = MLAN_OID_POWER_CFG_EXT;
+ req->req_id = MLAN_IOCTL_POWER_CFG;
+ if (!user_data_len)
+ req->action = MLAN_ACT_GET;
+ else {
+ req->action = MLAN_ACT_SET;
+ pcfg->param.power_ext.len = user_data_len;
+ memcpy((t_u8 *) & pcfg->param.power_ext.power_data, (t_u8 *) data,
+ sizeof(data));
+ }
+ if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ if (!user_data_len) {
+ if (copy_to_user
+ (wrq->u.data.pointer, (t_u8 *) & pcfg->param.power_ext.power_data,
+ sizeof(int) * pcfg->param.power_ext.len)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ wrq->u.data.length = pcfg->param.power_ext.len;
+ }
+ done:
+ if (req)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Get Tx/Rx data rates
+ *
+ * @param priv A pointer to moal_private structure
+ * @param wrq A pointer to iwreq structure
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_get_txrx_rate(moal_private * priv, struct iwreq *wrq)
+{
+ int ret = 0;
+ mlan_ds_rate *rate = NULL;
+ mlan_ioctl_req *req = NULL;
+
+ ENTER();
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_rate));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+ rate = (mlan_ds_rate *) req->pbuf;
+ rate->sub_command = MLAN_OID_GET_DATA_RATE;
+ req->req_id = MLAN_IOCTL_RATE;
+ req->action = MLAN_ACT_GET;
+
+ if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ if (copy_to_user
+ (wrq->u.data.pointer, (t_u8 *) & rate->param.data_rate,
+ sizeof(int) * 2)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ wrq->u.data.length = 2;
+ done:
+ if (req)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Turn on/off the sdio clock
+ *
+ * @param priv A pointer to moal_private structure
+ * @param wrq A pointer to iwreq structure
+ *
+ * @return 0/MLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static int
+woal_sdio_clock_ioctl(moal_private * priv, struct iwreq *wrq)
+{
+ int ret = 0;
+ int data = 2;
+ /* Initialize the clock state as on */
+ static int clock_state = 1;
+
+ ENTER();
+
+ if (wrq->u.data.length) {
+ if (copy_from_user(&data, wrq->u.data.pointer, sizeof(int))) {
+ PRINTM(MERROR, "Copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ } else {
+ wrq->u.data.length = sizeof(clock_state) / sizeof(int);
+ if (copy_to_user(wrq->u.data.pointer, &clock_state, sizeof(int))) {
+ PRINTM(MERROR, "Copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+
+ goto done;
+ }
+ switch (data) {
+ case CMD_DISABLED:
+ PRINTM(MINFO, "SDIO clock is turned off\n");
+ ret = woal_sdio_set_bus_clock(priv->phandle, MFALSE);
+ clock_state = data;
+ break;
+ case CMD_ENABLED:
+ PRINTM(MINFO, "SDIO clock is turned on\n");
+ ret = woal_sdio_set_bus_clock(priv->phandle, MTRUE);
+ clock_state = data;
+ break;
+ default:
+ ret = -EINVAL;
+ PRINTM(MINFO, "sdioclock: wrong parameter\n");
+ break;
+ }
+ done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set/Get beacon interval
+ *
+ * @param priv A pointer to moal_private structure
+ * @param wrq A pointer to iwreq structure
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_beacon_interval(moal_private * priv, struct iwreq *wrq)
+{
+ int ret = 0;
+ mlan_ds_bss *bss = NULL;
+ mlan_ioctl_req *req = NULL;
+ int bcn = 0;
+
+ ENTER();
+
+ if (wrq->u.data.length) {
+ if (copy_from_user(&bcn, wrq->u.data.pointer, sizeof(int))) {
+ PRINTM(MERROR, "Copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ if ((bcn < MLAN_MIN_BEACON_INTERVAL) ||
+ (bcn > MLAN_MAX_BEACON_INTERVAL)) {
+ ret = -EINVAL;
+ goto done;
+ }
+ }
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_bss));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+ bss = (mlan_ds_bss *) req->pbuf;
+ bss->sub_command = MLAN_OID_IBSS_BCN_INTERVAL;
+ req->req_id = MLAN_IOCTL_BSS;
+ if (!wrq->u.data.length)
+ req->action = MLAN_ACT_GET;
+ else {
+ req->action = MLAN_ACT_SET;
+ bss->param.bcn_interval = bcn;
+ }
+
+ if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ if (copy_to_user
+ (wrq->u.data.pointer, (t_u8 *) & bss->param.bcn_interval,
+ sizeof(int))) {
+ ret = -EFAULT;
+ goto done;
+ }
+ wrq->u.data.length = 1;
+ done:
+ if (req)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set/Get ATIM window
+ *
+ * @param priv A pointer to moal_private structure
+ * @param wrq A pointer to iwreq structure
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_atim_window(moal_private * priv, struct iwreq *wrq)
+{
+ int ret = 0;
+ mlan_ds_bss *bss = NULL;
+ mlan_ioctl_req *req = NULL;
+ int atim = 0;
+
+ ENTER();
+
+ if (wrq->u.data.length) {
+ if (copy_from_user(&atim, wrq->u.data.pointer, sizeof(int))) {
+ PRINTM(MERROR, "Copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ if ((atim < 0) || (atim > MLAN_MAX_ATIM_WINDOW)) {
+ ret = -EINVAL;
+ goto done;
+ }
+ }
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_bss));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+ bss = (mlan_ds_bss *) req->pbuf;
+ bss->sub_command = MLAN_OID_IBSS_ATIM_WINDOW;
+ req->req_id = MLAN_IOCTL_BSS;
+ if (!wrq->u.data.length)
+ req->action = MLAN_ACT_GET;
+ else {
+ req->action = MLAN_ACT_SET;
+ bss->param.atim_window = atim;
+ }
+
+ if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ if (copy_to_user
+ (wrq->u.data.pointer, (t_u8 *) & bss->param.atim_window, sizeof(int))) {
+ ret = -EFAULT;
+ goto done;
+ }
+ wrq->u.data.length = 1;
+ done:
+ if (req)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set/Get TX data rate
+ *
+ * @param priv A pointer to moal_private structure
+ * @param wrq A pointer to iwreq structure
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_set_get_txrate(moal_private * priv, struct iwreq *wrq)
+{
+ int ret = 0;
+ mlan_ds_rate *rate = NULL;
+ mlan_ioctl_req *req = NULL;
+ int rateindex = 0;
+
+ ENTER();
+ if (wrq->u.data.length) {
+ if (copy_from_user(&rateindex, wrq->u.data.pointer, sizeof(int))) {
+ PRINTM(MERROR, "Copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ }
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_rate));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ rate = (mlan_ds_rate *) req->pbuf;
+ rate->param.rate_cfg.rate_type = MLAN_RATE_INDEX;
+ rate->sub_command = MLAN_OID_RATE_CFG;
+ req->req_id = MLAN_IOCTL_RATE;
+ if (!wrq->u.data.length)
+ req->action = MLAN_ACT_GET;
+ else {
+ req->action = MLAN_ACT_SET;
+ if (rateindex == AUTO_RATE)
+ rate->param.rate_cfg.is_rate_auto = 1;
+ else {
+ if ((rateindex != MLAN_RATE_INDEX_MCS32) &&
+ ((rateindex < 0) || (rateindex > MLAN_RATE_INDEX_MCS15))) {
+ ret = -EINVAL;
+ goto done;
+ }
+ }
+ rate->param.rate_cfg.rate = rateindex;
+ }
+
+ if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) {
+ ret = -EFAULT;
+ goto done;
+ } else {
+ if (wrq->u.data.length)
+ priv->rate_index = rateindex;
+ }
+ if (!wrq->u.data.length) {
+ if (rate->param.rate_cfg.is_rate_auto)
+ rateindex = AUTO_RATE;
+ else
+ rateindex = rate->param.rate_cfg.rate;
+ wrq->u.data.length = 1;
+ if (copy_to_user(wrq->u.data.pointer, &rateindex, sizeof(int))) {
+ ret = -EFAULT;
+ }
+ }
+ done:
+ if (req)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set/Get region code
+ *
+ * @param priv A pointer to moal_private structure
+ * @param wrq A pointer to iwreq structure
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_set_get_regioncode(moal_private * priv, struct iwreq *wrq)
+{
+ int ret = 0;
+ mlan_ds_misc_cfg *cfg = NULL;
+ mlan_ioctl_req *req = NULL;
+ int region = 0;
+
+ ENTER();
+
+ if (wrq->u.data.length) {
+ if (copy_from_user(&region, wrq->u.data.pointer, sizeof(int))) {
+ PRINTM(MERROR, "Copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ }
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ cfg = (mlan_ds_misc_cfg *) req->pbuf;
+ cfg->sub_command = MLAN_OID_MISC_REGION;
+ req->req_id = MLAN_IOCTL_MISC_CFG;
+ if (!wrq->u.data.length)
+ req->action = MLAN_ACT_GET;
+ else {
+ req->action = MLAN_ACT_SET;
+ cfg->param.region_code = region;
+ }
+
+ if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ if (!wrq->u.data.length) {
+ wrq->u.data.length = 1;
+ if (copy_to_user
+ (wrq->u.data.pointer, &cfg->param.region_code, sizeof(int)))
+ ret = -EFAULT;
+ }
+ done:
+ if (req)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set/Get radio
+ *
+ * @param priv A pointer to moal_private structure
+ * @param wrq A pointer to iwreq structure
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_set_get_radio(moal_private * priv, struct iwreq *wrq)
+{
+ int ret = 0;
+ mlan_bss_info bss_info;
+ int option = 0;
+
+ ENTER();
+
+ memset(&bss_info, 0, sizeof(bss_info));
+
+ if (wrq->u.data.length) {
+ /* Set radio */
+ if (copy_from_user(&option, wrq->u.data.pointer, sizeof(int))) {
+ PRINTM(MERROR, "Copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ if (MLAN_STATUS_SUCCESS != woal_set_radio(priv, (t_u8) option))
+ ret = -EFAULT;
+ } else {
+ /* Get radio status */
+ woal_get_bss_info(priv, MOAL_IOCTL_WAIT, &bss_info);
+ wrq->u.data.length = 1;
+ if (copy_to_user
+ (wrq->u.data.pointer, &bss_info.radio_on,
+ sizeof(bss_info.radio_on))) {
+ PRINTM(MERROR, "Copy to user failed\n");
+ ret = -EFAULT;
+ }
+ }
+ done:
+ LEAVE();
+ return ret;
+}
+
+#ifdef DEBUG_LEVEL1
+/**
+ * @brief Get/Set the bit mask of driver debug message control
+ *
+ * @param priv A pointer to moal_private structure
+ * @param wrq A pointer to wrq structure
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_drv_dbg(moal_private * priv, struct iwreq *wrq)
+{
+ int data[4];
+ int ret = 0;
+
+ ENTER();
+
+ if (!wrq->u.data.length) {
+ data[0] = drvdbg;
+ /* Return the current driver debug bit masks */
+ if (copy_to_user(wrq->u.data.pointer, data, sizeof(int))) {
+ PRINTM(MERROR, "Copy to user failed\n");
+ ret = -EFAULT;
+ goto drvdbgexit;
+ }
+ wrq->u.data.length = 1;
+ } else if (wrq->u.data.length < 3) {
+ /* Get the driver debug bit masks from user */
+ if (copy_from_user
+ (data, wrq->u.data.pointer, sizeof(int) * wrq->u.data.length)) {
+ PRINTM(MERROR, "Copy from user failed\n");
+ ret = -EFAULT;
+ goto drvdbgexit;
+ }
+ drvdbg = data[0];
+ /* Set the driver debug bit masks into mlan */
+ woal_set_drvdbg(priv, drvdbg);
+ } else {
+ PRINTM(MERROR, "Invalid parameter number\n");
+ goto drvdbgexit;
+ }
+
+ printk(KERN_ALERT "drvdbg = 0x%08x\n", drvdbg);
+#ifdef DEBUG_LEVEL2
+ printk(KERN_ALERT "MINFO (%08x) %s\n", MINFO, (drvdbg & MINFO) ? "X" : "");
+ printk(KERN_ALERT "MWARN (%08x) %s\n", MWARN, (drvdbg & MWARN) ? "X" : "");
+ printk(KERN_ALERT "MENTRY (%08x) %s\n", MENTRY,
+ (drvdbg & MENTRY) ? "X" : "");
+#endif
+ printk(KERN_ALERT "MIF_D (%08x) %s\n", MIF_D, (drvdbg & MIF_D) ? "X" : "");
+ printk(KERN_ALERT "MFW_D (%08x) %s\n", MFW_D, (drvdbg & MFW_D) ? "X" : "");
+ printk(KERN_ALERT "MEVT_D (%08x) %s\n", MEVT_D,
+ (drvdbg & MEVT_D) ? "X" : "");
+ printk(KERN_ALERT "MCMD_D (%08x) %s\n", MCMD_D,
+ (drvdbg & MCMD_D) ? "X" : "");
+ printk(KERN_ALERT "MDAT_D (%08x) %s\n", MDAT_D,
+ (drvdbg & MDAT_D) ? "X" : "");
+ printk(KERN_ALERT "MIOCTL (%08x) %s\n", MIOCTL,
+ (drvdbg & MIOCTL) ? "X" : "");
+ printk(KERN_ALERT "MINTR (%08x) %s\n", MINTR, (drvdbg & MINTR) ? "X" : "");
+ printk(KERN_ALERT "MEVENT (%08x) %s\n", MEVENT,
+ (drvdbg & MEVENT) ? "X" : "");
+ printk(KERN_ALERT "MCMND (%08x) %s\n", MCMND, (drvdbg & MCMND) ? "X" : "");
+ printk(KERN_ALERT "MDATA (%08x) %s\n", MDATA, (drvdbg & MDATA) ? "X" : "");
+ printk(KERN_ALERT "MERROR (%08x) %s\n", MERROR,
+ (drvdbg & MERROR) ? "X" : "");
+ printk(KERN_ALERT "MFATAL (%08x) %s\n", MFATAL,
+ (drvdbg & MFATAL) ? "X" : "");
+ printk(KERN_ALERT "MMSG (%08x) %s\n", MMSG, (drvdbg & MMSG) ? "X" : "");
+
+ drvdbgexit:
+ LEAVE();
+ return ret;
+}
+#endif /* DEBUG_LEVEL1 */
+
+/**
+ * @brief Set/Get QoS configuration
+ *
+ * @param priv A pointer to moal_private structure
+ * @param wrq A pointer to iwreq structure
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_set_get_qos_cfg(moal_private * priv, struct iwreq *wrq)
+{
+ int ret = 0;
+ mlan_ds_wmm_cfg *cfg = NULL;
+ mlan_ioctl_req *req = NULL;
+ int data = 0;
+
+ ENTER();
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_wmm_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+ cfg = (mlan_ds_wmm_cfg *) req->pbuf;
+ cfg->sub_command = MLAN_OID_WMM_CFG_QOS;
+ req->req_id = MLAN_IOCTL_WMM_CFG;
+ if (wrq->u.data.length) {
+ if (copy_from_user(&data, wrq->u.data.pointer, sizeof(int))) {
+ PRINTM(MERROR, "Copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ req->action = MLAN_ACT_SET;
+ cfg->param.qos_cfg = (t_u8) data;
+ } else
+ req->action = MLAN_ACT_GET;
+ if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ if (!wrq->u.data.length) {
+ data = (int) cfg->param.qos_cfg;
+ if (copy_to_user(wrq->u.data.pointer, &data, sizeof(int))) {
+ ret = -EFAULT;
+ goto done;
+ }
+ wrq->u.data.length = 1;
+ }
+ done:
+ if (req)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set/Get WWS mode
+ *
+ * @param priv A pointer to moal_private structure
+ * @param wrq A pointer to iwreq structure
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_wws_cfg(moal_private * priv, struct iwreq *wrq)
+{
+ int ret = 0;
+ mlan_ds_misc_cfg *wws = NULL;
+ mlan_ioctl_req *req = NULL;
+ int data = 0;
+
+ ENTER();
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+ wws = (mlan_ds_misc_cfg *) req->pbuf;
+ wws->sub_command = MLAN_OID_MISC_WWS;
+ req->req_id = MLAN_IOCTL_MISC_CFG;
+ if (wrq->u.data.length) {
+ if (copy_from_user(&data, wrq->u.data.pointer, sizeof(int))) {
+ PRINTM(MERROR, "Copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ if (data != CMD_DISABLED && data != CMD_ENABLED) {
+ ret = -EINVAL;
+ goto done;
+ }
+ req->action = MLAN_ACT_SET;
+ wws->param.wws_cfg = data;
+ } else
+ req->action = MLAN_ACT_GET;
+ if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ if (!wrq->u.data.length) {
+ data = wws->param.wws_cfg;
+ if (copy_to_user(wrq->u.data.pointer, &data, sizeof(int))) {
+ ret = -EFAULT;
+ goto done;
+ }
+ wrq->u.data.length = 1;
+ }
+ done:
+ if (req)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set/Get sleep period
+ *
+ * @param priv A pointer to moal_private structure
+ * @param wrq A pointer to iwreq structure
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_sleep_pd(moal_private * priv, struct iwreq *wrq)
+{
+ int ret = 0;
+ mlan_ds_pm_cfg *pm_cfg = NULL;
+ mlan_ioctl_req *req = NULL;
+ int data = 0;
+
+ ENTER();
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_pm_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+ pm_cfg = (mlan_ds_pm_cfg *) req->pbuf;
+ pm_cfg->sub_command = MLAN_OID_PM_CFG_SLEEP_PD;
+ req->req_id = MLAN_IOCTL_PM_CFG;
+ if (wrq->u.data.length) {
+ if (copy_from_user(&data, wrq->u.data.pointer, sizeof(int))) {
+ PRINTM(MERROR, "Copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ if ((data <= MAX_SLEEP_PERIOD && data >= MIN_SLEEP_PERIOD) ||
+ (data == 0)
+ || (data == SLEEP_PERIOD_RESERVED_FF)
+ ) {
+ req->action = MLAN_ACT_SET;
+ pm_cfg->param.sleep_period = data;
+ } else {
+ ret = -EINVAL;
+ goto done;
+ }
+ } else
+ req->action = MLAN_ACT_GET;
+
+ if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ if (!wrq->u.data.length) {
+ data = pm_cfg->param.sleep_period;
+ if (copy_to_user(wrq->u.data.pointer, &data, sizeof(int))) {
+ ret = -EFAULT;
+ goto done;
+ }
+ wrq->u.data.length = 1;
+ }
+
+ done:
+ if (req)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Configure sleep parameters
+ *
+ * @param priv A pointer to moal_private structure
+ * @param req A pointer to ifreq structure
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_sleep_params_ioctl(moal_private * priv, struct iwreq *wrq)
+{
+ int ret = 0;
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_pm_cfg *pm = NULL;
+ mlan_ds_sleep_params *psleep_params = NULL;
+ int data[6] = { 0 }, i;
+#ifdef DEBUG_LEVEL1
+ char err_str[][35] = { {"sleep clock error in ppm"},
+ {"wakeup offset in usec"},
+ {"clock stabilization time in usec"},
+ {"value of reserved for debug"}
+ };
+#endif
+
+ ENTER();
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_pm_cfg));
+ if (req == NULL) {
+ LEAVE();
+ return -ENOMEM;
+ }
+
+ pm = (mlan_ds_pm_cfg *) req->pbuf;
+ pm->sub_command = MLAN_OID_PM_CFG_SLEEP_PARAMS;
+ req->req_id = MLAN_IOCTL_PM_CFG;
+ psleep_params = (pmlan_ds_sleep_params) & pm->param.sleep_params;
+
+ if (wrq->u.data.length == 0) {
+ req->action = MLAN_ACT_GET;
+ } else if (wrq->u.data.length == 6) {
+ if (copy_from_user(data, wrq->u.data.pointer, sizeof(int) *
+ wrq->u.data.length)) {
+ /* copy_from_user failed */
+ PRINTM(MERROR, "S_PARAMS: copy from user failed\n");
+ LEAVE();
+ return -EINVAL;
+ }
+#define MIN_VAL 0x0000
+#define MAX_VAL 0xFFFF
+ for (i = 0; i < 6; i++) {
+ if ((i == 3) || (i == 4)) {
+ /* These two cases are handled below the loop */
+ continue;
+ }
+ if (data[i] < MIN_VAL || data[i] > MAX_VAL) {
+ PRINTM(MERROR, "Invalid %s (0-65535)!\n", err_str[i]);
+ ret = -EINVAL;
+ goto done;
+ }
+ }
+ if (data[3] < 0 || data[3] > 2) {
+ PRINTM(MERROR, "Invalid control periodic calibration (0-2)!\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ if (data[4] < 0 || data[4] > 2) {
+ PRINTM(MERROR, "Invalid control of external sleep clock (0-2)!\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ req->action = MLAN_ACT_SET;
+ psleep_params->error = data[0];
+ psleep_params->offset = data[1];
+ psleep_params->stable_time = data[2];
+ psleep_params->cal_control = data[3];
+ psleep_params->ext_sleep_clk = data[4];
+ psleep_params->reserved = data[5];
+ } else {
+ ret = -EINVAL;
+ goto done;
+ }
+
+ if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ data[0] = psleep_params->error;
+ data[1] = psleep_params->offset;
+ data[2] = psleep_params->stable_time;
+ data[3] = psleep_params->cal_control;
+ data[4] = psleep_params->ext_sleep_clk;
+ data[5] = psleep_params->reserved;
+ wrq->u.data.length = 6;
+
+ if (copy_to_user(wrq->u.data.pointer, data, sizeof(int) *
+ wrq->u.data.length)) {
+ PRINTM(MERROR, "QCONFIG: copy to user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+
+ done:
+ if (req)
+ kfree(req);
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set/get user provisioned local power constraint
+ *
+ * @param priv A pointer to moal_private structure
+ * @param wrq A pointer to iwreq structure
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_set_get_11h_local_pwr_constraint(moal_private * priv, struct iwreq *wrq)
+{
+ int ret = 0, data = 0;
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_11h_cfg *ds_11hcfg = NULL;
+
+ ENTER();
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_11h_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+ ds_11hcfg = (mlan_ds_11h_cfg *) req->pbuf;
+ if (wrq->u.data.length) {
+ if (copy_from_user(&data, wrq->u.data.pointer, sizeof(int))) {
+ PRINTM(MINFO, "Copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ ds_11hcfg->param.usr_local_power_constraint = (t_s8) data;
+ req->action = MLAN_ACT_SET;
+ } else
+ req->action = MLAN_ACT_GET;
+
+ ds_11hcfg->sub_command = MLAN_OID_11H_LOCAL_POWER_CONSTRAINT;
+ req->req_id = MLAN_IOCTL_11H_CFG;
+
+ if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ /* Copy response to user */
+ if (req->action == MLAN_ACT_GET) {
+ data = (int) ds_11hcfg->param.usr_local_power_constraint;
+ if (copy_to_user(wrq->u.data.pointer, &data, sizeof(int))) {
+ PRINTM(MINFO, "Copy to user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ wrq->u.data.length = 1;
+ }
+
+ done:
+ if (req)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set/get HT stream configurations
+ *
+ * @param priv A pointer to moal_private structure
+ * @param wrq A pointer to iwreq structure
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_ht_stream_cfg_ioctl(moal_private * priv, struct iwreq *wrq)
+{
+ int ret = 0, data = 0;
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_11n_cfg *cfg = NULL;
+
+ ENTER();
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_11n_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+ cfg = (mlan_ds_11n_cfg *) req->pbuf;
+ if (wrq->u.data.length) {
+ if (copy_from_user(&data, wrq->u.data.pointer, sizeof(int))) {
+ PRINTM(MINFO, "Copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ if (data != HT_STREAM_MODE_1X1 && data != HT_STREAM_MODE_2X2) {
+ PRINTM(MINFO, "Invalid argument\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ cfg->param.stream_cfg = data;
+ req->action = MLAN_ACT_SET;
+ } else
+ req->action = MLAN_ACT_GET;
+
+ cfg->sub_command = MLAN_OID_11N_CFG_STREAM_CFG;
+ req->req_id = MLAN_IOCTL_11N_CFG;
+
+ if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ /* Copy response to user */
+ data = (int) cfg->param.stream_cfg;
+ if (copy_to_user(wrq->u.data.pointer, &data, sizeof(int))) {
+ PRINTM(MINFO, "Copy to user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ wrq->u.data.length = 1;
+
+ done:
+ if (req)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set/get MAC control configuration
+ *
+ * @param priv A pointer to moal_private structure
+ * @param wrq A pointer to iwreq structure
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_mac_control_ioctl(moal_private * priv, struct iwreq *wrq)
+{
+ int ret = 0, data = 0;
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_misc_cfg *cfg = NULL;
+
+ ENTER();
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+ cfg = (mlan_ds_misc_cfg *) req->pbuf;
+ if (wrq->u.data.length) {
+ if (copy_from_user(&data, wrq->u.data.pointer, sizeof(int))) {
+ PRINTM(MINFO, "Copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ /* Validation will be done later */
+ cfg->param.mac_ctrl = data;
+ req->action = MLAN_ACT_SET;
+ } else
+ req->action = MLAN_ACT_GET;
+
+ cfg->sub_command = MLAN_OID_MISC_MAC_CONTROL;
+ req->req_id = MLAN_IOCTL_MISC_CFG;
+
+ if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ /* Copy response to user */
+ data = (int) cfg->param.mac_ctrl;
+ if (copy_to_user(wrq->u.data.pointer, &data, sizeof(int))) {
+ PRINTM(MINFO, "Copy to user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ wrq->u.data.length = 1;
+
+ done:
+ if (req)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Get thermal reading
+ *
+ * @param priv A pointer to moal_private structure
+ * @param wrq A pointer to iwreq structure
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_thermal_ioctl(moal_private * priv, struct iwreq *wrq)
+{
+ int ret = 0, data = 0;
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_misc_cfg *cfg = NULL;
+
+ ENTER();
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+ cfg = (mlan_ds_misc_cfg *) req->pbuf;
+ if (wrq->u.data.length) {
+ PRINTM(MERROR, "Set is not supported for this command\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ req->action = MLAN_ACT_GET;
+
+ cfg->sub_command = MLAN_OID_MISC_THERMAL;
+ req->req_id = MLAN_IOCTL_MISC_CFG;
+
+ if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ /* Copy response to user */
+ data = (int) cfg->param.thermal;
+ if (copy_to_user(wrq->u.data.pointer, &data, sizeof(int))) {
+ PRINTM(MINFO, "Copy to user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ wrq->u.data.length = 1;
+
+ done:
+ if (req)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+#if defined(REASSOCIATION)
+/**
+ * @brief Set/Get reassociation settings
+ *
+ * @param priv A pointer to moal_private structure
+ * @param wrq A pointer to iwreq structure
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_set_get_reassoc(moal_private * priv, struct iwreq *wrq)
+{
+ moal_handle *handle = priv->phandle;
+ int ret = 0;
+ int data = 0;
+
+ ENTER();
+
+ if (wrq->u.data.length) {
+ if (copy_from_user(&data, wrq->u.data.pointer, sizeof(int))) {
+ PRINTM(MERROR, "Copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ if (data == 0) {
+ handle->reassoc_on &= ~MBIT(priv->bss_index);
+ priv->reassoc_on = MFALSE;
+ priv->reassoc_required = MFALSE;
+ if (!handle->reassoc_on && handle->is_reassoc_timer_set == MTRUE) {
+ woal_cancel_timer(&handle->reassoc_timer);
+ handle->is_reassoc_timer_set = MFALSE;
+ }
+ } else {
+ handle->reassoc_on |= MBIT(priv->bss_index);
+ priv->reassoc_on = MTRUE;
+ }
+ } else {
+ data = (int) (priv->reassoc_on);
+ if (copy_to_user(wrq->u.data.pointer, &data, sizeof(int))) {
+ ret = -EFAULT;
+ goto done;
+ }
+ wrq->u.data.length = 1;
+ }
+
+ done:
+ LEAVE();
+ return ret;
+}
+#endif /* REASSOCIATION */
+
+/**
+ * @brief implement WMM enable command
+ *
+ * @param priv Pointer to the moal_private driver data struct
+ * @param wrq Pointer to user data
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_wmm_enable_ioctl(moal_private * priv, struct iwreq *wrq)
+{
+ int ret = 0;
+ mlan_ds_wmm_cfg *wmm = NULL;
+ mlan_ioctl_req *req = NULL;
+ int data = 0;
+
+ ENTER();
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_wmm_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+ wmm = (mlan_ds_wmm_cfg *) req->pbuf;
+ req->req_id = MLAN_IOCTL_WMM_CFG;
+ wmm->sub_command = MLAN_OID_WMM_CFG_ENABLE;
+
+ if (wrq->u.data.length) {
+ /* Set WMM configuration */
+ if (copy_from_user(&data, wrq->u.data.pointer, sizeof(int))) {
+ PRINTM(MERROR, "Copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ if ((data < CMD_DISABLED) || (data > CMD_ENABLED)) {
+ ret = -EINVAL;
+ goto done;
+ }
+ req->action = MLAN_ACT_SET;
+ if (data == CMD_DISABLED)
+ wmm->param.wmm_enable = MFALSE;
+ else
+ wmm->param.wmm_enable = MTRUE;
+ } else {
+ /* Get WMM status */
+ req->action = MLAN_ACT_GET;
+ }
+
+ if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ if (wrq->u.data.pointer) {
+ if (copy_to_user
+ (wrq->u.data.pointer, &wmm->param.wmm_enable,
+ sizeof(wmm->param.wmm_enable))) {
+ PRINTM(MERROR, "Copy to user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ wrq->u.data.length = 1;
+ }
+ done:
+ if (req)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Implement 802.11D enable command
+ *
+ * @param priv Pointer to the moal_private driver data struct
+ * @param wrq Pointer to user data
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_11d_enable_ioctl(moal_private * priv, struct iwreq *wrq)
+{
+ int ret = 0;
+ mlan_ds_11d_cfg *pcfg_11d = NULL;
+ mlan_ioctl_req *req = NULL;
+ int data = 0;
+
+ ENTER();
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_11d_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ pcfg_11d = (mlan_ds_11d_cfg *) req->pbuf;
+ req->req_id = MLAN_IOCTL_11D_CFG;
+ pcfg_11d->sub_command = MLAN_OID_11D_CFG_ENABLE;
+ if (wrq->u.data.length) {
+ /* Set 11D configuration */
+ if (copy_from_user(&data, wrq->u.data.pointer, sizeof(int))) {
+ PRINTM(MERROR, "Copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ if ((data < CMD_DISABLED) || (data > CMD_ENABLED)) {
+ ret = -EINVAL;
+ goto done;
+ }
+ if (data == CMD_DISABLED)
+ pcfg_11d->param.enable_11d = MFALSE;
+ else
+ pcfg_11d->param.enable_11d = MTRUE;
+ req->action = MLAN_ACT_SET;
+ } else {
+ req->action = MLAN_ACT_GET;
+ }
+
+ if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ if (wrq->u.data.pointer) {
+ if (copy_to_user
+ (wrq->u.data.pointer, &pcfg_11d->param.enable_11d,
+ sizeof(pcfg_11d->param.enable_11d))) {
+ PRINTM(MERROR, "Copy to user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ wrq->u.data.length = 1;
+ }
+ done:
+ if (req)
+ kfree(req);
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Implement 802.11D clear chan table command
+ *
+ * @param priv Pointer to the moal_private driver data struct
+ * @param wrq Pointer to user data
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_11d_clr_chan_table(moal_private * priv, struct iwreq *wrq)
+{
+ int ret = 0;
+ mlan_ds_11d_cfg *pcfg_11d = NULL;
+ mlan_ioctl_req *req = NULL;
+
+ ENTER();
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_11d_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ pcfg_11d = (mlan_ds_11d_cfg *) req->pbuf;
+ req->req_id = MLAN_IOCTL_11D_CFG;
+ pcfg_11d->sub_command = MLAN_OID_11D_CLR_CHAN_TABLE;
+ req->action = MLAN_ACT_SET;
+
+ if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ done:
+ if (req)
+ kfree(req);
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Control WPS Session Enable/Disable
+ *
+ * @param priv Pointer to the moal_private driver data struct
+ * @param wrq Pointer to user data
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_wps_cfg_ioctl(moal_private * priv, struct iwreq *wrq)
+{
+ int ret = 0;
+ mlan_ds_wps_cfg *pwps = NULL;
+ mlan_ioctl_req *req = NULL;
+ char buf[8];
+ struct iwreq *wreq = (struct iwreq *) wrq;
+
+ ENTER();
+
+ PRINTM(MINFO, "WOAL_WPS_SESSION\n");
+
+ memset(buf, 0, sizeof(buf));
+ if (copy_from_user(buf, wreq->u.data.pointer,
+ MIN(sizeof(buf) - 1, wreq->u.data.length))) {
+ PRINTM(MERROR, "Copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_wps_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ pwps = (mlan_ds_wps_cfg *) req->pbuf;
+ req->req_id = MLAN_IOCTL_WPS_CFG;
+ req->action = MLAN_ACT_SET;
+ pwps->sub_command = MLAN_OID_WPS_CFG_SESSION;
+ if (buf[0] == 1)
+ pwps->param.wps_session = MLAN_WPS_CFG_SESSION_START;
+ else
+ pwps->param.wps_session = MLAN_WPS_CFG_SESSION_END;
+
+ if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ done:
+ if (req)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set WPA passphrase and SSID
+ *
+ * @param priv A pointer to moal_private structure
+ * @param wrq A pointer to user data
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_passphrase(moal_private * priv, struct iwreq *wrq)
+{
+ t_u16 len = 0;
+ static char buf[256];
+ char *begin, *end, *opt;
+ int ret = 0, action = -1, i;
+ mlan_ds_sec_cfg *sec = NULL;
+ mlan_ioctl_req *req = NULL;
+ t_u8 zero_mac[] = { 0, 0, 0, 0, 0, 0 };
+ t_u8 *mac = NULL;
+
+ ENTER();
+
+ if (!wrq->u.data.length || wrq->u.data.length >= sizeof(buf)) {
+ PRINTM(MERROR, "Argument missing or too long for setpassphrase\n");
+ ret = -EINVAL;
+ goto done;
+ }
+
+ if (copy_from_user(buf, wrq->u.data.pointer, wrq->u.data.length)) {
+ PRINTM(MERROR, "Copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ buf[wrq->u.data.length] = '\0';
+
+ /* Parse the buf to get the cmd_action */
+ begin = buf;
+ end = woal_strsep(&begin, ';', '/');
+ if (end)
+ action = woal_atox(end);
+ if (action < 0 || action > 2 || end[1] != '\0') {
+ PRINTM(MERROR, "Invalid action argument %s\n", end);
+ ret = -EINVAL;
+ goto done;
+ }
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_sec_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+ sec = (mlan_ds_sec_cfg *) req->pbuf;
+ sec->sub_command = MLAN_OID_SEC_CFG_PASSPHRASE;
+ req->req_id = MLAN_IOCTL_SEC_CFG;
+ if (action == 0)
+ req->action = MLAN_ACT_GET;
+ else
+ req->action = MLAN_ACT_SET;
+ while (begin) {
+ end = woal_strsep(&begin, ';', '/');
+ opt = woal_strsep(&end, '=', '/');
+ if (!opt || !end || !end[0]) {
+ PRINTM(MERROR, "Invalid option\n");
+ ret = -EINVAL;
+ break;
+ } else if (!strnicmp(opt, "ssid", strlen(opt))) {
+ if (strlen(end) > MLAN_MAX_SSID_LENGTH) {
+ PRINTM(MERROR, "SSID length exceeds max length\n");
+ ret = -EFAULT;
+ break;
+ }
+ sec->param.passphrase.ssid.ssid_len = strlen(end);
+ strncpy((char *) sec->param.passphrase.ssid.ssid, end, strlen(end));
+ PRINTM(MINFO, "ssid=%s, len=%d\n", sec->param.passphrase.ssid.ssid,
+ (int) sec->param.passphrase.ssid.ssid_len);
+ } else if (!strnicmp(opt, "bssid", strlen(opt))) {
+ woal_mac2u8((t_u8 *) & sec->param.passphrase.bssid, end);
+ } else if (!strnicmp(opt, "psk", strlen(opt)) &&
+ req->action == MLAN_ACT_SET) {
+ if (strlen(end) != MLAN_PMK_HEXSTR_LENGTH) {
+ PRINTM(MERROR, "Invalid PMK length\n");
+ ret = -EINVAL;
+ break;
+ }
+ woal_ascii2hex((t_u8 *) (sec->param.passphrase.psk.pmk.pmk), end,
+ MLAN_PMK_HEXSTR_LENGTH / 2);
+ sec->param.passphrase.psk_type = MLAN_PSK_PMK;
+ } else if (!strnicmp(opt, "passphrase", strlen(opt)) &&
+ req->action == MLAN_ACT_SET) {
+ if (strlen(end) < MLAN_MIN_PASSPHRASE_LENGTH ||
+ strlen(end) > MLAN_MAX_PASSPHRASE_LENGTH) {
+ PRINTM(MERROR, "Invalid length for passphrase\n");
+ ret = -EINVAL;
+ break;
+ }
+ sec->param.passphrase.psk_type = MLAN_PSK_PASSPHRASE;
+ strncpy(sec->param.passphrase.psk.passphrase.passphrase, end,
+ sizeof(sec->param.passphrase.psk.passphrase.passphrase));
+ sec->param.passphrase.psk.passphrase.passphrase_len = strlen(end);
+ PRINTM(MINFO, "passphrase=%s, len=%d\n",
+ sec->param.passphrase.psk.passphrase.passphrase,
+ (int) sec->param.passphrase.psk.passphrase.passphrase_len);
+ } else {
+ PRINTM(MERROR, "Invalid option %s\n", opt);
+ ret = -EINVAL;
+ break;
+ }
+ }
+ if (ret)
+ goto done;
+
+ if (action == 2)
+ sec->param.passphrase.psk_type = MLAN_PSK_CLEAR;
+ if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ if (action == 0) {
+ memset(buf, 0, sizeof(buf));
+ if (sec->param.passphrase.ssid.ssid_len) {
+ len += sprintf(buf + len, "ssid:");
+ memcpy(buf + len, sec->param.passphrase.ssid.ssid,
+ sec->param.passphrase.ssid.ssid_len);
+ len += sec->param.passphrase.ssid.ssid_len;
+ len += sprintf(buf + len, " ");
+ }
+ if (memcmp(&sec->param.passphrase.bssid, zero_mac, sizeof(zero_mac))) {
+ mac = (t_u8 *) & sec->param.passphrase.bssid;
+ len += sprintf(buf + len, "bssid:");
+ for (i = 0; i < ETH_ALEN - 1; ++i)
+ len += sprintf(buf + len, "%02x:", mac[i]);
+ len += sprintf(buf + len, "%02x ", mac[i]);
+ }
+ if (sec->param.passphrase.psk_type == MLAN_PSK_PMK) {
+ len += sprintf(buf + len, "psk:");
+ for (i = 0; i < MLAN_MAX_KEY_LENGTH; ++i)
+ len +=
+ sprintf(buf + len, "%02x",
+ sec->param.passphrase.psk.pmk.pmk[i]);
+ len += sprintf(buf + len, "\n");
+ }
+ if (sec->param.passphrase.psk_type == MLAN_PSK_PASSPHRASE) {
+ len +=
+ sprintf(buf + len, "passphrase:%s \n",
+ sec->param.passphrase.psk.passphrase.passphrase);
+ }
+ if (wrq->u.data.pointer) {
+ if (copy_to_user(wrq->u.data.pointer, buf, MIN(len, sizeof(buf)))) {
+ PRINTM(MERROR, "Copy to user failed, len %d\n", len);
+ ret = -EFAULT;
+ goto done;
+ }
+ wrq->u.data.length = len;
+ }
+
+ }
+ done:
+ if (req)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Get esupp mode
+ *
+ * @param priv A pointer to moal_private structure
+ * @param wrq A pointer to iwreq structure
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_get_esupp_mode(moal_private * priv, struct iwreq *wrq)
+{
+ int ret = 0;
+ mlan_ds_sec_cfg *sec = NULL;
+ mlan_ioctl_req *req = NULL;
+
+ ENTER();
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_sec_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+ sec = (mlan_ds_sec_cfg *) req->pbuf;
+ sec->sub_command = MLAN_OID_SEC_CFG_ESUPP_MODE;
+ req->req_id = MLAN_IOCTL_SEC_CFG;
+ req->action = MLAN_ACT_GET;
+
+ if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ if (copy_to_user
+ (wrq->u.data.pointer, (t_u8 *) & sec->param.esupp_mode,
+ sizeof(int) * 3)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ wrq->u.data.length = 3;
+ done:
+ if (req)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/** AES key length */
+#define AES_KEY_LEN 16
+/**
+ * @brief Adhoc AES control
+ *
+ * @param priv A pointer to moal_private structure
+ * @param wrq A pointer to user data
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_adhoc_aes_ioctl(moal_private * priv, struct iwreq *wrq)
+{
+ static char buf[256];
+ int ret = 0, action = -1;
+ unsigned int i;
+ t_u8 key_ascii[32];
+ t_u8 key_hex[16];
+ t_u8 *tmp;
+ mlan_bss_info bss_info;
+ mlan_ds_sec_cfg *sec = NULL;
+ mlan_ioctl_req *req = NULL;
+ t_u8 bcast_addr[] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
+
+ ENTER();
+
+ memset(key_ascii, 0x00, sizeof(key_ascii));
+ memset(key_hex, 0x00, sizeof(key_hex));
+
+ /* Get current BSS information */
+ memset(&bss_info, 0, sizeof(bss_info));
+ woal_get_bss_info(priv, MOAL_IOCTL_WAIT, &bss_info);
+ if (bss_info.bss_mode != MLAN_BSS_MODE_IBSS ||
+ bss_info.media_connected == MTRUE) {
+ PRINTM(MERROR, "STA is connected or not in IBSS mode.\n");
+ ret = -EOPNOTSUPP;
+ goto done;
+ }
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_sec_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ if (wrq->u.data.length) {
+ if (wrq->u.data.length >= sizeof(buf)) {
+ PRINTM(MERROR, "Too many arguments\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ if (copy_from_user(buf, wrq->u.data.pointer, wrq->u.data.length)) {
+ PRINTM(MERROR, "Copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ buf[wrq->u.data.length] = '\0';
+
+ if (wrq->u.data.length == 1) {
+ /* Get Adhoc AES Key */
+ req->req_id = MLAN_IOCTL_SEC_CFG;
+ req->action = MLAN_ACT_GET;
+ sec = (mlan_ds_sec_cfg *) req->pbuf;
+ sec->sub_command = MLAN_OID_SEC_CFG_ENCRYPT_KEY;
+ sec->param.encrypt_key.key_len = AES_KEY_LEN;
+ sec->param.encrypt_key.key_index = MLAN_KEY_INDEX_UNICAST;
+ if (MLAN_STATUS_SUCCESS !=
+ woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ memcpy(key_hex, sec->param.encrypt_key.key_material,
+ sizeof(key_hex));
+ HEXDUMP("Adhoc AES Key (HEX)", key_hex, sizeof(key_hex));
+
+ wrq->u.data.length = sizeof(key_ascii) + 1;
+
+ tmp = key_ascii;
+ for (i = 0; i < sizeof(key_hex); i++)
+ tmp += sprintf((char *) tmp, "%02x", key_hex[i]);
+ } else if (wrq->u.data.length >= 2) {
+ /* Parse the buf to get the cmd_action */
+ action = woal_atox(&buf[0]);
+ if (action < 1 || action > 2) {
+ PRINTM(MERROR, "Invalid action argument %d\n", action);
+ ret = -EINVAL;
+ goto done;
+ }
+
+ req->req_id = MLAN_IOCTL_SEC_CFG;
+ req->action = MLAN_ACT_SET;
+ sec = (mlan_ds_sec_cfg *) req->pbuf;
+ sec->sub_command = MLAN_OID_SEC_CFG_ENCRYPT_KEY;
+
+ if (action == 1) {
+ /* Set Adhoc AES Key */
+ memcpy(key_ascii, &buf[2], sizeof(key_ascii));
+ woal_ascii2hex(key_hex, (char *) key_ascii, sizeof(key_hex));
+ HEXDUMP("Adhoc AES Key (HEX)", key_hex, sizeof(key_hex));
+
+ sec->param.encrypt_key.key_len = AES_KEY_LEN;
+ sec->param.encrypt_key.key_index = MLAN_KEY_INDEX_UNICAST;
+ sec->param.encrypt_key.key_flags =
+ KEY_FLAG_SET_TX_KEY | KEY_FLAG_GROUP_KEY;
+ memcpy(sec->param.encrypt_key.mac_addr, (u8 *) bcast_addr,
+ ETH_ALEN);
+ memcpy(sec->param.encrypt_key.key_material, key_hex,
+ sec->param.encrypt_key.key_len);
+
+ if (MLAN_STATUS_SUCCESS !=
+ woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ } else if (action == 2) {
+ /* Clear Adhoc AES Key */
+ sec->param.encrypt_key.key_len = AES_KEY_LEN;
+ sec->param.encrypt_key.key_index = MLAN_KEY_INDEX_UNICAST;
+ sec->param.encrypt_key.key_flags = KEY_FLAG_REMOVE_KEY;
+ memcpy(sec->param.encrypt_key.mac_addr, (u8 *) bcast_addr,
+ ETH_ALEN);
+ memset(sec->param.encrypt_key.key_material, 0,
+ sizeof(sec->param.encrypt_key.key_material));
+
+ if (MLAN_STATUS_SUCCESS !=
+ woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ } else {
+ PRINTM(MERROR, "Invalid argument\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ }
+
+ HEXDUMP("Adhoc AES Key (ASCII)", key_ascii, sizeof(key_ascii));
+ wrq->u.data.length = sizeof(key_ascii);
+ if (wrq->u.data.pointer) {
+ if (copy_to_user(wrq->u.data.pointer, &key_ascii,
+ sizeof(key_ascii))) {
+ PRINTM(MERROR, "copy_to_user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ }
+ }
+
+ done:
+ if (req)
+ kfree(req);
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief arpfilter ioctl function
+ *
+ * @param priv A pointer to moal_private structure
+ * @param wrq A pointer to iwreq structure
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_arp_filter(moal_private * priv, struct iwreq *wrq)
+{
+ int ret = 0;
+ mlan_ds_misc_cfg *misc = NULL;
+ mlan_ioctl_req *req = NULL;
+
+ ENTER();
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+ misc = (mlan_ds_misc_cfg *) req->pbuf;
+ misc->sub_command = MLAN_OID_MISC_GEN_IE;
+ req->req_id = MLAN_IOCTL_MISC_CFG;
+ req->action = MLAN_ACT_SET;
+ misc->param.gen_ie.type = MLAN_IE_TYPE_ARP_FILTER;
+ misc->param.gen_ie.len = wrq->u.data.length;
+
+ /* get the whole command from user */
+ if (copy_from_user
+ (misc->param.gen_ie.ie_data, wrq->u.data.pointer, wrq->u.data.length)) {
+ PRINTM(MERROR, "copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+
+ if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ done:
+ if (req)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set/get IP address
+ *
+ * @param priv A pointer to moal_private structure
+ * @param wrq A pointer to iwreq structure
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_set_get_ip_addr(moal_private * priv, struct iwreq *wrq)
+{
+ char buf[IPADDR_MAX_BUF];
+ struct iwreq *wreq = (struct iwreq *) wrq;
+ mlan_ioctl_req *ioctl_req = NULL;
+ mlan_ds_misc_cfg *misc = NULL;
+ int ret = 0, op_code = 0, data_length = wrq->u.data.length;
+
+ ENTER();
+
+ memset(buf, 0, IPADDR_MAX_BUF);
+ ioctl_req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
+ if (ioctl_req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+ misc = (mlan_ds_misc_cfg *) ioctl_req->pbuf;
+
+ if (data_length <= 1) { /* GET */
+ ioctl_req->action = MLAN_ACT_GET;
+ } else {
+ if (copy_from_user(buf, wreq->u.data.pointer,
+ MIN(IPADDR_MAX_BUF - 1, wreq->u.data.length))) {
+ PRINTM(MERROR, "Copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ /* Make sure we have the operation argument */
+ if (data_length > 2 && buf[1] != ';') {
+ PRINTM(MERROR, "No operation argument. Separate with ';'\n");
+ ret = -EINVAL;
+ goto done;
+ } else {
+ buf[1] = '\0';
+ }
+ ioctl_req->action = MLAN_ACT_SET;
+ /* only one IP is supported in current firmware */
+ memset(misc->param.ipaddr_cfg.ip_addr[0], 0, IPADDR_LEN);
+ in4_pton(&buf[2], MIN((IPADDR_MAX_BUF - 3), (wreq->u.data.length - 2)),
+ misc->param.ipaddr_cfg.ip_addr[0], ' ', NULL);
+ /* only one IP is supported in current firmware */
+ misc->param.ipaddr_cfg.ip_addr_num = 1;
+ misc->param.ipaddr_cfg.ip_addr_type = IPADDR_TYPE_IPV4;
+ }
+ if (woal_atoi(&op_code, &buf[0]) != MLAN_STATUS_SUCCESS) {
+ ret = -EINVAL;
+ goto done;
+ }
+ misc->param.ipaddr_cfg.op_code = (t_u32) op_code;
+ ioctl_req->req_id = MLAN_IOCTL_MISC_CFG;
+ misc->sub_command = MLAN_OID_MISC_IP_ADDR;
+
+ /* Send ioctl to mlan */
+ if (MLAN_STATUS_SUCCESS !=
+ woal_request_ioctl(priv, ioctl_req, MOAL_IOCTL_WAIT)) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ if (ioctl_req->action == MLAN_ACT_GET) {
+ snprintf(buf, IPADDR_MAX_BUF, "%d;%d.%d.%d.%d",
+ misc->param.ipaddr_cfg.op_code,
+ misc->param.ipaddr_cfg.ip_addr[0][0],
+ misc->param.ipaddr_cfg.ip_addr[0][1],
+ misc->param.ipaddr_cfg.ip_addr[0][2],
+ misc->param.ipaddr_cfg.ip_addr[0][3]);
+ wrq->u.data.length = IPADDR_MAX_BUF;
+ if (copy_to_user(wrq->u.data.pointer, buf, IPADDR_MAX_BUF)) {
+ PRINTM(MERROR, "Copy to user failed\n");
+ ret = -EFAULT;
+ }
+ }
+
+ done:
+ if (ioctl_req)
+ kfree(ioctl_req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set/Get Transmit beamforming capabilities
+ *
+ * @param priv A pointer to moal_private structure
+ * @param wrq A pointer to iwreq structure
+ *
+ * @return 0 -- success, otherwise fail
+ */
+static int
+woal_tx_bf_cap_ioctl(moal_private * priv, struct iwreq *wrq)
+{
+ int ret = 0, data_length = wrq->u.data.length;
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_11n_cfg *bf_cfg = NULL;
+ int bf_cap = 0;
+
+ ENTER();
+
+ if (data_length > 1) {
+ PRINTM(MERROR, "Invalid no of arguments!\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ /* Allocate an IOCTL request buffer */
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_11n_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ /* Fill request buffer */
+ bf_cfg = (mlan_ds_11n_cfg *) req->pbuf;
+ req->req_id = MLAN_IOCTL_11N_CFG;
+ bf_cfg->sub_command = MLAN_OID_11N_CFG_TX_BF_CAP;
+ req->action = MLAN_ACT_GET;
+ if (data_length) { /* SET */
+ if (copy_from_user(&bf_cap, wrq->u.data.pointer, sizeof(int))) {
+ PRINTM(MERROR, "copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ bf_cfg->param.tx_bf_cap = bf_cap;
+ req->action = MLAN_ACT_SET;
+ }
+
+ /* Send IOCTL request to MLAN */
+ if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ bf_cap = bf_cfg->param.tx_bf_cap;
+ if (copy_to_user(wrq->u.data.pointer, &bf_cap, sizeof(int))) {
+ ret = -EFAULT;
+ goto done;
+ }
+ wrq->u.data.length = 1;
+
+ done:
+ if (req)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/* Maximum input output characters in group WOAL_SET_GET_256_CHAR */
+#define MAX_IN_OUT_CHAR 256
+/** Tx BF Global conf argument index */
+#define BF_ENABLE_PARAM 1
+#define SOUND_ENABLE_PARAM 2
+#define FB_TYPE_PARAM 3
+#define SNR_THRESHOLD_PARAM 4
+#define SOUND_INTVL_PARAM 5
+#define BF_MODE_PARAM 6
+#define MAX_TX_BF_GLOBAL_ARGS 6
+#define BF_CFG_ACT_GET 0
+#define BF_CFG_ACT_SET 1
+
+/**
+ * @brief Set/Get Transmit beamforming configuration
+ *
+ * @param priv A pointer to moal_private structure
+ * @param wrq A pointer to iwreq structure
+ *
+ * @return 0 -- success, otherwise fail
+ */
+static int
+woal_tx_bf_cfg_ioctl(moal_private * priv, struct iwreq *wrq)
+{
+ int ret = 0, data_length = wrq->u.data.length;
+ int bf_action = 0, interval = 0;
+ int snr = 0, i, tmp_val;
+ t_u8 buf[MAX_IN_OUT_CHAR], char_count = 0;
+ t_u8 *str, *token, *pos;
+ t_u16 action = 0;
+
+ mlan_ds_11n_tx_bf_cfg bf_cfg;
+ mlan_trigger_sound_args *bf_sound = NULL;
+ mlan_tx_bf_peer_args *tx_bf_peer = NULL;
+ mlan_snr_thr_args *bf_snr = NULL;
+ mlan_bf_periodicity_args *bf_periodicity = NULL;
+ mlan_bf_global_cfg_args *bf_global = NULL;
+
+ ENTER();
+
+ memset(&bf_cfg, 0, sizeof(bf_cfg));
+ /* Pointer to corresponding buffer */
+ bf_sound = bf_cfg.body.bf_sound;
+ tx_bf_peer = bf_cfg.body.tx_bf_peer;
+ bf_snr = bf_cfg.body.bf_snr;
+ bf_periodicity = bf_cfg.body.bf_periodicity;
+ bf_global = &bf_cfg.body.bf_global_cfg;
+
+ /* Total characters in buffer */
+ char_count = data_length - 1;
+ memset(buf, 0, sizeof(buf));
+ if (char_count) {
+ if (data_length > sizeof(buf)) {
+ PRINTM(MERROR, "Too many arguments\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ if (copy_from_user(buf, wrq->u.data.pointer, data_length)) {
+ PRINTM(MERROR, "copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+
+ if (char_count > 1 && buf[1] != ';') {
+ PRINTM(MERROR, "No action argument. Separate with ';'\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ /* Replace ';' with NULL in the string to separate args */
+ for (i = 0; i < char_count; i++) {
+ if (buf[i] == ';')
+ buf[i] = '\0';
+ }
+ /* The first byte represents the beamforming action */
+ if (woal_atoi(&bf_action, &buf[0]) != MLAN_STATUS_SUCCESS) {
+ ret = -EINVAL;
+ goto done;
+ }
+ switch (bf_action) {
+ case BF_GLOBAL_CONFIGURATION:
+ if (char_count == 1) {
+ action = MLAN_ACT_GET;
+ bf_cfg.action = BF_CFG_ACT_GET;
+ } else {
+ action = MLAN_ACT_SET;
+ bf_cfg.action = BF_CFG_ACT_SET;
+ /* Eliminate action field */
+ token = &buf[2];
+ for (i = 1, str = &buf[2]; token != NULL; i++) {
+ token = strstr(str, " ");
+ pos = str;
+ if (token != NULL) {
+ *token = '\0';
+ str = token + 1;
+ }
+ woal_atoi(&tmp_val, pos);
+ switch (i) {
+ case BF_ENABLE_PARAM:
+ bf_global->bf_enbl = (t_u8) tmp_val;
+ break;
+ case SOUND_ENABLE_PARAM:
+ bf_global->sounding_enbl = (t_u8) tmp_val;
+ break;
+ case FB_TYPE_PARAM:
+ bf_global->fb_type = (t_u8) tmp_val;
+ break;
+ case SNR_THRESHOLD_PARAM:
+ bf_global->snr_threshold = (t_u8) tmp_val;
+ break;
+ case SOUND_INTVL_PARAM:
+ bf_global->sounding_interval = (t_u16) tmp_val;
+ break;
+ case BF_MODE_PARAM:
+ bf_global->bf_mode = (t_u8) tmp_val;
+ break;
+ default:
+ PRINTM(MERROR, "Invalid Argument\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ }
+ }
+ break;
+ case TRIGGER_SOUNDING_FOR_PEER:
+ /* First arg = 2 BfAction Second arg = 17 MAC "00:50:43:20:BF:64" */
+ if (char_count != 19) {
+ PRINTM(MERROR, "Invalid argument\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ woal_mac2u8(bf_sound->peer_mac, &buf[2]);
+ action = MLAN_ACT_SET;
+ bf_cfg.action = BF_CFG_ACT_SET;
+ break;
+ case SET_GET_BF_PERIODICITY:
+ /* First arg = 2 BfAction Second arg = 18 MAC "00:50:43:20:BF:64;"
+ Third arg = 1 (min char) TX BF interval 10 (max char) u32
+ maximum value 4294967295 */
+ if (char_count < 19 || char_count > 30) {
+ PRINTM(MERROR, "Invalid argument\n");
+ ret = -EINVAL;
+ goto done;
+ }
+
+ woal_mac2u8(bf_periodicity->peer_mac, &buf[2]);
+ if (char_count == 19) {
+ action = MLAN_ACT_GET;
+ bf_cfg.action = BF_CFG_ACT_GET;
+ } else {
+ action = MLAN_ACT_SET;
+ bf_cfg.action = BF_CFG_ACT_SET;
+ if (woal_atoi(&interval, &buf[20]) != MLAN_STATUS_SUCCESS) {
+ ret = -EINVAL;
+ goto done;
+ }
+ bf_periodicity->interval = interval;
+ }
+ break;
+ case TX_BF_FOR_PEER_ENBL:
+ /* Handle only SET operation here First arg = 2 BfAction Second arg
+ = 18 MAC "00:50:43:20:BF:64;" Third arg = 2 enable/disable bf
+ Fourth arg = 2 enable/disable sounding Fifth arg = 1 FB Type */
+ if (char_count != 25 && char_count != 1) {
+ PRINTM(MERROR, "Invalid argument\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ if (char_count == 1) {
+ action = MLAN_ACT_GET;
+ bf_cfg.action = BF_CFG_ACT_GET;
+ } else {
+ woal_mac2u8(tx_bf_peer->peer_mac, &buf[2]);
+ woal_atoi(&tmp_val, &buf[20]);
+ tx_bf_peer->bf_enbl = (t_u8) tmp_val;
+ woal_atoi(&tmp_val, &buf[22]);
+ tx_bf_peer->sounding_enbl = (t_u8) tmp_val;
+ woal_atoi(&tmp_val, &buf[24]);
+ tx_bf_peer->fb_type = (t_u8) tmp_val;
+ action = MLAN_ACT_SET;
+ bf_cfg.action = BF_CFG_ACT_SET;
+ }
+ break;
+ case SET_SNR_THR_PEER:
+ /* First arg = 2 BfAction Second arg = 18 MAC "00:50:43:20:BF:64;"
+ Third arg = 1/2 SNR u8 - can be 1/2 charerters */
+ if (char_count != 1 && !(char_count == 21 || char_count == 22)) {
+ PRINTM(MERROR, "Invalid argument\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ if (char_count == 1) {
+ action = MLAN_ACT_GET;
+ bf_cfg.action = BF_CFG_ACT_GET;
+ } else {
+ woal_mac2u8(bf_snr->peer_mac, &buf[2]);
+ if (woal_atoi(&snr, &buf[20]) != MLAN_STATUS_SUCCESS) {
+ ret = -EINVAL;
+ goto done;
+ }
+ bf_snr->snr = snr;
+ action = MLAN_ACT_SET;
+ bf_cfg.action = BF_CFG_ACT_SET;
+ }
+ break;
+ default:
+ ret = -EINVAL;
+ goto done;
+ }
+
+ /* Save the value */
+ bf_cfg.bf_action = bf_action;
+ if (MLAN_STATUS_SUCCESS !=
+ woal_set_get_tx_bf_cfg(priv, action, &bf_cfg)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ } else {
+ ret = -EINVAL;
+ goto done;
+ }
+
+ if (action == MLAN_ACT_GET) {
+ data_length = 0;
+ memset(buf, 0, sizeof(buf));
+ switch (bf_action) {
+ case BF_GLOBAL_CONFIGURATION:
+ data_length +=
+ sprintf(buf + data_length, "%d ", (int) bf_global->bf_enbl);
+ data_length +=
+ sprintf(buf + data_length, "%d ",
+ (int) bf_global->sounding_enbl);
+ data_length +=
+ sprintf(buf + data_length, "%d ", (int) bf_global->fb_type);
+ data_length +=
+ sprintf(buf + data_length, "%d ",
+ (int) bf_global->snr_threshold);
+ data_length +=
+ sprintf(buf + data_length, "%d ",
+ (int) bf_global->sounding_interval);
+ data_length +=
+ sprintf(buf + data_length, "%d ", (int) bf_global->bf_mode);
+ break;
+ case TRIGGER_SOUNDING_FOR_PEER:
+ data_length += sprintf(buf + data_length,
+ "%02x:%02x:%02x:%02x:%02x:%02x",
+ bf_sound->peer_mac[0], bf_sound->peer_mac[1],
+ bf_sound->peer_mac[2], bf_sound->peer_mac[3],
+ bf_sound->peer_mac[4],
+ bf_sound->peer_mac[5]);
+ data_length += sprintf(buf + data_length, "%c", ';');
+ data_length += sprintf(buf + data_length, "%d", bf_sound->status);
+ break;
+ case SET_GET_BF_PERIODICITY:
+ data_length += sprintf(buf + data_length,
+ "%02x:%02x:%02x:%02x:%02x:%02x",
+ bf_periodicity->peer_mac[0],
+ bf_periodicity->peer_mac[1],
+ bf_periodicity->peer_mac[2],
+ bf_periodicity->peer_mac[3],
+ bf_periodicity->peer_mac[4],
+ bf_periodicity->peer_mac[5]);
+ data_length += sprintf(buf + data_length, "%c", ' ');
+ data_length +=
+ sprintf(buf + data_length, "%d", bf_periodicity->interval);
+ break;
+ case TX_BF_FOR_PEER_ENBL:
+ for (i = 0; i < bf_cfg.no_of_peers; i++) {
+ data_length += sprintf(buf + data_length,
+ "%02x:%02x:%02x:%02x:%02x:%02x",
+ tx_bf_peer->peer_mac[0],
+ tx_bf_peer->peer_mac[1],
+ tx_bf_peer->peer_mac[2],
+ tx_bf_peer->peer_mac[3],
+ tx_bf_peer->peer_mac[4],
+ tx_bf_peer->peer_mac[5]);
+ data_length += sprintf(buf + data_length, "%c", ' ');
+ data_length +=
+ sprintf(buf + data_length, "%d;", tx_bf_peer->bf_enbl);
+ data_length +=
+ sprintf(buf + data_length, "%d;",
+ tx_bf_peer->sounding_enbl);
+ data_length +=
+ sprintf(buf + data_length, "%d ", tx_bf_peer->fb_type);
+ tx_bf_peer++;
+ }
+ break;
+ case SET_SNR_THR_PEER:
+ for (i = 0; i < bf_cfg.no_of_peers; i++) {
+ data_length += sprintf(buf + data_length,
+ "%02x:%02x:%02x:%02x:%02x:%02x",
+ bf_snr->peer_mac[0], bf_snr->peer_mac[1],
+ bf_snr->peer_mac[2], bf_snr->peer_mac[3],
+ bf_snr->peer_mac[4],
+ bf_snr->peer_mac[5]);
+ data_length += sprintf(buf + data_length, "%c", ';');
+ data_length += sprintf(buf + data_length, "%d", bf_snr->snr);
+ data_length += sprintf(buf + data_length, "%c", ' ');
+ bf_snr++;
+ }
+ break;
+ default:
+ ret = -EINVAL;
+ goto done;
+ }
+ buf[data_length] = '\0';
+ }
+
+ wrq->u.data.length = data_length;
+ if (copy_to_user(wrq->u.data.pointer, buf, wrq->u.data.length)) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Create a brief scan resp to relay basic BSS info to the app layer
+ *
+ * When the beacon/probe response has not been buffered, use the saved BSS
+ * information available to provide a minimum response for the application
+ * ioctl retrieval routines. Include:
+ * - Timestamp
+ * - Beacon Period
+ * - Capabilities (including WMM Element if available)
+ * - SSID
+ *
+ * @param ppbuffer Output parameter: Buffer used to create basic scan rsp
+ * @param pbss_desc Pointer to a BSS entry in the scan table to create
+ * scan response from for delivery to the application layer
+ *
+ * @return N/A
+ */
+static void
+wlan_scan_create_brief_table_entry(t_u8 ** ppbuffer,
+ BSSDescriptor_t * pbss_desc)
+{
+ t_u8 *ptmp_buf = *ppbuffer;
+ t_u8 tmp_ssid_hdr[2];
+ t_u8 ie_len = 0;
+
+ ENTER();
+
+ if (copy_to_user(ptmp_buf, pbss_desc->time_stamp,
+ sizeof(pbss_desc->time_stamp))) {
+ PRINTM(MINFO, "Copy to user failed\n");
+ LEAVE();
+ return;
+ }
+ ptmp_buf += sizeof(pbss_desc->time_stamp);
+
+ if (copy_to_user(ptmp_buf, &pbss_desc->beacon_period,
+ sizeof(pbss_desc->beacon_period))) {
+ PRINTM(MINFO, "Copy to user failed\n");
+ LEAVE();
+ return;
+ }
+ ptmp_buf += sizeof(pbss_desc->beacon_period);
+
+ if (copy_to_user
+ (ptmp_buf, &pbss_desc->cap_info, sizeof(pbss_desc->cap_info))) {
+ PRINTM(MINFO, "Copy to user failed\n");
+ LEAVE();
+ return;
+ }
+ ptmp_buf += sizeof(pbss_desc->cap_info);
+
+ tmp_ssid_hdr[0] = 0; /* Element ID for SSID is zero */
+ tmp_ssid_hdr[1] = pbss_desc->ssid.ssid_len;
+ if (copy_to_user(ptmp_buf, tmp_ssid_hdr, sizeof(tmp_ssid_hdr))) {
+ PRINTM(MINFO, "Copy to user failed\n");
+ LEAVE();
+ return;
+ }
+ ptmp_buf += sizeof(tmp_ssid_hdr);
+
+ if (copy_to_user(ptmp_buf, pbss_desc->ssid.ssid, pbss_desc->ssid.ssid_len)) {
+ PRINTM(MINFO, "Copy to user failed\n");
+ LEAVE();
+ return;
+ }
+ ptmp_buf += pbss_desc->ssid.ssid_len;
+
+ if (pbss_desc->wmm_ie.vend_hdr.element_id == WMM_IE) {
+ ie_len = sizeof(IEEEtypes_Header_t) + pbss_desc->wmm_ie.vend_hdr.len;
+ if (copy_to_user(ptmp_buf, &pbss_desc->wmm_ie, ie_len)) {
+ PRINTM(MINFO, "Copy to user failed\n");
+ LEAVE();
+ return;
+ }
+
+ ptmp_buf += ie_len;
+ }
+
+ if (pbss_desc->pwpa_ie) {
+ if ((*(pbss_desc->pwpa_ie)).vend_hdr.element_id == WPA_IE) {
+ ie_len =
+ sizeof(IEEEtypes_Header_t) +
+ (*(pbss_desc->pwpa_ie)).vend_hdr.len;
+ if (copy_to_user(ptmp_buf, pbss_desc->pwpa_ie, ie_len)) {
+ PRINTM(MINFO, "Copy to user failed\n");
+ LEAVE();
+ return;
+ }
+ }
+
+ ptmp_buf += ie_len;
+ }
+
+ if (pbss_desc->prsn_ie) {
+ if ((*(pbss_desc->prsn_ie)).ieee_hdr.element_id == RSN_IE) {
+ ie_len =
+ sizeof(IEEEtypes_Header_t) +
+ (*(pbss_desc->prsn_ie)).ieee_hdr.len;
+ if (copy_to_user(ptmp_buf, pbss_desc->prsn_ie, ie_len)) {
+ PRINTM(MINFO, "Copy to user failed\n");
+ LEAVE();
+ return;
+ }
+ }
+
+ ptmp_buf += ie_len;
+ }
+
+ *ppbuffer = ptmp_buf;
+ LEAVE();
+}
+
+/**
+ * @brief Create a wlan_ioctl_get_scan_table_entry for a given BSS
+ * Descriptor for inclusion in the ioctl response to the user space
+ * application.
+ *
+ *
+ * @param pbss_desc Pointer to a BSS entry in the scan table to form
+ * scan response from for delivery to the application layer
+ * @param ppbuffer Output parameter: Buffer used to output scan return struct
+ * @param pspace_left Output parameter: Number of bytes available in the
+ * response buffer.
+ *
+ * @return MLAN_STATUS_SUCCESS, or < 0 with IOCTL error code
+ */
+static int
+wlan_get_scan_table_ret_entry(BSSDescriptor_t * pbss_desc,
+ t_u8 ** ppbuffer, int *pspace_left)
+{
+ wlan_ioctl_get_scan_table_entry *prsp_entry;
+ wlan_ioctl_get_scan_table_entry tmp_rsp_entry;
+ int space_needed;
+ t_u8 *pcurrent;
+ int variable_size;
+
+ const int fixed_size = sizeof(wlan_ioctl_get_scan_table_entry);
+
+ ENTER();
+
+ pcurrent = *ppbuffer;
+
+ /* The variable size returned is the stored beacon size */
+ variable_size = pbss_desc->beacon_buf_size;
+
+ /* If we stored a beacon and its size was zero, set the variable size
+ return value to the size of the brief scan response
+ wlan_scan_create_brief_table_entry creates. Also used if we are not
+ configured to store beacons in the first place */
+ if (!variable_size) {
+ variable_size = pbss_desc->ssid.ssid_len + 2;
+ variable_size += (sizeof(pbss_desc->beacon_period)
+ + sizeof(pbss_desc->time_stamp)
+ + sizeof(pbss_desc->cap_info));
+ if (pbss_desc->wmm_ie.vend_hdr.element_id == WMM_IE) {
+ variable_size += (sizeof(IEEEtypes_Header_t)
+ + pbss_desc->wmm_ie.vend_hdr.len);
+ }
+
+ if (pbss_desc->pwpa_ie) {
+ if ((*(pbss_desc->pwpa_ie)).vend_hdr.element_id == WPA_IE) {
+ variable_size += (sizeof(IEEEtypes_Header_t)
+ + (*(pbss_desc->pwpa_ie)).vend_hdr.len);
+ }
+ }
+
+ if (pbss_desc->prsn_ie) {
+ if ((*(pbss_desc->prsn_ie)).ieee_hdr.element_id == RSN_IE) {
+ variable_size += (sizeof(IEEEtypes_Header_t)
+ + (*(pbss_desc->prsn_ie)).ieee_hdr.len);
+ }
+ }
+ }
+
+ space_needed = fixed_size + variable_size;
+
+ PRINTM(MINFO, "GetScanTable: need(%d), left(%d)\n",
+ space_needed, *pspace_left);
+
+ if (space_needed >= *pspace_left) {
+ *pspace_left = 0;
+ LEAVE();
+ return -E2BIG;
+ }
+
+ *pspace_left -= space_needed;
+
+ tmp_rsp_entry.fixed_field_length = (sizeof(tmp_rsp_entry)
+ -
+ sizeof(tmp_rsp_entry.fixed_field_length)
+ -
+ sizeof(tmp_rsp_entry.bss_info_length));
+
+ memcpy(tmp_rsp_entry.fixed_fields.bssid,
+ pbss_desc->mac_address, sizeof(prsp_entry->fixed_fields.bssid));
+
+ tmp_rsp_entry.fixed_fields.rssi = pbss_desc->rssi;
+ tmp_rsp_entry.fixed_fields.channel = pbss_desc->channel;
+ tmp_rsp_entry.fixed_fields.network_tsf = pbss_desc->network_tsf;
+ tmp_rsp_entry.bss_info_length = variable_size;
+
+ /*
+ * Copy fixed fields to user space
+ */
+ if (copy_to_user(pcurrent, &tmp_rsp_entry, fixed_size)) {
+ PRINTM(MINFO, "Copy to user failed\n");
+ LEAVE();
+ return -EFAULT;
+ }
+
+ pcurrent += fixed_size;
+
+ if (pbss_desc->pbeacon_buf) {
+ /*
+ * Copy variable length elements to user space
+ */
+ if (copy_to_user(pcurrent, pbss_desc->pbeacon_buf,
+ pbss_desc->beacon_buf_size)) {
+ PRINTM(MINFO, "Copy to user failed\n");
+ LEAVE();
+ return -EFAULT;
+ }
+
+ pcurrent += pbss_desc->beacon_buf_size;
+ } else {
+ wlan_scan_create_brief_table_entry(&pcurrent, pbss_desc);
+ }
+
+ *ppbuffer = pcurrent;
+
+ LEAVE();
+
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief Retrieve the scan response/beacon table
+ *
+ * @param wrq A pointer to iwreq structure
+ * @param scan_resp A pointer to mlan_scan_resp structure
+ * @param scan_start argument
+ *
+ * @return MLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static int
+moal_ret_get_scan_table_ioctl(struct iwreq *wrq,
+ mlan_scan_resp * scan_resp, t_u32 scan_start)
+{
+ pBSSDescriptor_t pbss_desc, scan_table;
+ wlan_ioctl_get_scan_table_info *prsp_info;
+ int ret_code;
+ int ret_len;
+ int space_left;
+ t_u8 *pcurrent;
+ t_u8 *pbuffer_end;
+ t_u32 num_scans_done;
+
+ ENTER();
+
+ num_scans_done = 0;
+ ret_code = MLAN_STATUS_SUCCESS;
+
+ prsp_info = (wlan_ioctl_get_scan_table_info *) wrq->u.data.pointer;
+ pcurrent = (t_u8 *) prsp_info->scan_table_entry_buf;
+
+ pbuffer_end = wrq->u.data.pointer + wrq->u.data.length - 1;
+ space_left = pbuffer_end - pcurrent;
+ scan_table = (BSSDescriptor_t *) (scan_resp->pscan_table);
+
+ PRINTM(MINFO, "GetScanTable: scan_start req = %d\n", scan_start);
+ PRINTM(MINFO, "GetScanTable: length avail = %d\n", wrq->u.data.length);
+
+ if (!scan_start) {
+ PRINTM(MINFO, "GetScanTable: get current BSS Descriptor\n");
+
+ /* Use to get current association saved descriptor */
+ pbss_desc = scan_table;
+
+ ret_code = wlan_get_scan_table_ret_entry(pbss_desc,
+ &pcurrent, &space_left);
+
+ if (ret_code == MLAN_STATUS_SUCCESS) {
+ num_scans_done = 1;
+ }
+ } else {
+ scan_start--;
+
+ while (space_left
+ && (scan_start + num_scans_done < scan_resp->num_in_scan_table)
+ && (ret_code == MLAN_STATUS_SUCCESS)) {
+
+ pbss_desc = (scan_table + (scan_start + num_scans_done));
+
+ PRINTM(MINFO, "GetScanTable: get current BSS Descriptor [%d]\n",
+ scan_start + num_scans_done);
+
+ ret_code = wlan_get_scan_table_ret_entry(pbss_desc,
+ &pcurrent, &space_left);
+
+ if (ret_code == MLAN_STATUS_SUCCESS) {
+ num_scans_done++;
+ }
+ }
+ }
+
+ prsp_info->scan_number = num_scans_done;
+ ret_len = pcurrent - (t_u8 *) wrq->u.data.pointer;
+
+ wrq->u.data.length = ret_len;
+
+ /* Return ret_code (EFAULT or E2BIG) in the case where no scan results were
+ successfully encoded. */
+ LEAVE();
+ return (num_scans_done ? MLAN_STATUS_SUCCESS : ret_code);
+}
+
+/**
+ * @brief Get scan table ioctl
+ *
+ * @param priv A pointer to moal_private structure
+ * @param wrq A pointer to iwreq structure
+ *
+ * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING -- success, otherwise fail
+ */
+static mlan_status
+woal_get_scan_table_ioctl(moal_private * priv, struct iwreq *wrq)
+{
+ int ret = 0;
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_scan *scan = NULL;
+ t_u32 scan_start;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ /* Allocate an IOCTL request buffer */
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_scan));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ /* Fill request buffer */
+ scan = (mlan_ds_scan *) req->pbuf;
+ req->req_id = MLAN_IOCTL_SCAN;
+ req->action = MLAN_ACT_GET;
+
+ /* get the whole command from user */
+ if (copy_from_user(&scan_start, wrq->u.data.pointer, sizeof(scan_start))) {
+ PRINTM(MERROR, "copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ if (scan_start) {
+ scan->sub_command = MLAN_OID_SCAN_NORMAL;
+ } else {
+ scan->sub_command = MLAN_OID_SCAN_GET_CURRENT_BSS;
+ }
+ /* Send IOCTL request to MLAN */
+ status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
+ if (status == MLAN_STATUS_SUCCESS) {
+ status = moal_ret_get_scan_table_ioctl(wrq,
+ &scan->param.scan_resp,
+ scan_start);
+ }
+ done:
+ if (req && (status != MLAN_STATUS_PENDING))
+ kfree(req);
+ LEAVE();
+ return status;
+}
+
+/**
+ * @brief Set user scan
+ *
+ * @param priv A pointer to moal_private structure
+ * @param wrq A pointer to iwreq structure
+ *
+ * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING -- success, otherwise fail
+ */
+static mlan_status
+woal_set_user_scan_ioctl(moal_private * priv, struct iwreq *wrq)
+{
+ int ret = 0;
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_scan *scan = NULL;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+ union iwreq_data wrqu;
+ moal_handle *handle = priv->phandle;
+
+ ENTER();
+
+ if (handle->scan_pending_on_block == MTRUE) {
+ PRINTM(MINFO, "scan already in processing...\n");
+ LEAVE();
+ return ret;
+ }
+ if (MOAL_ACQ_SEMAPHORE_BLOCK(&handle->async_sem)) {
+ PRINTM(MERROR, "Acquire semaphore error, request_scan\n");
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+ handle->scan_pending_on_block = MTRUE;
+
+ /* Allocate an IOCTL request buffer */
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_scan) + wrq->u.data.length);
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ /* Fill request buffer */
+ scan = (mlan_ds_scan *) req->pbuf;
+ scan->sub_command = MLAN_OID_SCAN_USER_CONFIG;
+ req->req_id = MLAN_IOCTL_SCAN;
+ req->action = MLAN_ACT_SET;
+
+ if (copy_from_user(scan->param.user_scan.scan_cfg_buf,
+ wrq->u.data.pointer, wrq->u.data.length)) {
+ PRINTM(MINFO, "Copy from user failed\n");
+ LEAVE();
+ return -EFAULT;
+ }
+
+ /* Send IOCTL request to MLAN */
+ status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
+ if (status == MLAN_STATUS_SUCCESS) {
+ memset(&wrqu, 0, sizeof(union iwreq_data));
+ wireless_send_event(priv->netdev, SIOCGIWSCAN, &wrqu, NULL);
+ }
+ handle->scan_pending_on_block = MFALSE;
+ MOAL_REL_SEMAPHORE(&handle->async_sem);
+
+ done:
+ if (req && (status != MLAN_STATUS_PENDING))
+ kfree(req);
+ LEAVE();
+ return status;
+}
+
+/**
+ * @brief Cmd52 read/write register
+ *
+ * @param priv A pointer to moal_private structure
+ * @param wrq A pointer to iwreq structure
+ * @return MLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static int
+woal_cmd52rdwr_ioctl(moal_private * priv, struct iwreq *wrq)
+{
+ t_u8 rw = 0, func, data = 0;
+ int buf[3], reg, ret = MLAN_STATUS_SUCCESS;
+ int data_length = wrq->u.data.length;
+
+ ENTER();
+
+ if (data_length < 2 || data_length > 3) {
+ PRINTM(MERROR, "Invalid number of arguments\n");
+ ret = -EINVAL;
+ goto done;
+ }
+
+ if (copy_from_user(buf, wrq->u.data.pointer, sizeof(int) * data_length)) {
+ PRINTM(MERROR, "Copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+
+ func = (t_u8) buf[0];
+ if (func > 7) {
+ PRINTM(MERROR, "Invalid function number!\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ reg = (t_u32) buf[1];
+ if (data_length == 2) {
+ rw = 0; /* CMD52 read */
+ PRINTM(MINFO, "Cmd52 read, func=%d, reg=0x%08X\n", func, reg);
+ }
+ if (data_length == 3) {
+ rw = 1; /* CMD52 write */
+ data = (t_u8) buf[2];
+ PRINTM(MINFO, "Cmd52 write, func=%d, reg=0x%08X, data=0x%02X\n", func,
+ reg, data);
+ }
+
+ if (!rw) {
+ sdio_claim_host(((struct sdio_mmc_card *) priv->phandle->card)->func);
+ if (func)
+ data =
+ sdio_readb(((struct sdio_mmc_card *) priv->phandle->card)->func,
+ reg, &ret);
+ else
+ data =
+ sdio_f0_readb(((struct sdio_mmc_card *) priv->phandle->card)->
+ func, reg, &ret);
+ sdio_release_host(((struct sdio_mmc_card *) priv->phandle->card)->func);
+ if (ret) {
+ PRINTM(MERROR, "sdio_readb: reading register 0x%X failed\n", reg);
+ goto done;
+ }
+ } else {
+ sdio_claim_host(((struct sdio_mmc_card *) priv->phandle->card)->func);
+ if (func)
+ sdio_writeb(((struct sdio_mmc_card *) priv->phandle->card)->func,
+ data, reg, &ret);
+ else
+ sdio_f0_writeb(((struct sdio_mmc_card *) priv->phandle->card)->func,
+ data, reg, &ret);
+ sdio_release_host(((struct sdio_mmc_card *) priv->phandle->card)->func);
+ if (ret) {
+ PRINTM(MERROR, "sdio_writeb: writing register 0x%X failed\n", reg);
+ goto done;
+ }
+ }
+
+ buf[0] = data;
+ wrq->u.data.length = 1;
+ if (copy_to_user(wrq->u.data.pointer, buf, sizeof(int))) {
+ PRINTM(MERROR, "Copy to user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+
+ done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Cmd53 read/write register
+ *
+ * @param priv A pointer to moal_private structure
+ * @param wrq A pointer to iwreq structure
+ * @return MLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static int
+woal_cmd53rdwr_ioctl(moal_private * priv, struct iwreq *wrq)
+{
+ t_u8 *buf = NULL;
+ t_u8 rw, func, mode;
+ t_u16 blklen = 0, blknum = 0;
+ int reg = 0, pattern_len = 0, pos = 0, ret = MLAN_STATUS_SUCCESS;
+ t_u32 total_len = 0;
+ t_u8 *data = NULL;
+
+ ENTER();
+
+ if (!(buf = (t_u8 *) kmalloc(WOAL_2K_BYTES, GFP_KERNEL))) {
+ PRINTM(MERROR, "Cannot allocate buffer for command!\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ if (!(data = (t_u8 *) kmalloc(WOAL_2K_BYTES, GFP_KERNEL))) {
+ PRINTM(MERROR, "Cannot allocate buffer for command!\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ if (wrq->u.data.length > WOAL_2K_BYTES) {
+ PRINTM(MERROR, "Data lengh is too large!\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ if (copy_from_user(buf, wrq->u.data.pointer, wrq->u.data.length)) {
+ PRINTM(MINFO, "Copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+
+ rw = buf[0]; /* read/write (0/1) */
+ func = buf[1]; /* func (0/1/2) */
+ reg = buf[5]; /* address */
+ reg = (reg << 8) + buf[4];
+ reg = (reg << 8) + buf[3];
+ reg = (reg << 8) + buf[2];
+ mode = buf[6]; /* byte mode/block mode (0/1) */
+ blklen = buf[8]; /* block size */
+ blklen = (blklen << 8) + buf[7];
+ blknum = buf[10]; /* block number or byte number */
+ blknum = (blknum << 8) + buf[9];
+
+ if (mode != BYTE_MODE)
+ mode = BLOCK_MODE;
+ total_len = (mode == BLOCK_MODE) ? blknum * blklen : blknum;
+ if (total_len > WOAL_2K_BYTES) {
+ PRINTM(MERROR, "Total data length is too large!\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ PRINTM(MINFO, "CMD53 read/write, func = %d, addr = %#x, mode = %d, "
+ "block size = %d, block(byte) number = %d\n",
+ func, reg, mode, blklen, blknum);
+
+ if (!rw) {
+ sdio_claim_host(((struct sdio_mmc_card *) priv->phandle->card)->func);
+ if (sdio_readsb
+ (((struct sdio_mmc_card *) priv->phandle->card)->func, data, reg,
+ total_len))
+ PRINTM(MERROR, "sdio_readsb: reading memory 0x%x failed\n", reg);
+ sdio_release_host(((struct sdio_mmc_card *) priv->phandle->card)->func);
+
+ if (copy_to_user(wrq->u.data.pointer, data, total_len)) {
+ PRINTM(MINFO, "Copy to user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ wrq->u.data.length = total_len;
+ } else {
+ pattern_len = wrq->u.data.length - 11;
+ if (pattern_len > total_len)
+ pattern_len = total_len;
+ memset(data, 0, sizeof(data));
+
+ /* Copy/duplicate the pattern to data buffer */
+ for (pos = 0; pos < total_len; pos++)
+ data[pos] = buf[11 + (pos % pattern_len)];
+
+ sdio_claim_host(((struct sdio_mmc_card *) priv->phandle->card)->func);
+ if (sdio_writesb
+ (((struct sdio_mmc_card *) priv->phandle->card)->func, reg, data,
+ total_len))
+ PRINTM(MERROR, "sdio_writesb: writing memory 0x%x failed\n", reg);
+ sdio_release_host(((struct sdio_mmc_card *) priv->phandle->card)->func);
+ }
+
+ done:
+ if (buf)
+ kfree(buf);
+ if (data)
+ kfree(data);
+ LEAVE();
+ return ret;
+}
+
+#if defined(SDIO_MULTI_PORT_TX_AGGR) || defined(SDIO_MULTI_PORT_RX_AGGR)
+/**
+ * @brief Set SDIO Multi-point aggregation control parameters
+ *
+ * @param priv A pointer to moal_private structure
+ * @param wrq A pointer to iwreq structure
+ *
+ * @return 0/MLAN_STATUS_PENDING --success, otherwise fail
+ */
+static int
+woal_do_sdio_mpa_ctrl(moal_private * priv, struct iwreq *wrq)
+{
+ int data[6], data_length = wrq->u.data.length;
+ int ret = 0;
+ mlan_ds_misc_cfg *misc = NULL;
+ mlan_ioctl_req *req = NULL;
+
+ ENTER();
+
+ if (sizeof(int) * wrq->u.data.length > sizeof(data)) {
+ PRINTM(MERROR, "Too many arguments\n");
+ ret = -EINVAL;
+ goto done;
+ }
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+ misc = (mlan_ds_misc_cfg *) req->pbuf;
+ memset(misc, 0, sizeof(mlan_ds_misc_cfg));
+
+ misc->sub_command = MLAN_OID_MISC_SDIO_MPA_CTRL;
+ req->req_id = MLAN_IOCTL_MISC_CFG;
+
+ /* Get the values first, then modify these values if user had modified them
+ */
+
+ req->action = MLAN_ACT_GET;
+ if ((ret = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) !=
+ MLAN_STATUS_SUCCESS) {
+ PRINTM(MERROR, "woal_request_ioctl returned %d\n", ret);
+ ret = -EFAULT;
+ goto done;
+ }
+
+ if (data_length == 0) {
+ data[0] = misc->param.mpa_ctrl.tx_enable;
+ data[1] = misc->param.mpa_ctrl.rx_enable;
+ data[2] = misc->param.mpa_ctrl.tx_buf_size;
+ data[3] = misc->param.mpa_ctrl.rx_buf_size;
+ data[4] = misc->param.mpa_ctrl.tx_max_ports;
+ data[5] = misc->param.mpa_ctrl.rx_max_ports;
+
+ PRINTM(MINFO, "Get Param: %d %d %d %d %d %d\n", data[0], data[1],
+ data[2], data[3], data[4], data[5]);
+
+ if (copy_to_user(wrq->u.data.pointer, data, sizeof(data))) {
+ ret = -EFAULT;
+ goto done;
+ }
+ wrq->u.data.length = sizeof(data) / sizeof(int);
+ goto done;
+ }
+
+ if (copy_from_user(data, wrq->u.data.pointer, sizeof(int) * data_length)) {
+ PRINTM(MINFO, "Copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+
+ switch (data_length) {
+ case 6:
+ misc->param.mpa_ctrl.rx_max_ports = data[5];
+ case 5:
+ misc->param.mpa_ctrl.tx_max_ports = data[4];
+ case 4:
+ misc->param.mpa_ctrl.rx_buf_size = data[3];
+ case 3:
+ misc->param.mpa_ctrl.tx_buf_size = data[2];
+ case 2:
+ misc->param.mpa_ctrl.rx_enable = data[1];
+ case 1:
+ /* Set cmd */
+ req->action = MLAN_ACT_SET;
+
+ PRINTM(MINFO, "Set Param: %d %d %d %d %d %d\n", data[0], data[1],
+ data[2], data[3], data[4], data[5]);
+
+ misc->param.mpa_ctrl.tx_enable = data[0];
+ break;
+ default:
+ PRINTM(MERROR, "Default case error\n");
+ ret = -EINVAL;
+ goto done;
+ }
+
+ if ((ret = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT) !=
+ MLAN_STATUS_SUCCESS)) {
+ PRINTM(MERROR, "woal_request_ioctl returned %d\n", ret);
+ ret = -EFAULT;
+ goto done;
+ }
+
+ done:
+ if (req)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+#endif /* SDIO_MULTI_PORT_TX_AGGR || SDIO_MULTI_PORT_RX_AGGR */
+
+/**
+ * @brief Set/Get scan configuration parameters
+ *
+ * @param priv A pointer to moal_private structure
+ * @param wrq A pointer to iwreq structure
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_set_get_scan_cfg(moal_private * priv, struct iwreq *wrq)
+{
+ int ret = 0;
+ int arg_len = 7;
+ int data[arg_len];
+ mlan_ds_scan *scan = NULL;
+ mlan_ioctl_req *req = NULL;
+
+ ENTER();
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_scan));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+ if (wrq->u.data.length > arg_len) {
+ ret = -EINVAL;
+ goto done;
+ }
+ scan = (mlan_ds_scan *) req->pbuf;
+ scan->sub_command = MLAN_OID_SCAN_CONFIG;
+ req->req_id = MLAN_IOCTL_SCAN;
+ memset(data, 0, sizeof(data));
+ if (wrq->u.data.length) {
+ if (copy_from_user
+ (data, wrq->u.data.pointer, (wrq->u.data.length * sizeof(int)))) {
+ PRINTM(MERROR, "Copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ if ((data[0] < 0) || (data[0] > MLAN_SCAN_TYPE_PASSIVE)) {
+ PRINTM(MERROR, "Invalid argument for scan type\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ if ((data[1] < 0) || (data[1] > MLAN_SCAN_MODE_ANY)) {
+ PRINTM(MERROR, "Invalid argument for scan mode\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ if ((data[2] < 0) || (data[2] > MAX_PROBES)) {
+ PRINTM(MERROR, "Invalid argument for scan probes\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ if (((data[3] < 0) || (data[3] > MRVDRV_MAX_ACTIVE_SCAN_CHAN_TIME)) ||
+ ((data[4] < 0) || (data[4] > MRVDRV_MAX_ACTIVE_SCAN_CHAN_TIME)) ||
+ ((data[5] < 0) || (data[5] > MRVDRV_MAX_PASSIVE_SCAN_CHAN_TIME))) {
+ PRINTM(MERROR, "Invalid argument for scan time\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ if ((data[6] < 0) || (data[6] > 1)) {
+ PRINTM(MERROR, "Invalid argument for extended scan\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ req->action = MLAN_ACT_SET;
+ memcpy(&scan->param.scan_cfg, data, sizeof(data));
+ } else
+ req->action = MLAN_ACT_GET;
+ if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ if (!wrq->u.data.length) {
+ memcpy(data, &scan->param.scan_cfg, sizeof(data));
+ if (copy_to_user(wrq->u.data.pointer, data, sizeof(data))) {
+ ret = -EFAULT;
+ goto done;
+ }
+ wrq->u.data.length = sizeof(data) / sizeof(int);
+ }
+ done:
+ if (req)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set/Get PS configuration parameters
+ *
+ * @param priv A pointer to moal_private structure
+ * @param wrq A pointer to iwreq structure
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_set_get_ps_cfg(moal_private * priv, struct iwreq *wrq)
+{
+ int data[7], ret = 0;
+ mlan_ds_pm_cfg *pm_cfg = NULL;
+ mlan_ioctl_req *req = NULL;
+ int allowed = 3;
+ int i = 3;
+
+ ENTER();
+
+ allowed++; /* For ad-hoc awake period parameter */
+ allowed++; /* For beacon missing timeout parameter */
+ allowed += 2; /* For delay to PS and PS mode parameters */
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_pm_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+ if (wrq->u.data.length > allowed) {
+ ret = -EINVAL;
+ goto done;
+ }
+ pm_cfg = (mlan_ds_pm_cfg *) req->pbuf;
+ pm_cfg->sub_command = MLAN_OID_PM_CFG_PS_CFG;
+ req->req_id = MLAN_IOCTL_PM_CFG;
+ memset(data, 0, sizeof(data));
+ if (wrq->u.data.length) {
+ if (copy_from_user
+ (data, wrq->u.data.pointer, (wrq->u.data.length * sizeof(int)))) {
+ PRINTM(MERROR, "Copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ if ((data[0] < PS_NULL_DISABLE)) {
+ PRINTM(MERROR, "Invalid argument for PS null interval\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ if ((data[1] != MRVDRV_IGNORE_MULTIPLE_DTIM)
+ && (data[1] != MRVDRV_MATCH_CLOSEST_DTIM)
+ && ((data[1] < MRVDRV_MIN_MULTIPLE_DTIM)
+ || (data[1] > MRVDRV_MAX_MULTIPLE_DTIM))) {
+ PRINTM(MERROR, "Invalid argument for multiple DTIM\n");
+ ret = -EINVAL;
+ goto done;
+ }
+
+ if ((data[2] < MRVDRV_MIN_LISTEN_INTERVAL)
+ && (data[2] != MRVDRV_LISTEN_INTERVAL_DISABLE)) {
+ PRINTM(MERROR, "Invalid argument for listen interval\n");
+ ret = -EINVAL;
+ goto done;
+ }
+
+ if ((data[i] != SPECIAL_ADHOC_AWAKE_PD) &&
+ ((data[i] < MIN_ADHOC_AWAKE_PD) ||
+ (data[i] > MAX_ADHOC_AWAKE_PD))) {
+ PRINTM(MERROR, "Invalid argument for adhoc awake period\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ i++;
+ if ((data[i] != DISABLE_BCN_MISS_TO) &&
+ ((data[i] < MIN_BCN_MISS_TO) || (data[i] > MAX_BCN_MISS_TO))) {
+ PRINTM(MERROR, "Invalid argument for beacon miss timeout\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ i++;
+ if (wrq->u.data.length < allowed - 1)
+ data[i] = DELAY_TO_PS_UNCHANGED;
+ else if ((data[i] < MIN_DELAY_TO_PS) || (data[i] > MAX_DELAY_TO_PS)) {
+ PRINTM(MERROR, "Invalid argument for delay to PS\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ i++;
+ if ((data[i] != PS_MODE_UNCHANGED) && (data[i] != PS_MODE_AUTO) &&
+ (data[i] != PS_MODE_POLL) && (data[i] != PS_MODE_NULL)) {
+ PRINTM(MERROR, "Invalid argument for PS mode\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ i++;
+ req->action = MLAN_ACT_SET;
+ memcpy(&pm_cfg->param.ps_cfg, data,
+ MIN(sizeof(pm_cfg->param.ps_cfg), sizeof(data)));
+ } else
+ req->action = MLAN_ACT_GET;
+
+ if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ memcpy(data, &pm_cfg->param.ps_cfg,
+ MIN((sizeof(int) * allowed), sizeof(pm_cfg->param.ps_cfg)));
+ if (copy_to_user(wrq->u.data.pointer, data, sizeof(int) * allowed)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ wrq->u.data.length = allowed;
+
+ if (req->action == MLAN_ACT_SET) {
+ pm_cfg = (mlan_ds_pm_cfg *) req->pbuf;
+ pm_cfg->sub_command = MLAN_OID_PM_CFG_IEEE_PS;
+ pm_cfg->param.ps_mode = 1;
+ req->req_id = MLAN_IOCTL_PM_CFG;
+ req->action = MLAN_ACT_SET;
+ woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
+ }
+
+ done:
+ if (req)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Private IOCTL entry to send an ADDTS TSPEC
+ *
+ * Receive a ADDTS command from the application. The command structure
+ * contains a TSPEC and timeout in milliseconds. The timeout is performed
+ * in the firmware after the ADDTS command frame is sent.
+ *
+ * The TSPEC is received in the API as an opaque block. The firmware will
+ * send the entire data block, including the bytes after the TSPEC. This
+ * is done to allow extra IEs to be packaged with the TSPEC in the ADDTS
+ * action frame.
+ *
+ * The IOCTL structure contains two return fields:
+ * - The firmware command result, which indicates failure and timeouts
+ * - The IEEE Status code which contains the corresponding value from
+ * any ADDTS response frame received.
+ *
+ * In addition, the opaque TSPEC data block passed in is replaced with the
+ * TSPEC received in the ADDTS response frame. In case of failure, the
+ * AP may modify the TSPEC on return and in the case of success, the
+ * medium time is returned as calculated by the AP. Along with the TSPEC,
+ * any IEs that are sent in the ADDTS response are also returned and can be
+ * parsed using the IOCTL length as an indicator of extra elements.
+ *
+ * The return value to the application layer indicates a driver execution
+ * success or failure. A successful return could still indicate a firmware
+ * failure or AP negotiation failure via the commandResult field copied
+ * back to the application.
+ *
+ * @param priv Pointer to the mlan_private driver data struct
+ * @param wrq A pointer to iwreq structure containing the
+ * wlan_ioctl_wmm_addts_req_t struct for this ADDTS request
+ *
+ * @return 0 if successful; IOCTL error code otherwise
+ */
+static int
+woal_wmm_addts_req_ioctl(moal_private * priv, struct iwreq *wrq)
+{
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_wmm_cfg *cfg = NULL;
+ wlan_ioctl_wmm_addts_req_t addts_ioctl;
+ int ret = 0;
+
+ ENTER();
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_wmm_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ req->req_id = MLAN_IOCTL_WMM_CFG;
+ cfg = (mlan_ds_wmm_cfg *) req->pbuf;
+ cfg->sub_command = MLAN_OID_WMM_CFG_ADDTS;
+
+ memset(&addts_ioctl, 0x00, sizeof(addts_ioctl));
+
+ if (wrq->u.data.length) {
+ if (copy_from_user(&addts_ioctl, wrq->u.data.pointer,
+ MIN(wrq->u.data.length, sizeof(addts_ioctl)))) {
+ PRINTM(MERROR, "TSPEC: ADDTS copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+
+ cfg->param.addts.timeout = addts_ioctl.timeout_ms;
+ cfg->param.addts.ie_data_len = (t_u8) addts_ioctl.ie_data_len;
+
+ memcpy(cfg->param.addts.ie_data,
+ addts_ioctl.ie_data, cfg->param.addts.ie_data_len);
+
+ if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req,
+ MOAL_IOCTL_WAIT)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ addts_ioctl.cmd_result = cfg->param.addts.result;
+ addts_ioctl.ieee_status_code = (t_u8) cfg->param.addts.status_code;
+ addts_ioctl.ie_data_len = cfg->param.addts.ie_data_len;
+
+ memcpy(addts_ioctl.ie_data,
+ cfg->param.addts.ie_data, cfg->param.addts.ie_data_len);
+
+ wrq->u.data.length = (sizeof(addts_ioctl)
+ - sizeof(addts_ioctl.ie_data)
+ + cfg->param.addts.ie_data_len);
+
+ if (copy_to_user(wrq->u.data.pointer, &addts_ioctl, wrq->u.data.length)) {
+ PRINTM(MERROR, "TSPEC: ADDTS copy to user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ }
+
+ done:
+ if (req)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Private IOCTL entry to send a DELTS TSPEC
+ *
+ * Receive a DELTS command from the application. The command structure
+ * contains a TSPEC and reason code along with space for a command result
+ * to be returned. The information is packaged is sent to the wlan_cmd.c
+ * firmware command prep and send routines for execution in the firmware.
+ *
+ * The reason code is not used for WMM implementations but is indicated in
+ * the 802.11e specification.
+ *
+ * The return value to the application layer indicates a driver execution
+ * success or failure. A successful return could still indicate a firmware
+ * failure via the cmd_result field copied back to the application.
+ *
+ * @param priv Pointer to the mlan_private driver data struct
+ * @param wrq A pointer to iwreq structure containing the
+ * wlan_ioctl_wmm_delts_req_t struct for this DELTS request
+ *
+ * @return 0 if successful; IOCTL error code otherwise
+ */
+static int
+woal_wmm_delts_req_ioctl(moal_private * priv, struct iwreq *wrq)
+{
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_wmm_cfg *cfg = NULL;
+ wlan_ioctl_wmm_delts_req_t delts_ioctl;
+ int ret = 0;
+
+ ENTER();
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_wmm_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ req->req_id = MLAN_IOCTL_WMM_CFG;
+ cfg = (mlan_ds_wmm_cfg *) req->pbuf;
+ cfg->sub_command = MLAN_OID_WMM_CFG_DELTS;
+
+ memset(&delts_ioctl, 0x00, sizeof(delts_ioctl));
+
+ if (wrq->u.data.length) {
+ if (copy_from_user(&delts_ioctl, wrq->u.data.pointer,
+ MIN(wrq->u.data.length, sizeof(delts_ioctl)))) {
+ PRINTM(MERROR, "TSPEC: DELTS copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+
+ cfg->param.delts.status_code = (t_u32) delts_ioctl.ieee_reason_code;
+ cfg->param.delts.ie_data_len = (t_u8) delts_ioctl.ie_data_len;
+
+ memcpy(cfg->param.delts.ie_data,
+ delts_ioctl.ie_data, cfg->param.delts.ie_data_len);
+
+ if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req,
+ MOAL_IOCTL_WAIT)) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ /* Return the firmware command result back to the application layer */
+ delts_ioctl.cmd_result = cfg->param.delts.result;
+ wrq->u.data.length = sizeof(delts_ioctl);
+
+ if (copy_to_user(wrq->u.data.pointer, &delts_ioctl, wrq->u.data.length)) {
+ PRINTM(MERROR, "TSPEC: DELTS copy to user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ }
+
+ done:
+ if (req)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Private IOCTL entry to get/set a specified AC Queue's parameters
+ *
+ * Receive a AC Queue configuration command which is used to get, set, or
+ * default the parameters associated with a specific WMM AC Queue.
+ *
+ * @param priv Pointer to the mlan_private driver data struct
+ * @param wrq A pointer to iwreq structure containing the
+ * wlan_ioctl_wmm_queue_config_t struct
+ *
+ * @return 0 if successful; IOCTL error code otherwise
+ */
+static int
+woal_wmm_queue_config_ioctl(moal_private * priv, struct iwreq *wrq)
+{
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_wmm_cfg *pwmm = NULL;
+ mlan_ds_wmm_queue_config *pqcfg = NULL;
+ wlan_ioctl_wmm_queue_config_t qcfg_ioctl;
+ int ret = 0;
+
+ ENTER();
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_wmm_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ req->req_id = MLAN_IOCTL_WMM_CFG;
+ pwmm = (mlan_ds_wmm_cfg *) req->pbuf;
+ pwmm->sub_command = MLAN_OID_WMM_CFG_QUEUE_CONFIG;
+
+ memset(&qcfg_ioctl, 0x00, sizeof(qcfg_ioctl));
+ pqcfg = (mlan_ds_wmm_queue_config *) & pwmm->param.q_cfg;
+
+ if (wrq->u.data.length) {
+ if (copy_from_user(&qcfg_ioctl, wrq->u.data.pointer,
+ MIN(wrq->u.data.length, sizeof(qcfg_ioctl)))) {
+ PRINTM(MERROR, "QCONFIG: copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+
+ pqcfg->action = qcfg_ioctl.action;
+ pqcfg->access_category = qcfg_ioctl.access_category;
+ pqcfg->msdu_lifetime_expiry = qcfg_ioctl.msdu_lifetime_expiry;
+
+ if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req,
+ MOAL_IOCTL_WAIT)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ memset(&qcfg_ioctl, 0x00, sizeof(qcfg_ioctl));
+ qcfg_ioctl.action = pqcfg->action;
+ qcfg_ioctl.access_category = pqcfg->access_category;
+ qcfg_ioctl.msdu_lifetime_expiry = pqcfg->msdu_lifetime_expiry;
+ wrq->u.data.length = sizeof(qcfg_ioctl);
+
+ if (copy_to_user(wrq->u.data.pointer, &qcfg_ioctl, wrq->u.data.length)) {
+ PRINTM(MERROR, "QCONFIG: copy to user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ }
+
+ done:
+ if (req)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Private IOCTL entry to get and start/stop queue stats on a WMM AC
+ *
+ * Receive a AC Queue statistics command from the application for a specific
+ * WMM AC. The command can:
+ * - Turn stats on
+ * - Turn stats off
+ * - Collect and clear the stats
+ *
+ * @param priv Pointer to the moal_private driver data struct
+ * @param wrq A pointer to iwreq structure containing the
+ * wlan_ioctl_wmm_queue_stats_t struct
+ *
+ * @return 0 if successful; IOCTL error code otherwise
+ */
+static int
+woal_wmm_queue_stats_ioctl(moal_private * priv, struct iwreq *wrq)
+{
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_wmm_cfg *pwmm = NULL;
+ mlan_ds_wmm_queue_stats *pqstats = NULL;
+ wlan_ioctl_wmm_queue_stats_t qstats_ioctl;
+ int ret = 0;
+
+ ENTER();
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_wmm_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ req->req_id = MLAN_IOCTL_WMM_CFG;
+ pwmm = (mlan_ds_wmm_cfg *) req->pbuf;
+ pwmm->sub_command = MLAN_OID_WMM_CFG_QUEUE_STATS;
+
+ memset(&qstats_ioctl, 0x00, sizeof(qstats_ioctl));
+ pqstats = (mlan_ds_wmm_queue_stats *) & pwmm->param.q_stats;
+
+ if (wrq->u.data.length) {
+ if (copy_from_user(&qstats_ioctl, wrq->u.data.pointer,
+ MIN(wrq->u.data.length, sizeof(qstats_ioctl)))) {
+ PRINTM(MERROR, "QSTATS: copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+
+ memcpy((void *) pqstats, (void *) &qstats_ioctl, sizeof(qstats_ioctl));
+ PRINTM(MINFO, "QSTATS: IOCTL [%d,%d]\n", qstats_ioctl.action,
+ qstats_ioctl.user_priority);
+
+ if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req,
+ MOAL_IOCTL_WAIT)) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ memset(&qstats_ioctl, 0x00, sizeof(qstats_ioctl));
+ memcpy((void *) &qstats_ioctl, (void *) pqstats, sizeof(qstats_ioctl));
+ wrq->u.data.length = sizeof(qstats_ioctl);
+
+ if (copy_to_user
+ (wrq->u.data.pointer, &qstats_ioctl, wrq->u.data.length)) {
+ PRINTM(MERROR, "QSTATS: copy to user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ }
+
+ done:
+ if (req)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Private IOCTL entry to get the status of the WMM queues
+ *
+ * Return the following information for each WMM AC:
+ * - WMM IE Acm Required
+ * - Firmware Flow Required
+ * - Firmware Flow Established
+ * - Firmware Queue Enabled
+ * - Firmware Delivery Enabled
+ * - Firmware Trigger Enabled
+ *
+ * @param priv Pointer to the moal_private driver data struct
+ * @param wrq A pointer to iwreq structure containing the
+ * wlan_ioctl_wmm_queue_status_t struct for request
+ *
+ * @return 0 if successful; IOCTL error code otherwise
+ */
+static int
+woal_wmm_queue_status_ioctl(moal_private * priv, struct iwreq *wrq)
+{
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_wmm_cfg *pwmm = NULL;
+ wlan_ioctl_wmm_queue_status_t qstatus_ioctl;
+ int ret = 0;
+
+ ENTER();
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_wmm_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ req->req_id = MLAN_IOCTL_WMM_CFG;
+ pwmm = (mlan_ds_wmm_cfg *) req->pbuf;
+ pwmm->sub_command = MLAN_OID_WMM_CFG_QUEUE_STATUS;
+
+ if (wrq->u.data.length == sizeof(qstatus_ioctl)) {
+ if (MLAN_STATUS_SUCCESS !=
+ woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ memset(&qstatus_ioctl, 0x00, sizeof(qstatus_ioctl));
+ memcpy((void *) &qstatus_ioctl, (void *) &pwmm->param.q_status,
+ sizeof(qstatus_ioctl));
+ wrq->u.data.length = sizeof(qstatus_ioctl);
+ } else {
+ wrq->u.data.length = 0;
+ }
+
+ if (copy_to_user(wrq->u.data.pointer, &qstatus_ioctl, wrq->u.data.length)) {
+ PRINTM(MERROR, "QSTATUS: copy to user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+
+ done:
+ if (req)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Private IOCTL entry to get the status of the WMM Traffic Streams
+ *
+ * @param priv Pointer to the moal_private driver data struct
+ * @param wrq A pointer to iwreq structure containing the
+ * wlan_ioctl_wmm_ts_status_t struct for request
+ *
+ * @return 0 if successful; IOCTL error code otherwise
+ */
+static int
+woal_wmm_ts_status_ioctl(moal_private * priv, struct iwreq *wrq)
+{
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_wmm_cfg *pwmm = NULL;
+ wlan_ioctl_wmm_ts_status_t ts_status_ioctl;
+ int ret = 0;
+
+ ENTER();
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_wmm_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ req->req_id = MLAN_IOCTL_WMM_CFG;
+ pwmm = (mlan_ds_wmm_cfg *) req->pbuf;
+ pwmm->sub_command = MLAN_OID_WMM_CFG_TS_STATUS;
+
+ memset(&ts_status_ioctl, 0x00, sizeof(ts_status_ioctl));
+
+ if (wrq->u.data.length == sizeof(ts_status_ioctl)) {
+ if (copy_from_user(&ts_status_ioctl, wrq->u.data.pointer,
+ MIN(wrq->u.data.length, sizeof(ts_status_ioctl)))) {
+ PRINTM(MERROR, "TS_STATUS: copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+
+ memset(&pwmm->param.ts_status, 0x00, sizeof(ts_status_ioctl));
+ pwmm->param.ts_status.tid = ts_status_ioctl.tid;
+
+ if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req,
+ MOAL_IOCTL_WAIT)) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ memset(&ts_status_ioctl, 0x00, sizeof(ts_status_ioctl));
+ memcpy((void *) &ts_status_ioctl, (void *) &pwmm->param.ts_status,
+ sizeof(ts_status_ioctl));
+ wrq->u.data.length = sizeof(ts_status_ioctl);
+ } else {
+ wrq->u.data.length = 0;
+ }
+
+ if (copy_to_user(wrq->u.data.pointer, &ts_status_ioctl, wrq->u.data.length)) {
+ PRINTM(MERROR, "TS_STATUS: copy to user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+
+ done:
+ if (req)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Private IOCTL entry to get the By-passed TX packet from upper layer
+ *
+ * @param priv Pointer to the moal_private driver data struct
+ * @param wrq A pointer to iwreq structure containing the packet
+ *
+ * @return 0 if successful; IOCTL error code otherwise
+ */
+static int
+woal_bypassed_packet_ioctl(moal_private * priv, struct iwreq *wrq)
+{
+ int ret = 0;
+ struct sk_buff *skb = NULL;
+ struct ethhdr *eth;
+ t_u16 moreLen = 0, copyLen = 0;
+ ENTER();
+
+#define MLAN_BYPASS_PKT_EXTRA_OFFSET (4)
+
+ copyLen = wrq->u.data.length;
+ moreLen = MLAN_MIN_DATA_HEADER_LEN + MLAN_BYPASS_PKT_EXTRA_OFFSET
+ + sizeof(mlan_buffer);
+
+ skb = alloc_skb(copyLen + moreLen, GFP_KERNEL);
+ if (skb == NULL) {
+ PRINTM(MERROR, "kmalloc no memory !!\n");
+ LEAVE();
+ return -ENOMEM;
+ }
+
+ skb_reserve(skb, moreLen);
+
+ if (copy_from_user(skb_put(skb, copyLen), wrq->u.data.pointer, copyLen)) {
+ PRINTM(MERROR, "PortBlock: copy from user failed\n");
+ dev_kfree_skb_any(skb);
+ ret = -EFAULT;
+ goto done;
+ }
+
+ eth = (struct ethhdr *) skb->data;
+ eth->h_proto = __constant_htons(eth->h_proto);
+ skb->dev = priv->netdev;
+
+ HEXDUMP("Bypass TX Data", skb->data, MIN(skb->len, 100));
+
+ woal_hard_start_xmit(skb, priv->netdev);
+ done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set/Get auth type
+ *
+ * @param priv Pointer to the moal_private driver data struct
+ * @param wrq A pointer to iwreq structure
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_auth_type(moal_private * priv, struct iwreq *wrq)
+{
+ int auth_type;
+ t_u32 auth_mode;
+ int ret = 0;
+
+ ENTER();
+ if (wrq->u.data.length == 0) {
+ if (MLAN_STATUS_SUCCESS !=
+ woal_get_auth_mode(priv, MOAL_IOCTL_WAIT, &auth_mode)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ auth_type = auth_mode;
+ if (copy_to_user(wrq->u.data.pointer, &auth_type, sizeof(auth_type))) {
+ PRINTM(MERROR, "Copy to user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ wrq->u.data.length = 1;
+ } else {
+ if (copy_from_user(&auth_type, wrq->u.data.pointer, sizeof(auth_type))) {
+ PRINTM(MERROR, "Copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ PRINTM(MINFO, "SET: auth_type %d\n", auth_type);
+ if (((auth_type < MLAN_AUTH_MODE_OPEN) ||
+ (auth_type > MLAN_AUTH_MODE_SHARED))
+ && (auth_type != MLAN_AUTH_MODE_AUTO)) {
+ ret = -EINVAL;
+ goto done;
+ }
+ auth_mode = auth_type;
+ if (MLAN_STATUS_SUCCESS !=
+ woal_set_auth_mode(priv, MOAL_IOCTL_WAIT, auth_mode)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ }
+ done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set/Get Port Control mode
+ *
+ * @param priv Pointer to the moal_private driver data struct
+ * @param wrq A pointer to iwreq structure
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_port_ctrl(moal_private * priv, struct iwreq *wrq)
+{
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_sec_cfg *sec = NULL;
+ int ret = 0;
+ ENTER();
+
+ /* Allocate an IOCTL request buffer */
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_sec_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ /* Fill request buffer */
+ sec = (mlan_ds_sec_cfg *) req->pbuf;
+ sec->sub_command = MLAN_OID_SEC_CFG_PORT_CTRL_ENABLED;
+ req->req_id = MLAN_IOCTL_SEC_CFG;
+
+ if (wrq->u.data.length) {
+ if (copy_from_user(&sec->param.port_ctrl_enabled,
+ wrq->u.data.pointer, sizeof(int)) != 0) {
+ PRINTM(MERROR, "port_ctrl:Copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ req->action = MLAN_ACT_SET;
+ } else {
+ req->action = MLAN_ACT_GET;
+ }
+
+ /* Send IOCTL request to MLAN */
+ if (woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT) != MLAN_STATUS_SUCCESS) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ if (!wrq->u.data.length) {
+ if (copy_to_user(wrq->u.data.pointer, &sec->param.port_ctrl_enabled,
+ sizeof(int))) {
+ PRINTM(MERROR, "port_ctrl:Copy to user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ wrq->u.data.length = 1;
+ }
+
+ done:
+ if (req)
+ kfree(req);
+
+ LEAVE();
+ return ret;
+}
+
+#if defined(DFS_TESTING_SUPPORT)
+/**
+ * @brief Set/Get DFS Testing settings
+ *
+ * @param priv Pointer to the moal_private driver data struct
+ * @param wrq A pointer to iwreq structure
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_dfs_testing(moal_private * priv, struct iwreq *wrq)
+{
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_11h_cfg *ds_11hcfg = NULL;
+ int ret = 0;
+ int data[4];
+ int data_length = wrq->u.data.length;
+ ENTER();
+
+ /* Allocate an IOCTL request buffer */
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_11h_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ /* Fill request buffer */
+ ds_11hcfg = (mlan_ds_11h_cfg *) req->pbuf;
+ ds_11hcfg->sub_command = MLAN_OID_11H_DFS_TESTING;
+ req->req_id = MLAN_IOCTL_11H_CFG;
+
+ if (!data_length) {
+ req->action = MLAN_ACT_GET;
+ } else if (data_length == 4) {
+ if (copy_from_user
+ (data, wrq->u.data.pointer, sizeof(int) * data_length)) {
+ PRINTM(MERROR, "Copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ if ((unsigned) data[0] > 0xFFFF) {
+ PRINTM(MERROR, "The maximum user CAC is 65535 msec.\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ if ((unsigned) data[1] > 0xFFFF) {
+ PRINTM(MERROR, "The maximum user NOP is 65535 sec.\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ if ((unsigned) data[3] > 0xFF) {
+ PRINTM(MERROR, "The maximum user fixed channel is 255.\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ ds_11hcfg->param.dfs_testing.usr_cac_period_msec = (t_u16) data[0];
+ ds_11hcfg->param.dfs_testing.usr_nop_period_sec = (t_u16) data[1];
+ ds_11hcfg->param.dfs_testing.usr_no_chan_change = data[2] ? 1 : 0;
+ ds_11hcfg->param.dfs_testing.usr_fixed_new_chan = (t_u8) data[3];
+ priv->phandle->cac_period_jiffies = (t_u16) data[0] * HZ / 1000;
+ req->action = MLAN_ACT_SET;
+ } else {
+ PRINTM(MERROR, "Invalid number of args!\n");
+ ret = -EINVAL;
+ goto done;
+ }
+
+ /* Send IOCTL request to MLAN */
+ if (woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT) != MLAN_STATUS_SUCCESS) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ if (!data_length) {
+ data[0] = ds_11hcfg->param.dfs_testing.usr_cac_period_msec;
+ data[1] = ds_11hcfg->param.dfs_testing.usr_nop_period_sec;
+ data[2] = ds_11hcfg->param.dfs_testing.usr_no_chan_change;
+ data[3] = ds_11hcfg->param.dfs_testing.usr_fixed_new_chan;
+ if (copy_to_user(wrq->u.data.pointer, &data, sizeof(int) * 4)) {
+ PRINTM(MERROR, "Copy to user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ wrq->u.data.length = 4;
+ }
+
+ done:
+ if (req)
+ kfree(req);
+
+ LEAVE();
+ return ret;
+}
+#endif /* DFS_SUPPORT && DFS_TESTING_SUPPORT */
+
+/**
+ * @brief Set/Get Mgmt Frame passthru mask
+ *
+ * @param priv A pointer to moal_private structure
+ * @param wrq A pointer to iwreq structure
+ *
+ * @return 0 -- success, otherwise fail
+ */
+static int
+woal_mgmt_frame_passthru_ctrl(moal_private * priv, struct iwreq *wrq)
+{
+ int ret = 0, data_length = wrq->u.data.length;
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_misc_cfg *mgmt_cfg = NULL;
+ int mask = 0;
+
+ ENTER();
+
+ if (data_length > 1) {
+ PRINTM(MERROR, "Invalid no of arguments!\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ /* Allocate an IOCTL request buffer */
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ /* Fill request buffer */
+ mgmt_cfg = (mlan_ds_misc_cfg *) req->pbuf;
+ req->req_id = MLAN_IOCTL_MISC_CFG;
+ mgmt_cfg->sub_command = MLAN_OID_MISC_RX_MGMT_IND;
+
+ if (data_length) { /* SET */
+ if (copy_from_user(&mask, wrq->u.data.pointer, sizeof(int))) {
+ PRINTM(MERROR, "copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ mgmt_cfg->param.mgmt_subtype_mask = mask;
+ req->action = MLAN_ACT_SET;
+ } else {
+ req->action = MLAN_ACT_GET;
+ }
+
+ /* Send IOCTL request to MLAN */
+ if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ mask = mgmt_cfg->param.mgmt_subtype_mask;
+ if (copy_to_user(wrq->u.data.pointer, &mask, sizeof(int))) {
+ ret = -EFAULT;
+ goto done;
+ }
+ wrq->u.data.length = 1;
+
+ done:
+ if (req)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set/Get Tx/Rx antenna
+ *
+ * @param priv A pointer to moal_private structure
+ * @param wrq A pointer to iwreq structure
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_set_get_tx_rx_ant(moal_private * priv, struct iwreq *wrq)
+{
+ int ret = 0;
+ mlan_ds_radio_cfg *radio = NULL;
+ mlan_ioctl_req *req = NULL;
+ int data[2] = { 0 };
+
+ ENTER();
+
+ if (wrq->u.data.length > 2) {
+ PRINTM(MERROR, "Invalid number of argument!\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_radio_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+ radio = (mlan_ds_radio_cfg *) req->pbuf;
+ radio->sub_command = MLAN_OID_ANT_CFG;
+ req->req_id = MLAN_IOCTL_RADIO_CFG;
+ if (wrq->u.data.length) {
+ if (copy_from_user(data, wrq->u.data.pointer, sizeof(data))) {
+ PRINTM(MERROR, "Copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ radio->param.ant_cfg.tx_antenna = data[0];
+ radio->param.ant_cfg.rx_antenna = data[0];
+ if (wrq->u.data.length == 2)
+ radio->param.ant_cfg.rx_antenna = data[1];
+ req->action = MLAN_ACT_SET;
+ } else
+ req->action = MLAN_ACT_GET;
+ if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ if (!wrq->u.data.length) {
+ wrq->u.data.length = 1;
+ data[0] = radio->param.ant_cfg.tx_antenna;
+ data[1] = radio->param.ant_cfg.rx_antenna;
+ if (data[0] && data[1] && (data[0] != data[1]))
+ wrq->u.data.length = 2;
+ if (copy_to_user(wrq->u.data.pointer, data, sizeof(data))) {
+ ret = -EFAULT;
+ goto done;
+ }
+ }
+ done:
+ if (req)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/********************************************************
+ Global Functions
+********************************************************/
+/**
+ * @brief ioctl function - entry point
+ *
+ * @param dev A pointer to net_device structure
+ * @param req A pointer to ifreq structure
+ * @param cmd Command
+ *
+ * @return 0 --success, otherwise fail
+ */
+int
+woal_wext_do_ioctl(struct net_device *dev, struct ifreq *req, int cmd)
+{
+ moal_private *priv = (moal_private *) netdev_priv(dev);
+ struct iwreq *wrq = (struct iwreq *) req;
+ int ret = 0;
+
+ if (!IS_STA_WEXT(cfg80211_wext))
+ return -EOPNOTSUPP;
+
+ ENTER();
+
+ PRINTM(MINFO, "woal_wext_do_ioctl: ioctl cmd = 0x%x\n", cmd);
+ switch (cmd) {
+ case WOAL_SETONEINT_GETWORDCHAR:
+ switch (wrq->u.data.flags) {
+ case WOAL_VERSION: /* Get driver version */
+ ret = woal_get_driver_version(priv, req);
+ break;
+ case WOAL_VEREXT: /* Get extended driver version */
+ ret = woal_get_driver_verext(priv, req);
+ break;
+ default:
+ ret = -EOPNOTSUPP;
+ break;
+ }
+ break;
+ case WOAL_SETNONE_GETNONE:
+ switch (wrq->u.data.flags) {
+ case WOAL_WARMRESET:
+ ret = woal_warm_reset(priv);
+ break;
+ case WOAL_11D_CLR_CHAN_TABLE:
+ ret = woal_11d_clr_chan_table(priv, wrq);
+ break;
+ default:
+ ret = -EOPNOTSUPP;
+ break;
+ }
+ break;
+ case WOAL_SETONEINT_GETONEINT:
+ switch (wrq->u.data.flags) {
+ case WOAL_SET_GET_TXRATE:
+ ret = woal_set_get_txrate(priv, wrq);
+ break;
+ case WOAL_SET_GET_REGIONCODE:
+ ret = woal_set_get_regioncode(priv, wrq);
+ break;
+ case WOAL_SET_RADIO:
+ ret = woal_set_get_radio(priv, wrq);
+ break;
+ case WOAL_WMM_ENABLE:
+ ret = woal_wmm_enable_ioctl(priv, wrq);
+ break;
+ case WOAL_11D_ENABLE:
+ ret = woal_11d_enable_ioctl(priv, wrq);
+ break;
+ case WOAL_SET_GET_QOS_CFG:
+ ret = woal_set_get_qos_cfg(priv, wrq);
+ break;
+#if defined(REASSOCIATION)
+ case WOAL_SET_GET_REASSOC:
+ ret = woal_set_get_reassoc(priv, wrq);
+ break;
+#endif /* REASSOCIATION */
+ case WOAL_TXBUF_CFG:
+ ret = woal_txbuf_cfg(priv, wrq);
+ break;
+ case WOAL_SET_GET_WWS_CFG:
+ ret = woal_wws_cfg(priv, wrq);
+ break;
+ case WOAL_SLEEP_PD:
+ ret = woal_sleep_pd(priv, wrq);
+ break;
+ case WOAL_AUTH_TYPE:
+ ret = woal_auth_type(priv, wrq);
+ break;
+ case WOAL_PORT_CTRL:
+ ret = woal_port_ctrl(priv, wrq);
+ break;
+#if defined(WIFI_DIRECT_SUPPORT)
+#if defined(STA_SUPPORT) && defined(UAP_SUPPORT)
+ case WOAL_SET_GET_BSS_ROLE:
+ ret = woal_set_get_bss_role(priv, wrq);
+ break;
+#endif
+#endif
+ case WOAL_SET_GET_11H_LOCAL_PWR_CONSTRAINT:
+ ret = woal_set_get_11h_local_pwr_constraint(priv, wrq);
+ break;
+ case WOAL_HT_STREAM_CFG:
+ ret = woal_ht_stream_cfg_ioctl(priv, wrq);
+ break;
+ case WOAL_MAC_CONTROL:
+ ret = woal_mac_control_ioctl(priv, wrq);
+ break;
+ case WOAL_THERMAL:
+ ret = woal_thermal_ioctl(priv, wrq);
+ break;
+ default:
+ ret = -EOPNOTSUPP;
+ break;
+ }
+ break;
+
+ case WOAL_SET_GET_SIXTEEN_INT:
+ switch ((int) wrq->u.data.flags) {
+ case WOAL_TX_POWERCFG:
+ ret = woal_tx_power_cfg(priv, wrq);
+ break;
+#ifdef DEBUG_LEVEL1
+ case WOAL_DRV_DBG:
+ ret = woal_drv_dbg(priv, wrq);
+ break;
+#endif
+ case WOAL_BEACON_INTERVAL:
+ ret = woal_beacon_interval(priv, wrq);
+ break;
+ case WOAL_ATIM_WINDOW:
+ ret = woal_atim_window(priv, wrq);
+ break;
+ case WOAL_SIGNAL:
+ ret = woal_get_signal(priv, wrq);
+ break;
+ case WOAL_DEEP_SLEEP:
+ ret = woal_deep_sleep_ioctl(priv, wrq);
+ break;
+ case WOAL_11N_TX_CFG:
+ ret = woal_11n_tx_cfg(priv, wrq);
+ break;
+ case WOAL_11N_AMSDU_AGGR_CTRL:
+ ret = woal_11n_amsdu_aggr_ctrl(priv, wrq);
+ break;
+ case WOAL_11N_HTCAP_CFG:
+ ret = woal_11n_htcap_cfg(priv, wrq);
+ break;
+ case WOAL_PRIO_TBL:
+ ret = woal_11n_prio_tbl(priv, wrq);
+ break;
+ case WOAL_ADDBA_UPDT:
+ ret = woal_addba_para_updt(priv, wrq);
+ break;
+ case WOAL_ADDBA_REJECT:
+ ret = woal_addba_reject(priv, wrq);
+ break;
+ case WOAL_TX_BF_CAP:
+ ret = woal_tx_bf_cap_ioctl(priv, wrq);
+ break;
+ case WOAL_HS_CFG:
+ ret = woal_hs_cfg(priv, wrq, MTRUE);
+ break;
+ case WOAL_HS_SETPARA:
+ ret = woal_hs_setpara(priv, wrq);
+ break;
+ case WOAL_REG_READ_WRITE:
+ ret = woal_reg_read_write(priv, wrq);
+ break;
+ case WOAL_INACTIVITY_TIMEOUT_EXT:
+ ret = woal_inactivity_timeout_ext(priv, wrq);
+ break;
+ case WOAL_SDIO_CLOCK:
+ ret = woal_sdio_clock_ioctl(priv, wrq);
+ break;
+ case WOAL_CMD_52RDWR:
+ ret = woal_cmd52rdwr_ioctl(priv, wrq);
+ break;
+ case WOAL_BAND_CFG:
+ ret = woal_band_cfg(priv, wrq);
+ break;
+ case WOAL_SCAN_CFG:
+ ret = woal_set_get_scan_cfg(priv, wrq);
+ break;
+ case WOAL_PS_CFG:
+ ret = woal_set_get_ps_cfg(priv, wrq);
+ break;
+ case WOAL_MEM_READ_WRITE:
+ ret = woal_mem_read_write(priv, wrq);
+ break;
+#if defined(SDIO_MULTI_PORT_TX_AGGR) || defined(SDIO_MULTI_PORT_RX_AGGR)
+ case WOAL_SDIO_MPA_CTRL:
+ ret = woal_do_sdio_mpa_ctrl(priv, wrq);
+ break;
+#endif
+ case WOAL_SLEEP_PARAMS:
+ ret = woal_sleep_params_ioctl(priv, wrq);
+ break;
+#if defined(DFS_TESTING_SUPPORT)
+ case WOAL_DFS_TESTING:
+ ret = woal_dfs_testing(priv, wrq);
+ break;
+#endif
+ case WOAL_MGMT_FRAME_CTRL:
+ ret = woal_mgmt_frame_passthru_ctrl(priv, wrq);
+ break;
+ case WOAL_SET_GET_TX_RX_ANT:
+ ret = woal_set_get_tx_rx_ant(priv, wrq);
+ break;
+ default:
+ ret = -EINVAL;
+ break;
+ }
+ break;
+
+ case WOALGETLOG:
+ ret = woal_get_log(priv, wrq);
+ break;
+
+ case WOAL_SET_GET_256_CHAR:
+ switch (wrq->u.data.flags) {
+ case WOAL_PASSPHRASE:
+ ret = woal_passphrase(priv, wrq);
+ break;
+ case WOAL_ADHOC_AES:
+ ret = woal_adhoc_aes_ioctl(priv, wrq);
+ break;
+ case WOAL_WMM_QUEUE_STATUS:
+ ret = woal_wmm_queue_status_ioctl(priv, wrq);
+ break;
+
+ case WOAL_WMM_TS_STATUS:
+ ret = woal_wmm_ts_status_ioctl(priv, wrq);
+ break;
+ case WOAL_IP_ADDRESS:
+ ret = woal_set_get_ip_addr(priv, wrq);
+ break;
+ case WOAL_TX_BF_CFG:
+ ret = woal_tx_bf_cfg_ioctl(priv, wrq);
+ break;
+ default:
+ ret = -EINVAL;
+ break;
+ }
+ break;
+
+ case WOAL_SETADDR_GETNONE:
+ switch ((int) wrq->u.data.flags) {
+ case WOAL_DEAUTH:
+ ret = woal_deauth(priv, wrq);
+ break;
+ default:
+ ret = -EINVAL;
+ break;
+ }
+ break;
+
+ case WOAL_SETNONE_GETTWELVE_CHAR:
+ /*
+ * We've not used IW_PRIV_TYPE_FIXED so sub-ioctl number is
+ * in flags of iwreq structure, otherwise it will be in
+ * mode member of iwreq structure.
+ */
+ switch ((int) wrq->u.data.flags) {
+ case WOAL_WPS_SESSION:
+ ret = woal_wps_cfg_ioctl(priv, wrq);
+ break;
+ default:
+ ret = -EINVAL;
+ break;
+ }
+ break;
+ case WOAL_SETNONE_GET_FOUR_INT:
+ switch ((int) wrq->u.data.flags) {
+ case WOAL_DATA_RATE:
+ ret = woal_get_txrx_rate(priv, wrq);
+ break;
+ case WOAL_ESUPP_MODE:
+ ret = woal_get_esupp_mode(priv, wrq);
+ break;
+ default:
+ ret = -EINVAL;
+ break;
+ }
+ break;
+
+ case WOAL_SET_GET_64_INT:
+ switch ((int) wrq->u.data.flags) {
+ case WOAL_ECL_SYS_CLOCK:
+ ret = woal_ecl_sys_clock(priv, wrq);
+ break;
+ }
+
+ break;
+
+ case WOAL_HOST_CMD:
+ ret = woal_host_command(priv, wrq);
+ break;
+ case WOAL_ARP_FILTER:
+ ret = woal_arp_filter(priv, wrq);
+ break;
+ case WOAL_SET_INTS_GET_CHARS:
+ switch ((int) wrq->u.data.flags) {
+ case WOAL_READ_EEPROM:
+ ret = woal_read_eeprom(priv, wrq);
+ break;
+ }
+ break;
+ case WOAL_SET_GET_2K_BYTES:
+ switch ((int) wrq->u.data.flags) {
+ case WOAL_CMD_53RDWR:
+ ret = woal_cmd53rdwr_ioctl(priv, wrq);
+ break;
+ case WOAL_SET_USER_SCAN:
+ ret = woal_set_user_scan_ioctl(priv, wrq);
+ break;
+ case WOAL_GET_SCAN_TABLE:
+ ret = woal_get_scan_table_ioctl(priv, wrq);
+ break;
+ case WOAL_WMM_ADDTS:
+ ret = woal_wmm_addts_req_ioctl(priv, wrq);
+ break;
+ case WOAL_WMM_DELTS:
+ ret = woal_wmm_delts_req_ioctl(priv, wrq);
+ break;
+ case WOAL_WMM_QUEUE_CONFIG:
+ ret = woal_wmm_queue_config_ioctl(priv, wrq);
+ break;
+ case WOAL_WMM_QUEUE_STATS:
+ ret = woal_wmm_queue_stats_ioctl(priv, wrq);
+ break;
+ case WOAL_BYPASSED_PACKET:
+ ret = woal_bypassed_packet_ioctl(priv, wrq);
+ break;
+ default:
+ ret = -EINVAL;
+ break;
+ }
+ break;
+
+#ifdef UAP_WEXT
+ case WOAL_FROYO_START:
+ break;
+ case WOAL_FROYO_WL_FW_RELOAD:
+ break;
+ case WOAL_FROYO_STOP:
+ if (IS_UAP_WEXT(cfg80211_wext) && MLAN_STATUS_SUCCESS !=
+ woal_disconnect(priv, MOAL_IOCTL_WAIT, NULL)) {
+ ret = -EFAULT;
+ }
+ break;
+#endif
+ default:
+ ret = -EINVAL;
+ break;
+ }
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Get mode
+ *
+ * @param priv A pointer to moal_private structure
+ * @param wait_option Wait option (MOAL_WAIT or MOAL_NO_WAIT)
+ *
+ * @return Wireless mode
+ */
+t_u32
+woal_get_mode(moal_private * priv, t_u8 wait_option)
+{
+ int ret = 0;
+ mlan_ds_bss *bss = NULL;
+ mlan_ioctl_req *req = NULL;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+ t_u32 mode = priv->w_stats.status;
+ ENTER();
+
+ /* Allocate an IOCTL request buffer */
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_bss));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ /* Fill request buffer */
+ bss = (mlan_ds_bss *) req->pbuf;
+ bss->sub_command = MLAN_OID_BSS_MODE;
+ req->req_id = MLAN_IOCTL_BSS;
+ req->action = MLAN_ACT_GET;
+
+ /* Send IOCTL request to MLAN */
+ status = woal_request_ioctl(priv, req, wait_option);
+ if (status == MLAN_STATUS_SUCCESS) {
+ switch (bss->param.bss_mode) {
+ case MLAN_BSS_MODE_INFRA:
+ mode = IW_MODE_INFRA;
+ break;
+ case MLAN_BSS_MODE_IBSS:
+ mode = IW_MODE_ADHOC;
+ break;
+ default:
+ mode = IW_MODE_AUTO;
+ break;
+ }
+ }
+ done:
+ if (req && (status != MLAN_STATUS_PENDING))
+ kfree(req);
+ LEAVE();
+ return mode;
+}
+
+/**
+ * @brief Get statistics information
+ *
+ * @param priv A pointer to moal_private structure
+ * @param wait_option Wait option
+ * @param stats A pointer to mlan_ds_get_stats structure
+ *
+ * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING -- success, otherwise fail
+ */
+mlan_status
+woal_get_stats_info(moal_private * priv, t_u8 wait_option,
+ mlan_ds_get_stats * stats)
+{
+ int ret = 0;
+ mlan_ds_get_info *info = NULL;
+ mlan_ioctl_req *req = NULL;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+ ENTER();
+
+ /* Allocate an IOCTL request buffer */
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_get_info));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ /* Fill request buffer */
+ info = (mlan_ds_get_info *) req->pbuf;
+ info->sub_command = MLAN_OID_GET_STATS;
+ req->req_id = MLAN_IOCTL_GET_INFO;
+ req->action = MLAN_ACT_GET;
+
+ /* Send IOCTL request to MLAN */
+ status = woal_request_ioctl(priv, req, wait_option);
+ if (status == MLAN_STATUS_SUCCESS) {
+ if (stats)
+ memcpy(stats, &info->param.stats, sizeof(mlan_ds_get_stats));
+ priv->w_stats.discard.fragment = info->param.stats.fcs_error;
+ priv->w_stats.discard.retries = info->param.stats.retry;
+ priv->w_stats.discard.misc = info->param.stats.ack_failure;
+ }
+ done:
+ if (req && (status != MLAN_STATUS_PENDING))
+ kfree(req);
+ LEAVE();
+ return status;
+}
+
+/**
+ * @brief Get data rates
+ *
+ * @param priv A pointer to moal_private structure
+ * @param wait_option Wait option
+ * @param m_rates A pointer to moal_802_11_rates structure
+ *
+ * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING -- success, otherwise fail
+ */
+mlan_status
+woal_get_data_rates(moal_private * priv, t_u8 wait_option,
+ moal_802_11_rates * m_rates)
+{
+ int ret = 0;
+ mlan_ds_rate *rate = NULL;
+ mlan_ioctl_req *req = NULL;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+ ENTER();
+
+ /* Allocate an IOCTL request buffer */
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_rate));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ /* Fill request buffer */
+ rate = (mlan_ds_rate *) req->pbuf;
+ rate->sub_command = MLAN_OID_SUPPORTED_RATES;
+ req->req_id = MLAN_IOCTL_RATE;
+ req->action = MLAN_ACT_GET;
+
+ /* Send IOCTL request to MLAN */
+ status = woal_request_ioctl(priv, req, wait_option);
+ if (status == MLAN_STATUS_SUCCESS) {
+ if (m_rates)
+ m_rates->num_of_rates =
+ woal_copy_rates(m_rates->rates, m_rates->num_of_rates,
+ rate->param.rates, MLAN_SUPPORTED_RATES);
+ }
+ done:
+ if (req && (status != MLAN_STATUS_PENDING))
+ kfree(req);
+ LEAVE();
+ return status;
+}
+
+/**
+ * @brief Get channel list
+ *
+ * @param priv A pointer to moal_private structure
+ * @param wait_option Wait option
+ * @param chan_list A pointer to mlan_chan_list structure
+ *
+ * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING -- success, otherwise fail
+ */
+mlan_status
+woal_get_channel_list(moal_private * priv, t_u8 wait_option,
+ mlan_chan_list * chan_list)
+{
+ int ret = 0;
+ mlan_ds_bss *bss = NULL;
+ mlan_ioctl_req *req = NULL;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+ ENTER();
+
+ /* Allocate an IOCTL request buffer */
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_bss));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ /* Fill request buffer */
+ bss = (mlan_ds_bss *) req->pbuf;
+ bss->sub_command = MLAN_OID_BSS_CHANNEL_LIST;
+ req->req_id = MLAN_IOCTL_BSS;
+ req->action = MLAN_ACT_GET;
+
+ /* Send IOCTL request to MLAN */
+ status = woal_request_ioctl(priv, req, wait_option);
+ if (status == MLAN_STATUS_SUCCESS) {
+ if (chan_list) {
+ memcpy(chan_list, &bss->param.chanlist, sizeof(mlan_chan_list));
+ }
+ }
+ done:
+ if (req && (status != MLAN_STATUS_PENDING))
+ kfree(req);
+ LEAVE();
+ return status;
+}
+
+/**
+ * @brief Handle get info resp
+ *
+ * @param priv Pointer to moal_private structure
+ * @param info Pointer to mlan_ds_get_info structure
+ *
+ * @return N/A
+ */
+void
+woal_ioctl_get_info_resp(moal_private * priv, mlan_ds_get_info * info)
+{
+ ENTER();
+ switch (info->sub_command) {
+ case MLAN_OID_GET_STATS:
+ priv->w_stats.discard.fragment = info->param.stats.fcs_error;
+ priv->w_stats.discard.retries = info->param.stats.retry;
+ priv->w_stats.discard.misc = info->param.stats.ack_failure;
+ break;
+ case MLAN_OID_GET_SIGNAL:
+ if (info->param.signal.selector & BCN_RSSI_AVG_MASK)
+ priv->w_stats.qual.level = info->param.signal.bcn_rssi_avg;
+ if (info->param.signal.selector & BCN_NF_AVG_MASK)
+ priv->w_stats.qual.noise = info->param.signal.bcn_nf_avg;
+ break;
+ default:
+ break;
+ }
+ LEAVE();
+}
+
+/**
+ * @brief Handle get BSS resp
+ *
+ * @param priv Pointer to moal_private structure
+ * @param bss Pointer to mlan_ds_bss structure
+ *
+ * @return N/A
+ */
+void
+woal_ioctl_get_bss_resp(moal_private * priv, mlan_ds_bss * bss)
+{
+ t_u32 mode = 0;
+
+ ENTER();
+
+ switch (bss->sub_command) {
+ case MLAN_OID_BSS_MODE:
+ if (bss->param.bss_mode == MLAN_BSS_MODE_INFRA)
+ mode = IW_MODE_INFRA;
+ else if (bss->param.bss_mode == MLAN_BSS_MODE_IBSS)
+ mode = IW_MODE_ADHOC;
+ else
+ mode = IW_MODE_AUTO;
+ priv->w_stats.status = mode;
+ break;
+ default:
+ break;
+ }
+
+ LEAVE();
+ return;
+}
diff --git a/drivers/net/wireless/sd8797/mlinux/moal_priv.h b/drivers/net/wireless/sd8797/mlinux/moal_priv.h
new file mode 100644
index 000000000000..de491f6d6a29
--- /dev/null
+++ b/drivers/net/wireless/sd8797/mlinux/moal_priv.h
@@ -0,0 +1,715 @@
+/** @file moal_priv.h
+ *
+ * @brief This file contains definition for extended private IOCTL call.
+ *
+ * Copyright (C) 2008-2011, Marvell International Ltd.
+ *
+ * This software file (the "File") is distributed by Marvell International
+ * Ltd. under the terms of the GNU General Public License Version 2, June 1991
+ * (the "License"). You may use, redistribute and/or modify this File in
+ * accordance with the terms and conditions of the License, a copy of which
+ * is available by writing to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
+ * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
+ *
+ * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
+ * ARE EXPRESSLY DISCLAIMED. The License provides additional details about
+ * this warranty disclaimer.
+ *
+ */
+
+/********************************************************
+Change log:
+ 10/31/2008: initial version
+********************************************************/
+
+#ifndef _WOAL_PRIV_H_
+#define _WOAL_PRIV_H_
+
+/** Command disabled */
+#define CMD_DISABLED 0
+/** Command enabled */
+#define CMD_ENABLED 1
+/** Command get */
+#define CMD_GET 2
+
+/** 2K bytes */
+#define WOAL_2K_BYTES 2000
+
+/** PRIVATE CMD ID */
+#define WOAL_IOCTL (SIOCIWFIRSTPRIV) /* 0x8BE0 defined in
+ wireless.h */
+
+/** Private command ID to set one int/get word char */
+#define WOAL_SETONEINT_GETWORDCHAR (WOAL_IOCTL + 1)
+/** Private command ID to get version */
+#define WOAL_VERSION 1
+/** Private command ID to get extended version */
+#define WOAL_VEREXT 2
+
+/** Private command ID to set/get none */
+#define WOAL_SETNONE_GETNONE (WOAL_IOCTL + 2)
+/** Private command ID for warm reset */
+#define WOAL_WARMRESET 1
+/** Private command ID to clear 11d chan table */
+#define WOAL_11D_CLR_CHAN_TABLE 4
+
+/** Private command ID to set/get sixteen int */
+#define WOAL_SET_GET_SIXTEEN_INT (WOAL_IOCTL + 3)
+/** Private command ID to set/get TX power configurations */
+#define WOAL_TX_POWERCFG 1
+#ifdef DEBUG_LEVEL1
+/** Private command ID to set/get driver debug */
+#define WOAL_DRV_DBG 2
+#endif
+/** Private command ID to set/get beacon interval */
+#define WOAL_BEACON_INTERVAL 3
+/** Private command ID to set/get ATIM window */
+#define WOAL_ATIM_WINDOW 4
+/** Private command ID to get RSSI */
+#define WOAL_SIGNAL 5
+/** Private command ID to set/get Deep Sleep mode */
+#define WOAL_DEEP_SLEEP 7
+/** Private command ID for 11n ht configration */
+#define WOAL_11N_TX_CFG 8
+/** Private command ID for 11n usr ht configration */
+#define WOAL_11N_HTCAP_CFG 9
+/** Private command ID for TX Aggregation */
+#define WOAL_PRIO_TBL 10
+/** Private command ID for Updating ADDBA variables */
+#define WOAL_ADDBA_UPDT 11
+/** Private command ID to set/get Host Sleep configuration */
+#define WOAL_HS_CFG 12
+/** Private command ID to set Host Sleep parameters */
+#define WOAL_HS_SETPARA 13
+/** Private command ID to read/write registers */
+#define WOAL_REG_READ_WRITE 14
+/** Private command ID to set/get band/adhocband */
+#define WOAL_BAND_CFG 15
+/** Private command ID for TX Aggregation */
+#define WOAL_11N_AMSDU_AGGR_CTRL 17
+/** Private command ID to set/get Inactivity timeout */
+#define WOAL_INACTIVITY_TIMEOUT_EXT 18
+/** Private command ID to turn on/off sdio clock */
+#define WOAL_SDIO_CLOCK 19
+/** Private command ID to read/write Command 52 */
+#define WOAL_CMD_52RDWR 20
+/** Private command ID to set/get scan configuration parameter */
+#define WOAL_SCAN_CFG 21
+/** Private command ID to set/get PS configuration parameter */
+#define WOAL_PS_CFG 22
+/** Private command ID to read/write memory */
+#define WOAL_MEM_READ_WRITE 23
+#if defined(SDIO_MULTI_PORT_TX_AGGR) || defined(SDIO_MULTI_PORT_RX_AGGR)
+/** Private command ID to control SDIO MP-A */
+#define WOAL_SDIO_MPA_CTRL 25
+#endif
+/** Private command ID for Updating ADDBA variables */
+#define WOAL_ADDBA_REJECT 27
+/** Private command ID to set/get sleep parameters */
+#define WOAL_SLEEP_PARAMS 28
+/** Private command ID to set/get TX BF capabilities */
+#define WOAL_TX_BF_CAP 31
+#if defined(DFS_TESTING_SUPPORT)
+/** Private command ID to set/get dfs testing settings */
+#define WOAL_DFS_TESTING 33
+#endif
+/** Private command ID to set/get tx/rx antenna */
+#define WOAL_SET_GET_TX_RX_ANT 35
+/** Private command ID to set/get management frame passthru mask */
+#define WOAL_MGMT_FRAME_CTRL 36
+
+/** Private command ID to set one int/get one int */
+#define WOAL_SETONEINT_GETONEINT (WOAL_IOCTL + 5)
+/** Private command ID to set/get Tx rate */
+#define WOAL_SET_GET_TXRATE 1
+/** Private command ID to set/get region code */
+#define WOAL_SET_GET_REGIONCODE 2
+/** Private command ID to turn on/off radio */
+#define WOAL_SET_RADIO 3
+/** Private command ID to enable WMM */
+#define WOAL_WMM_ENABLE 4
+/** Private command ID to enable 802.11D */
+#define WOAL_11D_ENABLE 5
+/** Private command ID to set/get QoS configuration */
+#define WOAL_SET_GET_QOS_CFG 7
+#if defined(REASSOCIATION)
+/** Private command ID to set/get reassociation setting */
+#define WOAL_SET_GET_REASSOC 9
+#endif /* REASSOCIATION */
+/** Private command ID for Updating Transmit buffer configration */
+#define WOAL_TXBUF_CFG 10
+/** Private command ID to set/get WWS mode */
+#define WOAL_SET_GET_WWS_CFG 12
+/** Private command ID to set/get sleep period */
+#define WOAL_SLEEP_PD 13
+/** Private command ID to set/get auth type */
+#define WOAL_AUTH_TYPE 18
+/** Private command ID to set/get port control */
+#define WOAL_PORT_CTRL 19
+#if defined(WIFI_DIRECT_SUPPORT)
+#if defined(STA_SUPPORT) && defined(UAP_SUPPORT)
+/** Private command ID for set/get BSS role */
+#define WOAL_SET_GET_BSS_ROLE 21
+#endif
+#endif
+/** Private command ID for set/get 11h local power constraint */
+#define WOAL_SET_GET_11H_LOCAL_PWR_CONSTRAINT 22
+/** Private command ID to set/get 11N HT stream configuration */
+#define WOAL_HT_STREAM_CFG 23
+/** Private command ID to set/get MAC control */
+#define WOAL_MAC_CONTROL 24
+/** Private command ID to get thermal value */
+#define WOAL_THERMAL 25
+
+/** Private command ID to get log */
+#define WOALGETLOG (WOAL_IOCTL + 7)
+
+/** Private command ID to set a wext address variable */
+#define WOAL_SETADDR_GETNONE (WOAL_IOCTL + 8)
+/** Private command ID to send deauthentication */
+#define WOAL_DEAUTH 1
+
+/** Private command to get/set 256 chars */
+#define WOAL_SET_GET_256_CHAR (WOAL_IOCTL + 9)
+/** Private command to read/write passphrase */
+#define WOAL_PASSPHRASE 1
+/** Private command to get/set Ad-Hoc AES */
+#define WOAL_ADHOC_AES 2
+/** Private command ID to get WMM queue status */
+#define WOAL_WMM_QUEUE_STATUS 4
+/** Private command ID to get Traffic stream status */
+#define WOAL_WMM_TS_STATUS 5
+#define WOAL_IP_ADDRESS 7
+/** Private command ID to set/get TX bemaforming */
+#define WOAL_TX_BF_CFG 8
+
+/** Get log buffer size */
+#define GETLOG_BUFSIZE 512
+
+/** Private command ID to set none/get twelve chars*/
+#define WOAL_SETNONE_GETTWELVE_CHAR (WOAL_IOCTL + 11)
+/** Private command ID for WPS session */
+#define WOAL_WPS_SESSION 1
+
+/** Private command ID to set none/get four int */
+#define WOAL_SETNONE_GET_FOUR_INT (WOAL_IOCTL + 13)
+/** Private command ID to get data rates */
+#define WOAL_DATA_RATE 1
+/** Private command ID to get E-Supplicant mode */
+#define WOAL_ESUPP_MODE 2
+
+/** Private command to get/set 64 ints */
+#define WOAL_SET_GET_64_INT (WOAL_IOCTL + 15)
+/** Private command ID to set/get ECL system clock */
+#define WOAL_ECL_SYS_CLOCK 1
+
+/** Private command ID for hostcmd */
+#define WOAL_HOST_CMD (WOAL_IOCTL + 17)
+
+/** Private command ID for arpfilter */
+#define WOAL_ARP_FILTER (WOAL_IOCTL + 19)
+
+/** Private command ID to set ints and get chars */
+#define WOAL_SET_INTS_GET_CHARS (WOAL_IOCTL + 21)
+/** Private command ID to read EEPROM data */
+#define WOAL_READ_EEPROM 1
+
+/** Private command ID to set/get 2K bytes */
+#define WOAL_SET_GET_2K_BYTES (WOAL_IOCTL + 23)
+
+/** Private command ID to read/write Command 53 */
+#define WOAL_CMD_53RDWR 2
+
+/** Private command ID for setuserscan */
+#define WOAL_SET_USER_SCAN 3
+/** Private command ID for getscantable */
+#define WOAL_GET_SCAN_TABLE 4
+
+/** Private command ID to request ADDTS */
+#define WOAL_WMM_ADDTS 7
+/** Private command ID to request DELTS */
+#define WOAL_WMM_DELTS 8
+/** Private command ID to queue configuration */
+#define WOAL_WMM_QUEUE_CONFIG 9
+/** Private command ID to queue stats */
+#define WOAL_WMM_QUEUE_STATS 10
+/** Private command ID to Bypass auth packet */
+#define WOAL_BYPASSED_PACKET 11
+
+#ifdef UAP_WEXT
+/** The following command IDs are for Froyo app */
+/** Private command ID to start driver */
+#define WOAL_FROYO_START (WOAL_IOCTL + 28)
+/** Private command ID to reload FW */
+#define WOAL_FROYO_WL_FW_RELOAD (WOAL_IOCTL + 29)
+/** Private command ID to stop driver */
+#define WOAL_FROYO_STOP (WOAL_IOCTL + 30)
+#endif
+
+/**
+ * iwpriv ioctl handlers
+ */
+static const struct iw_priv_args woal_private_args[] = {
+ {
+ WOAL_SETONEINT_GETWORDCHAR,
+ IW_PRIV_TYPE_INT | 1,
+ IW_PRIV_TYPE_CHAR | 128,
+ ""},
+ {
+ WOAL_VERSION,
+ IW_PRIV_TYPE_INT | 1,
+ IW_PRIV_TYPE_CHAR | 128,
+ "version"},
+ {
+ WOAL_VEREXT,
+ IW_PRIV_TYPE_INT | 1,
+ IW_PRIV_TYPE_CHAR | 128,
+ "verext"},
+ {
+ WOAL_SETNONE_GETNONE,
+ IW_PRIV_TYPE_NONE,
+ IW_PRIV_TYPE_NONE,
+ ""},
+ {
+ WOAL_WARMRESET,
+ IW_PRIV_TYPE_NONE,
+ IW_PRIV_TYPE_NONE,
+ "warmreset"},
+ {
+ WOAL_SETONEINT_GETONEINT,
+ IW_PRIV_TYPE_INT | 1,
+ IW_PRIV_TYPE_INT | 1,
+ ""},
+ {
+ WOAL_SET_GET_TXRATE,
+ IW_PRIV_TYPE_INT | 1,
+ IW_PRIV_TYPE_INT | 1,
+ "txratecfg"},
+ {
+ WOAL_SET_GET_REGIONCODE,
+ IW_PRIV_TYPE_INT | 1,
+ IW_PRIV_TYPE_INT | 1,
+ "regioncode"},
+ {
+ WOAL_SET_RADIO,
+ IW_PRIV_TYPE_INT | 1,
+ IW_PRIV_TYPE_INT | 1,
+ "radioctrl"},
+ {
+ WOAL_WMM_ENABLE,
+ IW_PRIV_TYPE_INT | 1,
+ IW_PRIV_TYPE_INT | 1,
+ "wmmcfg"},
+ {
+ WOAL_11D_ENABLE,
+ IW_PRIV_TYPE_INT | 1,
+ IW_PRIV_TYPE_INT | 1,
+ "11dcfg"},
+ {
+ WOAL_11D_CLR_CHAN_TABLE,
+ IW_PRIV_TYPE_NONE,
+ IW_PRIV_TYPE_NONE,
+ "11dclrtbl"},
+ {
+ WOAL_SET_GET_QOS_CFG,
+ IW_PRIV_TYPE_INT | 1,
+ IW_PRIV_TYPE_INT | 1,
+ "qoscfg"},
+ {
+ WOAL_SET_GET_WWS_CFG,
+ IW_PRIV_TYPE_INT | 1,
+ IW_PRIV_TYPE_INT | 1,
+ "wwscfg"},
+#if defined(REASSOCIATION)
+ {
+ WOAL_SET_GET_REASSOC,
+ IW_PRIV_TYPE_INT | 1,
+ IW_PRIV_TYPE_INT | 1,
+ "reassoctrl"},
+#endif
+ {
+ WOAL_TXBUF_CFG,
+ IW_PRIV_TYPE_INT | 1,
+ IW_PRIV_TYPE_INT | 1,
+ "txbufcfg"},
+ {
+ WOAL_SLEEP_PD,
+ IW_PRIV_TYPE_INT | 1,
+ IW_PRIV_TYPE_INT | 1,
+ "sleeppd"},
+ {
+ WOAL_AUTH_TYPE,
+ IW_PRIV_TYPE_INT | 1,
+ IW_PRIV_TYPE_INT | 1,
+ "authtype"},
+ {
+ WOAL_PORT_CTRL,
+ IW_PRIV_TYPE_INT | 1,
+ IW_PRIV_TYPE_INT | 1,
+ "port_ctrl"},
+#if defined(WIFI_DIRECT_SUPPORT)
+#if defined(STA_SUPPORT) && defined(UAP_SUPPORT)
+ {
+ WOAL_SET_GET_BSS_ROLE,
+ IW_PRIV_TYPE_INT | 1,
+ IW_PRIV_TYPE_INT | 1,
+ "bssrole"},
+#endif
+#endif
+ {
+ WOAL_SET_GET_11H_LOCAL_PWR_CONSTRAINT,
+ IW_PRIV_TYPE_INT | 1,
+ IW_PRIV_TYPE_INT | 1,
+ "powercons"},
+ {
+ WOAL_HT_STREAM_CFG,
+ IW_PRIV_TYPE_INT | 1,
+ IW_PRIV_TYPE_INT | 1,
+ "htstreamcfg"},
+ {
+ WOAL_MAC_CONTROL,
+ IW_PRIV_TYPE_INT | 1,
+ IW_PRIV_TYPE_INT | 1,
+ "macctrl"},
+ {
+ WOAL_THERMAL,
+ IW_PRIV_TYPE_INT | 1,
+ IW_PRIV_TYPE_INT | 1,
+ "thermal"},
+ {
+ WOAL_SET_GET_SIXTEEN_INT,
+ IW_PRIV_TYPE_INT | 16,
+ IW_PRIV_TYPE_INT | 16,
+ ""},
+ {
+ WOAL_TX_POWERCFG,
+ IW_PRIV_TYPE_INT | 16,
+ IW_PRIV_TYPE_INT | 16,
+ "txpowercfg"},
+#ifdef DEBUG_LEVEL1
+ {
+ WOAL_DRV_DBG,
+ IW_PRIV_TYPE_INT | 16,
+ IW_PRIV_TYPE_INT | 16,
+ "drvdbg"},
+#endif
+ {
+ WOAL_BEACON_INTERVAL,
+ IW_PRIV_TYPE_INT | 16,
+ IW_PRIV_TYPE_INT | 16,
+ "bcninterval"},
+ {
+ WOAL_ATIM_WINDOW,
+ IW_PRIV_TYPE_INT | 16,
+ IW_PRIV_TYPE_INT | 16,
+ "atimwindow"},
+ {
+ WOAL_SIGNAL,
+ IW_PRIV_TYPE_INT | 16,
+ IW_PRIV_TYPE_INT | 16,
+ "getsignal"},
+ {
+ WOAL_DEEP_SLEEP,
+ IW_PRIV_TYPE_INT | 16,
+ IW_PRIV_TYPE_INT | 16,
+ "deepsleep",
+ },
+ {
+ WOAL_11N_TX_CFG,
+ IW_PRIV_TYPE_INT | 16,
+ IW_PRIV_TYPE_INT | 16,
+ "httxcfg"},
+ {
+ WOAL_11N_HTCAP_CFG,
+ IW_PRIV_TYPE_INT | 16,
+ IW_PRIV_TYPE_INT | 16,
+ "htcapinfo"},
+ {
+ WOAL_PRIO_TBL,
+ IW_PRIV_TYPE_INT | 16,
+ IW_PRIV_TYPE_INT | 16,
+ "aggrpriotbl"},
+ {
+ WOAL_11N_AMSDU_AGGR_CTRL,
+ IW_PRIV_TYPE_INT | 16,
+ IW_PRIV_TYPE_INT | 16,
+ "amsduaggrctrl"},
+ {
+ WOAL_ADDBA_UPDT,
+ IW_PRIV_TYPE_INT | 16,
+ IW_PRIV_TYPE_INT | 16,
+ "addbapara"},
+ {
+ WOAL_ADDBA_REJECT,
+ IW_PRIV_TYPE_INT | 16,
+ IW_PRIV_TYPE_INT | 16,
+ "addbareject"},
+ {
+ WOAL_TX_BF_CAP,
+ IW_PRIV_TYPE_INT | 16,
+ IW_PRIV_TYPE_INT | 16,
+ "httxbfcap"},
+ {
+ WOAL_HS_CFG,
+ IW_PRIV_TYPE_INT | 16,
+ IW_PRIV_TYPE_INT | 16,
+ "hscfg"},
+ {
+ WOAL_HS_SETPARA,
+ IW_PRIV_TYPE_INT | 16,
+ IW_PRIV_TYPE_INT | 16,
+ "hssetpara"},
+ {
+ WOAL_REG_READ_WRITE,
+ IW_PRIV_TYPE_INT | 16,
+ IW_PRIV_TYPE_INT | 16,
+ "regrdwr"},
+ {
+ WOAL_BAND_CFG,
+ IW_PRIV_TYPE_INT | 16,
+ IW_PRIV_TYPE_INT | 16,
+ "bandcfg"},
+ {
+ WOAL_INACTIVITY_TIMEOUT_EXT,
+ IW_PRIV_TYPE_INT | 16,
+ IW_PRIV_TYPE_INT | 16,
+ "inactivityto"},
+ {
+ WOAL_SDIO_CLOCK,
+ IW_PRIV_TYPE_INT | 16,
+ IW_PRIV_TYPE_INT | 16,
+ "sdioclock"},
+ {
+ WOAL_CMD_52RDWR,
+ IW_PRIV_TYPE_INT | 16,
+ IW_PRIV_TYPE_INT | 16,
+ "sdcmd52rw"},
+ {
+ WOAL_SCAN_CFG,
+ IW_PRIV_TYPE_INT | 16,
+ IW_PRIV_TYPE_INT | 16,
+ "scancfg"},
+ {
+ WOAL_PS_CFG,
+ IW_PRIV_TYPE_INT | 16,
+ IW_PRIV_TYPE_INT | 16,
+ "pscfg"},
+ {
+ WOAL_MEM_READ_WRITE,
+ IW_PRIV_TYPE_INT | 16,
+ IW_PRIV_TYPE_INT | 16,
+ "memrdwr"},
+#if defined(SDIO_MULTI_PORT_TX_AGGR) || defined(SDIO_MULTI_PORT_RX_AGGR)
+ {
+ WOAL_SDIO_MPA_CTRL,
+ IW_PRIV_TYPE_INT | 16,
+ IW_PRIV_TYPE_INT | 16,
+ "mpactrl"},
+#endif
+ {
+ WOAL_SLEEP_PARAMS,
+ IW_PRIV_TYPE_INT | 16,
+ IW_PRIV_TYPE_INT | 16,
+ "sleepparams"},
+#if defined(DFS_TESTING_SUPPORT)
+ {
+ WOAL_DFS_TESTING,
+ IW_PRIV_TYPE_INT | 16,
+ IW_PRIV_TYPE_INT | 16,
+ "dfstesting"},
+#endif
+ {
+ WOAL_MGMT_FRAME_CTRL,
+ IW_PRIV_TYPE_INT | 16,
+ IW_PRIV_TYPE_INT | 16,
+ "mgmtframectrl"},
+ {
+ WOAL_SET_GET_TX_RX_ANT,
+ IW_PRIV_TYPE_INT | 16,
+ IW_PRIV_TYPE_INT | 16,
+ "antcfg"},
+ {
+ WOALGETLOG,
+ IW_PRIV_TYPE_NONE,
+ IW_PRIV_TYPE_CHAR | GETLOG_BUFSIZE,
+ "getlog"},
+ {
+ WOAL_SETADDR_GETNONE,
+ IW_PRIV_TYPE_ADDR | 1,
+ IW_PRIV_TYPE_NONE,
+ ""},
+ {
+ WOAL_DEAUTH,
+ IW_PRIV_TYPE_ADDR | 1,
+ IW_PRIV_TYPE_NONE,
+ "deauth"},
+ {
+ WOAL_SET_GET_256_CHAR,
+ IW_PRIV_TYPE_CHAR | 256,
+ IW_PRIV_TYPE_CHAR | 256,
+ ""},
+ {
+ WOAL_PASSPHRASE,
+ IW_PRIV_TYPE_CHAR | 256,
+ IW_PRIV_TYPE_CHAR | 256,
+ "passphrase"},
+ {
+ WOAL_ADHOC_AES,
+ IW_PRIV_TYPE_CHAR | 256,
+ IW_PRIV_TYPE_CHAR | 256,
+ "adhocaes"},
+ {
+ WOAL_WMM_QUEUE_STATUS,
+ IW_PRIV_TYPE_CHAR | 256,
+ IW_PRIV_TYPE_CHAR | 256,
+ "qstatus"},
+ {
+ WOAL_WMM_TS_STATUS,
+ IW_PRIV_TYPE_CHAR | 256,
+ IW_PRIV_TYPE_CHAR | 256,
+ "ts_status"},
+ {
+ WOAL_IP_ADDRESS,
+ IW_PRIV_TYPE_CHAR | 256,
+ IW_PRIV_TYPE_CHAR | 256,
+ "ipaddr"},
+ {
+ WOAL_TX_BF_CFG,
+ IW_PRIV_TYPE_CHAR | 256,
+ IW_PRIV_TYPE_CHAR | 256,
+ "httxbfcfg"},
+ {
+ WOAL_SETNONE_GETTWELVE_CHAR,
+ IW_PRIV_TYPE_NONE,
+ IW_PRIV_TYPE_CHAR | 12,
+ ""},
+ {
+ WOAL_WPS_SESSION,
+ IW_PRIV_TYPE_NONE,
+ IW_PRIV_TYPE_CHAR | 12,
+ "wpssession"},
+ {
+ WOAL_SETNONE_GET_FOUR_INT,
+ IW_PRIV_TYPE_NONE,
+ IW_PRIV_TYPE_INT | 4,
+ ""},
+ {
+ WOAL_DATA_RATE,
+ IW_PRIV_TYPE_NONE,
+ IW_PRIV_TYPE_INT | 4,
+ "getdatarate"},
+ {
+ WOAL_ESUPP_MODE,
+ IW_PRIV_TYPE_NONE,
+ IW_PRIV_TYPE_INT | 4,
+ "esuppmode"},
+ {
+ WOAL_SET_GET_64_INT,
+ IW_PRIV_TYPE_INT | 64,
+ IW_PRIV_TYPE_INT | 64,
+ ""},
+ {
+ WOAL_ECL_SYS_CLOCK,
+ IW_PRIV_TYPE_INT | 64,
+ IW_PRIV_TYPE_INT | 64,
+ "sysclock"},
+ {
+ WOAL_HOST_CMD,
+ IW_PRIV_TYPE_BYTE | 2047,
+ IW_PRIV_TYPE_BYTE | 2047,
+ "hostcmd"},
+ {
+ WOAL_ARP_FILTER,
+ IW_PRIV_TYPE_BYTE | 2047,
+ IW_PRIV_TYPE_BYTE | 2047,
+ "arpfilter"},
+ {
+ WOAL_SET_INTS_GET_CHARS,
+ IW_PRIV_TYPE_INT | 16,
+ IW_PRIV_TYPE_BYTE | 256,
+ ""},
+ {
+ WOAL_READ_EEPROM,
+ IW_PRIV_TYPE_INT | 16,
+ IW_PRIV_TYPE_BYTE | 256,
+ "rdeeprom"},
+ {
+ WOAL_SET_GET_2K_BYTES,
+ IW_PRIV_TYPE_BYTE | WOAL_2K_BYTES,
+ IW_PRIV_TYPE_BYTE | WOAL_2K_BYTES,
+ ""},
+ {
+ WOAL_CMD_53RDWR,
+ IW_PRIV_TYPE_BYTE | WOAL_2K_BYTES,
+ IW_PRIV_TYPE_BYTE | WOAL_2K_BYTES,
+ "sdcmd53rw"},
+ {
+ WOAL_SET_USER_SCAN,
+ IW_PRIV_TYPE_BYTE | WOAL_2K_BYTES,
+ IW_PRIV_TYPE_BYTE | WOAL_2K_BYTES,
+ "setuserscan"},
+ {
+ WOAL_GET_SCAN_TABLE,
+ IW_PRIV_TYPE_BYTE | WOAL_2K_BYTES,
+ IW_PRIV_TYPE_BYTE | WOAL_2K_BYTES,
+ "getscantable"},
+ {
+ WOAL_WMM_ADDTS,
+ IW_PRIV_TYPE_BYTE | WOAL_2K_BYTES,
+ IW_PRIV_TYPE_BYTE | WOAL_2K_BYTES,
+ "addts"},
+ {
+ WOAL_WMM_DELTS,
+ IW_PRIV_TYPE_BYTE | WOAL_2K_BYTES,
+ IW_PRIV_TYPE_BYTE | WOAL_2K_BYTES,
+ "delts"},
+ {
+ WOAL_WMM_QUEUE_CONFIG,
+ IW_PRIV_TYPE_BYTE | WOAL_2K_BYTES,
+ IW_PRIV_TYPE_BYTE | WOAL_2K_BYTES,
+ "qconfig"},
+ {
+ WOAL_WMM_QUEUE_STATS,
+ IW_PRIV_TYPE_BYTE | WOAL_2K_BYTES,
+ IW_PRIV_TYPE_BYTE | WOAL_2K_BYTES,
+ "qstats"},
+ {
+ WOAL_BYPASSED_PACKET,
+ IW_PRIV_TYPE_BYTE | WOAL_2K_BYTES,
+ IW_PRIV_TYPE_BYTE | WOAL_2K_BYTES,
+ "pb_bypass"},
+#ifdef UAP_WEXT
+ {
+ WOAL_FROYO_START,
+ IW_PRIV_TYPE_NONE,
+ IW_PRIV_TYPE_NONE,
+ "START"},
+ {
+ WOAL_FROYO_STOP,
+ IW_PRIV_TYPE_NONE,
+ IW_PRIV_TYPE_NONE,
+ "STOP"},
+ {
+ WOAL_FROYO_WL_FW_RELOAD,
+ IW_PRIV_TYPE_CHAR | 256,
+ IW_PRIV_TYPE_CHAR | 256,
+ "WL_FW_RELOAD"},
+#endif
+};
+
+/** moal_802_11_rates */
+typedef struct _moal_802_11_rates
+{
+ /** Num of rates */
+ t_u8 num_of_rates;
+ /** Rates */
+ t_u8 rates[MLAN_SUPPORTED_RATES];
+} moal_802_11_rates;
+
+#if defined(STA_WEXT) || defined(UAP_WEXT)
+int woal_wext_do_ioctl(struct net_device *dev, struct ifreq *req, int cmd);
+#endif
+
+#endif /* _WOAL_PRIV_H_ */
diff --git a/drivers/net/wireless/sd8797/mlinux/moal_proc.c b/drivers/net/wireless/sd8797/mlinux/moal_proc.c
new file mode 100644
index 000000000000..cd292351f827
--- /dev/null
+++ b/drivers/net/wireless/sd8797/mlinux/moal_proc.c
@@ -0,0 +1,631 @@
+/** @file moal_proc.c
+ *
+ * @brief This file contains functions for proc file.
+ *
+ * Copyright (C) 2008-2010, Marvell International Ltd.
+ *
+ * This software file (the "File") is distributed by Marvell International
+ * Ltd. under the terms of the GNU General Public License Version 2, June 1991
+ * (the "License"). You may use, redistribute and/or modify this File in
+ * accordance with the terms and conditions of the License, a copy of which
+ * is available by writing to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
+ * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
+ *
+ * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
+ * ARE EXPRESSLY DISCLAIMED. The License provides additional details about
+ * this warranty disclaimer.
+ *
+ */
+
+/********************************************************
+Change log:
+ 10/21/2008: initial version
+********************************************************/
+
+#include "moal_main.h"
+#ifdef UAP_SUPPORT
+#include "moal_uap.h"
+#endif
+#include "moal_sdio.h"
+
+/********************************************************
+ Local Variables
+********************************************************/
+#ifdef CONFIG_PROC_FS
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,26)
+#define PROC_DIR NULL
+#define MWLAN_PROC_DIR "mwlan/"
+/** Proc top level directory entry */
+struct proc_dir_entry *proc_mwlan = NULL;
+#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,24)
+#define PROC_DIR &proc_root
+#else
+#define PROC_DIR proc_net
+#endif
+
+#ifdef STA_SUPPORT
+static char *szModes[] = {
+ "Unknown",
+ "Managed",
+ "Ad-hoc",
+ "Auto",
+};
+#endif
+
+extern int drv_mode;
+
+/********************************************************
+ Global Variables
+********************************************************/
+
+/********************************************************
+ Local Functions
+********************************************************/
+/**
+ * @brief Proc read function for info
+ *
+ * @param page Pointer to buffer
+ * @param start Read data starting position
+ * @param offset Offset
+ * @param count Counter
+ * @param eof End of file flag
+ * @param data Data to output
+ *
+ * @return Number of output data
+ */
+static int
+woal_info_proc_read(char *page, char **start, off_t offset,
+ int count, int *eof, void *data)
+{
+ char *p = page;
+ struct net_device *netdev = data;
+ char fmt[MLAN_MAX_VER_STR_LEN];
+ moal_private *priv = (moal_private *) netdev_priv(netdev);
+#ifdef STA_SUPPORT
+ int i = 0;
+ moal_handle *handle = priv->phandle;
+ mlan_bss_info info;
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,35)
+ struct dev_mc_list *mcptr = netdev->mc_list;
+ int mc_count = netdev->mc_count;
+#else
+ struct netdev_hw_addr *mcptr = NULL;
+ int mc_count = netdev_mc_count(netdev);
+#endif /* < 2.6.35 */
+#else
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,34)
+ int i = 0;
+#endif /* >= 2.6.34 */
+#endif
+#ifdef UAP_SUPPORT
+ mlan_ds_uap_stats ustats;
+#endif
+
+ ENTER();
+
+ if (offset) {
+ *eof = 1;
+ goto exit;
+ }
+ memset(fmt, 0, sizeof(fmt));
+#ifdef UAP_SUPPORT
+ if (GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_UAP) {
+ p += sprintf(p, "driver_name = " "\"uap\"\n");
+ woal_uap_get_version(priv, fmt, sizeof(fmt) - 1);
+ if (MLAN_STATUS_SUCCESS !=
+ woal_uap_get_stats(priv, MOAL_PROC_WAIT, &ustats)) {
+ *eof = 1;
+ goto exit;
+ }
+ }
+#endif /* UAP_SUPPORT */
+#ifdef STA_SUPPORT
+ if (GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_STA) {
+ woal_get_version(handle, fmt, sizeof(fmt) - 1);
+ memset(&info, 0, sizeof(info));
+ if (MLAN_STATUS_SUCCESS !=
+ woal_get_bss_info(priv, MOAL_PROC_WAIT, &info)) {
+ *eof = 1;
+ goto exit;
+ }
+ p += sprintf(p, "driver_name = " "\"wlan\"\n");
+ }
+#endif
+ p += sprintf(p, "driver_version = %s", fmt);
+ p += sprintf(p, "\ninterface_name=\"%s\"\n", netdev->name);
+#if defined(WIFI_DIRECT_SUPPORT)
+ if (priv->bss_type == MLAN_BSS_TYPE_WIFIDIRECT) {
+ if (GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_STA)
+ p += sprintf(p, "bss_mode = \"WIFIDIRECT-Client\"\n");
+ else
+ p += sprintf(p, "bss_mode = \"WIFIDIRECT-GO\"\n");
+ }
+#endif
+#ifdef STA_SUPPORT
+ if (priv->bss_type == MLAN_BSS_TYPE_STA)
+ p += sprintf(p, "bss_mode =\"%s\"\n", szModes[info.bss_mode]);
+#endif
+ p += sprintf(p, "media_state=\"%s\"\n",
+ ((priv->media_connected ==
+ MFALSE) ? "Disconnected" : "Connected"));
+ p += sprintf(p, "mac_address=\"%02x:%02x:%02x:%02x:%02x:%02x\"\n",
+ netdev->dev_addr[0], netdev->dev_addr[1], netdev->dev_addr[2],
+ netdev->dev_addr[3], netdev->dev_addr[4], netdev->dev_addr[5]);
+#ifdef STA_SUPPORT
+ if (GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_STA) {
+ p += sprintf(p, "multicast_count=\"%d\"\n", mc_count);
+ p += sprintf(p, "essid=\"%s\"\n", info.ssid.ssid);
+ p += sprintf(p, "bssid=\"%02x:%02x:%02x:%02x:%02x:%02x\"\n",
+ info.bssid[0], info.bssid[1],
+ info.bssid[2], info.bssid[3],
+ info.bssid[4], info.bssid[5]);
+ p += sprintf(p, "channel=\"%d\"\n", (int) info.bss_chan);
+ p += sprintf(p, "region_code = \"%02x\"\n", (t_u8) info.region_code);
+
+ /*
+ * Put out the multicast list
+ */
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,35)
+ for (i = 0; i < netdev->mc_count; i++) {
+ p += sprintf(p,
+ "multicast_address[%d]=\"%02x:%02x:%02x:%02x:%02x:%02x\"\n",
+ i,
+ mcptr->dmi_addr[0], mcptr->dmi_addr[1],
+ mcptr->dmi_addr[2], mcptr->dmi_addr[3],
+ mcptr->dmi_addr[4], mcptr->dmi_addr[5]);
+
+ mcptr = mcptr->next;
+ }
+#else
+ netdev_for_each_mc_addr(mcptr, netdev)
+ p += sprintf(p,
+ "multicast_address[%d]=\"%02x:%02x:%02x:%02x:%02x:%02x\"\n",
+ i++,
+ mcptr->addr[0], mcptr->addr[1],
+ mcptr->addr[2], mcptr->addr[3],
+ mcptr->addr[4], mcptr->addr[5]);
+#endif /* < 2.6.35 */
+ }
+#endif
+ p += sprintf(p, "num_tx_bytes = %lu\n", priv->stats.tx_bytes);
+ p += sprintf(p, "num_rx_bytes = %lu\n", priv->stats.rx_bytes);
+ p += sprintf(p, "num_tx_pkts = %lu\n", priv->stats.tx_packets);
+ p += sprintf(p, "num_rx_pkts = %lu\n", priv->stats.rx_packets);
+ p += sprintf(p, "num_tx_pkts_dropped = %lu\n", priv->stats.tx_dropped);
+ p += sprintf(p, "num_rx_pkts_dropped = %lu\n", priv->stats.rx_dropped);
+ p += sprintf(p, "num_tx_pkts_err = %lu\n", priv->stats.tx_errors);
+ p += sprintf(p, "num_rx_pkts_err = %lu\n", priv->stats.rx_errors);
+ p += sprintf(p, "carrier %s\n",
+ ((netif_carrier_ok(priv->netdev)) ? "on" : "off"));
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,34)
+ for (i = 0; i < netdev->num_tx_queues; i++) {
+ p += sprintf(p, "tx queue %d: %s\n", i,
+ ((netif_tx_queue_stopped(netdev_get_tx_queue(netdev, 0))) ?
+ "stopped" : "started"));
+ }
+#else
+ p += sprintf(p, "tx queue %s\n",
+ ((netif_queue_stopped(priv->netdev)) ? "stopped" : "started"));
+#endif
+#ifdef UAP_SUPPORT
+ if (GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_UAP) {
+ p += sprintf(p, "tkip_mic_failures = %u\n", ustats.tkip_mic_failures);
+ p += sprintf(p, "ccmp_decrypt_errors = %u\n",
+ ustats.ccmp_decrypt_errors);
+ p += sprintf(p, "wep_undecryptable_count = %u\n",
+ ustats.wep_undecryptable_count);
+ p += sprintf(p, "wep_icv_error_count = %u\n",
+ ustats.wep_icv_error_count);
+ p += sprintf(p, "decrypt_failure_count = %u\n",
+ ustats.decrypt_failure_count);
+ p += sprintf(p, "mcast_tx_count = %u\n", ustats.mcast_tx_count);
+ p += sprintf(p, "failed_count = %u\n", ustats.failed_count);
+ p += sprintf(p, "retry_count = %u\n", ustats.retry_count);
+ p += sprintf(p, "multiple_retry_count = %u\n",
+ ustats.multi_retry_count);
+ p += sprintf(p, "frame_duplicate_count = %u\n", ustats.frame_dup_count);
+ p += sprintf(p, "rts_success_count = %u\n", ustats.rts_success_count);
+ p += sprintf(p, "rts_failure_count = %u\n", ustats.rts_failure_count);
+ p += sprintf(p, "ack_failure_count = %u\n", ustats.ack_failure_count);
+ p += sprintf(p, "rx_fragment_count = %u\n", ustats.rx_fragment_count);
+ p += sprintf(p, "mcast_rx_frame_count = %u\n",
+ ustats.mcast_rx_frame_count);
+ p += sprintf(p, "fcs_error_count = %u\n", ustats.fcs_error_count);
+ p += sprintf(p, "tx_frame_count = %u\n", ustats.tx_frame_count);
+ p += sprintf(p, "rsna_tkip_cm_invoked = %u\n",
+ ustats.rsna_tkip_cm_invoked);
+ p += sprintf(p, "rsna_4way_hshk_failures = %u\n",
+ ustats.rsna_4way_hshk_failures);
+ }
+#endif /* UAP_SUPPORT */
+ exit:
+ LEAVE();
+ return (p - page);
+}
+
+#define CMD52_STR_LEN 50
+/*
+ * @brief Parse cmd52 string
+ *
+ * @param buffer A pointer user buffer
+ * @param len Length user buffer
+ * @param func Parsed func number
+ * @param reg Parsed reg value
+ * @param val Parsed value to set
+ * @return BT_STATUS_SUCCESS
+ */
+static int
+parse_cmd52_string(const char __user * buffer, size_t len, int *func, int *reg,
+ int *val)
+{
+ int ret = MLAN_STATUS_SUCCESS;
+ char *string = NULL;
+ char *pos = NULL;
+
+ ENTER();
+
+ string = (char *) kmalloc(CMD52_STR_LEN, GFP_KERNEL);
+ memset(string, 0, CMD52_STR_LEN);
+ memcpy(string, buffer + strlen("sdcmd52rw="), len - strlen("sdcmd52rw="));
+ string = strstrip(string);
+
+ *func = -1;
+ *reg = -1;
+ *val = -1;
+
+ /* Get func */
+ pos = strsep(&string, " \t");
+ if (pos) {
+ *func = woal_string_to_number(pos);
+ }
+
+ /* Get reg */
+ pos = strsep(&string, " \t");
+ if (pos) {
+ *reg = woal_string_to_number(pos);
+ }
+
+ /* Get val (optional) */
+ pos = strsep(&string, " \t");
+ if (pos) {
+ *val = woal_string_to_number(pos);
+ }
+ if (string)
+ kfree(string);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief config proc write function
+ *
+ * @param f file pointer
+ * @param buf pointer to data buffer
+ * @param cnt data number to write
+ * @param data data to write
+ * @return number of data
+ */
+static int
+woal_config_write(struct file *f, const char *buf, unsigned long cnt,
+ void *data)
+{
+ char databuf[101];
+ char *line;
+ t_u32 config_data = 0;
+ moal_handle *handle = (moal_handle *) data;
+ int func, reg, val;
+
+ ENTER();
+ if (!MODULE_GET) {
+ LEAVE();
+ return 0;
+ }
+
+ if (cnt >= sizeof(databuf)) {
+ MODULE_PUT;
+ LEAVE();
+ return (int) cnt;
+ }
+ memset(databuf, 0, sizeof(databuf));
+ if (copy_from_user(databuf, buf, cnt)) {
+ MODULE_PUT;
+ LEAVE();
+ return 0;
+ }
+ line = databuf;
+ if (!strncmp(databuf, "soft_reset", strlen("soft_reset"))) {
+ line += strlen("soft_reset") + 1;
+ config_data = (t_u32) woal_string_to_number(line);
+ PRINTM(MINFO, "soft_reset: %d\n", (int) config_data);
+ if (woal_request_soft_reset(handle) == MLAN_STATUS_SUCCESS) {
+ handle->hardware_status = HardwareStatusReset;
+ } else {
+ PRINTM(MERROR, "Could not perform soft reset\n");
+ }
+ }
+ if (!strncmp(databuf, "drv_mode", strlen("drv_mode"))) {
+ line += strlen("drv_mode") + 1;
+ config_data = (t_u32) woal_string_to_number(line);
+ PRINTM(MINFO, "drv_mode: %d\n", (int) config_data);
+ if (config_data != (t_u32) drv_mode)
+ if (woal_switch_drv_mode(handle, config_data) !=
+ MLAN_STATUS_SUCCESS) {
+ PRINTM(MERROR, "Could not switch drv mode\n");
+ }
+ }
+ if (!strncmp(databuf, "sdcmd52rw=", strlen("sdcmd52rw="))) {
+ parse_cmd52_string(databuf, (size_t) cnt, &func, &reg, &val);
+ woal_sdio_read_write_cmd52(handle, func, reg, val);
+ }
+ MODULE_PUT;
+ LEAVE();
+ return (int) cnt;
+}
+
+/**
+ * @brief config proc read function
+ *
+ * @param page pointer to buffer
+ * @param s read data starting position
+ * @param off offset
+ * @param cnt counter
+ * @param eof end of file flag
+ * @param data data to output
+ * @return number of output data
+ */
+static int
+woal_config_read(char *page, char **s, off_t off, int cnt, int *eof, void *data)
+{
+ char *p = page;
+ moal_handle *handle = (moal_handle *) data;
+
+ ENTER();
+ if (!MODULE_GET) {
+ LEAVE();
+ return 0;
+ }
+ p += sprintf(p, "hardware_status=%d\n", (int) handle->hardware_status);
+ p += sprintf(p, "netlink_num=%d\n", (int) handle->netlink_num);
+ p += sprintf(p, "drv_mode=%d\n", (int) drv_mode);
+ p += sprintf(p, "sdcmd52rw=%d 0x%0x 0x%02X\n", handle->cmd52_func,
+ handle->cmd52_reg, handle->cmd52_val);
+ MODULE_PUT;
+ LEAVE();
+ return p - page;
+}
+
+/********************************************************
+ Global Functions
+********************************************************/
+/**
+ * @brief Convert string to number
+ *
+ * @param s Pointer to numbered string
+ *
+ * @return Converted number from string s
+ */
+int
+woal_string_to_number(char *s)
+{
+ int r = 0;
+ int base = 0;
+ int pn = 1;
+
+ if (!strncmp(s, "-", 1)) {
+ pn = -1;
+ s++;
+ }
+ if (!strncmp(s, "0x", 2) || !strncmp(s, "0X", 2)) {
+ base = 16;
+ s += 2;
+ } else
+ base = 10;
+
+ for (s = s; *s; s++) {
+ if ((*s >= '0') && (*s <= '9'))
+ r = (r * base) + (*s - '0');
+ else if ((*s >= 'A') && (*s <= 'F'))
+ r = (r * base) + (*s - 'A' + 10);
+ else if ((*s >= 'a') && (*s <= 'f'))
+ r = (r * base) + (*s - 'a' + 10);
+ else
+ break;
+ }
+
+ return (r * pn);
+}
+
+/**
+ * @brief Create the top level proc directory
+ *
+ * @param handle Pointer to woal_handle
+ *
+ * @return N/A
+ */
+void
+woal_proc_init(moal_handle * handle)
+{
+ struct proc_dir_entry *r;
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,26)
+ struct proc_dir_entry *pde = PROC_DIR;
+#endif
+ char config_proc_dir[20];
+
+ ENTER();
+
+ PRINTM(MINFO, "Create Proc Interface\n");
+ if (!handle->proc_mwlan) {
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,26)
+ /* Check if directory already exists */
+ for (pde = pde->subdir; pde; pde = pde->next) {
+ if (pde->namelen && !strcmp("mwlan", pde->name)) {
+ /* Directory exists */
+ PRINTM(MWARN, "proc interface already exists!\n");
+ handle->proc_mwlan = pde;
+ break;
+ }
+ }
+ if (pde == NULL) {
+ handle->proc_mwlan = proc_mkdir("mwlan", PROC_DIR);
+ if (!handle->proc_mwlan)
+ PRINTM(MERROR, "Cannot create proc interface!\n");
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24)
+ else
+ atomic_set(&handle->proc_mwlan->count, 1);
+#endif
+ }
+#else
+ if (!proc_mwlan) {
+ handle->proc_mwlan = proc_mkdir("mwlan", PROC_DIR);
+ if (!handle->proc_mwlan) {
+ PRINTM(MERROR, "Cannot create proc interface!\n");
+ }
+ } else {
+ handle->proc_mwlan = proc_mwlan;
+ }
+#endif
+ if (handle->proc_mwlan) {
+ if (handle->handle_idx)
+ sprintf(config_proc_dir, "config%d", handle->handle_idx);
+ else
+ strcpy(config_proc_dir, "config");
+
+ r = create_proc_entry(config_proc_dir, 0644, handle->proc_mwlan);
+
+ if (r) {
+ r->data = handle;
+ r->read_proc = woal_config_read;
+ r->write_proc = woal_config_write;
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,30)
+ r->owner = THIS_MODULE;
+#endif
+ } else
+ PRINTM(MMSG, "Fail to create proc config\n");
+ }
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,26)
+ proc_mwlan = handle->proc_mwlan;
+#endif
+ }
+
+ LEAVE();
+}
+
+/**
+ * @brief Remove the top level proc directory
+ *
+ * @param handle pointer moal_handle
+ *
+ * @return N/A
+ */
+void
+woal_proc_exit(moal_handle * handle)
+{
+ ENTER();
+
+ PRINTM(MINFO, "Remove Proc Interface\n");
+ if (handle->proc_mwlan) {
+ char config_proc_dir[20];
+ if (handle->handle_idx)
+ sprintf(config_proc_dir, "config%d", handle->handle_idx);
+ else
+ strcpy(config_proc_dir, "config");
+ remove_proc_entry(config_proc_dir, handle->proc_mwlan);
+
+ /* Remove only if we are the only instance using this */
+ if (atomic_read(&(handle->proc_mwlan->count)) > 1) {
+ PRINTM(MWARN, "More than one interface using proc!\n");
+ } else {
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24)
+ atomic_dec(&(handle->proc_mwlan->count));
+#endif
+ remove_proc_entry("mwlan", PROC_DIR);
+ handle->proc_mwlan = NULL;
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,26)
+ proc_mwlan = NULL;
+#endif
+ }
+ }
+
+ LEAVE();
+}
+
+/**
+ * @brief Create proc file for interface
+ *
+ * @param priv pointer moal_private
+ *
+ * @return N/A
+ */
+void
+woal_create_proc_entry(moal_private * priv)
+{
+ struct net_device *dev = priv->netdev;
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,26)
+ char proc_dir_name[20];
+#endif
+
+ ENTER();
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,26)
+ if (!priv->proc_entry) {
+ memset(proc_dir_name, 0, sizeof(proc_dir_name));
+ strcpy(proc_dir_name, MWLAN_PROC_DIR);
+ strcat(proc_dir_name, dev->name);
+ /* Try to create mwlan/mlanX first */
+ priv->proc_entry = proc_mkdir(proc_dir_name, PROC_DIR);
+ if (priv->proc_entry) {
+ /* Success. Continue normally */
+ if (!priv->phandle->proc_mwlan) {
+ priv->phandle->proc_mwlan = priv->proc_entry->parent;
+ }
+ atomic_inc(&(priv->phandle->proc_mwlan->count));
+ } else {
+ /* Failure. mwlan may not exist. Try to create that first */
+ priv->phandle->proc_mwlan = proc_mkdir("mwlan", PROC_DIR);
+ if (!priv->phandle->proc_mwlan) {
+ /* Failure. Something broken */
+ LEAVE();
+ return;
+ } else {
+ /* Success. Now retry creating mlanX */
+ priv->proc_entry = proc_mkdir(proc_dir_name, PROC_DIR);
+ atomic_inc(&(priv->phandle->proc_mwlan->count));
+ }
+ }
+#else
+ if (priv->phandle->proc_mwlan && !priv->proc_entry) {
+ priv->proc_entry = proc_mkdir(dev->name, priv->phandle->proc_mwlan);
+ atomic_inc(&(priv->phandle->proc_mwlan->count));
+#endif
+ strcpy(priv->proc_entry_name, dev->name);
+ if (priv->proc_entry) {
+ create_proc_read_entry("info", 0, priv->proc_entry,
+ woal_info_proc_read, dev);
+ }
+ }
+
+ LEAVE();
+}
+
+/**
+ * @brief Remove proc file
+ *
+ * @param priv Pointer moal_private
+ *
+ * @return N/A
+ */
+void
+woal_proc_remove(moal_private * priv)
+{
+ ENTER();
+ if (priv->phandle->proc_mwlan && priv->proc_entry) {
+ remove_proc_entry("info", priv->proc_entry);
+ remove_proc_entry(priv->proc_entry_name, priv->phandle->proc_mwlan);
+ atomic_dec(&(priv->phandle->proc_mwlan->count));
+ priv->proc_entry = NULL;
+ }
+ LEAVE();
+}
+#endif
diff --git a/drivers/net/wireless/sd8797/mlinux/moal_sdio.h b/drivers/net/wireless/sd8797/mlinux/moal_sdio.h
new file mode 100644
index 000000000000..5a5bc2c3718c
--- /dev/null
+++ b/drivers/net/wireless/sd8797/mlinux/moal_sdio.h
@@ -0,0 +1,140 @@
+/** @file moal_sdio.h
+ *
+ * @brief This file contains definitions for SDIO interface.
+ * driver.
+ *
+ * Copyright (C) 2008-2011, Marvell International Ltd.
+ *
+ * This software file (the "File") is distributed by Marvell International
+ * Ltd. under the terms of the GNU General Public License Version 2, June 1991
+ * (the "License"). You may use, redistribute and/or modify this File in
+ * accordance with the terms and conditions of the License, a copy of which
+ * is available by writing to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
+ * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
+ *
+ * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
+ * ARE EXPRESSLY DISCLAIMED. The License provides additional details about
+ * this warranty disclaimer.
+ *
+ */
+/****************************************************
+Change log:
+****************************************************/
+
+#ifndef _MOAL_SDIO_H
+#define _MOAL_SDIO_H
+
+#include <linux/mmc/sdio.h>
+#include <linux/mmc/sdio_ids.h>
+#include <linux/mmc/sdio_func.h>
+#include <linux/mmc/card.h>
+#include <linux/mmc/host.h>
+
+#include "moal_main.h"
+
+#ifndef BLOCK_MODE
+/** Block mode */
+#define BLOCK_MODE 1
+#endif
+
+#ifndef BYTE_MODE
+/** Byte Mode */
+#define BYTE_MODE 0
+#endif
+
+#ifndef FIXED_ADDRESS
+/** Fixed address mode */
+#define FIXED_ADDRESS 0
+#endif
+
+/** SD8797 chip revision ID */
+#define SD8797_A0 0x00
+#define SD8797_B0 0x10
+
+#define SD8797_A0_FW_NAME "mrvl/sd8797_uapsta_a0.bin"
+#define SD8797_B0_FW_NAME "mrvl/sd8797_uapsta.bin"
+
+#ifdef STA_SUPPORT
+/** Default firmware name */
+
+#define DEFAULT_FW_NAME "mrvl/sd8797_uapsta.bin"
+
+#ifndef DEFAULT_FW_NAME
+#define DEFAULT_FW_NAME ""
+#endif
+#endif /* STA_SUPPORT */
+
+#ifdef UAP_SUPPORT
+/** Default firmware name */
+
+#define DEFAULT_AP_FW_NAME "mrvl/sd8797_uapsta.bin"
+
+#ifndef DEFAULT_AP_FW_NAME
+#define DEFAULT_AP_FW_NAME ""
+#endif
+#endif /* UAP_SUPPORT */
+
+/** Default firmaware name */
+
+#define DEFAULT_AP_STA_FW_NAME "mrvl/sd8797_uapsta.bin"
+
+#ifndef DEFAULT_AP_STA_FW_NAME
+#define DEFAULT_AP_STA_FW_NAME ""
+#endif
+
+/********************************************************
+ Global Functions
+********************************************************/
+
+/** Function to write register */
+mlan_status woal_write_reg(moal_handle * handle, t_u32 reg, t_u32 data);
+/** Function to read register */
+mlan_status woal_read_reg(moal_handle * handle, t_u32 reg, t_u32 * data);
+/** Function to write data to IO memory */
+mlan_status woal_write_data_sync(moal_handle * handle, mlan_buffer * pmbuf,
+ t_u32 port, t_u32 timeout);
+/** Function to read data from IO memory */
+mlan_status woal_read_data_sync(moal_handle * handle, mlan_buffer * pmbuf,
+ t_u32 port, t_u32 timeout);
+
+/** Register to bus driver function */
+mlan_status woal_bus_register(void);
+/** Unregister from bus driver function */
+void woal_bus_unregister(void);
+
+/** Register device function */
+mlan_status woal_register_dev(moal_handle * handle);
+/** Unregister device function */
+void woal_unregister_dev(moal_handle * handle);
+
+int woal_sdio_set_bus_clock(moal_handle * handle, t_u8 option);
+
+#ifdef SDIO_SUSPEND_RESUME
+#ifdef MMC_PM_FUNC_SUSPENDED
+/** Notify SDIO bus driver that WLAN is suspended */
+void woal_wlan_is_suspended(moal_handle * handle);
+#endif
+/** SDIO Suspend */
+int woal_sdio_suspend(struct device *dev);
+/** SDIO Resume */
+int woal_sdio_resume(struct device *dev);
+#endif /* SDIO_SUSPEND_RESUME */
+
+/** Structure: SDIO MMC card */
+struct sdio_mmc_card
+{
+ /** sdio_func structure pointer */
+ struct sdio_func *func;
+ /** moal_handle structure pointer */
+ moal_handle *handle;
+ /** saved host clock value */
+ unsigned int host_clock;
+};
+
+/** cmd52 read write */
+int woal_sdio_read_write_cmd52(moal_handle * handle, int func, int reg,
+ int val);
+
+#endif /* _MOAL_SDIO_H */
diff --git a/drivers/net/wireless/sd8797/mlinux/moal_sdio_mmc.c b/drivers/net/wireless/sd8797/mlinux/moal_sdio_mmc.c
new file mode 100644
index 000000000000..94d2a1eef004
--- /dev/null
+++ b/drivers/net/wireless/sd8797/mlinux/moal_sdio_mmc.c
@@ -0,0 +1,728 @@
+/** @file moal_sdio_mmc.c
+ *
+ * @brief This file contains SDIO MMC IF (interface) module
+ * related functions.
+ *
+ * Copyright (C) 2008-2011, Marvell International Ltd.
+ *
+ * This software file (the "File") is distributed by Marvell International
+ * Ltd. under the terms of the GNU General Public License Version 2, June 1991
+ * (the "License"). You may use, redistribute and/or modify this File in
+ * accordance with the terms and conditions of the License, a copy of which
+ * is available by writing to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
+ * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
+ *
+ * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
+ * ARE EXPRESSLY DISCLAIMED. The License provides additional details about
+ * this warranty disclaimer.
+ *
+ */
+/****************************************************
+Change log:
+ 02/25/09: Initial creation -
+ This file supports SDIO MMC only
+****************************************************/
+
+#include <linux/firmware.h>
+
+#include "moal_sdio.h"
+
+/** define marvell vendor id */
+#define MARVELL_VENDOR_ID 0x02df
+
+/********************************************************
+ Local Variables
+********************************************************/
+
+/********************************************************
+ Global Variables
+********************************************************/
+
+#ifdef SDIO_SUSPEND_RESUME
+/** PM keep power */
+extern int pm_keep_power;
+#endif
+
+/** Device ID for SD8797 */
+#define SD_DEVICE_ID_8797 (0x9129)
+
+/** WLAN IDs */
+static const struct sdio_device_id wlan_ids[] = {
+ {SDIO_DEVICE(MARVELL_VENDOR_ID, SD_DEVICE_ID_8797)},
+ {},
+};
+
+MODULE_DEVICE_TABLE(sdio, wlan_ids);
+
+int woal_sdio_probe(struct sdio_func *func, const struct sdio_device_id *id);
+void woal_sdio_remove(struct sdio_func *func);
+
+#ifdef SDIO_SUSPEND_RESUME
+#ifdef MMC_PM_KEEP_POWER
+int woal_sdio_suspend(struct device *dev);
+int woal_sdio_resume(struct device *dev);
+
+static struct dev_pm_ops wlan_sdio_pm_ops = {
+ .suspend = woal_sdio_suspend,
+ .resume = woal_sdio_resume,
+};
+#endif
+#endif
+static struct sdio_driver wlan_sdio = {
+ .name = "wlan_sdio",
+ .id_table = wlan_ids,
+ .probe = woal_sdio_probe,
+ .remove = woal_sdio_remove,
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,29)
+ .drv = {
+ .owner = THIS_MODULE,
+#ifdef SDIO_SUSPEND_RESUME
+#ifdef MMC_PM_KEEP_POWER
+ .pm = &wlan_sdio_pm_ops,
+#endif
+#endif
+ }
+#else
+#ifdef SDIO_SUSPEND_RESUME
+#ifdef MMC_PM_KEEP_POWER
+ .drv = {
+ .pm = &wlan_sdio_pm_ops,
+ }
+#endif
+#endif
+#endif
+};
+
+/********************************************************
+ Local Functions
+********************************************************/
+/** @brief This function dump the sdio register
+ *
+ * @param handle A Pointer to the moal_handle structure
+ * @return N/A
+ */
+void
+woal_dump_sdio_reg(moal_handle * handle)
+{
+ int ret = 0;
+ t_u8 data;
+ data =
+ sdio_f0_readb(((struct sdio_mmc_card *) handle->card)->func, 0x05,
+ &ret);
+ PRINTM(MMSG, "fun0: reg 0x05=0x%x ret=%d\n", data, ret);
+ data =
+ sdio_f0_readb(((struct sdio_mmc_card *) handle->card)->func, 0x04,
+ &ret);
+ PRINTM(MMSG, "fun0: reg 0x04=0x%x ret=%d\n", data, ret);
+ data =
+ sdio_readb(((struct sdio_mmc_card *) handle->card)->func, 0x03, &ret);
+ PRINTM(MMSG, "fun1: reg 0x03=0x%x ret=%d\n", data, ret);
+ data =
+ sdio_readb(((struct sdio_mmc_card *) handle->card)->func, 0x04, &ret);
+ PRINTM(MMSG, "fun1: reg 0x04=0x%x ret=%d\n", data, ret);
+ data =
+ sdio_readb(((struct sdio_mmc_card *) handle->card)->func, 0x05, &ret);
+ PRINTM(MMSG, "fun1: reg 0x05=0x%x ret=%d\n", data, ret);
+ data =
+ sdio_readb(((struct sdio_mmc_card *) handle->card)->func, 0x60, &ret);
+ PRINTM(MMSG, "fun1: reg 0x60=0x%x ret=%d\n", data, ret);
+ data =
+ sdio_readb(((struct sdio_mmc_card *) handle->card)->func, 0x61, &ret);
+ PRINTM(MMSG, "fun1: reg 0x61=0x%x ret=%d\n", data, ret);
+ return;
+}
+
+/********************************************************
+ Global Functions
+********************************************************/
+
+/**
+ * @brief This function handles the interrupt.
+ *
+ * @param func A pointer to the sdio_func structure
+ * @return N/A
+ */
+static void
+woal_sdio_interrupt(struct sdio_func *func)
+{
+ moal_handle *handle;
+ struct sdio_mmc_card *card;
+
+ ENTER();
+
+ card = sdio_get_drvdata(func);
+ if (!card || !card->handle) {
+ PRINTM(MINFO,
+ "sdio_mmc_interrupt(func = %p) card or handle is NULL, card=%p\n",
+ func, card);
+ LEAVE();
+ return;
+ }
+ handle = card->handle;
+
+ PRINTM(MINFO, "*** IN SDIO IRQ ***\n");
+ woal_interrupt(handle);
+
+ LEAVE();
+}
+
+/** @brief This function handles client driver probe.
+ *
+ * @param func A pointer to sdio_func structure.
+ * @param id A pointer to sdio_device_id structure.
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE/error code
+ */
+int
+woal_sdio_probe(struct sdio_func *func, const struct sdio_device_id *id)
+{
+ int ret = MLAN_STATUS_SUCCESS;
+ struct sdio_mmc_card *card = NULL;
+
+ ENTER();
+
+ PRINTM(MINFO, "vendor=0x%4.04X device=0x%4.04X class=%d function=%d\n",
+ func->vendor, func->device, func->class, func->num);
+
+ card = kzalloc(sizeof(struct sdio_mmc_card), GFP_KERNEL);
+ if (!card) {
+ PRINTM(MFATAL, "Failed to allocate memory in probe function!\n");
+ LEAVE();
+ return -ENOMEM;
+ }
+
+ card->func = func;
+
+#ifdef MMC_QUIRK_BLKSZ_FOR_BYTE_MODE
+ /* The byte mode patch is available in kernel MMC driver which fixes one
+ issue in MP-A transfer. bit1: use func->cur_blksize for byte mode */
+ func->card->quirks |= MMC_QUIRK_BLKSZ_FOR_BYTE_MODE;
+#endif
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27)
+ /* wait for chip fully wake up */
+ if (!func->enable_timeout)
+ func->enable_timeout = 200;
+#endif
+ sdio_claim_host(func);
+ ret = sdio_enable_func(func);
+ if (ret) {
+ sdio_disable_func(func);
+ sdio_release_host(func);
+ kfree(card);
+ PRINTM(MFATAL, "sdio_enable_func() failed: ret=%d\n", ret);
+ LEAVE();
+ return -EIO;
+ }
+ sdio_release_host(func);
+ if (NULL == woal_add_card(card)) {
+ PRINTM(MERROR, "woal_add_card failed\n");
+ kfree(card);
+ sdio_claim_host(func);
+ sdio_disable_func(func);
+ sdio_release_host(func);
+ ret = MLAN_STATUS_FAILURE;
+ }
+
+ LEAVE();
+ return ret;
+}
+
+/** @brief This function handles client driver remove.
+ *
+ * @param func A pointer to sdio_func structure.
+ * @return N/A
+ */
+void
+woal_sdio_remove(struct sdio_func *func)
+{
+ struct sdio_mmc_card *card;
+
+ ENTER();
+
+ PRINTM(MINFO, "SDIO func=%d\n", func->num);
+
+ if (func) {
+ card = sdio_get_drvdata(func);
+ if (card) {
+ woal_remove_card(card);
+ kfree(card);
+ }
+ }
+
+ LEAVE();
+}
+
+#ifdef SDIO_SUSPEND_RESUME
+#ifdef MMC_PM_KEEP_POWER
+#ifdef MMC_PM_FUNC_SUSPENDED
+/** @brief This function tells lower driver that WLAN is suspended
+ *
+ * @param handle A Pointer to the moal_handle structure
+ * @return N/A
+ */
+void
+woal_wlan_is_suspended(moal_handle * handle)
+{
+ ENTER();
+ if (handle->suspend_notify_req == MTRUE) {
+ handle->is_suspended = MTRUE;
+ sdio_func_suspended(((struct sdio_mmc_card *) handle->card)->func);
+ }
+ LEAVE();
+}
+#endif
+
+/** @brief This function handles client driver suspend
+ *
+ * @param dev A pointer to device structure
+ * @return MLAN_STATUS_SUCCESS or error code
+ */
+int
+woal_sdio_suspend(struct device *dev)
+{
+ struct sdio_func *func = dev_to_sdio_func(dev);
+ mmc_pm_flag_t pm_flags = 0;
+ moal_handle *handle = NULL;
+ struct sdio_mmc_card *cardp;
+ int i;
+ int ret = MLAN_STATUS_SUCCESS;
+ int hs_actived = 0;
+ mlan_ds_ps_info pm_info;
+
+ ENTER();
+ PRINTM(MCMND, "<--- Enter woal_sdio_suspend --->\n");
+ if (func) {
+ pm_flags = sdio_get_host_pm_caps(func);
+ PRINTM(MCMND, "%s: suspend: PM flags = 0x%x\n", sdio_func_id(func),
+ pm_flags);
+ if (!(pm_flags & MMC_PM_KEEP_POWER)) {
+ PRINTM(MERROR, "%s: cannot remain alive while host is suspended\n",
+ sdio_func_id(func));
+ LEAVE();
+ return -ENOSYS;
+ }
+ cardp = sdio_get_drvdata(func);
+ if (!cardp || !cardp->handle) {
+ PRINTM(MERROR, "Card or moal_handle structure is not valid\n");
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+ }
+ } else {
+ PRINTM(MERROR, "sdio_func is not specified\n");
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+ }
+
+ handle = cardp->handle;
+ handle->suspend_fail = MFALSE;
+ memset(&pm_info, 0, sizeof(pm_info));
+ if (MLAN_STATUS_SUCCESS ==
+ woal_get_pm_info(woal_get_priv(handle, MLAN_BSS_ROLE_ANY), &pm_info)) {
+ if (pm_info.is_suspend_allowed == MFALSE) {
+ PRINTM(MMSG, "suspend not allowed!");
+ ret = -EBUSY;
+ goto done;
+ }
+ }
+ for (i = 0; i < handle->priv_num; i++)
+ netif_device_detach(handle->priv[i]->netdev);
+
+ if (pm_keep_power) {
+ /* Enable the Host Sleep */
+#ifdef MMC_PM_FUNC_SUSPENDED
+ handle->suspend_notify_req = MTRUE;
+#endif
+ hs_actived = woal_enable_hs(woal_get_priv(handle, MLAN_BSS_ROLE_ANY));
+#ifdef MMC_PM_FUNC_SUSPENDED
+ handle->suspend_notify_req = MFALSE;
+#endif
+ if (hs_actived) {
+#ifdef MMC_PM_SKIP_RESUME_PROBE
+ PRINTM(MCMND, "suspend with MMC_PM_KEEP_POWER and "
+ "MMC_PM_SKIP_RESUME_PROBE\n");
+ ret = sdio_set_host_pm_flags(func, MMC_PM_KEEP_POWER |
+ MMC_PM_SKIP_RESUME_PROBE);
+#else
+ PRINTM(MCMND, "suspend with MMC_PM_KEEP_POWER\n");
+ ret = sdio_set_host_pm_flags(func, MMC_PM_KEEP_POWER);
+#endif
+ } else {
+ PRINTM(MMSG, "HS not actived, suspend fail!");
+ ret = -EBUSY;
+ goto done;
+ }
+ }
+
+ /* Indicate device suspended */
+ handle->is_suspended = MTRUE;
+ done:
+ PRINTM(MCMND, "<--- Leave woal_sdio_suspend --->\n");
+ LEAVE();
+ return ret;
+}
+
+/** @brief This function handles client driver resume
+ *
+ * @param dev A pointer to device structure
+ * @return MLAN_STATUS_SUCCESS
+ */
+int
+woal_sdio_resume(struct device *dev)
+{
+ struct sdio_func *func = dev_to_sdio_func(dev);
+ mmc_pm_flag_t pm_flags = 0;
+ moal_handle *handle = NULL;
+ struct sdio_mmc_card *cardp;
+ int i;
+
+ ENTER();
+ PRINTM(MCMND, "<--- Enter woal_sdio_resume --->\n");
+ if (func) {
+ pm_flags = sdio_get_host_pm_caps(func);
+ PRINTM(MCMND, "%s: resume: PM flags = 0x%x\n", sdio_func_id(func),
+ pm_flags);
+ cardp = sdio_get_drvdata(func);
+ if (!cardp || !cardp->handle) {
+ PRINTM(MERROR, "Card or moal_handle structure is not valid\n");
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+ }
+ } else {
+ PRINTM(MERROR, "sdio_func is not specified\n");
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+ }
+ handle = cardp->handle;
+
+ if (handle->is_suspended == MFALSE) {
+ PRINTM(MWARN, "Device already resumed\n");
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+ }
+
+ handle->is_suspended = MFALSE;
+ for (i = 0; i < handle->priv_num; i++)
+ netif_device_attach(handle->priv[i]->netdev);
+
+ /* Disable Host Sleep */
+ woal_cancel_hs(woal_get_priv(handle, MLAN_BSS_ROLE_ANY), MOAL_NO_WAIT);
+ PRINTM(MCMND, "<--- Leave woal_sdio_resume --->\n");
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+#endif
+#endif /* SDIO_SUSPEND_RESUME */
+
+/**
+ * @brief This function writes data into card register
+ *
+ * @param handle A Pointer to the moal_handle structure
+ * @param reg Register offset
+ * @param data Value
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status
+woal_write_reg(moal_handle * handle, t_u32 reg, t_u32 data)
+{
+ mlan_status ret = MLAN_STATUS_FAILURE;
+ sdio_writeb(((struct sdio_mmc_card *) handle->card)->func, (t_u8) data, reg,
+ (int *) &ret);
+ return ret;
+}
+
+/**
+ * @brief This function reads data from card register
+ *
+ * @param handle A Pointer to the moal_handle structure
+ * @param reg Register offset
+ * @param data Value
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status
+woal_read_reg(moal_handle * handle, t_u32 reg, t_u32 * data)
+{
+ mlan_status ret = MLAN_STATUS_FAILURE;
+ t_u8 val;
+
+ val =
+ sdio_readb(((struct sdio_mmc_card *) handle->card)->func, reg,
+ (int *) &ret);
+ *data = val;
+
+ return ret;
+}
+
+/**
+ * @brief This function writes multiple bytes into card memory
+ *
+ * @param handle A Pointer to the moal_handle structure
+ * @param pmbuf Pointer to mlan_buffer structure
+ * @param port Port
+ * @param timeout Time out value
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status
+woal_write_data_sync(moal_handle * handle, mlan_buffer * pmbuf, t_u32 port,
+ t_u32 timeout)
+{
+ mlan_status ret = MLAN_STATUS_FAILURE;
+ t_u8 *buffer = (t_u8 *) (pmbuf->pbuf + pmbuf->data_offset);
+ t_u8 blkmode = (port & MLAN_SDIO_BYTE_MODE_MASK) ? BYTE_MODE : BLOCK_MODE;
+ t_u32 blksz = (blkmode == BLOCK_MODE) ? MLAN_SDIO_BLOCK_SIZE : 1;
+ t_u32 blkcnt =
+ (blkmode ==
+ BLOCK_MODE) ? (pmbuf->data_len /
+ MLAN_SDIO_BLOCK_SIZE) : pmbuf->data_len;
+ t_u32 ioport = (port & MLAN_SDIO_IO_PORT_MASK);
+#ifdef SDIO_MMC_DEBUG
+ handle->cmd53w = 1;
+#endif
+ if (!sdio_writesb
+ (((struct sdio_mmc_card *) handle->card)->func, ioport, buffer,
+ blkcnt * blksz))
+ ret = MLAN_STATUS_SUCCESS;
+#ifdef SDIO_MMC_DEBUG
+ handle->cmd53w = 2;
+#endif
+ return ret;
+}
+
+/**
+ * @brief This function reads multiple bytes from card memory
+ *
+ * @param handle A Pointer to the moal_handle structure
+ * @param pmbuf Pointer to mlan_buffer structure
+ * @param port Port
+ * @param timeout Time out value
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status
+woal_read_data_sync(moal_handle * handle, mlan_buffer * pmbuf, t_u32 port,
+ t_u32 timeout)
+{
+ mlan_status ret = MLAN_STATUS_FAILURE;
+ t_u8 *buffer = (t_u8 *) (pmbuf->pbuf + pmbuf->data_offset);
+ t_u8 blkmode = (port & MLAN_SDIO_BYTE_MODE_MASK) ? BYTE_MODE : BLOCK_MODE;
+ t_u32 blksz = (blkmode == BLOCK_MODE) ? MLAN_SDIO_BLOCK_SIZE : 1;
+ t_u32 blkcnt =
+ (blkmode ==
+ BLOCK_MODE) ? (pmbuf->data_len /
+ MLAN_SDIO_BLOCK_SIZE) : pmbuf->data_len;
+ t_u32 ioport = (port & MLAN_SDIO_IO_PORT_MASK);
+
+#ifdef SDIO_MMC_DEBUG
+ handle->cmd53r = 1;
+#endif
+ if (!sdio_readsb
+ (((struct sdio_mmc_card *) handle->card)->func, buffer, ioport,
+ blkcnt * blksz))
+ ret = MLAN_STATUS_SUCCESS;
+ else
+ woal_dump_sdio_reg(handle);
+#ifdef SDIO_MMC_DEBUG
+ handle->cmd53r = 2;
+#endif
+ return ret;
+}
+
+/**
+ * @brief This function registers the IF module in bus driver
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status
+woal_bus_register(void)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ /* SDIO Driver Registration */
+ if (sdio_register_driver(&wlan_sdio)) {
+ PRINTM(MFATAL, "SDIO Driver Registration Failed \n");
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function de-registers the IF module in bus driver
+ *
+ * @return N/A
+ */
+void
+woal_bus_unregister(void)
+{
+ ENTER();
+
+ /* SDIO Driver Unregistration */
+ sdio_unregister_driver(&wlan_sdio);
+
+ LEAVE();
+}
+
+/**
+ * @brief This function de-registers the device
+ *
+ * @param handle A pointer to moal_handle structure
+ * @return N/A
+ */
+void
+woal_unregister_dev(moal_handle * handle)
+{
+ ENTER();
+ if (handle->card) {
+ /* Release the SDIO IRQ */
+ sdio_claim_host(((struct sdio_mmc_card *) handle->card)->func);
+ sdio_release_irq(((struct sdio_mmc_card *) handle->card)->func);
+ sdio_disable_func(((struct sdio_mmc_card *) handle->card)->func);
+ sdio_release_host(((struct sdio_mmc_card *) handle->card)->func);
+
+ sdio_set_drvdata(((struct sdio_mmc_card *) handle->card)->func, NULL);
+
+ PRINTM(MWARN, "Making the sdio dev card as NULL\n");
+ }
+
+ LEAVE();
+}
+
+/**
+ * @brief This function registers the device
+ *
+ * @param handle A pointer to moal_handle structure
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status
+woal_register_dev(moal_handle * handle)
+{
+ int ret = MLAN_STATUS_SUCCESS;
+ struct sdio_mmc_card *card = handle->card;
+ struct sdio_func *func;
+
+ ENTER();
+
+ func = card->func;
+ sdio_claim_host(func);
+ /* Request the SDIO IRQ */
+ ret = sdio_claim_irq(func, woal_sdio_interrupt);
+ if (ret) {
+ PRINTM(MFATAL, "sdio_claim_irq failed: ret=%d\n", ret);
+ goto release_host;
+ }
+
+ /* Set block size */
+ ret = sdio_set_block_size(card->func, MLAN_SDIO_BLOCK_SIZE);
+ if (ret) {
+ PRINTM(MERROR, "sdio_set_block_seize(): cannot set SDIO block size\n");
+ ret = MLAN_STATUS_FAILURE;
+ goto release_irq;
+ }
+
+ sdio_release_host(func);
+ sdio_set_drvdata(func, card);
+
+ handle->hotplug_device = &func->dev;
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+
+ release_irq:
+ sdio_release_irq(func);
+ release_host:
+ sdio_release_host(func);
+ handle->card = NULL;
+
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+}
+
+/**
+ * @brief This function set bus clock on/off
+ *
+ * @param handle A pointer to moal_handle structure
+ * @param option TRUE--on , FALSE--off
+ * @return MLAN_STATUS_SUCCESS
+ */
+int
+woal_sdio_set_bus_clock(moal_handle * handle, t_u8 option)
+{
+ struct sdio_mmc_card *cardp = (struct sdio_mmc_card *) handle->card;
+ struct mmc_host *host = cardp->func->card->host;
+
+ ENTER();
+ if (option == MTRUE) {
+ /* restore value if non-zero */
+ if (cardp->host_clock)
+ host->ios.clock = cardp->host_clock;
+ } else {
+ /* backup value if non-zero, then clear */
+ if (host->ios.clock)
+ cardp->host_clock = host->ios.clock;
+ host->ios.clock = 0;
+ }
+
+ host->ops->set_ios(host, &host->ios);
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function updates card reg based on the Cmd52 value in dev structure
+ *
+ * @param handle A pointer to moal_handle structure
+ * @param func A pointer to store func variable
+ * @param reg A pointer to store reg variable
+ * @param val A pointer to store val variable
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+int
+woal_sdio_read_write_cmd52(moal_handle * handle, int func, int reg, int val)
+{
+ int ret = MLAN_STATUS_SUCCESS;
+ struct sdio_mmc_card *card = (struct sdio_mmc_card *) handle->card;
+
+ ENTER();
+ /* Save current func and reg for read */
+ handle->cmd52_func = func;
+ handle->cmd52_reg = reg;
+ sdio_claim_host(card->func);
+ if (val >= 0) {
+ /* Perform actual write only if val is provided */
+ if (func)
+ sdio_writeb(card->func, val, reg, &ret);
+ else
+ sdio_f0_writeb(card->func, val, reg, &ret);
+ if (ret) {
+ PRINTM(MERROR, "Cannot write value (0x%x) to func %d reg 0x%x\n",
+ val, func, reg);
+ } else {
+ PRINTM(MMSG, "write value (0x%x) to func %d reg 0x%x\n", (u8) val,
+ func, reg);
+ handle->cmd52_val = val;
+ }
+ } else {
+ if (func)
+ val = sdio_readb(card->func, reg, &ret);
+ else
+ val = sdio_f0_readb(card->func, reg, &ret);
+ if (ret) {
+ PRINTM(MERROR, "Cannot read value from func %d reg 0x%x\n", func,
+ reg);
+ } else {
+ PRINTM(MMSG, "read value (0x%x) from func %d reg 0x%x\n", (u8) val,
+ func, reg);
+ handle->cmd52_val = val;
+ }
+ }
+ sdio_release_host(card->func);
+ LEAVE();
+ return ret;
+}
diff --git a/drivers/net/wireless/sd8797/mlinux/moal_shim.c b/drivers/net/wireless/sd8797/mlinux/moal_shim.c
new file mode 100644
index 000000000000..51f192a160f9
--- /dev/null
+++ b/drivers/net/wireless/sd8797/mlinux/moal_shim.c
@@ -0,0 +1,1458 @@
+/** @file moal_shim.c
+ *
+ * @brief This file contains the callback functions registered to MLAN
+ *
+ * Copyright (C) 2008-2011, Marvell International Ltd.
+ *
+ * This software file (the "File") is distributed by Marvell International
+ * Ltd. under the terms of the GNU General Public License Version 2, June 1991
+ * (the "License"). You may use, redistribute and/or modify this File in
+ * accordance with the terms and conditions of the License, a copy of which
+ * is available by writing to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
+ * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
+ *
+ * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
+ * ARE EXPRESSLY DISCLAIMED. The License provides additional details about
+ * this warranty disclaimer.
+ *
+ */
+
+/********************************************************
+Change log:
+ 10/21/2008: initial version
+********************************************************/
+
+#include "moal_main.h"
+#include "moal_sdio.h"
+#ifdef UAP_SUPPORT
+#include "moal_uap.h"
+#endif
+#ifdef STA_CFG80211
+#include "moal_cfg80211.h"
+#endif
+
+/********************************************************
+ Local Variables
+********************************************************/
+/** moal_lock */
+typedef struct _moal_lock
+{
+ /** Lock */
+ spinlock_t lock;
+ /** Flags */
+ unsigned long flags;
+} moal_lock;
+
+/********************************************************
+ Global Variables
+********************************************************/
+extern int cfg80211_wext;
+
+/********************************************************
+ Local Functions
+********************************************************/
+
+/********************************************************
+ Global Functions
+********************************************************/
+
+/**
+ * @brief Alloc a buffer
+ *
+ * @param pmoal_handle Pointer to the MOAL context
+ * @param size The size of the buffer to be allocated
+ * @param flag The type of the buffer to be allocated
+ * @param ppbuf Pointer to a buffer location to store buffer pointer allocated
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status
+moal_malloc(IN t_void * pmoal_handle,
+ IN t_u32 size, IN t_u32 flag, OUT t_u8 ** ppbuf)
+{
+ moal_handle *handle = (moal_handle *) pmoal_handle;
+ t_u32 mem_flag = GFP_ATOMIC; /* Default type: GFP_ATOMIC */
+
+ if (flag & MLAN_MEM_DMA)
+ mem_flag |= GFP_DMA;
+
+ if (!(*ppbuf = kmalloc(size, mem_flag))) {
+ PRINTM(MERROR, "%s: allocate buffer %d failed!\n", __FUNCTION__,
+ (int) size);
+ return MLAN_STATUS_FAILURE;
+ }
+ handle->malloc_count++;
+
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief Free a buffer
+ *
+ * @param pmoal_handle Pointer to the MOAL context
+ * @param pbuf Pointer to the buffer to be freed
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status
+moal_mfree(IN t_void * pmoal_handle, IN t_u8 * pbuf)
+{
+ moal_handle *handle = (moal_handle *) pmoal_handle;
+
+ if (!pbuf)
+ return MLAN_STATUS_FAILURE;
+ kfree(pbuf);
+ handle->malloc_count--;
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief Fill memory with constant byte
+ *
+ * @param pmoal_handle Pointer to the MOAL context
+ * @param pmem Pointer to the memory area
+ * @param byte A constant byte
+ * @param num Number of bytes to fill
+ *
+ * @return Pointer to the memory area
+ */
+t_void *
+moal_memset(IN t_void * pmoal_handle,
+ IN t_void * pmem, IN t_u8 byte, IN t_u32 num)
+{
+ t_void *p = pmem;
+
+ if (pmem && num)
+ p = memset(pmem, byte, num);
+
+ return p;
+}
+
+/**
+ * @brief Copy memory from one area to another
+ *
+ * @param pmoal_handle Pointer to the MOAL context
+ * @param pdest Pointer to the dest memory
+ * @param psrc Pointer to the src memory
+ * @param num Number of bytes to move
+ *
+ * @return Pointer to the dest memory
+ */
+t_void *
+moal_memcpy(IN t_void * pmoal_handle,
+ IN t_void * pdest, IN const t_void * psrc, IN t_u32 num)
+{
+ t_void *p = pdest;
+
+ if (pdest && psrc && num)
+ p = memcpy(pdest, psrc, num);
+
+ return p;
+}
+
+/**
+ * @brief Move memory from one area to another
+ *
+ * @param pmoal_handle Pointer to the MOAL context
+ * @param pdest Pointer to the dest memory
+ * @param psrc Pointer to the src memory
+ * @param num Number of bytes to move
+ *
+ * @return Pointer to the dest memory
+ */
+t_void *
+moal_memmove(IN t_void * pmoal_handle,
+ IN t_void * pdest, IN const t_void * psrc, IN t_u32 num)
+{
+ t_void *p = pdest;
+
+ if (pdest && psrc && num)
+ p = memmove(pdest, psrc, num);
+
+ return p;
+}
+
+/**
+ * @brief Compare two memory areas
+ *
+ * @param pmoal_handle Pointer to the MOAL context
+ * @param pmem1 Pointer to the first memory
+ * @param pmem2 Pointer to the second memory
+ * @param num Number of bytes to compare
+ *
+ * @return Compare result returns by memcmp
+ */
+t_s32
+moal_memcmp(IN t_void * pmoal_handle,
+ IN const t_void * pmem1, IN const t_void * pmem2, IN t_u32 num)
+{
+ t_s32 result;
+
+ result = memcmp(pmem1, pmem2, num);
+
+ return result;
+}
+
+/**
+ * @brief Delay function
+ *
+ * @param pmoal_handle Pointer to the MOAL context
+ * @param delay delay in micro-second
+ *
+ * @return N/A
+ */
+t_void
+moal_udelay(IN t_void * pmoal_handle, IN t_u32 delay)
+{
+ if (delay >= 1000)
+ mdelay(delay / 1000);
+ if (delay % 1000)
+ udelay(delay % 1000);
+}
+
+/**
+ * @brief Retrieves the current system time
+ *
+ * @param pmoal_handle Pointer to the MOAL context
+ * @param psec Pointer to buf for the seconds of system time
+ * @param pusec Pointer to buf the micro seconds of system time
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+mlan_status
+moal_get_system_time(IN t_void * pmoal_handle,
+ OUT t_u32 * psec, OUT t_u32 * pusec)
+{
+ struct timeval t;
+
+ do_gettimeofday(&t);
+ *psec = (t_u32) t.tv_sec;
+ *pusec = (t_u32) t.tv_usec;
+
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief Initializes the timer
+ *
+ * @param pmoal_handle Pointer to the MOAL context
+ * @param pptimer Pointer to the timer
+ * @param callback Pointer to callback function
+ * @param pcontext Pointer to context
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status
+moal_init_timer(IN t_void * pmoal_handle,
+ OUT t_void ** pptimer,
+ IN t_void(*callback) (t_void * pcontext), IN t_void * pcontext)
+{
+ moal_drv_timer *timer = NULL;
+
+ if (!
+ (timer =
+ (moal_drv_timer *) kmalloc(sizeof(moal_drv_timer), GFP_KERNEL)))
+ return MLAN_STATUS_FAILURE;
+ woal_initialize_timer(timer, callback, pcontext);
+ *pptimer = (t_void *) timer;
+
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief Free the timer
+ *
+ * @param pmoal_handle Pointer to the MOAL context
+ * @param ptimer Pointer to the timer
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+mlan_status
+moal_free_timer(IN t_void * pmoal_handle, IN t_void * ptimer)
+{
+ moal_drv_timer *timer = (moal_drv_timer *) ptimer;
+
+ if (timer) {
+ if ((timer->timer_is_canceled == MFALSE) && timer->time_period) {
+ PRINTM(MWARN, "mlan try to free timer without stop timer!\n");
+ woal_cancel_timer(timer);
+ }
+ kfree(timer);
+ }
+
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief Start the timer
+ *
+ * @param pmoal_handle Pointer to the MOAL context
+ * @param ptimer Pointer to the timer
+ * @param periodic Periodic timer
+ * @param msec Timer value in milliseconds
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status
+moal_start_timer(IN t_void * pmoal_handle,
+ IN t_void * ptimer, IN t_u8 periodic, IN t_u32 msec)
+{
+ if (!ptimer)
+ return MLAN_STATUS_FAILURE;
+
+ ((moal_drv_timer *) ptimer)->timer_is_periodic = periodic;
+ woal_mod_timer((moal_drv_timer *) ptimer, msec);
+
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief Stop the timer
+ *
+ * @param pmoal_handle Pointer to the MOAL context
+ * @param ptimer Pointer to the timer
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status
+moal_stop_timer(IN t_void * pmoal_handle, IN t_void * ptimer)
+{
+ if (!ptimer)
+ return MLAN_STATUS_FAILURE;
+ woal_cancel_timer((moal_drv_timer *) ptimer);
+
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief Initializes the lock
+ *
+ * @param pmoal_handle Pointer to the MOAL context
+ * @param pplock Pointer to the lock
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status
+moal_init_lock(IN t_void * pmoal_handle, OUT t_void ** pplock)
+{
+ moal_handle *handle = (moal_handle *) pmoal_handle;
+ moal_lock *mlock = NULL;
+
+ if (!(mlock = (moal_lock *) kmalloc(sizeof(moal_lock), GFP_ATOMIC)))
+ return MLAN_STATUS_FAILURE;
+ spin_lock_init(&mlock->lock);
+ *pplock = (t_void *) mlock;
+
+ handle->lock_count++;
+
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief Free the lock
+ *
+ * @param pmoal_handle Pointer to the MOAL context
+ * @param plock Lock
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+mlan_status
+moal_free_lock(IN t_void * pmoal_handle, IN t_void * plock)
+{
+ moal_handle *handle = (moal_handle *) pmoal_handle;
+ moal_lock *mlock = plock;
+
+ if (mlock) {
+ kfree(mlock);
+ handle->lock_count--;
+ }
+
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief Request a spin lock
+ *
+ * @param pmoal_handle Pointer to the MOAL context
+ * @param plock Pointer to the lock
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status
+moal_spin_lock(IN t_void * pmoal_handle, IN t_void * plock)
+{
+ moal_lock *mlock = plock;
+ unsigned long flags = 0;
+
+ if (mlock) {
+ spin_lock_irqsave(&mlock->lock, flags);
+ mlock->flags = flags;
+ return MLAN_STATUS_SUCCESS;
+ } else {
+ return MLAN_STATUS_FAILURE;
+ }
+}
+
+/**
+ * @brief Request a spin_unlock
+ *
+ * @param pmoal_handle Pointer to the MOAL context
+ * @param plock Pointer to the lock
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status
+moal_spin_unlock(IN t_void * pmoal_handle, IN t_void * plock)
+{
+ moal_lock *mlock = (moal_lock *) plock;
+
+ if (mlock) {
+ spin_unlock_irqrestore(&mlock->lock, mlock->flags);
+
+ return MLAN_STATUS_SUCCESS;
+ } else {
+ return MLAN_STATUS_FAILURE;
+ }
+}
+
+/**
+ * @brief This function reads one block of firmware data from MOAL
+ *
+ * @param pmoal_handle Pointer to the MOAL context
+ * @param offset Offset from where the data will be copied
+ * @param len Length to be copied
+ * @param pbuf Buffer where the data will be copied
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status
+moal_get_fw_data(IN t_void * pmoal_handle,
+ IN t_u32 offset, IN t_u32 len, OUT t_u8 * pbuf)
+{
+ moal_handle *handle = (moal_handle *) pmoal_handle;
+
+ if (!pbuf || !len)
+ return MLAN_STATUS_FAILURE;
+
+ if (offset + len > handle->firmware->size)
+ return MLAN_STATUS_FAILURE;
+
+ memcpy(pbuf, handle->firmware->data + offset, len);
+
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function is called when MLAN completes the initialization firmware.
+ *
+ * @param pmoal_handle Pointer to the MOAL context
+ * @param status The status code for mlan_init_fw request
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+mlan_status
+moal_init_fw_complete(IN t_void * pmoal_handle, IN mlan_status status)
+{
+ moal_handle *handle = (moal_handle *) pmoal_handle;
+ ENTER();
+ if (status == MLAN_STATUS_SUCCESS)
+ handle->hardware_status = HardwareStatusReady;
+ handle->init_wait_q_woken = MTRUE;
+ wake_up_interruptible(&handle->init_wait_q);
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function is called when MLAN shutdown firmware is completed.
+ *
+ * @param pmoal_handle Pointer to the MOAL context
+ * @param status The status code for mlan_shutdown request
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+mlan_status
+moal_shutdown_fw_complete(IN t_void * pmoal_handle, IN mlan_status status)
+{
+ moal_handle *handle = (moal_handle *) pmoal_handle;
+ ENTER();
+ handle->hardware_status = HardwareStatusNotReady;
+ handle->init_wait_q_woken = MTRUE;
+ wake_up_interruptible(&handle->init_wait_q);
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function is called when an MLAN IOCTL is completed.
+ *
+ * @param pmoal_handle Pointer to the MOAL context
+ * @param pioctl_req pointer to structure mlan_ioctl_req
+ * @param status The status code for mlan_ioctl request
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+mlan_status
+moal_ioctl_complete(IN t_void * pmoal_handle,
+ IN pmlan_ioctl_req pioctl_req, IN mlan_status status)
+{
+ moal_handle *handle = (moal_handle *) pmoal_handle;
+ moal_private *priv = NULL;
+ wait_queue *wait;
+ ENTER();
+
+ if (!atomic_read(&handle->ioctl_pending))
+ PRINTM(MERROR, "ERR: Unexpected IOCTL completed: %p\n", pioctl_req);
+ else
+ atomic_dec(&handle->ioctl_pending);
+ priv = woal_bss_index_to_priv(handle, pioctl_req->bss_index);
+
+ wait = (wait_queue *) pioctl_req->reserved_1;
+ PRINTM(MIOCTL,
+ "IOCTL completed: %p id=0x%x sub_id=0x%x, action=%d, status=%d, status_code=0x%x\n",
+ pioctl_req, pioctl_req->req_id, (*(t_u32 *) pioctl_req->pbuf),
+ (int) pioctl_req->action, status, pioctl_req->status_code);
+ if (wait) {
+ wait->condition = MTRUE;
+ wait->status = status;
+ if ((status != MLAN_STATUS_SUCCESS) &&
+ (pioctl_req->status_code == MLAN_ERROR_CMD_TIMEOUT)) {
+ PRINTM(MERROR, "IOCTL: command timeout\n");
+ } else {
+ wake_up_interruptible(wait->wait);
+ }
+ } else {
+ if (priv && (status == MLAN_STATUS_SUCCESS) &&
+ (pioctl_req->action == MLAN_ACT_GET))
+ woal_process_ioctl_resp(priv, pioctl_req);
+ if (status != MLAN_STATUS_SUCCESS)
+ PRINTM(MERROR,
+ "IOCTL failed: id=0x%x, action=%d, status_code=0x%x\n",
+ pioctl_req->req_id, (int) pioctl_req->action,
+ pioctl_req->status_code);
+ kfree(pioctl_req);
+ }
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function allocates mlan_buffer.
+ *
+ * @param pmoal_handle Pointer to the MOAL context
+ * @param size allocation size requested
+ * @param pmbuf pointer to pointer to the allocated buffer
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status
+moal_alloc_mlan_buffer(IN t_void * pmoal_handle,
+ IN t_u32 size, OUT pmlan_buffer * pmbuf)
+{
+ if (NULL ==
+ (*pmbuf = woal_alloc_mlan_buffer((moal_handle *) pmoal_handle, size)))
+ return MLAN_STATUS_FAILURE;
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function frees mlan_buffer.
+ *
+ * @param pmoal_handle Pointer to the MOAL context
+ * @param pmbuf pointer to buffer to be freed
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status
+moal_free_mlan_buffer(IN t_void * pmoal_handle, IN pmlan_buffer pmbuf)
+{
+ if (!pmbuf)
+ return MLAN_STATUS_FAILURE;
+ woal_free_mlan_buffer((moal_handle *) pmoal_handle, pmbuf);
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function is called when MLAN complete send data packet.
+ *
+ * @param pmoal_handle Pointer to the MOAL context
+ * @param pmbuf Pointer to the mlan buffer structure
+ * @param status The status code for mlan_send_packet request
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+mlan_status
+moal_send_packet_complete(IN t_void * pmoal_handle,
+ IN pmlan_buffer pmbuf, IN mlan_status status)
+{
+ moal_private *priv = NULL;
+ moal_handle *handle = (moal_handle *) pmoal_handle;
+ struct sk_buff *skb = NULL;
+ int i;
+ ENTER();
+ if (pmbuf && pmbuf->buf_type == MLAN_BUF_TYPE_RAW_DATA) {
+ woal_free_mlan_buffer(handle, pmbuf);
+ atomic_dec(&handle->tx_pending);
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+ }
+ if (pmbuf) {
+ priv = woal_bss_index_to_priv(pmoal_handle, pmbuf->bss_index);
+ skb = (struct sk_buff *) pmbuf->pdesc;
+ if (priv) {
+ woal_set_trans_start(priv->netdev);
+ if (skb) {
+ if (status == MLAN_STATUS_SUCCESS) {
+ priv->stats.tx_packets++;
+ priv->stats.tx_bytes += skb->len;
+ } else {
+ priv->stats.tx_errors++;
+ }
+ if (atomic_dec_return(&handle->tx_pending) < LOW_TX_PENDING) {
+ for (i = 0; i < handle->priv_num; i++) {
+#ifdef STA_SUPPORT
+ if ((GET_BSS_ROLE(handle->priv[i]) == MLAN_BSS_ROLE_STA)
+ && (handle->priv[i]->media_connected ||
+ priv->is_adhoc_link_sensed)) {
+ woal_wake_queue(handle->priv[i]->netdev);
+ }
+#endif
+#ifdef UAP_SUPPORT
+ if ((GET_BSS_ROLE(handle->priv[i]) == MLAN_BSS_ROLE_UAP)
+ && (handle->priv[i]->media_connected)) {
+ woal_wake_queue(handle->priv[i]->netdev);
+ }
+#endif
+ }
+ }
+ }
+ }
+ if (skb)
+ dev_kfree_skb_any(skb);
+ }
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function write a command/data packet to card.
+ * This function blocks the call until it finishes
+ *
+ * @param pmoal_handle Pointer to the MOAL context
+ * @param pmbuf Pointer to the mlan buffer structure
+ * @param port Port number for sent
+ * @param timeout Timeout value in milliseconds (if 0 the wait is forever)
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status
+moal_write_data_sync(IN t_void * pmoal_handle,
+ IN pmlan_buffer pmbuf, IN t_u32 port, IN t_u32 timeout)
+{
+ return woal_write_data_sync((moal_handle *) pmoal_handle, pmbuf, port,
+ timeout);
+}
+
+/**
+ * @brief This function read data packet/event/command from card.
+ * This function blocks the call until it finish
+ *
+ * @param pmoal_handle Pointer to the MOAL context
+ * @param pmbuf Pointer to the mlan buffer structure
+ * @param port Port number for read
+ * @param timeout Timeout value in milliseconds (if 0 the wait is forever)
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status
+moal_read_data_sync(IN t_void * pmoal_handle,
+ IN OUT pmlan_buffer pmbuf, IN t_u32 port, IN t_u32 timeout)
+{
+ return woal_read_data_sync((moal_handle *) pmoal_handle, pmbuf, port,
+ timeout);
+}
+
+/**
+ * @brief This function writes data into card register.
+ *
+ * @param pmoal_handle Pointer to the MOAL context
+ * @param reg register offset
+ * @param data value
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status
+moal_write_reg(IN t_void * pmoal_handle, IN t_u32 reg, IN t_u32 data)
+{
+ return woal_write_reg((moal_handle *) pmoal_handle, reg, data);
+}
+
+/**
+ * @brief This function reads data from card register.
+ *
+ * @param pmoal_handle Pointer to the MOAL context
+ * @param reg register offset
+ * @param data value
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status
+moal_read_reg(IN t_void * pmoal_handle, IN t_u32 reg, OUT t_u32 * data)
+{
+ return woal_read_reg((moal_handle *) pmoal_handle, reg, data);
+}
+
+/**
+ * @brief This function uploads the packet to the network stack
+ *
+ * @param pmoal_handle Pointer to the MOAL context
+ * @param pmbuf Pointer to the mlan buffer structure
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status
+moal_recv_packet(IN t_void * pmoal_handle, IN pmlan_buffer pmbuf)
+{
+ mlan_status status = MLAN_STATUS_SUCCESS;
+ moal_private *priv = NULL;
+ struct sk_buff *skb = NULL;
+ ENTER();
+ if (pmbuf) {
+ priv = woal_bss_index_to_priv(pmoal_handle, pmbuf->bss_index);
+ skb = (struct sk_buff *) pmbuf->pdesc;
+ if (priv) {
+ if (skb) {
+ skb_reserve(skb, pmbuf->data_offset);
+ skb_put(skb, pmbuf->data_len);
+ pmbuf->pdesc = NULL;
+ pmbuf->pbuf = NULL;
+ pmbuf->data_offset = pmbuf->data_len = 0;
+ } else {
+ PRINTM(MERROR, "%s without skb attach!!!\n", __FUNCTION__);
+ if (!(skb = dev_alloc_skb(pmbuf->data_len + MLAN_NET_IP_ALIGN))) {
+ PRINTM(MERROR, "%s fail to alloc skb\n", __FUNCTION__);
+ status = MLAN_STATUS_FAILURE;
+ priv->stats.rx_dropped++;
+ goto done;
+ }
+ skb_reserve(skb, MLAN_NET_IP_ALIGN);
+ memcpy(skb->data, (t_u8 *) (pmbuf->pbuf + pmbuf->data_offset),
+ pmbuf->data_len);
+ skb_put(skb, pmbuf->data_len);
+ }
+ skb->dev = priv->netdev;
+ skb->protocol = eth_type_trans(skb, priv->netdev);
+ skb->ip_summed = CHECKSUM_NONE;
+ priv->stats.rx_bytes += skb->len;
+ priv->stats.rx_packets++;
+ if (in_interrupt())
+ netif_rx(skb);
+ else
+ netif_rx_ni(skb);
+ }
+ }
+ done:
+ LEAVE();
+ return status;
+}
+
+/**
+ * @brief This function handles event receive
+ *
+ * @param pmoal_handle Pointer to the MOAL context
+ * @param pmevent Pointer to the mlan event structure
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+mlan_status
+moal_recv_event(IN t_void * pmoal_handle, IN pmlan_event pmevent)
+{
+ moal_private *priv = NULL;
+#if defined(STA_WEXT) || defined(UAP_SUPPORT)
+ moal_private *pmpriv = NULL;
+#endif
+#if defined(STA_WEXT) || defined(UAP_WEXT)
+#if defined(STA_SUPPORT) || defined(UAP_WEXT)
+#if defined(UAP_SUPPORT) || defined(STA_WEXT)
+ union iwreq_data wrqu;
+#endif
+#endif
+#endif
+#if defined(SDIO_SUSPEND_RESUME)
+ mlan_ds_ps_info pm_info;
+#endif
+ ENTER();
+
+ PRINTM(MEVENT, "event id:0x%x\n", pmevent->event_id);
+ priv = woal_bss_index_to_priv(pmoal_handle, pmevent->bss_index);
+ if (priv == NULL) {
+ PRINTM(MERROR, "%s: priv is null\n", __FUNCTION__);
+ goto done;
+ }
+ switch (pmevent->event_id) {
+#ifdef STA_SUPPORT
+ case MLAN_EVENT_ID_FW_ADHOC_LINK_SENSED:
+ priv->is_adhoc_link_sensed = MTRUE;
+ if (!netif_carrier_ok(priv->netdev))
+ netif_carrier_on(priv->netdev);
+ woal_wake_queue(priv->netdev);
+#ifdef STA_WEXT
+ if (IS_STA_WEXT(cfg80211_wext))
+ woal_send_iwevcustom_event(priv, CUS_EVT_ADHOC_LINK_SENSED);
+#endif
+ break;
+
+ case MLAN_EVENT_ID_FW_ADHOC_LINK_LOST:
+ woal_stop_queue(priv->netdev);
+ if (netif_carrier_ok(priv->netdev))
+ netif_carrier_off(priv->netdev);
+ priv->is_adhoc_link_sensed = MFALSE;
+#ifdef STA_WEXT
+ if (IS_STA_WEXT(cfg80211_wext))
+ woal_send_iwevcustom_event(priv, CUS_EVT_ADHOC_LINK_LOST);
+#endif
+ break;
+
+ case MLAN_EVENT_ID_DRV_CONNECTED:
+#ifdef STA_WEXT
+ if (IS_STA_WEXT(cfg80211_wext) && pmevent->event_len == ETH_ALEN) {
+ memset(wrqu.ap_addr.sa_data, 0x00, ETH_ALEN);
+ memcpy(wrqu.ap_addr.sa_data, pmevent->event_buf, ETH_ALEN);
+ wrqu.ap_addr.sa_family = ARPHRD_ETHER;
+ wireless_send_event(priv->netdev, SIOCGIWAP, &wrqu, NULL);
+ }
+#endif
+#ifdef STA_CFG80211
+ if (IS_STA_CFG80211(cfg80211_wext))
+ memcpy(priv->cfg_bssid, pmevent->event_buf, ETH_ALEN);
+#endif
+ priv->media_connected = MTRUE;
+ if (!netif_carrier_ok(priv->netdev))
+ netif_carrier_on(priv->netdev);
+ woal_wake_queue(priv->netdev);
+ break;
+
+ case MLAN_EVENT_ID_DRV_SCAN_REPORT:
+ PRINTM(MINFO, "Scan report\n");
+ if (priv->phandle->scan_pending_on_block == MTRUE) {
+ priv->phandle->scan_pending_on_block = MFALSE;
+ MOAL_REL_SEMAPHORE(&priv->phandle->async_sem);
+ }
+
+ if (priv->report_scan_result) {
+#ifdef STA_WEXT
+ if (IS_STA_WEXT(cfg80211_wext)) {
+ memset(&wrqu, 0, sizeof(union iwreq_data));
+ wireless_send_event(priv->netdev, SIOCGIWSCAN, &wrqu, NULL);
+ }
+#endif
+#ifdef STA_CFG80211
+ if (IS_STA_CFG80211(cfg80211_wext)) {
+ woal_inform_bss_from_scan_result(priv, NULL);
+ PRINTM(MINFO, "Reporting scan results\n");
+ if (priv->scan_request) {
+ cfg80211_scan_done(priv->scan_request, MFALSE);
+ priv->scan_request = NULL;
+ }
+ }
+#endif /* STA_CFG80211 */
+
+ priv->report_scan_result = MFALSE;
+ }
+ break;
+
+ case MLAN_EVENT_ID_DRV_OBSS_SCAN_PARAM:
+#ifdef STA_WEXT
+ if (IS_STA_WEXT(cfg80211_wext)) {
+ memset(&wrqu, 0, sizeof(union iwreq_data));
+ memmove((pmevent->event_buf + strlen(CUS_EVT_OBSS_SCAN_PARAM) + 1),
+ pmevent->event_buf, pmevent->event_len);
+ memcpy(pmevent->event_buf, (t_u8 *) CUS_EVT_OBSS_SCAN_PARAM,
+ strlen(CUS_EVT_OBSS_SCAN_PARAM));
+ pmevent->event_buf[strlen(CUS_EVT_OBSS_SCAN_PARAM)] = 0;
+
+ wrqu.data.pointer = pmevent->event_buf;
+ wrqu.data.length =
+ pmevent->event_len + strlen(CUS_EVT_OBSS_SCAN_PARAM) + 1;
+ wireless_send_event(priv->netdev, IWEVCUSTOM, &wrqu,
+ pmevent->event_buf);
+ }
+#endif
+ break;
+ case MLAN_EVENT_ID_FW_BW_CHANGED:
+#ifdef STA_WEXT
+ if (IS_STA_WEXT(cfg80211_wext)) {
+ memset(&wrqu, 0, sizeof(union iwreq_data));
+ memmove((pmevent->event_buf + strlen(CUS_EVT_BW_CHANGED) + 1),
+ pmevent->event_buf, pmevent->event_len);
+ memcpy(pmevent->event_buf, (t_u8 *) CUS_EVT_BW_CHANGED,
+ strlen(CUS_EVT_BW_CHANGED));
+ pmevent->event_buf[strlen(CUS_EVT_BW_CHANGED)] = 0;
+
+ wrqu.data.pointer = pmevent->event_buf;
+ wrqu.data.length =
+ pmevent->event_len + strlen(CUS_EVT_BW_CHANGED) + 1;
+ wireless_send_event(priv->netdev, IWEVCUSTOM, &wrqu,
+ pmevent->event_buf);
+ }
+#endif
+ break;
+
+ case MLAN_EVENT_ID_FW_DISCONNECTED:
+ woal_send_disconnect_to_system(priv);
+#ifdef STA_CFG80211
+ if (IS_STA_CFG80211(cfg80211_wext)) {
+ if (!priv->cfg_disconnect &&
+ priv->wdev->iftype != NL80211_IFTYPE_ADHOC) {
+ PRINTM(MINFO, "Successfully disconnected from %pM:"
+ " Reason code %d\n", priv->cfg_bssid,
+ WLAN_REASON_DEAUTH_LEAVING);
+ /* This function must be called only when disconnect issued by
+ the FW, i.e. disconnected by AP. For IBSS mode this call is
+ not valid */
+ cfg80211_disconnected(priv->netdev,
+ WLAN_REASON_DEAUTH_LEAVING, NULL, 0,
+ GFP_KERNEL);
+ }
+ priv->cfg_disconnect = 0;
+ }
+#endif /* STA_CFG80211 */
+ /* Reset wireless stats signal info */
+#ifdef STA_WEXT
+ if (IS_STA_WEXT(cfg80211_wext)) {
+ priv->w_stats.qual.level = 0;
+ priv->w_stats.qual.noise = 0;
+ }
+#endif
+
+#ifdef REASSOCIATION
+ if (priv->reassoc_on == MTRUE) {
+ PRINTM(MINFO, "Reassoc: trigger the timer\n");
+ priv->reassoc_required = MTRUE;
+ priv->phandle->is_reassoc_timer_set = MTRUE;
+ woal_mod_timer(&priv->phandle->reassoc_timer,
+ REASSOC_TIMER_DEFAULT);
+ } else {
+ priv->rate_index = AUTO_RATE;
+ }
+#endif /* REASSOCIATION */
+ break;
+
+ case MLAN_EVENT_ID_FW_MIC_ERR_UNI:
+#ifdef STA_WEXT
+ if (IS_STA_WEXT(cfg80211_wext)) {
+#if WIRELESS_EXT >= 18
+ woal_send_mic_error_event(priv, MLAN_EVENT_ID_FW_MIC_ERR_UNI);
+#else
+ woal_send_iwevcustom_event(priv, CUS_EVT_MLME_MIC_ERR_UNI);
+#endif
+ }
+#endif /* STA_WEXT */
+ break;
+ case MLAN_EVENT_ID_FW_MIC_ERR_MUL:
+#ifdef STA_WEXT
+ if (IS_STA_WEXT(cfg80211_wext)) {
+#if WIRELESS_EXT >= 18
+ woal_send_mic_error_event(priv, MLAN_EVENT_ID_FW_MIC_ERR_MUL);
+#else
+ woal_send_iwevcustom_event(priv, CUS_EVT_MLME_MIC_ERR_MUL);
+#endif
+ }
+#endif /* STA_WEXT */
+ break;
+ case MLAN_EVENT_ID_FW_BCN_RSSI_LOW:
+#ifdef STA_WEXT
+ if (IS_STA_WEXT(cfg80211_wext))
+ woal_send_iwevcustom_event(priv, CUS_EVT_BEACON_RSSI_LOW);
+#endif
+ break;
+ case MLAN_EVENT_ID_FW_BCN_RSSI_HIGH:
+#ifdef STA_WEXT
+ if (IS_STA_WEXT(cfg80211_wext))
+ woal_send_iwevcustom_event(priv, CUS_EVT_BEACON_RSSI_HIGH);
+#endif
+ break;
+ case MLAN_EVENT_ID_FW_BCN_SNR_LOW:
+#ifdef STA_WEXT
+ if (IS_STA_WEXT(cfg80211_wext))
+ woal_send_iwevcustom_event(priv, CUS_EVT_BEACON_SNR_LOW);
+#endif
+ break;
+ case MLAN_EVENT_ID_FW_BCN_SNR_HIGH:
+#ifdef STA_WEXT
+ if (IS_STA_WEXT(cfg80211_wext))
+ woal_send_iwevcustom_event(priv, CUS_EVT_BEACON_SNR_HIGH);
+#endif
+ break;
+ case MLAN_EVENT_ID_FW_MAX_FAIL:
+#ifdef STA_WEXT
+ if (IS_STA_WEXT(cfg80211_wext))
+ woal_send_iwevcustom_event(priv, CUS_EVT_MAX_FAIL);
+#endif
+ break;
+ case MLAN_EVENT_ID_FW_DATA_RSSI_LOW:
+#ifdef STA_WEXT
+ if (IS_STA_WEXT(cfg80211_wext))
+ woal_send_iwevcustom_event(priv, CUS_EVT_DATA_RSSI_LOW);
+#endif
+ break;
+ case MLAN_EVENT_ID_FW_DATA_SNR_LOW:
+#ifdef STA_WEXT
+ if (IS_STA_WEXT(cfg80211_wext))
+ woal_send_iwevcustom_event(priv, CUS_EVT_DATA_SNR_LOW);
+#endif
+ break;
+ case MLAN_EVENT_ID_FW_DATA_RSSI_HIGH:
+#ifdef STA_WEXT
+ if (IS_STA_WEXT(cfg80211_wext))
+ woal_send_iwevcustom_event(priv, CUS_EVT_DATA_RSSI_HIGH);
+#endif
+ break;
+ case MLAN_EVENT_ID_FW_DATA_SNR_HIGH:
+#ifdef STA_WEXT
+ if (IS_STA_WEXT(cfg80211_wext))
+ woal_send_iwevcustom_event(priv, CUS_EVT_DATA_SNR_HIGH);
+#endif
+ break;
+ case MLAN_EVENT_ID_FW_LINK_QUALITY:
+#ifdef STA_WEXT
+ if (IS_STA_WEXT(cfg80211_wext))
+ woal_send_iwevcustom_event(priv, CUS_EVT_LINK_QUALITY);
+#endif
+ break;
+ case MLAN_EVENT_ID_FW_PORT_RELEASE:
+#ifdef STA_WEXT
+ if (IS_STA_WEXT(cfg80211_wext))
+ woal_send_iwevcustom_event(priv, CUS_EVT_PORT_RELEASE);
+#endif
+ break;
+ case MLAN_EVENT_ID_FW_PRE_BCN_LOST:
+#ifdef STA_WEXT
+ if (IS_STA_WEXT(cfg80211_wext))
+ woal_send_iwevcustom_event(priv, CUS_EVT_PRE_BEACON_LOST);
+#endif
+ break;
+ case MLAN_EVENT_ID_FW_WMM_CONFIG_CHANGE:
+#ifdef STA_WEXT
+ if (IS_STA_WEXT(cfg80211_wext))
+ woal_send_iwevcustom_event(priv, WMM_CONFIG_CHANGE_INDICATION);
+#endif
+ break;
+
+ case MLAN_EVENT_ID_DRV_REPORT_STRING:
+ PRINTM(MINFO, "Report string %s\n", pmevent->event_buf);
+#ifdef STA_WEXT
+ if (IS_STA_WEXT(cfg80211_wext))
+ woal_send_iwevcustom_event(priv, pmevent->event_buf);
+#endif
+ break;
+ case MLAN_EVENT_ID_FW_WEP_ICV_ERR:
+ DBG_HEXDUMP(MCMD_D, "WEP ICV error", pmevent->event_buf,
+ pmevent->event_len);
+#ifdef STA_WEXT
+ if (IS_STA_WEXT(cfg80211_wext))
+ woal_send_iwevcustom_event(priv, CUS_EVT_WEP_ICV_ERR);
+#endif
+ break;
+
+ case MLAN_EVENT_ID_DRV_DEFER_HANDLING:
+ queue_work(priv->phandle->workqueue, &priv->phandle->main_work);
+ break;
+ case MLAN_EVENT_ID_DRV_DBG_DUMP:
+ woal_moal_debug_info(priv, NULL, MFALSE);
+ break;
+ case MLAN_EVENT_ID_FW_BG_SCAN:
+ if (priv->media_connected == MTRUE)
+ priv->bg_scan_start = MFALSE;
+ priv->bg_scan_reported = MTRUE;
+#ifdef STA_WEXT
+ if (IS_STA_WEXT(cfg80211_wext)) {
+ woal_send_iwevcustom_event(priv, CUS_EVT_BG_SCAN);
+ memset(&wrqu, 0, sizeof(union iwreq_data));
+ wireless_send_event(priv->netdev, SIOCGIWSCAN, &wrqu, NULL);
+ }
+#endif
+ break;
+ case MLAN_EVENT_ID_FW_CHANNEL_SWITCH_ANN:
+#ifdef STA_WEXT
+ if (IS_STA_WEXT(cfg80211_wext))
+ woal_send_iwevcustom_event(priv, CUS_EVT_CHANNEL_SWITCH_ANN);
+#endif
+ break;
+#endif /* STA_SUPPORT */
+ case MLAN_EVENT_ID_FW_STOP_TX:
+ woal_stop_queue(priv->netdev);
+ if (netif_carrier_ok(priv->netdev))
+ netif_carrier_off(priv->netdev);
+ break;
+ case MLAN_EVENT_ID_FW_START_TX:
+ if (!netif_carrier_ok(priv->netdev))
+ netif_carrier_on(priv->netdev);
+ woal_wake_queue(priv->netdev);
+ break;
+ case MLAN_EVENT_ID_FW_HS_WAKEUP:
+ /* simulate HSCFG_CANCEL command */
+ woal_cancel_hs(priv, MOAL_NO_WAIT);
+#ifdef STA_WEXT
+#ifdef STA_SUPPORT
+ if (IS_STA_WEXT(cfg80211_wext) && (pmpriv = woal_get_priv((moal_handle
+ *)
+ pmoal_handle,
+ MLAN_BSS_ROLE_STA)))
+ woal_send_iwevcustom_event(pmpriv, CUS_EVT_HS_WAKEUP);
+#endif /* STA_SUPPORT */
+#endif /* STA_WEXT */
+#ifdef UAP_SUPPORT
+ if ((pmpriv =
+ woal_get_priv((moal_handle *) pmoal_handle, MLAN_BSS_ROLE_UAP))) {
+ pmevent->event_id = UAP_EVENT_ID_HS_WAKEUP;
+ woal_broadcast_event(pmpriv, (t_u8 *) & pmevent->event_id,
+ sizeof(t_u32));
+ }
+#endif /* UAP_SUPPORT */
+ break;
+ case MLAN_EVENT_ID_DRV_HS_ACTIVATED:
+#ifdef STA_WEXT
+#ifdef STA_SUPPORT
+ if (IS_STA_WEXT(cfg80211_wext) && (pmpriv = woal_get_priv((moal_handle
+ *)
+ pmoal_handle,
+ MLAN_BSS_ROLE_STA)))
+ {
+ woal_send_iwevcustom_event(pmpriv, CUS_EVT_HS_ACTIVATED);
+ }
+#endif /* STA_SUPPORT */
+#endif /* STA_WEXT */
+#if defined(UAP_SUPPORT)
+ if ((pmpriv =
+ woal_get_priv((moal_handle *) pmoal_handle, MLAN_BSS_ROLE_UAP))) {
+ pmevent->event_id = UAP_EVENT_ID_DRV_HS_ACTIVATED;
+ woal_broadcast_event(pmpriv, (t_u8 *) & pmevent->event_id,
+ sizeof(t_u32));
+ }
+#endif
+#if defined(SDIO_SUSPEND_RESUME)
+ if (priv->phandle->suspend_fail == MFALSE) {
+ woal_get_pm_info(priv, &pm_info);
+ if (pm_info.is_suspend_allowed == MTRUE) {
+ priv->phandle->hs_activated = MTRUE;
+#ifdef MMC_PM_FUNC_SUSPENDED
+ woal_wlan_is_suspended(priv->phandle);
+#endif
+ }
+ priv->phandle->hs_activate_wait_q_woken = MTRUE;
+ wake_up_interruptible(&priv->phandle->hs_activate_wait_q);
+ }
+#endif
+ break;
+ case MLAN_EVENT_ID_DRV_HS_DEACTIVATED:
+#ifdef STA_WEXT
+#ifdef STA_SUPPORT
+ if (IS_STA_WEXT(cfg80211_wext) && (pmpriv = woal_get_priv((moal_handle
+ *)
+ pmoal_handle,
+ MLAN_BSS_ROLE_STA)))
+ {
+ woal_send_iwevcustom_event(pmpriv, CUS_EVT_HS_DEACTIVATED);
+ }
+#endif
+#endif
+#if defined(UAP_SUPPORT)
+ if ((pmpriv =
+ woal_get_priv((moal_handle *) pmoal_handle, MLAN_BSS_ROLE_UAP))) {
+ pmevent->event_id = UAP_EVENT_ID_DRV_HS_DEACTIVATED;
+ woal_broadcast_event(pmpriv, (t_u8 *) & pmevent->event_id,
+ sizeof(t_u32));
+ }
+#endif
+#if defined(SDIO_SUSPEND_RESUME)
+ priv->phandle->hs_activated = MFALSE;
+#endif
+ break;
+#ifdef UAP_SUPPORT
+ case MLAN_EVENT_ID_UAP_FW_BSS_START:
+ priv->bss_started = MTRUE;
+ memcpy(priv->current_addr, pmevent->event_buf + 6, ETH_ALEN);
+ memcpy(priv->netdev->dev_addr, priv->current_addr, ETH_ALEN);
+ woal_broadcast_event(priv, pmevent->event_buf, pmevent->event_len);
+ break;
+ case MLAN_EVENT_ID_UAP_FW_BSS_ACTIVE:
+ priv->media_connected = MTRUE;
+ if (!netif_carrier_ok(priv->netdev))
+ netif_carrier_on(priv->netdev);
+ woal_wake_queue(priv->netdev);
+ woal_broadcast_event(priv, pmevent->event_buf, pmevent->event_len);
+ break;
+ case MLAN_EVENT_ID_UAP_FW_BSS_IDLE:
+ priv->media_connected = MFALSE;
+ woal_stop_queue(priv->netdev);
+ if (netif_carrier_ok(priv->netdev))
+ netif_carrier_off(priv->netdev);
+ woal_broadcast_event(priv, pmevent->event_buf, pmevent->event_len);
+ break;
+#ifdef WIFI_DIRECT_SUPPORT
+#if defined(STA_CFG80211) || defined(UAP_CFG80211)
+ case MLAN_EVENT_ID_FW_REMAIN_ON_CHAN_EXPIRED:
+ if (IS_STA_OR_UAP_CFG80211(cfg80211_wext)) {
+ PRINTM(MEVENT, "FW_REMAIN_ON_CH0ANNEL_EXPIRED cookie = %#llx\n",
+ priv->phandle->cookie);
+ priv->phandle->remain_on_channel = MFALSE;
+ if (priv->phandle->cookie) {
+ cfg80211_remain_on_channel_expired(priv->netdev,
+ priv->phandle->cookie,
+ &priv->phandle->chan,
+ priv->phandle->channel_type,
+ GFP_ATOMIC);
+ priv->phandle->cookie = 0;
+ }
+ }
+ break;
+#endif
+#endif
+ case MLAN_EVENT_ID_UAP_FW_STA_CONNECT:
+#if defined(STA_CFG80211) || defined(UAP_CFG80211)
+ if (IS_STA_OR_UAP_CFG80211(cfg80211_wext)) {
+ struct station_info sinfo;
+ t_u8 addr[ETH_ALEN];
+
+ sinfo.filled = 0;
+ sinfo.generation = 0;
+ /* copy the station mac address */
+ memset(addr, 0xFF, ETH_ALEN);
+ memcpy(addr, pmevent->event_buf, ETH_ALEN);
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,2,0) || defined(COMPAT_WIRELESS)
+ if (pmevent->event_len > ETH_ALEN) {
+ /* set station info filled flag */
+ sinfo.filled |= STATION_INFO_ASSOC_REQ_IES;
+ /* get the assoc request ies and length */
+ sinfo.assoc_req_ies =
+ (const t_u8 *) (pmevent->event_buf + ETH_ALEN);
+ sinfo.assoc_req_ies_len = pmevent->event_len - ETH_ALEN;
+
+ }
+#endif /* KERNEL_VERSION */
+ if (priv->netdev)
+ cfg80211_new_sta(priv->netdev,
+ (t_u8 *) addr, &sinfo, GFP_KERNEL);
+ }
+#endif /* UAP_CFG80211 */
+#ifdef UAP_WEXT
+ if (IS_UAP_WEXT(cfg80211_wext)) {
+ memset(&wrqu, 0, sizeof(union iwreq_data));
+ memmove((pmevent->event_buf + strlen(CUS_EVT_STA_CONNECTED) + 1),
+ pmevent->event_buf, pmevent->event_len);
+ memcpy(pmevent->event_buf, (t_u8 *) CUS_EVT_STA_CONNECTED,
+ strlen(CUS_EVT_STA_CONNECTED));
+ pmevent->event_buf[strlen(CUS_EVT_STA_CONNECTED)] = 0;
+ wrqu.data.pointer = pmevent->event_buf;
+ if ((pmevent->event_len + strlen(CUS_EVT_STA_CONNECTED) + 1) >
+ IW_CUSTOM_MAX)
+ wrqu.data.length = ETH_ALEN + strlen(CUS_EVT_STA_CONNECTED) + 1;
+ else
+ wrqu.data.length =
+ pmevent->event_len + strlen(CUS_EVT_STA_CONNECTED) + 1;
+ wireless_send_event(priv->netdev, IWEVCUSTOM, &wrqu,
+ pmevent->event_buf);
+ }
+#endif /* UAP_WEXT */
+ break;
+ case MLAN_EVENT_ID_UAP_FW_STA_DISCONNECT:
+#ifdef UAP_CFG80211
+ if (IS_UAP_CFG80211(cfg80211_wext)) {
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,0,0) || defined(COMPAT_WIRELESS)
+ /* skip 2 bytes extra header will get the mac address */
+ cfg80211_del_sta(priv->netdev, pmevent->event_buf + 2, GFP_KERNEL);
+#endif /* KERNEL_VERSION */
+ }
+#endif /* UAP_CFG80211 */
+#ifdef UAP_WEXT
+ if (IS_UAP_WEXT(cfg80211_wext)) {
+ memset(&wrqu, 0, sizeof(union iwreq_data));
+ memmove((pmevent->event_buf + strlen(CUS_EVT_STA_DISCONNECTED) + 1),
+ pmevent->event_buf, pmevent->event_len);
+ memcpy(pmevent->event_buf, (t_u8 *) CUS_EVT_STA_DISCONNECTED,
+ strlen(CUS_EVT_STA_DISCONNECTED));
+ pmevent->event_buf[strlen(CUS_EVT_STA_DISCONNECTED)] = 0;
+
+ wrqu.data.pointer = pmevent->event_buf;
+ wrqu.data.length =
+ pmevent->event_len + strlen(CUS_EVT_STA_DISCONNECTED) + 1;
+ wireless_send_event(priv->netdev, IWEVCUSTOM, &wrqu,
+ pmevent->event_buf);
+ }
+#endif /* UAP_WEXT */
+ break;
+ case MLAN_EVENT_ID_DRV_MGMT_FRAME:
+#ifdef WIFI_DIRECT_SUPPORT
+#if defined(STA_CFG80211) || defined(UAP_CFG80211)
+ if (IS_STA_OR_UAP_CFG80211(cfg80211_wext)) {
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,0,0) || defined(COMPAT_WIRELESS)
+ if (priv->netdev && priv->netdev->ieee80211_ptr->wiphy->mgmt_stypes) {
+ /* frmctl + durationid + addr1 + addr2 + addr3 + seqctl */
+#define PACKET_ADDR4_POS (2 + 2 + 6 + 6 + 6 + 2)
+ t_u8 *pkt;
+ pkt = ((t_u8 *) pmevent->event_buf + sizeof(pmevent->event_id));
+
+ /* move addr4 */
+ memmove(pkt + PACKET_ADDR4_POS,
+ pkt + PACKET_ADDR4_POS + ETH_ALEN,
+ pmevent->event_len - sizeof(pmevent->event_id)
+ - PACKET_ADDR4_POS - ETH_ALEN);
+ cfg80211_rx_mgmt(priv->netdev, priv->phandle->chan.center_freq,
+ ((const t_u8 *) pmevent->event_buf)
+ + sizeof(pmevent->event_id),
+ pmevent->event_len - sizeof(pmevent->event_id)
+ - MLAN_MAC_ADDR_LENGTH, GFP_ATOMIC);
+ }
+#endif /* KERNEL_VERSION */
+ }
+#endif /* STA_CFG80211 || UAP_CFG80211 */
+#endif /* WIFI_DIRECT_SUPPORT */
+#ifdef UAP_WEXT
+ if (IS_UAP_WEXT(cfg80211_wext)) {
+ woal_broadcast_event(priv, pmevent->event_buf, pmevent->event_len);
+ }
+#endif /* UAP_WEXT */
+ break;
+#endif /* UAP_SUPPORT */
+ case MLAN_EVENT_ID_DRV_PASSTHRU:
+ woal_broadcast_event(priv, pmevent->event_buf, pmevent->event_len);
+ break;
+ case MLAN_EVENT_ID_DRV_MEAS_REPORT:
+ /* We have received measurement report, wakeup measurement wait queue */
+ PRINTM(MINFO, "Measurement Report\n");
+ /* Going out of CAC checking period */
+ if (priv->phandle->cac_period == MTRUE) {
+ priv->phandle->cac_period = MFALSE;
+ if (priv->phandle->meas_wait_q_woken == MFALSE) {
+ priv->phandle->meas_wait_q_woken = MTRUE;
+ wake_up_interruptible(&priv->phandle->meas_wait_q);
+ }
+
+ /* Execute delayed BSS START command */
+ if (priv->phandle->delay_bss_start == MTRUE) {
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_bss *bss = NULL;
+
+ /* Clear flag */
+ priv->phandle->delay_bss_start = MFALSE;
+
+ PRINTM(MMSG, "Now CAC measure period end. "
+ "Execute delayed BSS Start command.\n");
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_bss));
+ bss = (mlan_ds_bss *) req->pbuf;
+ req->req_id = MLAN_IOCTL_BSS;
+ req->action = MLAN_ACT_SET;
+ bss->sub_command = MLAN_OID_BSS_START;
+ memcpy(&bss->param.ssid_bssid,
+ &priv->phandle->delay_ssid_bssid,
+ sizeof(mlan_ssid_bssid));
+
+ if (woal_request_ioctl(priv, req, MOAL_NO_WAIT)
+ != MLAN_STATUS_PENDING) {
+ PRINTM(MMSG, "Delayed BSS Start operation failed!\n");
+ kfree(req);
+ }
+
+ PRINTM(MMSG, "BSS START Complete!\n");
+ }
+ }
+ default:
+ break;
+ }
+ done:
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function prints the debug message in mlan
+ *
+ * @param pmoal_handle Pointer to the MOAL context
+ * @param level debug level
+ * @param pformat point to string format buf
+ *
+ * @return N/A
+ */
+t_void
+moal_print(IN t_void * pmoal_handle, IN t_u32 level, IN t_s8 * pformat, IN ...)
+{
+#ifdef DEBUG_LEVEL1
+ va_list args;
+
+ if (level & MHEX_DUMP) {
+ t_u8 *buf = NULL;
+ int len = 0;
+
+ va_start(args, pformat);
+ buf = (t_u8 *) va_arg(args, t_u8 *);
+ len = (int) va_arg(args, int);
+ va_end(args);
+
+#ifdef DEBUG_LEVEL2
+ if (level & MINFO)
+ HEXDUMP((char *) pformat, buf, len);
+ else
+#endif /* DEBUG_LEVEL2 */
+ {
+ if (level & MERROR)
+ DBG_HEXDUMP(MERROR, (char *) pformat, buf, len);
+ if (level & MCMD_D)
+ DBG_HEXDUMP(MCMD_D, (char *) pformat, buf, len);
+ if (level & MDAT_D)
+ DBG_HEXDUMP(MDAT_D, (char *) pformat, buf, len);
+ if (level & MIF_D)
+ DBG_HEXDUMP(MIF_D, (char *) pformat, buf, len);
+ if (level & MFW_D)
+ DBG_HEXDUMP(MFW_D, (char *) pformat, buf, len);
+ if (level & MEVT_D)
+ DBG_HEXDUMP(MEVT_D, (char *) pformat, buf, len);
+ }
+ } else {
+ va_start(args, pformat);
+ vprintk(pformat, args);
+ va_end(args);
+ }
+#endif /* DEBUG_LEVEL1 */
+}
+
+/**
+ * @brief This function prints the network interface name
+ *
+ * @param pmoal_handle Pointer to the MOAL context
+ * @param bss_index BSS index
+ * @param level debug level
+ *
+ * @return N/A
+ */
+t_void
+moal_print_netintf(IN t_void * pmoal_handle, IN t_u32 bss_index, IN t_u32 level)
+{
+#ifdef DEBUG_LEVEL1
+ moal_handle *phandle = (moal_handle *) pmoal_handle;
+
+ if (phandle && (drvdbg & level)) {
+ if ((bss_index < MLAN_MAX_BSS_NUM) && phandle->priv[bss_index] &&
+ phandle->priv[bss_index]->netdev)
+ printk("%s: ", phandle->priv[bss_index]->netdev->name);
+ }
+#endif /* DEBUG_LEVEL1 */
+}
+
+/**
+ * @brief This function asserts the existence of the passed argument
+ *
+ * @param pmoal_handle A pointer to moal_private structure
+ * @param cond Condition to check
+ *
+ * @return N/A
+ */
+t_void
+moal_assert(IN t_void * pmoal_handle, IN t_u32 cond)
+{
+ if (!cond)
+ panic("Assert failed: Panic!");
+}
diff --git a/drivers/net/wireless/sd8797/mlinux/moal_shim.h b/drivers/net/wireless/sd8797/mlinux/moal_shim.h
new file mode 100644
index 000000000000..ee50a2105f0f
--- /dev/null
+++ b/drivers/net/wireless/sd8797/mlinux/moal_shim.h
@@ -0,0 +1,95 @@
+/** @file moal_shim.h
+ *
+ * @brief This file contains declaration referring to
+ * functions defined in moal module
+ *
+ * Copyright (C) 2008-2011, Marvell International Ltd.
+ *
+ * This software file (the "File") is distributed by Marvell International
+ * Ltd. under the terms of the GNU General Public License Version 2, June 1991
+ * (the "License"). You may use, redistribute and/or modify this File in
+ * accordance with the terms and conditions of the License, a copy of which
+ * is available by writing to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
+ * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
+ *
+ * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
+ * ARE EXPRESSLY DISCLAIMED. The License provides additional details about
+ * this warranty disclaimer.
+ *
+ */
+/*************************************************************
+Change Log:
+ 10/21/2008: initial version
+************************************************************/
+
+#ifndef _MOAL_H
+#define _MOAL_H
+
+mlan_status moal_get_fw_data(IN t_void * pmoal_handle,
+ IN t_u32 offset, IN t_u32 len, OUT t_u8 * pbuf);
+mlan_status moal_init_fw_complete(IN t_void * pmoal_handle,
+ IN mlan_status status);
+mlan_status moal_shutdown_fw_complete(IN t_void * pmoal_handle,
+ IN mlan_status status);
+mlan_status moal_ioctl_complete(IN t_void * pmoal_handle,
+ IN pmlan_ioctl_req pioctl_req,
+ IN mlan_status status);
+mlan_status moal_alloc_mlan_buffer(IN t_void * pmoal_handle, IN t_u32 size,
+ OUT pmlan_buffer * pmbuf);
+mlan_status moal_free_mlan_buffer(IN t_void * pmoal_handle,
+ IN pmlan_buffer pmbuf);
+mlan_status moal_send_packet_complete(IN t_void * pmoal_handle,
+ IN pmlan_buffer pmbuf,
+ IN mlan_status status);
+/** moal_write_reg */
+mlan_status moal_write_reg(IN t_void * pmoal_handle,
+ IN t_u32 reg, IN t_u32 data);
+/** moal_read_reg */
+mlan_status moal_read_reg(IN t_void * pmoal_handle,
+ IN t_u32 reg, OUT t_u32 * data);
+mlan_status moal_write_data_sync(IN t_void * pmoal_handle,
+ IN pmlan_buffer pmbuf,
+ IN t_u32 port, IN t_u32 timeout);
+mlan_status moal_read_data_sync(IN t_void * pmoal_handle,
+ IN OUT pmlan_buffer pmbuf,
+ IN t_u32 port, IN t_u32 timeout);
+mlan_status moal_recv_packet(IN t_void * pmoal_handle, IN pmlan_buffer pmbuf);
+mlan_status moal_recv_event(IN t_void * pmoal_handle, IN pmlan_event pmevent);
+mlan_status moal_malloc(IN t_void * pmoal_handle,
+ IN t_u32 size, IN t_u32 flag, OUT t_u8 ** ppbuf);
+mlan_status moal_mfree(IN t_void * pmoal_handle, IN t_u8 * pbuf);
+t_void *moal_memset(IN t_void * pmoal_handle,
+ IN t_void * pmem, IN t_u8 byte, IN t_u32 num);
+t_void *moal_memcpy(IN t_void * pmoal_handle,
+ IN t_void * pdest, IN const t_void * psrc, IN t_u32 num);
+t_void *moal_memmove(IN t_void * pmoal_handle,
+ IN t_void * pdest, IN const t_void * psrc, IN t_u32 num);
+t_s32 moal_memcmp(IN t_void * pmoal_handle,
+ IN const t_void * pmem1,
+ IN const t_void * pmem2, IN t_u32 num);
+/** moal_udelay */
+t_void moal_udelay(IN t_void * pmoal_handle, IN t_u32 udelay);
+mlan_status moal_get_system_time(IN t_void * pmoal_handle, OUT t_u32 * psec,
+ OUT t_u32 * pusec);
+mlan_status moal_init_lock(IN t_void * pmoal_handle, OUT t_void ** pplock);
+mlan_status moal_free_lock(IN t_void * pmoal_handle, IN t_void * plock);
+mlan_status moal_spin_lock(IN t_void * pmoal_handle, IN t_void * plock);
+mlan_status moal_spin_unlock(IN t_void * pmoal_handle, IN t_void * plock);
+t_void moal_print(IN t_void * pmoal_handle, IN t_u32 level, IN t_s8 * pformat,
+ IN ...);
+t_void moal_print_netintf(IN t_void * pmoal_handle, IN t_u32 bss_index,
+ IN t_u32 level);
+t_void moal_assert(IN t_void * pmoal_handle, IN t_u32 cond);
+mlan_status moal_init_timer(IN t_void * pmoal_handle,
+ OUT t_void ** pptimer,
+ IN t_void(*callback) (t_void * pcontext),
+ IN t_void * pcontext);
+mlan_status moal_free_timer(IN t_void * pmoal_handle, IN t_void * ptimer);
+mlan_status moal_start_timer(IN t_void * pmoal_handle,
+ IN t_void * ptimer,
+ IN t_u8 periodic, IN t_u32 msec);
+mlan_status moal_stop_timer(IN t_void * pmoal_handle, IN t_void * ptimer);
+
+#endif /*_MOAL_H */
diff --git a/drivers/net/wireless/sd8797/mlinux/moal_sta_cfg80211.c b/drivers/net/wireless/sd8797/mlinux/moal_sta_cfg80211.c
new file mode 100644
index 000000000000..dfb4aefcbb33
--- /dev/null
+++ b/drivers/net/wireless/sd8797/mlinux/moal_sta_cfg80211.c
@@ -0,0 +1,2476 @@
+/** @file moal_sta_cfg80211.c
+ *
+ * @brief This file contains the functions for STA CFG80211.
+ *
+ * Copyright (C) 2011-2012, Marvell International Ltd.
+ *
+ * This software file (the "File") is distributed by Marvell International
+ * Ltd. under the terms of the GNU General Public License Version 2, June 1991
+ * (the "License"). You may use, redistribute and/or modify this File in
+ * accordance with the terms and conditions of the License, a copy of which
+ * is available by writing to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
+ * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
+ *
+ * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
+ * ARE EXPRESSLY DISCLAIMED. The License provides additional details about
+ * this warranty disclaimer.
+ *
+ */
+
+#include "moal_cfg80211.h"
+#include "moal_sta_cfg80211.h"
+static int woal_cfg80211_reg_notifier(struct wiphy *wiphy,
+ struct regulatory_request *request);
+
+static int woal_cfg80211_scan(struct wiphy *wiphy, struct net_device *dev,
+ struct cfg80211_scan_request *request);
+
+static int woal_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev,
+ struct cfg80211_connect_params *sme);
+
+static int woal_cfg80211_disconnect(struct wiphy *wiphy,
+ struct net_device *dev, t_u16 reason_code);
+
+static int woal_cfg80211_get_station(struct wiphy *wiphy,
+ struct net_device *dev,
+ t_u8 * mac, struct station_info *sinfo);
+
+static int woal_cfg80211_dump_station(struct wiphy *wiphy,
+ struct net_device *dev, int idx,
+ t_u8 * mac, struct station_info *sinfo);
+
+static int woal_cfg80211_set_power_mgmt(struct wiphy *wiphy,
+ struct net_device *dev, bool enabled,
+ int timeout);
+
+static int woal_cfg80211_set_tx_power(struct wiphy *wiphy,
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,36) && !defined(COMPAT_WIRELESS)
+ enum tx_power_setting type,
+#else
+ enum nl80211_tx_power_setting type,
+#endif
+ int dbm);
+
+static int woal_cfg80211_join_ibss(struct wiphy *wiphy,
+ struct net_device *dev,
+ struct cfg80211_ibss_params *params);
+
+static int woal_cfg80211_leave_ibss(struct wiphy *wiphy,
+ struct net_device *dev);
+
+#if defined(WIFI_DIRECT_SUPPORT)
+#if LINUX_VERSION_CODE >= WIFI_DIRECT_KERNEL_VERSION
+static int woal_cfg80211_mgmt_tx_cancel_wait(struct wiphy *wiphy,
+ struct net_device *dev,
+ u64 cookie);
+
+void woal_cfg80211_remain_on_channel_done(void *context);
+
+static int woal_cfg80211_remain_on_channel(struct wiphy *wiphy,
+ struct net_device *dev,
+ struct ieee80211_channel *chan,
+ enum nl80211_channel_type
+ channel_type, unsigned int duration,
+ u64 * cookie);
+
+static int woal_cfg80211_cancel_remain_on_channel(struct wiphy *wiphy,
+ struct net_device *dev,
+ u64 cookie);
+#endif /* KERNEL_VERSION */
+#endif /* WIFI_DIRECT_SUPPORT && V14_FEATURE */
+
+/** cfg80211 STA operations */
+static struct cfg80211_ops woal_cfg80211_sta_ops = {
+ .change_virtual_intf = woal_cfg80211_change_virtual_intf,
+ .scan = woal_cfg80211_scan,
+ .connect = woal_cfg80211_connect,
+ .disconnect = woal_cfg80211_disconnect,
+ .get_station = woal_cfg80211_get_station,
+ .dump_station = woal_cfg80211_dump_station,
+ .set_wiphy_params = woal_cfg80211_set_wiphy_params,
+ .set_channel = woal_cfg80211_set_channel,
+ .join_ibss = woal_cfg80211_join_ibss,
+ .leave_ibss = woal_cfg80211_leave_ibss,
+ .add_key = woal_cfg80211_add_key,
+ .del_key = woal_cfg80211_del_key,
+ .set_default_key = woal_cfg80211_set_default_key,
+ .set_power_mgmt = woal_cfg80211_set_power_mgmt,
+ .set_tx_power = woal_cfg80211_set_tx_power,
+};
+
+#if defined(WIFI_DIRECT_SUPPORT)
+#if LINUX_VERSION_CODE >= WIFI_DIRECT_KERNEL_VERSION
+/** cfg80211 Wifi Direct operations */
+static struct cfg80211_ops woal_cfg80211_wifi_direct_ops = {
+ .add_virtual_intf = woal_cfg80211_add_virtual_intf,
+ .del_virtual_intf = woal_cfg80211_del_virtual_intf,
+ .change_virtual_intf = woal_cfg80211_change_virtual_intf,
+ .scan = woal_cfg80211_scan,
+ .connect = woal_cfg80211_connect,
+ .disconnect = woal_cfg80211_disconnect,
+ .get_station = woal_cfg80211_get_station,
+ .dump_station = woal_cfg80211_dump_station,
+ .set_wiphy_params = woal_cfg80211_set_wiphy_params,
+ .set_channel = woal_cfg80211_set_channel,
+ .add_key = woal_cfg80211_add_key,
+ .del_key = woal_cfg80211_del_key,
+ .add_beacon = woal_cfg80211_add_beacon,
+ .set_beacon = woal_cfg80211_set_beacon,
+ .del_beacon = woal_cfg80211_del_beacon,
+ .mgmt_frame_register = woal_cfg80211_mgmt_frame_register,
+ .mgmt_tx = woal_cfg80211_mgmt_tx,
+ .mgmt_tx_cancel_wait = woal_cfg80211_mgmt_tx_cancel_wait,
+ .remain_on_channel = woal_cfg80211_remain_on_channel,
+ .cancel_remain_on_channel = woal_cfg80211_cancel_remain_on_channel,
+ .set_default_key = woal_cfg80211_set_default_key,
+ .set_power_mgmt = woal_cfg80211_set_power_mgmt,
+ .set_tx_power = woal_cfg80211_set_tx_power,
+};
+#endif /* KERNEL_VERSION */
+#endif /* WIFI_DIRECT_SUPPORT && V14_FEATURE */
+
+/********************************************************
+ Local Variables
+********************************************************/
+#if defined(WIFI_DIRECT_SUPPORT)
+#if LINUX_VERSION_CODE >= WIFI_DIRECT_KERNEL_VERSION
+static const struct ieee80211_txrx_stypes
+ ieee80211_mgmt_stypes[NUM_NL80211_IFTYPES] = {
+ [NL80211_IFTYPE_ADHOC] = {
+ .tx = 0x0000,
+ .rx = 0x0000,
+ },
+ [NL80211_IFTYPE_STATION] = {
+ .tx = BIT(IEEE80211_STYPE_ACTION >> 4) |
+ BIT(IEEE80211_STYPE_PROBE_RESP >> 4),
+ .rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
+ BIT(IEEE80211_STYPE_PROBE_REQ >> 4),
+ },
+ [NL80211_IFTYPE_AP] = {
+ .tx = 0xffff,
+ .rx = BIT(IEEE80211_STYPE_ASSOC_REQ >> 4) |
+ BIT(IEEE80211_STYPE_REASSOC_REQ >> 4) |
+ BIT(IEEE80211_STYPE_PROBE_REQ >> 4) |
+ BIT(IEEE80211_STYPE_DISASSOC >> 4) |
+ BIT(IEEE80211_STYPE_AUTH >> 4) |
+ BIT(IEEE80211_STYPE_DEAUTH >> 4) |
+ BIT(IEEE80211_STYPE_ACTION >> 4),
+ },
+ [NL80211_IFTYPE_AP_VLAN] = {
+ .tx = 0x0000,
+ .rx = 0x0000,
+ },
+ [NL80211_IFTYPE_P2P_CLIENT] = {
+ .tx = BIT(IEEE80211_STYPE_ACTION >> 4) |
+ BIT(IEEE80211_STYPE_PROBE_RESP >> 4),
+ .rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
+ BIT(IEEE80211_STYPE_PROBE_REQ >> 4),
+ },
+ [NL80211_IFTYPE_P2P_GO] = {
+ .tx = BIT(IEEE80211_STYPE_ACTION >> 4) |
+ // BIT(IEEE80211_STYPE_PROBE_RESP >> 4) |
+ 0,
+ .rx = BIT(IEEE80211_STYPE_ASSOC_REQ >> 4) |
+ BIT(IEEE80211_STYPE_REASSOC_REQ >> 4) |
+ BIT(IEEE80211_STYPE_PROBE_REQ >> 4) |
+ BIT(IEEE80211_STYPE_DISASSOC >> 4) |
+ BIT(IEEE80211_STYPE_AUTH >> 4) |
+ BIT(IEEE80211_STYPE_DEAUTH >> 4) |
+ BIT(IEEE80211_STYPE_ACTION >> 4),
+ },
+ [NL80211_IFTYPE_MESH_POINT] = {
+ .tx = 0x0000,
+ .rx = 0x0000,
+ },
+
+};
+#endif
+#endif /* WIFI_DIRECT_SUPPORT && V14_FEATURE */
+
+/********************************************************
+ Global Variables
+********************************************************/
+
+/********************************************************
+ Local Functions
+********************************************************/
+/**
+ * @brief Get the encryption mode from cipher
+ *
+ * @param cipher Cipher cuite
+ * @param wpa_enabled WPA enable or disable
+ *
+ * @return MLAN_ENCRYPTION_MODE_*
+ */
+static int
+woal_cfg80211_get_encryption_mode(t_u32 cipher, int *wpa_enabled)
+{
+ int encrypt_mode;
+
+ ENTER();
+
+ *wpa_enabled = 0;
+ switch (cipher) {
+ case IW_AUTH_CIPHER_NONE:
+ encrypt_mode = MLAN_ENCRYPTION_MODE_NONE;
+ break;
+ case WLAN_CIPHER_SUITE_WEP40:
+ encrypt_mode = MLAN_ENCRYPTION_MODE_WEP40;
+ break;
+ case WLAN_CIPHER_SUITE_WEP104:
+ encrypt_mode = MLAN_ENCRYPTION_MODE_WEP104;
+ break;
+ case WLAN_CIPHER_SUITE_TKIP:
+ encrypt_mode = MLAN_ENCRYPTION_MODE_TKIP;
+ *wpa_enabled = 1;
+ break;
+ case WLAN_CIPHER_SUITE_CCMP:
+ encrypt_mode = MLAN_ENCRYPTION_MODE_CCMP;
+ *wpa_enabled = 1;
+ break;
+ default:
+ encrypt_mode = -1;
+ }
+
+ LEAVE();
+ return encrypt_mode;
+}
+
+/**
+ * @brief Check the pairwise or group cipher for
+ * WEP enabled or not
+ *
+ * @param cipher MLAN Cipher cuite
+ *
+ * @return 1 -- enable or 0 -- disable
+ */
+static int
+woal_cfg80211_is_alg_wep(t_u32 cipher)
+{
+ int alg = 0;
+ ENTER();
+
+ if (cipher == MLAN_ENCRYPTION_MODE_WEP40 ||
+ cipher == MLAN_ENCRYPTION_MODE_WEP104)
+ alg = 1;
+
+ LEAVE();
+ return alg;
+}
+
+/**
+ * @brief Convert NL802.11 channel type into driver channel type
+ *
+ * The mapping is as follows -
+ * NL80211_CHAN_NO_HT -> NO_SEC_CHANNEL
+ * NL80211_CHAN_HT20 -> NO_SEC_CHANNEL
+ * NL80211_CHAN_HT40PLUS -> SEC_CHANNEL_ABOVE
+ * NL80211_CHAN_HT40MINUS -> SEC_CHANNEL_BELOW
+ * Others -> NO_SEC_CHANNEL
+ *
+ * @param channel_type Channel type
+ *
+ * @return Driver channel type
+ */
+static int
+woal_cfg80211_channel_type_to_channel(enum nl80211_channel_type channel_type)
+{
+ int channel;
+
+ ENTER();
+
+ switch (channel_type) {
+ case NL80211_CHAN_NO_HT:
+ case NL80211_CHAN_HT20:
+ channel = NO_SEC_CHANNEL;
+ break;
+ case NL80211_CHAN_HT40PLUS:
+ channel = SEC_CHANNEL_ABOVE;
+ break;
+ case NL80211_CHAN_HT40MINUS:
+ channel = SEC_CHANNEL_BELOW;
+ break;
+ default:
+ channel = NO_SEC_CHANNEL;
+ }
+ LEAVE();
+ return channel;
+}
+
+/**
+ * @brief Convert secondary channel type to NL80211 channel type
+ *
+ * The mapping is as follows -
+ * NO_SEC_CHANNEL -> NL80211_CHAN_HT20
+ * SEC_CHANNEL_ABOVE -> NL80211_CHAN_HT40PLUS
+ * SEC_CHANNEL_BELOW -> NL80211_CHAN_HT40MINUS
+ * Others -> NL80211_CHAN_HT20
+ *
+ * @param channel_type Driver channel type
+ *
+ * @return nl80211_channel_type type
+ */
+static enum nl80211_channel_type
+woal_channel_to_nl80211_channel_type(int channel_type)
+{
+ enum nl80211_channel_type channel;
+
+ ENTER();
+
+ switch (channel_type) {
+ case NO_SEC_CHANNEL:
+ channel = NL80211_CHAN_HT20;
+ break;
+ case SEC_CHANNEL_ABOVE:
+ channel = NL80211_CHAN_HT40PLUS;
+ break;
+ case SEC_CHANNEL_BELOW:
+ channel = NL80211_CHAN_HT40MINUS;
+ break;
+ default:
+ channel = NL80211_CHAN_HT20;
+ }
+ LEAVE();
+ return channel;
+}
+
+/**
+ * @brief Convert driver band configuration to IEEE band type
+ *
+ * @param band Driver band configuration
+ *
+ * @return IEEE band type
+ */
+t_u8
+woal_band_cfg_to_ieee_band(t_u32 band)
+{
+ t_u8 ret_radio_type;
+
+ ENTER();
+
+ switch (band) {
+ case BAND_A:
+ case BAND_AN:
+ case BAND_A | BAND_AN:
+ ret_radio_type = IEEE80211_BAND_5GHZ;
+ break;
+ case BAND_B:
+ case BAND_G:
+ case BAND_B | BAND_G:
+ case BAND_GN:
+ case BAND_B | BAND_GN:
+ default:
+ ret_radio_type = IEEE80211_BAND_2GHZ;
+ break;
+ }
+
+ LEAVE();
+ return ret_radio_type;
+}
+
+/**
+ * @brief Convert NL80211 interface type to MLAN_BSS_MODE_*
+ *
+ * @param iftype Interface type of NL80211
+ *
+ * @return Driver bss mode
+ */
+static t_u32
+woal_nl80211_iftype_to_mode(enum nl80211_iftype iftype)
+{
+ switch (iftype) {
+ case NL80211_IFTYPE_ADHOC:
+ return MLAN_BSS_MODE_IBSS;
+ case NL80211_IFTYPE_STATION:
+ return MLAN_BSS_MODE_INFRA;
+ case NL80211_IFTYPE_UNSPECIFIED:
+ default:
+ return MLAN_BSS_MODE_AUTO;
+ }
+}
+
+/**
+ * @brief Control WPS Session Enable/Disable
+ *
+ * @param priv Pointer to the moal_private driver data struct
+ * @param enable enable/disable flag
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_wps_cfg(moal_private * priv, int enable)
+{
+ int ret = 0;
+ mlan_ds_wps_cfg *pwps = NULL;
+ mlan_ioctl_req *req = NULL;
+
+ ENTER();
+
+ PRINTM(MINFO, "WOAL_WPS_SESSION\n");
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_wps_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ pwps = (mlan_ds_wps_cfg *) req->pbuf;
+ req->req_id = MLAN_IOCTL_WPS_CFG;
+ req->action = MLAN_ACT_SET;
+ pwps->sub_command = MLAN_OID_WPS_CFG_SESSION;
+ if (enable)
+ pwps->param.wps_session = MLAN_WPS_CFG_SESSION_START;
+ else
+ pwps->param.wps_session = MLAN_WPS_CFG_SESSION_END;
+
+ if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ done:
+ if (req)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief configure ASSOC IE
+ *
+ * @param priv A pointer to moal private structure
+ * @param ie A pointer to ie data
+ * @param ie_len The length of ie data
+ *
+ * @return 0 -- success, otherwise fail
+ */
+static int
+woal_cfg80211_assoc_ies_cfg(moal_private * priv, t_u8 * ie, int ie_len)
+{
+ int bytes_left = ie_len;
+ t_u8 *pcurrent_ptr = ie;
+ int total_ie_len;
+ t_u8 element_len;
+ int ret = MLAN_STATUS_SUCCESS;
+ IEEEtypes_ElementId_e element_id;
+ IEEEtypes_VendorSpecific_t *pvendor_ie;
+ t_u8 wps_oui[] = { 0x00, 0x50, 0xf2, 0x04 };
+
+ while (bytes_left >= 2) {
+ element_id = (IEEEtypes_ElementId_e) (*((t_u8 *) pcurrent_ptr));
+ element_len = *((t_u8 *) pcurrent_ptr + 1);
+ total_ie_len = element_len + sizeof(IEEEtypes_Header_t);
+ if (bytes_left < total_ie_len) {
+ PRINTM(MERROR, "InterpretIE: Error in processing IE, "
+ "bytes left < IE length\n");
+ bytes_left = 0;
+ continue;
+ }
+ switch (element_id) {
+ case RSN_IE:
+ if (MLAN_STATUS_SUCCESS !=
+ woal_set_get_gen_ie(priv, MLAN_ACT_SET, pcurrent_ptr,
+ &total_ie_len)) {
+ PRINTM(MERROR, "Fail to set RSN IE\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ PRINTM(MIOCTL, "Set RSN IE\n");
+ break;
+ case VENDOR_SPECIFIC_221:
+ pvendor_ie = (IEEEtypes_VendorSpecific_t *) pcurrent_ptr;
+ if (!memcmp(pvendor_ie->vend_hdr.oui, wps_oui, sizeof(wps_oui))) {
+ PRINTM(MIOCTL, "Enable WPS session\n");
+ woal_wps_cfg(priv, MTRUE);
+ }
+ if (MLAN_STATUS_SUCCESS !=
+ woal_set_get_gen_ie(priv, MLAN_ACT_SET, pcurrent_ptr,
+ &total_ie_len)) {
+ PRINTM(MERROR, "Fail to Set VENDOR SPECIFIC IE\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ PRINTM(MIOCTL, "Set VENDOR SPECIFIC IE, OUI: %02x:%02x:%02x:%02x\n",
+ pvendor_ie->vend_hdr.oui[0], pvendor_ie->vend_hdr.oui[1],
+ pvendor_ie->vend_hdr.oui[2], pvendor_ie->vend_hdr.oui_type);
+ break;
+ default:
+ if (MLAN_STATUS_SUCCESS !=
+ woal_set_get_gen_ie(priv, MLAN_ACT_SET, pcurrent_ptr,
+ &total_ie_len)) {
+ PRINTM(MERROR, "Fail to set GEN IE\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ PRINTM(MIOCTL, "Set GEN IE\n");
+ break;
+ }
+ pcurrent_ptr += element_len + 2;
+ /* Need to account for IE ID and IE Len */
+ bytes_left -= (element_len + 2);
+ }
+ done:
+ return ret;
+}
+
+/**
+ * @brief Send domain info command to FW
+ *
+ * @param wiphy A pointer to wiphy structure
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+static mlan_status
+woal_send_domain_info_cmd_fw(struct wiphy *wiphy)
+{
+ moal_private *priv = (moal_private *) woal_get_wiphy_priv(wiphy);
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ enum ieee80211_band band;
+ struct ieee80211_supported_band *sband = NULL;
+ struct ieee80211_channel *channel = NULL;
+ t_u8 no_of_sub_band = 0;
+ t_u8 no_of_parsed_chan = 0;
+ t_u8 first_chan = 0, next_chan = 0, max_pwr = 0;
+ t_u8 i, flag = 0;
+ mlan_ds_11d_cfg *cfg_11d = NULL;
+ mlan_ds_radio_cfg *radio_cfg = NULL;
+ mlan_ioctl_req *req = NULL;
+
+ ENTER();
+
+ /* Allocate an IOCTL request buffer */
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_radio_cfg));
+ if (req == NULL) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ radio_cfg = (mlan_ds_radio_cfg *) req->pbuf;
+ radio_cfg->sub_command = MLAN_OID_BAND_CFG;
+ req->req_id = MLAN_IOCTL_RADIO_CFG;
+ req->action = MLAN_ACT_GET;
+ if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ band = woal_band_cfg_to_ieee_band(radio_cfg->param.band_cfg.config_bands);
+ if (!wiphy->bands[band]) {
+ PRINTM(MERROR, "11D: setting domain info in FW failed");
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ kfree(req);
+
+ /* Allocate an IOCTL request buffer */
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_11d_cfg));
+ if (req == NULL) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ cfg_11d = (mlan_ds_11d_cfg *) req->pbuf;
+ cfg_11d->sub_command = MLAN_OID_11D_DOMAIN_INFO;
+ req->req_id = MLAN_IOCTL_11D_CFG;
+ req->action = MLAN_ACT_SET;
+
+ /* Set country code */
+ cfg_11d->param.domain_info.country_code[0] = priv->country_code[0];
+ cfg_11d->param.domain_info.country_code[1] = priv->country_code[1];
+ cfg_11d->param.domain_info.country_code[2] = ' ';
+ cfg_11d->param.domain_info.band = band;
+
+ sband = wiphy->bands[band];
+ for (i = 0; (i < sband->n_channels) &&
+ (no_of_sub_band < MRVDRV_MAX_SUBBAND_802_11D); i++) {
+ channel = &sband->channels[i];
+ if (channel->flags & IEEE80211_CHAN_DISABLED)
+ continue;
+
+ if (!flag) {
+ flag = 1;
+ next_chan = first_chan = (t_u32) channel->hw_value;
+ max_pwr = channel->max_power;
+ no_of_parsed_chan = 1;
+ continue;
+ }
+
+ if (channel->hw_value == next_chan + 1 && channel->max_power == max_pwr) {
+ next_chan++;
+ no_of_parsed_chan++;
+ } else {
+ cfg_11d->param.domain_info.sub_band[no_of_sub_band]
+ .first_chan = first_chan;
+ cfg_11d->param.domain_info.sub_band[no_of_sub_band]
+ .no_of_chan = no_of_parsed_chan;
+ cfg_11d->param.domain_info.sub_band[no_of_sub_band]
+ .max_tx_pwr = max_pwr;
+ no_of_sub_band++;
+ next_chan = first_chan = (t_u32) channel->hw_value;
+ max_pwr = channel->max_power;
+ no_of_parsed_chan = 1;
+ }
+ }
+
+ if (flag) {
+ cfg_11d->param.domain_info.sub_band[no_of_sub_band]
+ .first_chan = first_chan;
+ cfg_11d->param.domain_info.sub_band[no_of_sub_band]
+ .no_of_chan = no_of_parsed_chan;
+ cfg_11d->param.domain_info.sub_band[no_of_sub_band]
+ .max_tx_pwr = max_pwr;
+ no_of_sub_band++;
+ }
+ cfg_11d->param.domain_info.no_of_sub_band = no_of_sub_band;
+
+ /* Send domain info command to FW */
+ if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) {
+ ret = MLAN_STATUS_FAILURE;
+ PRINTM(MERROR, "11D: Error setting domain info in FW\n");
+ goto done;
+ }
+
+ done:
+ if (req)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Request the driver to change the channel and
+ * change domain info according to that channel
+ *
+ * @param wiphy A pointer to wiphy structure
+ * @param chan A pointer to ieee80211_channel structure
+ * @param channel_type Channel type of nl80211_channel_type
+ *
+ * @return 0 -- success, otherwise fail
+ */
+int
+woal_set_rf_channel(struct wiphy *wiphy,
+ struct ieee80211_channel *chan,
+ enum nl80211_channel_type channel_type)
+{
+ moal_private *priv = (moal_private *) woal_get_wiphy_priv(wiphy);
+ int ret = 0;
+ t_u32 mode, config_bands = 0;
+ mlan_ioctl_req *req1 = NULL, *req2 = NULL;
+ mlan_ds_radio_cfg *radio_cfg = NULL;
+ mlan_ds_bss *bss = NULL;
+
+ ENTER();
+
+ mode = woal_nl80211_iftype_to_mode(priv->wdev->iftype);
+
+ req1 = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_radio_cfg));
+ if (req1 == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ radio_cfg = (mlan_ds_radio_cfg *) req1->pbuf;
+ radio_cfg->sub_command = MLAN_OID_BAND_CFG;
+ req1->req_id = MLAN_IOCTL_RADIO_CFG;
+
+ if (chan) {
+ req1->action = MLAN_ACT_SET;
+ /* Set appropriate bands */
+ if (chan->band == IEEE80211_BAND_2GHZ)
+ config_bands = BAND_B | BAND_G | BAND_GN;
+ else
+ config_bands = BAND_AN | BAND_A;
+ if (mode == MLAN_BSS_MODE_IBSS)
+ radio_cfg->param.band_cfg.adhoc_start_band = config_bands;
+ radio_cfg->param.band_cfg.config_bands = config_bands;
+ /* Set channel offset */
+ radio_cfg->param.band_cfg.sec_chan_offset =
+ woal_cfg80211_channel_type_to_channel(channel_type);
+
+ if (MLAN_STATUS_SUCCESS !=
+ woal_request_ioctl(priv, req1, MOAL_IOCTL_WAIT)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ woal_send_domain_info_cmd_fw(wiphy);
+ }
+
+ PRINTM(MINFO, "Setting band %d, channel bandwidth %d and mode = %d\n",
+ config_bands, radio_cfg->param.band_cfg.sec_chan_offset, mode);
+
+ if (!chan)
+ goto done;
+
+ req2 = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_bss));
+ if (req2 == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ bss = (mlan_ds_bss *) req2->pbuf;
+
+ bss->param.bss_chan.freq = chan->center_freq;
+ /* Convert frequency to channel */
+ bss->param.bss_chan.channel =
+ ieee80211_frequency_to_channel(chan->center_freq);
+
+ bss->sub_command = MLAN_OID_BSS_CHANNEL;
+ req2->req_id = MLAN_IOCTL_BSS;
+ req2->action = MLAN_ACT_SET;
+
+ if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req2, MOAL_IOCTL_WAIT)) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ if (MLAN_STATUS_SUCCESS !=
+ woal_change_adhoc_chan(priv, bss->param.bss_chan.channel)) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ done:
+ if (req1)
+ kfree(req1);
+ if (req2)
+ kfree(req2);
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set ewpa mode
+ *
+ * @param priv A pointer to moal_private structure
+ * @param wait_option Wait option
+ * @param ssid_bssid A pointer to mlan_ssid_bssid structure
+ *
+ * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING -- success, otherwise fail
+ */
+mlan_status
+woal_set_ewpa_mode(moal_private * priv, t_u8 wait_option,
+ mlan_ssid_bssid * ssid_bssid)
+{
+ int ret = 0;
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_sec_cfg *sec = NULL;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ /* Allocate an IOCTL request buffer */
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_sec_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto error;
+ }
+ /* Fill request buffer */
+ sec = (mlan_ds_sec_cfg *) req->pbuf;
+ sec->sub_command = MLAN_OID_SEC_CFG_PASSPHRASE;
+ req->req_id = MLAN_IOCTL_SEC_CFG;
+ req->action = MLAN_ACT_GET;
+
+ /* Try Get All */
+ memset(&sec->param.passphrase, 0, sizeof(mlan_ds_passphrase));
+ memcpy(&sec->param.passphrase.ssid, &ssid_bssid->ssid,
+ sizeof(sec->param.passphrase.ssid));
+ memcpy(&sec->param.passphrase.bssid, &ssid_bssid->bssid,
+ MLAN_MAC_ADDR_LENGTH);
+ sec->param.passphrase.psk_type = MLAN_PSK_QUERY;
+
+ /* Send IOCTL request to MLAN */
+ if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, wait_option))
+ goto error;
+ sec->param.ewpa_enabled = MFALSE;
+ if (sec->param.passphrase.psk_type == MLAN_PSK_PASSPHRASE) {
+ if (sec->param.passphrase.psk.passphrase.passphrase_len > 0) {
+ sec->param.ewpa_enabled = MTRUE;
+ }
+ } else if (sec->param.passphrase.psk_type == MLAN_PSK_PMK)
+ sec->param.ewpa_enabled = MTRUE;
+
+ sec->sub_command = MLAN_OID_SEC_CFG_EWPA_ENABLED;
+ req->action = MLAN_ACT_SET;
+
+ /* Send IOCTL request to MLAN */
+ status = woal_request_ioctl(priv, req, wait_option);
+
+ error:
+ if (req && (status != MLAN_STATUS_PENDING))
+ kfree(req);
+ LEAVE();
+ return status;
+}
+
+/**
+ * @brief Set encryption mode and enable WPA
+ *
+ * @param priv A pointer to moal_private structure
+ * @param encrypt_mode Encryption mode
+ * @param wpa_enabled WPA enable or not
+ *
+ * @return 0 -- success, otherwise fail
+ */
+static int
+woal_cfg80211_set_auth(moal_private * priv, int encrypt_mode, int wpa_enabled)
+{
+ int ret = 0;
+
+ ENTER();
+
+ if (MLAN_STATUS_SUCCESS !=
+ woal_set_encrypt_mode(priv, MOAL_IOCTL_WAIT, encrypt_mode))
+ ret = -EFAULT;
+
+ if (wpa_enabled) {
+ if (MLAN_STATUS_SUCCESS !=
+ woal_set_wpa_enable(priv, MOAL_IOCTL_WAIT, 1))
+ ret = -EFAULT;
+ }
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Informs the CFG802.11 subsystem of a new BSS connection.
+ *
+ * The following information are sent to the CFG802.11 subsystem
+ * to register the new BSS connection. If we do not register the new BSS,
+ * a kernel panic will result.
+ * - MAC address
+ * - Capabilities
+ * - Beacon period
+ * - RSSI value
+ * - Channel
+ * - Supported rates IE
+ * - Extended capabilities IE
+ * - DS parameter set IE
+ * - HT Capability IE
+ * - Vendor Specific IE (221)
+ * - WPA IE
+ * - RSN IE
+ *
+ * @param priv A pointer to moal_private structure
+ * @param ssid A pointer to mlan_802_11_ssid structure
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status
+woal_inform_bss_from_scan_result(moal_private * priv, mlan_802_11_ssid * ssid)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ struct ieee80211_channel *chan;
+ mlan_scan_resp scan_resp;
+ BSSDescriptor_t *scan_table;
+ t_u8 *ie, *tmp, *ie_buf;
+ __le32 ie_len;
+ t_u64 ts = 0;
+ t_u8 *cap;
+ t_u8 *beacon;
+ int beacon_size, i, j;
+ IEEEtypes_ElementId_e element_id;
+ t_u8 element_len;
+ struct cfg80211_bss *pub = NULL;
+
+ ENTER();
+
+ memset(&scan_resp, 0, sizeof(scan_resp));
+ if (MLAN_STATUS_SUCCESS != woal_get_scan_table(priv,
+ MOAL_IOCTL_WAIT,
+ &scan_resp)) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ if (scan_resp.num_in_scan_table) {
+#define MAX_IE_BUF 2048
+ ie_buf = kzalloc(MAX_IE_BUF, GFP_KERNEL);
+ if (ie_buf == NULL) {
+ PRINTM(MERROR, "%s: failed to allocate ie_buf\n", __func__);
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ scan_table = (BSSDescriptor_t *) scan_resp.pscan_table;
+ for (i = 0; i < scan_resp.num_in_scan_table; i++) {
+ if (ssid) {
+ /* Inform specific BSS only */
+ if (memcmp(ssid->ssid, scan_table[i].ssid.ssid, ssid->ssid_len))
+ continue;
+ }
+ if (!scan_table[i].freq) {
+ PRINTM(MERROR, "Invalid channel number %d\n",
+ (int) scan_table[i].channel);
+ continue;
+ }
+ memset(ie_buf, 0, MAX_IE_BUF);
+ ie_buf[0] = WLAN_EID_SSID;
+ ie_buf[1] = scan_table[i].ssid.ssid_len;
+ memcpy(&ie_buf[sizeof(IEEEtypes_Header_t)],
+ scan_table[i].ssid.ssid, ie_buf[1]);
+
+ ie = ie_buf + ie_buf[1] + sizeof(IEEEtypes_Header_t);
+ ie_len = ie_buf[1] + sizeof(IEEEtypes_Header_t);
+
+ ie[0] = WLAN_EID_SUPP_RATES;
+
+ for (j = 0; j < sizeof(scan_table[i].supported_rates); j++) {
+ if (!scan_table[i].supported_rates[j])
+ break;
+ else {
+ ie[j + sizeof(IEEEtypes_Header_t)] =
+ scan_table[i].supported_rates[j];
+ }
+ }
+
+ ie[1] = j;
+ ie_len += ie[1] + sizeof(IEEEtypes_Header_t);
+
+ beacon = scan_table[i].pbeacon_buf;
+ beacon_size = scan_table[i].beacon_buf_size;
+
+ /* Skip time stamp, beacon interval and capability */
+
+ if (beacon) {
+ beacon += sizeof(scan_table[i].beacon_period)
+ + sizeof(scan_table[i].time_stamp) +
+ +sizeof(scan_table[i].cap_info);
+
+ beacon_size -= sizeof(scan_table[i].beacon_period)
+ + sizeof(scan_table[i].time_stamp)
+ + sizeof(scan_table[i].cap_info);
+ }
+
+ while (beacon_size >= sizeof(IEEEtypes_Header_t)) {
+ ie = ie_buf + ie_len;
+ element_id = *beacon;
+ element_len = *(beacon + 1);
+ if (beacon_size < (int) element_len +
+ sizeof(IEEEtypes_Header_t)) {
+ PRINTM(MERROR,
+ "Get scan: Error in processing IE, "
+ "bytes left < IE length\n");
+ break;
+ }
+ switch (element_id) {
+ case WLAN_EID_FH_PARAMS:
+ case WLAN_EID_DS_PARAMS:
+ case WLAN_EID_CF_PARAMS:
+ case WLAN_EID_IBSS_PARAMS:
+ case WLAN_EID_COUNTRY:
+ case WLAN_EID_PWR_CONSTRAINT:
+ case WLAN_EID_PWR_CAPABILITY:
+ case WLAN_EID_TPC_REQUEST:
+ case WLAN_EID_TPC_REPORT:
+ case WLAN_EID_CHANNEL_SWITCH:
+ case WLAN_EID_QUIET:
+ case WLAN_EID_IBSS_DFS:
+ case WLAN_EID_SUPPORTED_CHANNELS:
+ case WLAN_EID_ERP_INFO:
+ case WLAN_EID_EXT_SUPP_RATES:
+ case WLAN_EID_HT_CAPABILITY:
+ case WLAN_EID_HT_INFORMATION:
+ case EXT_CAPABILITY: // TODO: Replace when kernel macro
+ // available
+ case WLAN_EID_RSN:
+ case WAPI_IE: // TODO: Replace when kernel macro available
+ case WLAN_EID_VENDOR_SPECIFIC:
+ ie[0] = element_id;
+ ie[1] = element_len;
+ tmp = (t_u8 *) beacon;
+ memcpy(&ie[sizeof(IEEEtypes_Header_t)],
+ tmp + sizeof(IEEEtypes_Header_t), element_len);
+ ie_len += ie[1] + sizeof(IEEEtypes_Header_t);
+ break;
+ default:
+ break;
+ }
+ beacon += element_len + sizeof(IEEEtypes_Header_t);
+ beacon_size -= (element_len + sizeof(IEEEtypes_Header_t));
+ }
+ chan = ieee80211_get_channel(priv->wdev->wiphy, scan_table[i].freq);
+ cap = (t_u8 *) & scan_table[i].cap_info;
+ pub = cfg80211_inform_bss(priv->wdev->wiphy, chan,
+ scan_table[i].mac_address,
+ ts, (__le16) (*cap),
+ scan_table[i].beacon_period, ie_buf,
+ ie_len,
+ -RSSI_DBM_TO_MDM(scan_table[i].rssi),
+ GFP_KERNEL);
+ pub->len_information_elements = pub->len_beacon_ies;
+ }
+ kfree(ie_buf);
+ }
+
+ done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Informs the CFG802.11 subsystem of a new IBSS connection.
+ *
+ * The following information are sent to the CFG802.11 subsystem
+ * to register the new IBSS connection. If we do not register the
+ * new IBSS, a kernel panic will result.
+ * - MAC address
+ * - Capabilities
+ * - Beacon period
+ * - RSSI value
+ * - Channel
+ * - Supported rates IE
+ * - Extended capabilities IE
+ * - DS parameter set IE
+ * - HT Capability IE
+ * - Vendor Specific IE (221)
+ * - WPA IE
+ * - RSN IE
+ *
+ * @param priv A pointer to moal_private structure
+ * @param cahn A pointer to ieee80211_channel structure
+ * @param beacon_interval Beacon interval
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+static mlan_status
+woal_cfg80211_inform_ibss_bss(moal_private * priv,
+ struct ieee80211_channel *chan,
+ t_u16 beacon_interval)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_bss_info bss_info;
+ mlan_ds_get_signal signal;
+ t_u8 ie_buf[MLAN_MAX_SSID_LENGTH + sizeof(IEEEtypes_Header_t)];
+ int ie_len = 0;
+
+ ENTER();
+
+ ret = woal_get_bss_info(priv, MOAL_IOCTL_WAIT, &bss_info);
+ if (ret)
+ goto done;
+
+ memset(ie_buf, 0, sizeof(ie_buf));
+ ie_buf[0] = WLAN_EID_SSID;
+ ie_buf[1] = bss_info.ssid.ssid_len;
+
+ memcpy(&ie_buf[sizeof(IEEEtypes_Header_t)],
+ &bss_info.ssid.ssid, bss_info.ssid.ssid_len);
+ ie_len = ie_buf[1] + sizeof(IEEEtypes_Header_t);
+
+ /* Get signal information from the firmware */
+ memset(&signal, 0, sizeof(mlan_ds_get_signal));
+ if (MLAN_STATUS_SUCCESS !=
+ woal_get_signal_info(priv, MOAL_IOCTL_WAIT, &signal)) {
+ PRINTM(MERROR, "Error getting signal information\n");
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ cfg80211_inform_bss(priv->wdev->wiphy, chan,
+ bss_info.bssid, 0, WLAN_CAPABILITY_IBSS,
+ beacon_interval, ie_buf, ie_len, signal.bcn_rssi_avg,
+ GFP_KERNEL);
+
+ done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Request the driver for (re)association
+ *
+ * @param wiphy A pointer to wiphy structure
+ * @param sme A pointer to connect parameters
+ *
+ * @return 0 -- success, otherwise fail
+ */
+static int
+woal_cfg80211_assoc(struct wiphy *wiphy, void *sme)
+{
+ moal_private *priv = (moal_private *) woal_get_wiphy_priv(wiphy);
+ struct cfg80211_ibss_params *ibss_param = NULL;
+ struct cfg80211_connect_params *conn_param = NULL;
+ mlan_802_11_ssid req_ssid;
+ mlan_ssid_bssid ssid_bssid;
+ mlan_ds_radio_cfg *radio_cfg = NULL;
+ mlan_ioctl_req *req = NULL;
+ int ret = 0;
+ t_u32 auth_type = 0, mode;
+ int wpa_enabled = 0;
+ int group_enc_mode = 0, pairwise_enc_mode = 0;
+ int alg_is_wep = 0;
+
+ t_u8 *ssid, ssid_len = 0, *bssid;
+ t_u8 *ie = NULL;
+ int ie_len = 0;
+ struct ieee80211_channel *channel = NULL;
+ t_u16 beacon_interval = 0;
+ bool privacy;
+
+ ENTER();
+
+ mode = woal_nl80211_iftype_to_mode(priv->wdev->iftype);
+
+ if (mode == MLAN_BSS_MODE_IBSS) {
+ ibss_param = (struct cfg80211_ibss_params *) sme;
+ ssid = ibss_param->ssid;
+ ssid_len = ibss_param->ssid_len;
+ bssid = ibss_param->bssid;
+ channel = ibss_param->channel;
+ if (ibss_param->ie_len)
+ ie = ibss_param->ie;
+ ie_len = ibss_param->ie_len;
+ beacon_interval = ibss_param->beacon_interval;
+ privacy = ibss_param->privacy;
+ } else {
+ conn_param = (struct cfg80211_connect_params *) sme;
+ ssid = conn_param->ssid;
+ ssid_len = conn_param->ssid_len;
+ bssid = conn_param->bssid;
+ channel = conn_param->channel;
+ if (conn_param->ie_len)
+ ie = conn_param->ie;
+ ie_len = conn_param->ie_len;
+ privacy = conn_param->privacy;
+ }
+
+ memset(&req_ssid, 0, sizeof(mlan_802_11_ssid));
+ memset(&ssid_bssid, 0, sizeof(mlan_ssid_bssid));
+
+ req_ssid.ssid_len = ssid_len;
+ if (ssid_len > IW_ESSID_MAX_SIZE) {
+ PRINTM(MERROR, "Invalid SSID - aborting\n");
+ ret = -EINVAL;
+ goto done;
+ }
+
+ memcpy(req_ssid.ssid, ssid, ssid_len);
+ if (!req_ssid.ssid_len || req_ssid.ssid[0] < 0x20) {
+ PRINTM(MERROR, "Invalid SSID - aborting\n");
+ ret = -EINVAL;
+ goto done;
+ }
+
+ if (channel) {
+ /* Get the secondary channel offset */
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_radio_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+ radio_cfg = (mlan_ds_radio_cfg *) req->pbuf;
+ radio_cfg->sub_command = MLAN_OID_BAND_CFG;
+ req->req_id = MLAN_IOCTL_RADIO_CFG;
+ req->action = MLAN_ACT_GET;
+
+ if (MLAN_STATUS_SUCCESS !=
+ woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ if (MLAN_STATUS_SUCCESS != woal_set_rf_channel(wiphy,
+ channel,
+ woal_channel_to_nl80211_channel_type
+ (radio_cfg->param.
+ band_cfg.
+ sec_chan_offset))) {
+ ret = -EFAULT;
+ goto done;
+ }
+ }
+
+ if (MLAN_STATUS_SUCCESS !=
+ woal_set_ewpa_mode(priv, MOAL_IOCTL_WAIT, &ssid_bssid)) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ if (MLAN_STATUS_SUCCESS !=
+ woal_cfg80211_set_key(priv, 0, 0, NULL, 0, NULL, 0, 0, NULL, 1)) {
+ /* Disable keys */
+ ret = -EFAULT;
+ goto done;
+ }
+
+ if (ie && ie_len) { /* Set the IE */
+ if (MLAN_STATUS_SUCCESS !=
+ woal_cfg80211_assoc_ies_cfg(priv, ie, ie_len)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ }
+
+ if (conn_param && mode != MLAN_BSS_MODE_IBSS) {
+ /* These parameters are only for managed mode */
+ if (conn_param->auth_type == NL80211_AUTHTYPE_OPEN_SYSTEM)
+ auth_type = MLAN_AUTH_MODE_OPEN;
+ else if (conn_param->auth_type == NL80211_AUTHTYPE_SHARED_KEY)
+ auth_type = MLAN_AUTH_MODE_SHARED;
+ else if (conn_param->auth_type == NL80211_AUTHTYPE_NETWORK_EAP)
+ auth_type = MLAN_AUTH_MODE_NETWORKEAP;
+ else
+ auth_type = MLAN_AUTH_MODE_AUTO;
+
+ if (MLAN_STATUS_SUCCESS !=
+ woal_set_auth_mode(priv, MOAL_IOCTL_WAIT, auth_type)) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ if (conn_param->crypto.n_ciphers_pairwise) {
+ pairwise_enc_mode =
+ woal_cfg80211_get_encryption_mode(conn_param->
+ crypto.ciphers_pairwise[0],
+ &wpa_enabled);
+ ret = woal_cfg80211_set_auth(priv, pairwise_enc_mode, wpa_enabled);
+ if (ret)
+ goto done;
+ }
+
+ if (conn_param->crypto.cipher_group) {
+ group_enc_mode =
+ woal_cfg80211_get_encryption_mode(conn_param->
+ crypto.cipher_group,
+ &wpa_enabled);
+ ret = woal_cfg80211_set_auth(priv, group_enc_mode, wpa_enabled);
+ if (ret)
+ goto done;
+ }
+
+ if (conn_param->key) {
+ alg_is_wep =
+ woal_cfg80211_is_alg_wep(pairwise_enc_mode) |
+ woal_cfg80211_is_alg_wep(group_enc_mode);
+ if (alg_is_wep) {
+ PRINTM(MINFO, "Setting wep encryption with "
+ "key len %d\n", conn_param->key_len);
+ /* Set the WEP key */
+ if (MLAN_STATUS_SUCCESS !=
+ woal_cfg80211_set_wep_keys(priv, conn_param->key,
+ conn_param->key_len,
+ conn_param->key_idx)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ /* Enable the WEP key by key index */
+ if (MLAN_STATUS_SUCCESS !=
+ woal_cfg80211_set_wep_keys(priv, NULL, 0,
+ conn_param->key_idx)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ }
+ }
+ }
+
+ if (mode == MLAN_BSS_MODE_IBSS) {
+ mlan_ds_bss *bss = NULL;
+ /* Change beacon interval */
+ if ((beacon_interval < MLAN_MIN_BEACON_INTERVAL) ||
+ (beacon_interval > MLAN_MAX_BEACON_INTERVAL)) {
+ ret = -EINVAL;
+ goto done;
+ }
+ if (req)
+ kfree(req);
+ req = NULL;
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_bss));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+ bss = (mlan_ds_bss *) req->pbuf;
+ req->req_id = MLAN_IOCTL_BSS;
+ req->action = MLAN_ACT_SET;
+ bss->sub_command = MLAN_OID_IBSS_BCN_INTERVAL;
+ bss->param.bcn_interval = beacon_interval;
+ if (MLAN_STATUS_SUCCESS !=
+ woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ /* "privacy" is set only for ad-hoc mode */
+ if (privacy) {
+ /*
+ * Keep MLAN_ENCRYPTION_MODE_WEP40 for now so that
+ * the firmware can find a matching network from the
+ * scan. cfg80211 does not give us the encryption
+ * mode at this stage so just setting it to wep here
+ */
+ if (MLAN_STATUS_SUCCESS !=
+ woal_set_auth_mode(priv, MOAL_IOCTL_WAIT,
+ MLAN_AUTH_MODE_OPEN)) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ wpa_enabled = 0;
+ ret = woal_cfg80211_set_auth(priv,
+ MLAN_ENCRYPTION_MODE_WEP104,
+ wpa_enabled);
+ if (ret)
+ goto done;
+ }
+ }
+ memcpy(&ssid_bssid.ssid, &req_ssid, sizeof(mlan_802_11_ssid));
+ if (bssid)
+ memcpy(&ssid_bssid.bssid, bssid, ETH_ALEN);
+ if (MLAN_STATUS_SUCCESS != woal_find_essid(priv, &ssid_bssid)) {
+ /* Do specific SSID scanning */
+ if (MLAN_STATUS_SUCCESS !=
+ woal_request_scan(priv, MOAL_IOCTL_WAIT, &req_ssid)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ }
+
+ /* Disconnect before try to associate */
+ woal_disconnect(priv, MOAL_IOCTL_WAIT, NULL);
+
+ if (mode != MLAN_BSS_MODE_IBSS) {
+ if (MLAN_STATUS_SUCCESS !=
+ woal_find_best_network(priv, MOAL_IOCTL_WAIT, &ssid_bssid)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ /* Inform the BSS information to kernel, otherwise kernel will give a
+ panic after successful assoc */
+ if (MLAN_STATUS_SUCCESS !=
+ woal_inform_bss_from_scan_result(priv, &req_ssid)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ } else if (MLAN_STATUS_SUCCESS !=
+ woal_find_best_network(priv, MOAL_IOCTL_WAIT, &ssid_bssid))
+ /* Adhoc start, Check the channel command */
+ woal_11h_channel_check_ioctl(priv);
+
+ PRINTM(MINFO, "Trying to associate to %s and bssid %pM\n",
+ (char *) req_ssid.ssid, ssid_bssid.bssid);
+
+ /* Zero SSID implies use BSSID to connect */
+ if (bssid)
+ memset(&ssid_bssid.ssid, 0, sizeof(mlan_802_11_ssid));
+ else /* Connect to BSS by ESSID */
+ memset(&ssid_bssid.bssid, 0, MLAN_MAC_ADDR_LENGTH);
+
+ if (MLAN_STATUS_SUCCESS !=
+ woal_bss_start(priv, MOAL_IOCTL_WAIT, &ssid_bssid)) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ /* Inform the IBSS information to kernel, otherwise kernel will give a
+ panic after successful assoc */
+ if (mode == MLAN_BSS_MODE_IBSS) {
+ if (MLAN_STATUS_SUCCESS !=
+ woal_cfg80211_inform_ibss_bss(priv, channel, beacon_interval)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ }
+
+ done:
+ if (ret) {
+ /* clear IE */
+ ie_len = 0;
+ woal_set_get_gen_ie(priv, MLAN_ACT_SET, NULL, &ie_len);
+ }
+ if (req)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Request the driver to dump the station information
+ *
+ * @param priv A pointer to moal_private structure
+ * @param sinfo A pointer to station_info structure
+ *
+ * @return 0 -- success, otherwise fail
+ */
+static mlan_status
+woal_cfg80211_dump_station_info(moal_private * priv, struct station_info *sinfo)
+{
+ mlan_ds_get_signal signal;
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_rate *rate = NULL;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+ sinfo->filled = STATION_INFO_RX_BYTES | STATION_INFO_TX_BYTES |
+ STATION_INFO_RX_PACKETS | STATION_INFO_TX_PACKETS |
+ STATION_INFO_SIGNAL | STATION_INFO_TX_BITRATE;
+
+ /* Get signal information from the firmware */
+ memset(&signal, 0, sizeof(mlan_ds_get_signal));
+ if (MLAN_STATUS_SUCCESS !=
+ woal_get_signal_info(priv, MOAL_IOCTL_WAIT, &signal)) {
+ PRINTM(MERROR, "Error getting signal information\n");
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_rate));
+ if (req == NULL) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ rate = (mlan_ds_rate *) req->pbuf;
+ rate->sub_command = MLAN_OID_GET_DATA_RATE;
+ req->req_id = MLAN_IOCTL_RATE;
+ req->action = MLAN_ACT_GET;
+ if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ sinfo->txrate.flags = RATE_INFO_FLAGS_MCS;
+ if (rate->param.data_rate.tx_ht_bw == MLAN_HT_BW40) {
+ sinfo->txrate.flags |= RATE_INFO_FLAGS_40_MHZ_WIDTH;
+ }
+ if (rate->param.data_rate.tx_ht_gi == MLAN_HT_SGI) {
+ sinfo->txrate.flags |= RATE_INFO_FLAGS_SHORT_GI;
+ }
+ sinfo->txrate.mcs = rate->param.data_rate.tx_data_rate;
+ sinfo->rx_bytes = priv->stats.rx_bytes;
+ sinfo->tx_bytes = priv->stats.tx_bytes;
+ sinfo->rx_packets = priv->stats.rx_packets;
+ sinfo->tx_packets = priv->stats.tx_packets;
+ sinfo->signal = signal.bcn_rssi_avg;
+
+ done:
+ if (req)
+ kfree(req);
+
+ LEAVE();
+ return ret;
+}
+
+/********************************************************
+ Global Functions
+********************************************************/
+
+/**
+ * @brief Request the driver to change regulatory domain
+ *
+ * @param wiphy A pointer to wiphy structure
+ * @param request A pointer to regulatory_request structure
+ *
+ * @return 0
+ */
+static int
+woal_cfg80211_reg_notifier(struct wiphy *wiphy,
+ struct regulatory_request *request)
+{
+ moal_private *priv = (moal_private *) woal_get_wiphy_priv(wiphy);
+ int ret = 0;
+
+ ENTER();
+
+ PRINTM(MINFO, "cfg80211 regulatory domain callback "
+ "%c%c\n", request->alpha2[0], request->alpha2[1]);
+
+ if (MLAN_STATUS_SUCCESS != woal_set_region_code(priv, request->alpha2))
+ PRINTM(MERROR, "Set country code failed!\n");
+ memcpy(priv->country_code, request->alpha2, COUNTRY_CODE_LEN);
+
+ switch (request->initiator) {
+ case NL80211_REGDOM_SET_BY_DRIVER:
+ PRINTM(MINFO, "Regulatory domain BY_DRIVER\n");
+ break;
+ case NL80211_REGDOM_SET_BY_CORE:
+ PRINTM(MINFO, "Regulatory domain BY_CORE\n");
+ break;
+ case NL80211_REGDOM_SET_BY_USER:
+ PRINTM(MINFO, "Regulatory domain BY_USER\n");
+ break;
+ /* TODO: apply driver specific changes in channel flags based on the
+ request initiator if necessory. * */
+ case NL80211_REGDOM_SET_BY_COUNTRY_IE:
+ PRINTM(MINFO, "Regulatory domain BY_COUNTRY_IE\n");
+ break;
+ }
+
+ if (MLAN_STATUS_SUCCESS != woal_send_domain_info_cmd_fw(wiphy))
+ ret = -EFAULT;
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Request the driver to do a scan. Always returning
+ * zero meaning that the scan request is given to driver,
+ * and will be valid until passed to cfg80211_scan_done().
+ * To inform scan results, call cfg80211_inform_bss().
+ *
+ * @param wiphy A pointer to wiphy structure
+ * @param dev A pointer to net_device structure
+ * @param request A pointer to cfg80211_scan_request structure
+ *
+ * @return 0 -- success, otherwise fail
+ */
+static int
+woal_cfg80211_scan(struct wiphy *wiphy, struct net_device *dev,
+ struct cfg80211_scan_request *request)
+{
+ moal_private *priv = (moal_private *) woal_get_wiphy_priv(wiphy);
+ wlan_user_scan_cfg scan_req;
+ struct ieee80211_channel *chan;
+ int ret = 0, i;
+
+ ENTER();
+
+ PRINTM(MINFO, "Received scan request on %s\n", dev->name);
+
+ if (priv->scan_request && priv->scan_request != request) {
+ LEAVE();
+ return -EBUSY;
+ }
+ priv->scan_request = request;
+
+ memset(&scan_req, 0x00, sizeof(scan_req));
+ for (i = 0; i < priv->scan_request->n_ssids; i++) {
+ memcpy(scan_req.ssid_list[i].ssid,
+ priv->scan_request->ssids[i].ssid,
+ priv->scan_request->ssids[i].ssid_len);
+ if (priv->scan_request->ssids[i].ssid_len)
+ scan_req.ssid_list[i].max_len = 0;
+ else
+ scan_req.ssid_list[i].max_len = 0xff;
+ PRINTM(MIOCTL, "scan: ssid=%s\n", scan_req.ssid_list[i].ssid);
+ }
+#if defined(WIFI_DIRECT_SUPPORT)
+#if LINUX_VERSION_CODE >= WIFI_DIRECT_KERNEL_VERSION
+ if (priv->bss_type == MLAN_BSS_TYPE_WIFIDIRECT &&
+ priv->scan_request->n_ssids) {
+ if (!memcmp(scan_req.ssid_list[i - 1].ssid, "DIRECT-", 7)) {
+ /* Enable wildcard ssid scan */
+ memcpy(scan_req.ssid_list[i].ssid, "DIRECT-*", 8);
+ scan_req.ssid_list[i].max_len = 0xff;
+ }
+ }
+#endif
+#endif
+ for (i = 0; i < priv->scan_request->n_channels; i++) {
+ chan = priv->scan_request->channels[i];
+ scan_req.chan_list[i].chan_number = chan->hw_value;
+ scan_req.chan_list[i].radio_type = chan->band;
+ if (chan->flags & IEEE80211_CHAN_DISABLED)
+ scan_req.chan_list[i].scan_type = MLAN_SCAN_TYPE_PASSIVE;
+ else
+ scan_req.chan_list[i].scan_type = MLAN_SCAN_TYPE_ACTIVE;
+ scan_req.chan_list[i].scan_time = 0;
+ }
+ if (priv->scan_request->ie && priv->scan_request->ie_len) {
+ if (MLAN_STATUS_SUCCESS !=
+ woal_cfg80211_mgmt_frame_ie(priv, NULL, 0,
+ NULL, 0, NULL, 0,
+ (t_u8 *) priv->scan_request->ie,
+ priv->scan_request->ie_len,
+ MGMT_MASK_PROBE_REQ)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ } else {
+ /** Clear SCAN IE in Firmware */
+ woal_cfg80211_mgmt_frame_ie(priv, NULL, 0, NULL, 0, NULL, 0, NULL, 0,
+ MGMT_MASK_PROBE_REQ);
+ }
+ if (MLAN_STATUS_SUCCESS != woal_do_scan(priv, &scan_req)) {
+ ret = -EAGAIN;
+ }
+ done:
+ LEAVE();
+ return 0;
+}
+
+/**
+ * @brief Request the driver to connect to the ESS with
+ * the specified parameters from kernel
+ *
+ * @param wiphy A pointer to wiphy structure
+ * @param dev A pointer to net_device structure
+ * @param sme A pointer to cfg80211_connect_params structure
+ *
+ * @return 0 -- success, otherwise fail
+ */
+static int
+woal_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev,
+ struct cfg80211_connect_params *sme)
+{
+ moal_private *priv = (moal_private *) woal_get_wiphy_priv(wiphy);
+ int ret = 0;
+
+ ENTER();
+ PRINTM(MINFO, "Received association request on %s\n", dev->name);
+
+ if (priv->wdev->iftype != NL80211_IFTYPE_STATION
+#if defined(WIFI_DIRECT_SUPPORT)
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,37) || defined(COMPAT_WIRELESS)
+ && priv->wdev->iftype != NL80211_IFTYPE_P2P_CLIENT
+#endif /* KERNEL_VERSION */
+#endif /* WIFI_DIRECT_SUPPORT && V14_FEATURE */
+ ) {
+ PRINTM(MERROR, "Received infra assoc request "
+ "when station not in infra mode\n");
+ LEAVE();
+ return -EINVAL;
+ }
+#if defined(WIFI_DIRECT_SUPPORT)
+#if LINUX_VERSION_CODE >= WIFI_DIRECT_KERNEL_VERSION
+ if (priv->bss_type == MLAN_BSS_TYPE_WIFIDIRECT
+ && (priv->wdev->iftype == NL80211_IFTYPE_STATION
+ || priv->wdev->iftype == NL80211_IFTYPE_P2P_CLIENT)) {
+ /* if bsstype == wifi direct, and iftype == station or p2p client, that
+ means wpa_supplicant wants to enable wifi direct functionality, so
+ we should init p2p client. Note that due to kernel iftype check,
+ ICS wpa_supplicant could not updaet iftype to init p2p client, so
+ we have to done it here. */
+ if (MLAN_STATUS_SUCCESS != woal_cfg80211_init_p2p_client(priv)) {
+ PRINTM(MERROR, "Init p2p client for wpa_supplicant failed.\n");
+ ret = -EFAULT;
+
+ LEAVE();
+ return ret;
+ }
+ }
+#endif
+#endif
+
+ if (priv->scan_type == MLAN_SCAN_TYPE_PASSIVE)
+ woal_set_scan_type(priv, MLAN_SCAN_TYPE_ACTIVE);
+ ret = woal_cfg80211_assoc(wiphy, (void *) sme);
+
+ if (priv->scan_type == MLAN_SCAN_TYPE_PASSIVE)
+ woal_set_scan_type(priv, MLAN_SCAN_TYPE_PASSIVE);
+
+ if (!ret) {
+ cfg80211_connect_result(priv->netdev, priv->cfg_bssid, NULL, 0,
+ NULL, 0, WLAN_STATUS_SUCCESS, GFP_KERNEL);
+ PRINTM(MINFO, "Associated to bssid %pM successfully\n",
+ priv->cfg_bssid);
+ } else {
+ PRINTM(MINFO, "Association to bssid %pM failed\n", priv->cfg_bssid);
+ cfg80211_connect_result(priv->netdev, priv->cfg_bssid, NULL, 0,
+ NULL, 0, WLAN_STATUS_UNSPECIFIED_FAILURE,
+ GFP_KERNEL);
+ memset(priv->cfg_bssid, 0, ETH_ALEN);
+ }
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Request the driver to disconnect
+ *
+ * @param wiphy A pointer to wiphy structure
+ * @param dev A pointer to net_device structure
+ * @param reason_code Reason code
+ *
+ * @return 0 -- success, otherwise fail
+ */
+static int
+woal_cfg80211_disconnect(struct wiphy *wiphy, struct net_device *dev,
+ t_u16 reason_code)
+{
+ moal_private *priv = (moal_private *) woal_get_wiphy_priv(wiphy);
+
+ ENTER();
+ PRINTM(MINFO, "Received disassociation request on %s\n", dev->name);
+
+ if (priv->cfg_disconnect) {
+ PRINTM(MERROR, "Disassociation already in progress\n");
+ LEAVE();
+ return -EBUSY;
+ }
+
+ if (priv->media_connected == MFALSE) {
+ LEAVE();
+ return -EINVAL;
+ }
+
+ priv->cfg_disconnect = 1;
+
+ if (woal_disconnect(priv, MOAL_IOCTL_WAIT, priv->cfg_bssid) !=
+ MLAN_STATUS_SUCCESS) {
+ LEAVE();
+ return -EFAULT;
+ }
+
+ PRINTM(MINFO, "Successfully disconnected from %pM: Reason code %d\n",
+ priv->cfg_bssid, reason_code);
+
+ memset(priv->cfg_bssid, 0, ETH_ALEN);
+
+ LEAVE();
+ return 0;
+}
+
+/**
+ * @brief Request the driver to get the station information
+ *
+ * @param wiphy A pointer to wiphy structure
+ * @param dev A pointer to net_device structure
+ * @param mac MAC address of the station
+ * @param sinfo A pointer to station_info structure
+ *
+ * @return 0 -- success, otherwise fail
+ */
+static int
+woal_cfg80211_get_station(struct wiphy *wiphy,
+ struct net_device *dev,
+ t_u8 * mac, struct station_info *sinfo)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ moal_private *priv = (moal_private *) woal_get_wiphy_priv(wiphy);
+
+ ENTER();
+
+#if defined(WIFI_DIRECT_SUPPORT)
+#if LINUX_VERSION_CODE >= WIFI_DIRECT_KERNEL_VERSION
+ if (GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_UAP) {
+ LEAVE();
+ return woal_uap_cfg80211_get_station(wiphy, dev, mac, sinfo);
+ }
+#endif
+#endif
+ if (priv->media_connected == MFALSE) {
+ PRINTM(MINFO, "cfg80211: Media not connected!\n");
+ LEAVE();
+ return -ENOENT;
+ }
+ if (memcmp(mac, priv->cfg_bssid, ETH_ALEN)) {
+ PRINTM(MINFO, "cfg80211: Request not for this station!\n");
+ LEAVE();
+ return -ENOENT;
+ }
+
+ if (MLAN_STATUS_SUCCESS != woal_cfg80211_dump_station_info(priv, sinfo)) {
+ PRINTM(MERROR, "cfg80211: Failed to get station info\n");
+ ret = -EFAULT;
+ }
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Request the driver to dump the station information
+ *
+ * @param wiphy A pointer to wiphy structure
+ * @param dev A pointer to net_device structure
+ * @param idx Station index
+ * @param mac MAC address of the station
+ * @param sinfo A pointer to station_info structure
+ *
+ * @return 0 -- success, otherwise fail
+ */
+static int
+woal_cfg80211_dump_station(struct wiphy *wiphy,
+ struct net_device *dev, int idx,
+ t_u8 * mac, struct station_info *sinfo)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ moal_private *priv = (moal_private *) woal_get_wiphy_priv(wiphy);
+
+ ENTER();
+
+ if (!priv->media_connected || idx != 0) {
+ PRINTM(MINFO, "cfg80211: Media not connected or"
+ " not for this station!\n");
+ LEAVE();
+ return -ENOENT;
+ }
+
+ memcpy(mac, priv->cfg_bssid, ETH_ALEN);
+
+ if (MLAN_STATUS_SUCCESS != woal_cfg80211_dump_station_info(priv, sinfo)) {
+ PRINTM(MERROR, "cfg80211: Failed to get station info\n");
+ ret = -EFAULT;
+ }
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Request the driver to Join the specified
+ * IBSS (or create if necessary)
+ *
+ * @param wiphy A pointer to wiphy structure
+ * @param dev A pointer to net_device structure
+ * @param params A pointer to cfg80211_ibss_params structure
+ *
+ * @return 0 -- success, otherwise fail
+ */
+static int
+woal_cfg80211_join_ibss(struct wiphy *wiphy, struct net_device *dev,
+ struct cfg80211_ibss_params *params)
+{
+ moal_private *priv = (moal_private *) woal_get_wiphy_priv(wiphy);
+ int ret = 0;
+
+ ENTER();
+
+ if (priv->wdev->iftype != NL80211_IFTYPE_ADHOC) {
+ PRINTM(MERROR, "Request IBSS join received "
+ "when station not in ibss mode\n");
+ LEAVE();
+ return -EINVAL;
+ }
+
+ ret = woal_cfg80211_assoc(wiphy, (void *) params);
+
+ if (!ret) {
+ cfg80211_ibss_joined(priv->netdev, priv->cfg_bssid, GFP_KERNEL);
+ PRINTM(MINFO, "Joined/created adhoc network with bssid"
+ " %pM successfully\n", priv->cfg_bssid);
+ } else {
+ PRINTM(MINFO, "Failed creating/joining adhoc network\n");
+ memset(priv->cfg_bssid, 0, ETH_ALEN);
+ }
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Request the driver to leave the IBSS
+ *
+ * @param wiphy A pointer to wiphy structure
+ * @param dev A pointer to net_device structure
+ *
+ * @return 0 -- success, otherwise fail
+ */
+static int
+woal_cfg80211_leave_ibss(struct wiphy *wiphy, struct net_device *dev)
+{
+ moal_private *priv = (moal_private *) woal_get_wiphy_priv(wiphy);
+
+ ENTER();
+
+ if (priv->cfg_disconnect) {
+ PRINTM(MERROR, "IBSS leave already in progress\n");
+ LEAVE();
+ return -EBUSY;
+ }
+
+ if (priv->media_connected == MFALSE) {
+ LEAVE();
+ return -EINVAL;
+ }
+
+ priv->cfg_disconnect = 1;
+
+ PRINTM(MINFO, "Leaving from IBSS %pM\n", priv->cfg_bssid);
+ if (woal_disconnect(priv, MOAL_IOCTL_WAIT, priv->cfg_bssid) !=
+ MLAN_STATUS_SUCCESS) {
+ LEAVE();
+ return -EFAULT;
+ }
+
+ memset(priv->cfg_bssid, 0, ETH_ALEN);
+
+ LEAVE();
+ return 0;
+}
+
+/**
+ * @brief Request the driver to change the IEEE power save
+ * mdoe
+ *
+ * @param wiphy A pointer to wiphy structure
+ * @param dev A pointer to net_device structure
+ * @param enabled Enable or disable
+ * @param timeout Timeout value
+ *
+ * @return 0 -- success, otherwise fail
+ */
+static int
+woal_cfg80211_set_power_mgmt(struct wiphy *wiphy,
+ struct net_device *dev, bool enabled, int timeout)
+{
+ int ret = 0, disabled;
+ moal_private *priv = (moal_private *) woal_get_wiphy_priv(wiphy);
+
+ ENTER();
+
+ if (enabled)
+ disabled = 0;
+ else
+ disabled = 1;
+
+ if (MLAN_STATUS_SUCCESS !=
+ woal_set_get_power_mgmt(priv, MLAN_ACT_SET, &disabled, timeout)) {
+ ret = -EOPNOTSUPP;
+ }
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Request the driver to change the transmit power
+ *
+ * @param wiphy A pointer to wiphy structure
+ * @param type TX power adjustment type
+ * @param dbm TX power in dbm
+ *
+ * @return 0 -- success, otherwise fail
+ */
+static int
+woal_cfg80211_set_tx_power(struct wiphy *wiphy,
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,36) && !defined(COMPAT_WIRELESS)
+ enum tx_power_setting type,
+#else
+ enum nl80211_tx_power_setting type,
+#endif
+ int dbm)
+{
+ int ret = 0;
+ moal_private *priv = (moal_private *) woal_get_wiphy_priv(wiphy);
+ mlan_power_cfg_t power_cfg;
+
+ ENTER();
+
+ if (type) {
+ power_cfg.is_power_auto = 0;
+ power_cfg.power_level = dbm;
+ } else
+ power_cfg.is_power_auto = 1;
+
+ if (MLAN_STATUS_SUCCESS !=
+ woal_set_get_tx_power(priv, MLAN_ACT_SET, &power_cfg))
+ ret = -EFAULT;
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Sets up the CFG802.11 specific HT capability fields
+ * with default values
+ *
+ * @param ht_info A pointer to ieee80211_sta_ht_cap structure
+ * @param dev_cap Device capability informations
+ * @param mcs_set Device MCS sets
+ *
+ * @return N/A
+ */
+static void
+woal_cfg80211_setup_sta_ht_cap(struct ieee80211_sta_ht_cap *ht_info,
+ t_u32 dev_cap, t_u8 * mcs_set)
+{
+ ENTER();
+
+ ht_info->ht_supported = true;
+ ht_info->ampdu_factor = 0x3;
+ ht_info->ampdu_density = 0x6;
+
+ memset(&ht_info->mcs, 0, sizeof(ht_info->mcs));
+ ht_info->cap = 0;
+ if (mcs_set)
+ memcpy(ht_info->mcs.rx_mask, mcs_set, sizeof(ht_info->mcs.rx_mask));
+ if (dev_cap & MBIT(8)) /* 40Mhz intolarance enabled */
+ ht_info->cap |= IEEE80211_HT_CAP_40MHZ_INTOLERANT;
+ if (dev_cap & MBIT(17)) /* Channel width 20/40Mhz support */
+ ht_info->cap |= IEEE80211_HT_CAP_SUP_WIDTH_20_40;
+ if ((dev_cap >> 20) & 0x03) /* Delayed ACK supported */
+ ht_info->cap |= IEEE80211_HT_CAP_DELAY_BA;
+ if (dev_cap & MBIT(22)) /* Rx LDPC supported */
+ ht_info->cap |= IEEE80211_HT_CAP_LDPC_CODING;
+ if (dev_cap & MBIT(23)) /* Short GI @ 20Mhz supported */
+ ht_info->cap |= IEEE80211_HT_CAP_SGI_20;
+ if (dev_cap & MBIT(24)) /* Short GI @ 40Mhz supported */
+ ht_info->cap |= IEEE80211_HT_CAP_SGI_40;
+ if (dev_cap & MBIT(25)) /* Tx STBC supported */
+ ht_info->cap |= IEEE80211_HT_CAP_TX_STBC;
+ if (dev_cap & MBIT(26)) /* Rx STBC supported */
+ ht_info->cap |= IEEE80211_HT_CAP_RX_STBC;
+ if (dev_cap & MBIT(27)) /* MIMO PS supported */
+ ht_info->cap |= IEEE80211_HT_CAP_SM_PS;
+ if (dev_cap & MBIT(29)) /* Green field supported */
+ ht_info->cap |= IEEE80211_HT_CAP_GRN_FLD;
+ if (dev_cap & MBIT(31)) /* MAX AMSDU supported */
+ ht_info->cap |= IEEE80211_HT_CAP_MAX_AMSDU;
+ ht_info->mcs.tx_params = IEEE80211_HT_MCS_TX_DEFINED;
+
+ LEAVE();
+}
+
+#if defined(WIFI_DIRECT_SUPPORT)
+#if LINUX_VERSION_CODE >= WIFI_DIRECT_KERNEL_VERSION
+/**
+ * @brief remain on channel config
+ *
+ * @param wiphy A pointer to wiphy structure
+ * @param wait_option Wait option
+ * @param cancel cancel remain on channel flag
+ * @param status A pointer to status, success, in process or reject
+ * @param chan A pointer to ieee80211_channel structure
+ * @param channel_type channel_type,
+ * @param duration Duration wait to receive frame
+ *
+ * @return 0 -- success, otherwise fail
+ */
+int
+woal_cfg80211_remain_on_channel_cfg(struct wiphy *wiphy,
+ t_u8 wait_option, t_u8 remove,
+ t_u8 * status,
+ struct ieee80211_channel *chan,
+ enum nl80211_channel_type channel_type,
+ t_u32 duration)
+{
+ mlan_ds_remain_chan chan_cfg;
+ moal_private *priv = (moal_private *) woal_get_wiphy_priv(wiphy);
+
+ int ret = 0;
+
+ ENTER();
+ memset(&chan_cfg, 0, sizeof(mlan_ds_remain_chan));
+ if (remove) {
+ chan_cfg.remove = MTRUE;
+ } else {
+ if (chan->band == IEEE80211_BAND_2GHZ)
+ chan_cfg.bandcfg = 0;
+ else if (chan->band == IEEE80211_BAND_5GHZ)
+ chan_cfg.bandcfg = 1;
+/** secondary channel is below */
+#define SEC_CHAN_BELOW 0x30
+/** secondary channel is above */
+#define SEC_CHAN_ABOVE 0x10
+ switch (channel_type) {
+ case NL80211_CHAN_HT40MINUS:
+ chan_cfg.bandcfg |= SEC_CHANNEL_BELOW;
+ break;
+ case NL80211_CHAN_HT40PLUS:
+ chan_cfg.bandcfg |= SEC_CHANNEL_ABOVE;
+ break;
+
+ case NL80211_CHAN_NO_HT:
+ case NL80211_CHAN_HT20:
+ default:
+ break;
+ }
+ chan_cfg.channel = ieee80211_frequency_to_channel(chan->center_freq);
+ chan_cfg.remain_period = duration;
+ }
+ if (MLAN_STATUS_SUCCESS ==
+ woal_set_remain_channel_ioctl(priv, wait_option, &chan_cfg))
+ *status = chan_cfg.status;
+ else
+ ret = -EFAULT;
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief tx mgmt frame
+ *
+ * @param wiphy A pointer to wiphy structure
+ * @param dev A pointer to net_device structure
+ * @param cookie A pointer to frame cookie
+ *
+ * @return 0 -- success, otherwise fail
+ */
+static int
+woal_cfg80211_mgmt_tx_cancel_wait(struct wiphy *wiphy,
+ struct net_device *dev, u64 cookie)
+{
+ moal_private *priv = (moal_private *) woal_get_wiphy_priv(wiphy);
+ int ret = 0;
+ t_u8 status = 1;
+
+ ENTER();
+
+ if (priv->phandle->remain_on_channel) {
+ if (woal_cfg80211_remain_on_channel_cfg(priv->wdev->wiphy,
+ MOAL_IOCTL_WAIT, MTRUE, &status,
+ NULL, 0, 0)) {
+ PRINTM(MERROR, "Fail to cancel remain on channel\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ if (priv->phandle->cookie) {
+ cfg80211_remain_on_channel_expired(priv->netdev,
+ priv->phandle->cookie,
+ &priv->phandle->chan,
+ priv->phandle->channel_type,
+ GFP_ATOMIC);
+ priv->phandle->cookie = 0;
+ }
+ priv->phandle->remain_on_channel = MFALSE;
+ }
+
+ done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Make chip remain on channel
+ *
+ * @param wiphy A pointer to wiphy structure
+ * @param dev A pointer to net_device structure
+ * @param chan A pointer to ieee80211_channel structure
+ * @param channel_type Channel type
+ * @param duration Duration for timer
+ * @param cookie A pointer to timer cookie
+ *
+ * @return 0 -- success, otherwise fail
+ */
+static int
+woal_cfg80211_remain_on_channel(struct wiphy *wiphy,
+ struct net_device *dev,
+ struct ieee80211_channel *chan,
+ enum nl80211_channel_type channel_type,
+ unsigned int duration, u64 * cookie)
+{
+ moal_private *priv = (moal_private *) woal_get_wiphy_priv(wiphy);
+ int ret = 0;
+ t_u8 status = 1;
+
+ ENTER();
+
+ if (!chan || !cookie) {
+ PRINTM(MERROR, "Invalid parameter for remain on channel\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ /** cancel previous remain on channel */
+ if (priv->phandle->remain_on_channel) {
+ if (woal_cfg80211_remain_on_channel_cfg
+ (wiphy, MOAL_IOCTL_WAIT, MTRUE, &status, NULL, 0, 0)) {
+ PRINTM(MERROR, "Fail to cancel remain on channel\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ priv->phandle->cookie = 0;
+ priv->phandle->remain_on_channel = MFALSE;
+ }
+ if (MLAN_STATUS_SUCCESS !=
+ woal_cfg80211_remain_on_channel_cfg(wiphy, MOAL_IOCTL_WAIT,
+ MFALSE, &status, chan, channel_type,
+ (t_u32) duration)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ if (status == 0) {
+ /* remain on channel operation success */
+ /* we need update the value cookie */
+ *cookie = (u64) random32() | 1;
+ priv->phandle->remain_on_channel = MTRUE;
+ priv->phandle->cookie = *cookie;
+ priv->phandle->channel_type = channel_type;
+ memcpy(&priv->phandle->chan, chan, sizeof(struct ieee80211_channel));
+ cfg80211_ready_on_channel(dev, *cookie, chan,
+ channel_type, duration, GFP_KERNEL);
+ PRINTM(MIOCTL, "Set remain on Channel: channel=%d cookie = %#llx\n",
+ ieee80211_frequency_to_channel(chan->center_freq),
+ priv->phandle->cookie);
+ }
+
+ done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Cancel remain on channel
+ *
+ * @param wiphy A pointer to wiphy structure
+ * @param dev A pointer to net_device structure
+ * @param cookie A pointer to timer cookie
+ *
+ * @return 0 -- success, otherwise fail
+ */
+static int
+woal_cfg80211_cancel_remain_on_channel(struct wiphy *wiphy,
+ struct net_device *dev, u64 cookie)
+{
+ moal_private *priv = (moal_private *) woal_get_wiphy_priv(wiphy);
+ int ret = 0;
+ t_u8 status = 1;
+
+ ENTER();
+ PRINTM(MIOCTL, "Cancel remain on Channel: cookie = %#llx\n", cookie);
+ if (woal_cfg80211_remain_on_channel_cfg
+ (wiphy, MOAL_IOCTL_WAIT, MTRUE, &status, NULL, 0, 0)) {
+ PRINTM(MERROR, "Fail to cancel remain on channel\n");
+ ret = -EFAULT;
+ goto done;
+ }
+
+ priv->phandle->remain_on_channel = MFALSE;
+ if (priv->phandle->cookie)
+ priv->phandle->cookie = 0;
+ done:
+ LEAVE();
+ return ret;
+}
+#endif /* KERNEL_VERSION */
+#endif /* WIFI_DIRECT_SUPPORT && V14_FEATURE */
+
+/**
+ * @brief Initialize the wiphy
+ *
+ * @param priv A pointer to moal_private structure
+ * @param wait_option Wait option
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status
+woal_cfg80211_sta_init_wiphy(moal_private * priv, t_u8 wait_option)
+{
+ int retry_count, rts_thr, frag_thr, disabled;
+ struct wiphy *wiphy = NULL;
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_11n_cfg *cfg_11n = NULL;
+ t_u32 hw_dev_cap;
+
+ ENTER();
+
+ if (priv->wdev)
+ wiphy = priv->wdev->wiphy;
+ else {
+ PRINTM(MERROR, "Invalid parameter when init wiphy.\n");
+ goto done;
+ }
+
+ /* Get 11n tx parameters from MLAN */
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_11n_cfg));
+ if (req == NULL) {
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+ cfg_11n = (mlan_ds_11n_cfg *) req->pbuf;
+ cfg_11n->sub_command = MLAN_OID_11N_HTCAP_CFG;
+ req->req_id = MLAN_IOCTL_11N_CFG;
+ req->action = MLAN_ACT_GET;
+ cfg_11n->param.htcap_cfg.hw_cap_req = MTRUE;
+
+ if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, wait_option)) {
+ kfree(req);
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+ hw_dev_cap = cfg_11n->param.htcap_cfg.htcap;
+
+ /* Get supported MCS sets */
+ memset(req->pbuf, 0, sizeof(mlan_ds_11n_cfg));
+ cfg_11n->sub_command = MLAN_OID_11N_CFG_SUPPORTED_MCS_SET;
+ req->req_id = MLAN_IOCTL_11N_CFG;
+ req->action = MLAN_ACT_GET;
+
+ if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, wait_option)) {
+ kfree(req);
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+
+ /* Initialize parameters for 2GHz and 5GHz bands */
+ woal_cfg80211_setup_sta_ht_cap(&wiphy->bands[IEEE80211_BAND_2GHZ]->ht_cap,
+ hw_dev_cap,
+ cfg_11n->param.supported_mcs_set);
+ /* For 2.4G band only card, this shouldn't be set
+ woal_cfg80211_setup_sta_ht_cap(&wiphy->bands[IEEE80211_BAND_5GHZ]->ht_cap,
+ hw_dev_cap, cfg_11n->param.supported_mcs_set); */
+ if (req)
+ kfree(req);
+
+ /* Set retry limit count to wiphy */
+ if (MLAN_STATUS_SUCCESS !=
+ woal_set_get_retry(priv, MLAN_ACT_GET, wait_option, &retry_count)) {
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+ wiphy->retry_long = (t_u8) retry_count;
+ wiphy->retry_short = (t_u8) retry_count;
+ wiphy->max_scan_ie_len = MAX_IE_SIZE;
+
+#if defined(WIFI_DIRECT_SUPPORT)
+#if LINUX_VERSION_CODE >= WIFI_DIRECT_KERNEL_VERSION
+ /* we should add mgmt_stypes for both STA & Wifi Direct, while only
+ initialize duration_timer for Wifi Direct */
+ wiphy->mgmt_stypes = ieee80211_mgmt_stypes;
+ wiphy->max_remain_on_channel_duration = MAX_REMAIN_ON_CHANNEL_DURATION;
+#endif /* KERNEL_VERSION */
+#endif /* WIFI_DIRECT_SUPPORT && V14_FEATURE */
+
+ /* Set RTS threshold to wiphy */
+ if (MLAN_STATUS_SUCCESS !=
+ woal_set_get_rts(priv, MLAN_ACT_GET, wait_option, &rts_thr)) {
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+ if (rts_thr < MLAN_RTS_MIN_VALUE || rts_thr > MLAN_RTS_MAX_VALUE)
+ rts_thr = MLAN_FRAG_RTS_DISABLED;
+ wiphy->rts_threshold = (t_u32) rts_thr;
+
+ /* Set fragment threshold to wiphy */
+ if (MLAN_STATUS_SUCCESS !=
+ woal_set_get_frag(priv, MLAN_ACT_GET, wait_option, &frag_thr)) {
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+ if (frag_thr < MLAN_RTS_MIN_VALUE || frag_thr > MLAN_RTS_MAX_VALUE)
+ frag_thr = MLAN_FRAG_RTS_DISABLED;
+ wiphy->frag_threshold = (t_u32) frag_thr;
+
+ /* Get IEEE power save mode */
+ if (MLAN_STATUS_SUCCESS != woal_set_get_power_mgmt(priv,
+ MLAN_ACT_GET, &disabled,
+ 0)) {
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+ /* Save the IEEE power save mode to wiphy, because after warmreset wiphy
+ power save should be updated instead of using the last saved
+ configuration */
+ if (disabled)
+ priv->wdev->ps = MFALSE;
+ else
+ priv->wdev->ps = MTRUE;
+
+ done:
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief Register the device with cfg80211
+ *
+ * @param dev A pointer to net_device structure
+ * @param bss_type BSS type
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status
+woal_register_sta_cfg80211(struct net_device * dev, t_u8 bss_type)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ moal_private *priv = (moal_private *) netdev_priv(dev);
+ void *wdev_priv = NULL;
+ struct wireless_dev *wdev = NULL;
+ mlan_fw_info fw_info;
+
+ ENTER();
+
+ /* Allocate wireless device */
+ wdev = kzalloc(sizeof(struct wireless_dev), GFP_KERNEL);
+ if (!wdev) {
+ PRINTM(MERROR, "Could not allocate wireless device\n");
+ ret = MLAN_STATUS_FAILURE;
+ goto err_wdev;
+ }
+
+ if (bss_type == MLAN_BSS_TYPE_STA)
+ /* Allocate wiphy */
+ wdev->wiphy = wiphy_new(&woal_cfg80211_sta_ops, sizeof(moal_private *));
+#if defined(WIFI_DIRECT_SUPPORT)
+#if LINUX_VERSION_CODE >= WIFI_DIRECT_KERNEL_VERSION
+ else if (bss_type == MLAN_BSS_TYPE_WIFIDIRECT)
+ /* Allocate wiphy */
+ wdev->wiphy =
+ wiphy_new(&woal_cfg80211_wifi_direct_ops, sizeof(moal_private *));
+#endif
+#endif
+ else {
+ PRINTM(MERROR, "Unexpected bss_type when register cfg80211\n");
+ ret = MLAN_STATUS_FAILURE;
+ goto err_wdev;
+ }
+
+ if (!wdev->wiphy) {
+ PRINTM(MERROR, "Could not allocate wiphy device\n");
+ ret = MLAN_STATUS_FAILURE;
+ goto err_wdev;
+ }
+ if (bss_type == MLAN_BSS_TYPE_STA) {
+ wdev->iftype = NL80211_IFTYPE_STATION;
+ wdev->wiphy->interface_modes =
+ MBIT(NL80211_IFTYPE_STATION) | MBIT(NL80211_IFTYPE_ADHOC);
+ wdev->wiphy->max_scan_ssids = 10;
+ }
+#if defined(WIFI_DIRECT_SUPPORT)
+#if LINUX_VERSION_CODE >= WIFI_DIRECT_KERNEL_VERSION
+ if (bss_type == MLAN_BSS_TYPE_WIFIDIRECT) {
+ wdev->iftype = NL80211_IFTYPE_STATION;
+ wdev->wiphy->interface_modes = MBIT(NL80211_IFTYPE_STATION) |
+ MBIT(NL80211_IFTYPE_P2P_GO) |
+ MBIT(NL80211_IFTYPE_P2P_CLIENT) |
+ MBIT(NL80211_IFTYPE_ADHOC) | MBIT(NL80211_IFTYPE_AP) |
+ MBIT(NL80211_IFTYPE_MONITOR);
+ wdev->wiphy->max_scan_ssids = 10;
+ }
+#endif
+#endif
+
+ /* Set phy name like net device name */
+ dev_set_name(&wdev->wiphy->dev, dev->name);
+
+ /* Make this wiphy known to this driver only */
+ wdev->wiphy->privid = mrvl_wiphy_privid;
+
+ /* Supported bands */
+ wdev->wiphy->bands[IEEE80211_BAND_2GHZ] = &cfg80211_band_2ghz;
+ if (MLAN_STATUS_SUCCESS ==
+ woal_request_get_fw_info(priv, MOAL_CMD_WAIT, &fw_info)) {
+ if (fw_info.fw_bands & BAND_A)
+ wdev->wiphy->bands[IEEE80211_BAND_5GHZ] = &cfg80211_band_5ghz;
+ }
+ /* Initialize cipher suits */
+ wdev->wiphy->cipher_suites = cfg80211_cipher_suites;
+ wdev->wiphy->n_cipher_suites = ARRAY_SIZE(cfg80211_cipher_suites);
+
+ wdev->wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM;
+
+ /* We are using custom domains */
+ wdev->wiphy->flags |= WIPHY_FLAG_CUSTOM_REGULATORY;
+
+ wdev->wiphy->reg_notifier = woal_cfg80211_reg_notifier;
+
+ /* Set moal_private pointer in wiphy_priv */
+ wdev_priv = wiphy_priv(wdev->wiphy);
+
+ *(unsigned long *) wdev_priv = (unsigned long) priv;
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,39) || defined(COMPAT_WIRELESS)
+ set_wiphy_dev(wdev->wiphy, (struct device *) priv->phandle->hotplug_device);
+#endif
+
+ if (wiphy_register(wdev->wiphy) < 0) {
+ PRINTM(MERROR, "Wiphy device registration failed!\n");
+ ret = MLAN_STATUS_FAILURE;
+ goto err_wdev;
+ }
+
+ dev_net_set(dev, wiphy_net(wdev->wiphy));
+ dev->ieee80211_ptr = wdev;
+ SET_NETDEV_DEV(dev, wiphy_dev(wdev->wiphy));
+ priv->wdev = wdev;
+
+ if (ret != MLAN_STATUS_SUCCESS) {
+ PRINTM(MERROR, "Wiphy device registration failed!\n");
+ } else {
+ PRINTM(MINFO, "Successfully registered wiphy device\n");
+ LEAVE();
+ return ret;
+ }
+
+ wiphy_unregister(wdev->wiphy);
+ err_wdev:
+ dev->ieee80211_ptr = NULL;
+ if (wdev && wdev->wiphy)
+ wiphy_free(wdev->wiphy);
+ kfree(wdev);
+ LEAVE();
+ return ret;
+}
diff --git a/drivers/net/wireless/sd8797/mlinux/moal_sta_cfg80211.h b/drivers/net/wireless/sd8797/mlinux/moal_sta_cfg80211.h
new file mode 100644
index 000000000000..a83957c5c031
--- /dev/null
+++ b/drivers/net/wireless/sd8797/mlinux/moal_sta_cfg80211.h
@@ -0,0 +1,41 @@
+/** @file moal_sta_cfg80211.h
+ *
+ * @brief This file contains the STA CFG80211 specific defines.
+ *
+ * Copyright (C) 2011, Marvell International Ltd.
+ *
+ * This software file (the "File") is distributed by Marvell International
+ * Ltd. under the terms of the GNU General Public License Version 2, June 1991
+ * (the "License"). You may use, redistribute and/or modify this File in
+ * accordance with the terms and conditions of the License, a copy of which
+ * is available by writing to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
+ * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
+ *
+ * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
+ * ARE EXPRESSLY DISCLAIMED. The License provides additional details about
+ * this warranty disclaimer.
+ *
+ */
+
+#ifndef _MOAL_STA_CFG80211_H_
+#define _MOAL_STA_CFG80211_H_
+
+/** Convert RSSI signal strength from dBm to mBm (100*dBm) */
+#define RSSI_DBM_TO_MDM(x) ((x) * 100)
+
+mlan_status woal_register_sta_cfg80211(struct net_device *dev, t_u8 bss_type);
+mlan_status woal_cfg80211_sta_init_wiphy(moal_private * priv, t_u8 wait_option);
+
+mlan_status
+woal_cfg80211_set_key(moal_private * priv, t_u8 is_enable_wep,
+ t_u32 cipher, const t_u8 * key, int key_len,
+ const t_u8 * seq, int seq_len, t_u8 key_index,
+ const t_u8 * addr, int disable);
+
+mlan_status
+woal_cfg80211_set_wep_keys(moal_private * priv, const t_u8 * key, int key_len,
+ t_u8 index);
+
+#endif /* _MOAL_STA_CFG80211_H_ */
diff --git a/drivers/net/wireless/sd8797/mlinux/moal_uap.c b/drivers/net/wireless/sd8797/mlinux/moal_uap.c
new file mode 100644
index 000000000000..7dac877abe00
--- /dev/null
+++ b/drivers/net/wireless/sd8797/mlinux/moal_uap.c
@@ -0,0 +1,2692 @@
+/** @file moal_uap.c
+ *
+ * @brief This file contains the major functions in UAP
+ * driver.
+ *
+ * Copyright (C) 2008-2012, Marvell International Ltd.
+ *
+ * This software file (the "File") is distributed by Marvell International
+ * Ltd. under the terms of the GNU General Public License Version 2, June 1991
+ * (the "License"). You may use, redistribute and/or modify this File in
+ * accordance with the terms and conditions of the License, a copy of which
+ * is available by writing to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
+ * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
+ *
+ * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
+ * ARE EXPRESSLY DISCLAIMED. The License provides additional details about
+ * this warranty disclaimer.
+ *
+ */
+
+/********************************************************
+Change log:
+ 10/21/2008: initial version
+********************************************************/
+
+#include "moal_main.h"
+#include "moal_uap.h"
+#include "moal_sdio.h"
+#include "moal_eth_ioctl.h"
+#if defined(STA_CFG80211) && defined(UAP_CFG80211)
+#include "moal_cfg80211.h"
+#endif
+
+/********************************************************
+ Local Variables
+********************************************************/
+
+/********************************************************
+ Global Variables
+********************************************************/
+
+/********************************************************
+ Local Functions
+********************************************************/
+/**
+ * @brief uap addba parameter handler
+ *
+ * @param dev A pointer to net_device structure
+ * @param req A pointer to ifreq structure
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_uap_addba_param(struct net_device *dev, struct ifreq *req)
+{
+ moal_private *priv = (moal_private *) netdev_priv(dev);
+ mlan_ioctl_req *ioctl_req = NULL;
+ mlan_ds_11n_cfg *cfg_11n = NULL;
+ addba_param param;
+ int ret = 0;
+
+ ENTER();
+ memset(&param, 0, sizeof(param));
+
+ /* Sanity check */
+ if (req->ifr_data == NULL) {
+ PRINTM(MERROR, "uap_addba_param() corrupt data\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ if (copy_from_user(&param, req->ifr_data, sizeof(param))) {
+ PRINTM(MERROR, "Copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ PRINTM(MIOCTL,
+ "addba param: action=%d, timeout=%d, txwinsize=%d, rxwinsize=%d txamsdu=%d rxamsdu=%d\n",
+ (int) param.action, (int) param.timeout, (int) param.txwinsize,
+ (int) param.rxwinsize, (int) param.txamsdu, (int) param.rxamsdu);
+ ioctl_req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_11n_cfg));
+ if (ioctl_req == NULL) {
+ LEAVE();
+ return -ENOMEM;
+ }
+ cfg_11n = (mlan_ds_11n_cfg *) ioctl_req->pbuf;
+ cfg_11n->sub_command = MLAN_OID_11N_CFG_ADDBA_PARAM;
+ ioctl_req->req_id = MLAN_IOCTL_11N_CFG;
+
+ if (!param.action) {
+ /* Get addba param from MLAN */
+ ioctl_req->action = MLAN_ACT_GET;
+ } else {
+ /* Set addba param in MLAN */
+ ioctl_req->action = MLAN_ACT_SET;
+ cfg_11n->param.addba_param.timeout = param.timeout;
+ cfg_11n->param.addba_param.txwinsize = param.txwinsize;
+ cfg_11n->param.addba_param.rxwinsize = param.rxwinsize;
+ cfg_11n->param.addba_param.txamsdu = param.txamsdu;
+ cfg_11n->param.addba_param.rxamsdu = param.rxamsdu;
+ }
+ if (MLAN_STATUS_SUCCESS !=
+ woal_request_ioctl(priv, ioctl_req, MOAL_IOCTL_WAIT)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ param.timeout = cfg_11n->param.addba_param.timeout;
+ param.txwinsize = cfg_11n->param.addba_param.txwinsize;
+ param.rxwinsize = cfg_11n->param.addba_param.rxwinsize;
+ param.txamsdu = cfg_11n->param.addba_param.txamsdu;
+ param.rxamsdu = cfg_11n->param.addba_param.rxamsdu;
+
+ /* Copy to user */
+ if (copy_to_user(req->ifr_data, &param, sizeof(param))) {
+ PRINTM(MERROR, "Copy to user failed!\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ done:
+ if (ioctl_req)
+ kfree(ioctl_req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief uap aggr priority tbl
+ *
+ * @param dev A pointer to net_device structure
+ * @param req A pointer to ifreq structure
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_uap_aggr_priotbl(struct net_device *dev, struct ifreq *req)
+{
+ moal_private *priv = (moal_private *) netdev_priv(dev);
+ mlan_ioctl_req *ioctl_req = NULL;
+ mlan_ds_11n_cfg *cfg_11n = NULL;
+ aggr_prio_tbl param;
+ int ret = 0;
+ int i = 0;
+
+ ENTER();
+ memset(&param, 0, sizeof(param));
+
+ /* Sanity check */
+ if (req->ifr_data == NULL) {
+ PRINTM(MERROR, "woal_uap_aggr_priotbl() corrupt data\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ if (copy_from_user(&param, req->ifr_data, sizeof(param))) {
+ PRINTM(MERROR, "Copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ DBG_HEXDUMP(MCMD_D, "aggr_prio_tbl", (t_u8 *) & param, sizeof(param));
+
+ ioctl_req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_11n_cfg));
+ if (ioctl_req == NULL) {
+ LEAVE();
+ return -ENOMEM;
+ }
+ cfg_11n = (mlan_ds_11n_cfg *) ioctl_req->pbuf;
+ cfg_11n->sub_command = MLAN_OID_11N_CFG_AGGR_PRIO_TBL;
+ ioctl_req->req_id = MLAN_IOCTL_11N_CFG;
+
+ if (!param.action) {
+ /* Get aggr_prio_tbl from MLAN */
+ ioctl_req->action = MLAN_ACT_GET;
+ } else {
+ /* Set aggr_prio_tbl in MLAN */
+ ioctl_req->action = MLAN_ACT_SET;
+ for (i = 0; i < MAX_NUM_TID; i++) {
+ cfg_11n->param.aggr_prio_tbl.ampdu[i] = param.ampdu[i];
+ cfg_11n->param.aggr_prio_tbl.amsdu[i] = param.amsdu[i];
+ }
+ }
+ if (MLAN_STATUS_SUCCESS !=
+ woal_request_ioctl(priv, ioctl_req, MOAL_IOCTL_WAIT)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ for (i = 0; i < MAX_NUM_TID; i++) {
+ param.ampdu[i] = cfg_11n->param.aggr_prio_tbl.ampdu[i];
+ param.amsdu[i] = cfg_11n->param.aggr_prio_tbl.amsdu[i];
+ }
+ /* Copy to user */
+ if (copy_to_user(req->ifr_data, &param, sizeof(param))) {
+ PRINTM(MERROR, "Copy to user failed!\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ done:
+ if (ioctl_req)
+ kfree(ioctl_req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief uap addba reject tbl
+ *
+ * @param dev A pointer to net_device structure
+ * @param req A pointer to ifreq structure
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_uap_addba_reject(struct net_device *dev, struct ifreq *req)
+{
+ moal_private *priv = (moal_private *) netdev_priv(dev);
+ mlan_ioctl_req *ioctl_req = NULL;
+ mlan_ds_11n_cfg *cfg_11n = NULL;
+ addba_reject_para param;
+ int ret = 0;
+ int i = 0;
+
+ ENTER();
+ memset(&param, 0, sizeof(param));
+
+ /* Sanity check */
+ if (req->ifr_data == NULL) {
+ PRINTM(MERROR, "woal_uap_addba_reject() corrupt data\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ if (copy_from_user(&param, req->ifr_data, sizeof(param))) {
+ PRINTM(MERROR, "Copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ DBG_HEXDUMP(MCMD_D, "addba_reject tbl", (t_u8 *) & param, sizeof(param));
+
+ ioctl_req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_11n_cfg));
+ if (ioctl_req == NULL) {
+ LEAVE();
+ return -ENOMEM;
+ }
+ cfg_11n = (mlan_ds_11n_cfg *) ioctl_req->pbuf;
+ cfg_11n->sub_command = MLAN_OID_11N_CFG_ADDBA_REJECT;
+ ioctl_req->req_id = MLAN_IOCTL_11N_CFG;
+
+ if (!param.action) {
+ /* Get addba_reject tbl from MLAN */
+ ioctl_req->action = MLAN_ACT_GET;
+ } else {
+ /* Set addba_reject tbl in MLAN */
+ ioctl_req->action = MLAN_ACT_SET;
+ for (i = 0; i < MAX_NUM_TID; i++) {
+ cfg_11n->param.addba_reject[i] = param.addba_reject[i];
+ }
+ }
+ if (MLAN_STATUS_SUCCESS !=
+ woal_request_ioctl(priv, ioctl_req, MOAL_IOCTL_WAIT)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ for (i = 0; i < MAX_NUM_TID; i++) {
+ param.addba_reject[i] = cfg_11n->param.addba_reject[i];
+ }
+ /* Copy to user */
+ if (copy_to_user(req->ifr_data, &param, sizeof(param))) {
+ PRINTM(MERROR, "Copy to user failed!\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ done:
+ if (ioctl_req)
+ kfree(ioctl_req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief uap get_fw_info handler
+ *
+ * @param dev A pointer to net_device structure
+ * @param req A pointer to ifreq structure
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_uap_get_fw_info(struct net_device *dev, struct ifreq *req)
+{
+ moal_private *priv = (moal_private *) netdev_priv(dev);
+ fw_info fw;
+ mlan_fw_info fw_info;
+ int ret = 0;
+
+ ENTER();
+ memset(&fw, 0, sizeof(fw));
+ memset(&fw_info, 0, sizeof(fw_info));
+
+ /* Sanity check */
+ if (req->ifr_data == NULL) {
+ PRINTM(MERROR, "woal_uap_get_fw_info() corrupt data\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ if (copy_from_user(&fw, req->ifr_data, sizeof(fw))) {
+ PRINTM(MERROR, "Copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ if (MLAN_STATUS_SUCCESS !=
+ woal_request_get_fw_info(priv, MOAL_IOCTL_WAIT, &fw_info)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ fw.fw_release_number = fw_info.fw_ver;
+ fw.hw_dev_mcs_support = fw_info.hw_dev_mcs_support;
+ /* Copy to user */
+ if (copy_to_user(req->ifr_data, &fw, sizeof(fw))) {
+ PRINTM(MERROR, "Copy to user failed!\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief configure deep sleep
+ *
+ * @param dev A pointer to net_device structure
+ * @param req A pointer to ifreq structure
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_uap_deep_sleep(struct net_device *dev, struct ifreq *req)
+{
+ moal_private *priv = (moal_private *) netdev_priv(dev);
+ mlan_ioctl_req *ioctl_req = NULL;
+ mlan_ds_pm_cfg *pm = NULL;
+ deep_sleep_para param;
+ int ret = 0;
+
+ ENTER();
+ memset(&param, 0, sizeof(param));
+
+ /* Sanity check */
+ if (req->ifr_data == NULL) {
+ PRINTM(MERROR, "woal_uap_deep_sleep() corrupt data\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ if (copy_from_user(&param, req->ifr_data, sizeof(param))) {
+ PRINTM(MERROR, "Copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ DBG_HEXDUMP(MCMD_D, "deep_sleep_para", (t_u8 *) & param, sizeof(param));
+
+ ioctl_req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_pm_cfg));
+ if (ioctl_req == NULL) {
+ LEAVE();
+ return -ENOMEM;
+ }
+ pm = (mlan_ds_pm_cfg *) ioctl_req->pbuf;
+ pm->sub_command = MLAN_OID_PM_CFG_DEEP_SLEEP;
+ ioctl_req->req_id = MLAN_IOCTL_PM_CFG;
+
+ if (!param.action) {
+ /* Get deep_sleep status from MLAN */
+ ioctl_req->action = MLAN_ACT_GET;
+ } else {
+ /* Set deep_sleep in MLAN */
+ ioctl_req->action = MLAN_ACT_SET;
+ if (param.deep_sleep == MTRUE) {
+ pm->param.auto_deep_sleep.auto_ds = DEEP_SLEEP_ON;
+ pm->param.auto_deep_sleep.idletime = param.idle_time;
+ } else {
+ pm->param.auto_deep_sleep.auto_ds = DEEP_SLEEP_OFF;
+ }
+ }
+ if (MLAN_STATUS_SUCCESS !=
+ woal_request_ioctl(priv, ioctl_req, MOAL_IOCTL_WAIT)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ if (pm->param.auto_deep_sleep.auto_ds == DEEP_SLEEP_ON)
+ param.deep_sleep = MTRUE;
+ else
+ param.deep_sleep = MFALSE;
+ param.idle_time = pm->param.auto_deep_sleep.idletime;
+ /* Copy to user */
+ if (copy_to_user(req->ifr_data, &param, sizeof(param))) {
+ PRINTM(MERROR, "Copy to user failed!\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ done:
+ if (ioctl_req)
+ kfree(ioctl_req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief configure tx_pause settings
+ *
+ * @param dev A pointer to net_device structure
+ * @param req A pointer to ifreq structure
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_uap_txdatapause(struct net_device *dev, struct ifreq *req)
+{
+ moal_private *priv = (moal_private *) netdev_priv(dev);
+ mlan_ioctl_req *ioctl_req = NULL;
+ mlan_ds_misc_cfg *misc = NULL;
+ tx_data_pause_para param;
+ int ret = 0;
+
+ ENTER();
+ memset(&param, 0, sizeof(param));
+
+ /* Sanity check */
+ if (req->ifr_data == NULL) {
+ PRINTM(MERROR, "woal_uap_txdatapause corrupt data\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ if (copy_from_user(&param, req->ifr_data, sizeof(param))) {
+ PRINTM(MERROR, "Copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ DBG_HEXDUMP(MCMD_D, "tx_data_pause_para", (t_u8 *) & param, sizeof(param));
+
+ ioctl_req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
+ if (ioctl_req == NULL) {
+ LEAVE();
+ return -ENOMEM;
+ }
+ misc = (mlan_ds_misc_cfg *) ioctl_req->pbuf;
+ misc->sub_command = MLAN_OID_MISC_TX_DATAPAUSE;
+ ioctl_req->req_id = MLAN_IOCTL_MISC_CFG;
+
+ if (!param.action) {
+ /* Get Tx data pause status from MLAN */
+ ioctl_req->action = MLAN_ACT_GET;
+ } else {
+ /* Set Tx data pause in MLAN */
+ ioctl_req->action = MLAN_ACT_SET;
+ misc->param.tx_datapause.tx_pause = param.txpause;
+ misc->param.tx_datapause.tx_buf_cnt = param.txbufcnt;
+ }
+ if (MLAN_STATUS_SUCCESS !=
+ woal_request_ioctl(priv, ioctl_req, MOAL_IOCTL_WAIT)) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ param.txpause = misc->param.tx_datapause.tx_pause;
+ param.txbufcnt = misc->param.tx_datapause.tx_buf_cnt;
+
+ /* Copy to user */
+ if (copy_to_user(req->ifr_data, &param, sizeof(param))) {
+ PRINTM(MERROR, "Copy to user failed!\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ done:
+ if (ioctl_req)
+ kfree(ioctl_req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief uap sdcmd52rw ioctl handler
+ *
+ * @param dev A pointer to net_device structure
+ * @param req A pointer to ifreq structure
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_uap_sdcmd52_rw(struct net_device *dev, struct ifreq *req)
+{
+ moal_private *priv = (moal_private *) netdev_priv(dev);
+ sdcmd52_para param;
+ t_u8 func, data = 0;
+ int ret = 0, reg;
+
+ ENTER();
+ memset(&param, 0, sizeof(param));
+
+ /* Sanity check */
+ if (req->ifr_data == NULL) {
+ PRINTM(MERROR, "woal_uap_sdcmd52_rw() corrupt data\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ if (copy_from_user(&param, req->ifr_data, sizeof(param))) {
+ PRINTM(MERROR, "Copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+
+ func = (t_u8) param.cmd52_params[0];
+ reg = (t_u32) param.cmd52_params[1];
+
+ if (!param.action) {
+ PRINTM(MINFO, "Cmd52 read, func=%d, reg=0x%08X\n", func, reg);
+ sdio_claim_host(((struct sdio_mmc_card *) priv->phandle->card)->func);
+ if (func)
+ data =
+ sdio_readb(((struct sdio_mmc_card *) priv->phandle->card)->func,
+ reg, &ret);
+ else
+ data =
+ sdio_f0_readb(((struct sdio_mmc_card *) priv->phandle->card)->
+ func, reg, &ret);
+ sdio_release_host(((struct sdio_mmc_card *) priv->phandle->card)->func);
+ if (ret) {
+ PRINTM(MERROR, "sdio_readb: reading register 0x%X failed\n", reg);
+ goto done;
+ }
+ param.cmd52_params[2] = data;
+ } else {
+ data = (t_u8) param.cmd52_params[2];
+ PRINTM(MINFO, "Cmd52 write, func=%d, reg=0x%08X, data=0x%02X\n", func,
+ reg, data);
+ sdio_claim_host(((struct sdio_mmc_card *) priv->phandle->card)->func);
+ if (func)
+ sdio_writeb(((struct sdio_mmc_card *) priv->phandle->card)->func,
+ data, reg, &ret);
+ else
+ sdio_f0_writeb(((struct sdio_mmc_card *) priv->phandle->card)->func,
+ data, reg, &ret);
+ sdio_release_host(((struct sdio_mmc_card *) priv->phandle->card)->func);
+ if (ret) {
+ PRINTM(MERROR, "sdio_writeb: writing register 0x%X failed\n", reg);
+ goto done;
+ }
+ }
+ /* Copy to user */
+ if (copy_to_user(req->ifr_data, &param, sizeof(param))) {
+ PRINTM(MERROR, "Copy to user failed!\n");
+ ret = -EFAULT;
+ }
+ done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief configure snmp mib
+ *
+ * @param dev A pointer to net_device structure
+ * @param req A pointer to ifreq structure
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_uap_snmp_mib(struct net_device *dev, struct ifreq *req)
+{
+ moal_private *priv = (moal_private *) netdev_priv(dev);
+ mlan_ioctl_req *ioctl_req = NULL;
+ mlan_ds_snmp_mib *snmp = NULL;
+ snmp_mib_para param;
+ t_u8 value[MAX_SNMP_VALUE_SIZE];
+ int ret = 0;
+
+ ENTER();
+ memset(&param, 0, sizeof(param));
+ memset(value, 0, MAX_SNMP_VALUE_SIZE);
+
+ /* Sanity check */
+ if (req->ifr_data == NULL) {
+ PRINTM(MERROR, "woal_uap_snmp_mib() corrupt data\n");
+ ret = -EFAULT;
+ goto done;
+ }
+
+ /* Copy from user */
+ if (copy_from_user(&param, req->ifr_data, sizeof(param))) {
+ PRINTM(MERROR, "Copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ DBG_HEXDUMP(MCMD_D, "snmp_mib_para", (t_u8 *) & param, sizeof(param));
+ if (param.action) {
+ if (copy_from_user(value, req->ifr_data + sizeof(param),
+ MIN(param.oid_val_len, MAX_SNMP_VALUE_SIZE))) {
+ PRINTM(MERROR, "Copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ DBG_HEXDUMP(MCMD_D, "snmp_mib_para value", value,
+ MIN(param.oid_val_len, sizeof(t_u32)));
+ }
+
+ ioctl_req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_snmp_mib));
+ if (ioctl_req == NULL) {
+ LEAVE();
+ return -ENOMEM;
+ }
+ snmp = (mlan_ds_snmp_mib *) ioctl_req->pbuf;
+ ioctl_req->req_id = MLAN_IOCTL_SNMP_MIB;
+ switch (param.oid) {
+ case OID_80211D_ENABLE:
+ snmp->sub_command = MLAN_OID_SNMP_MIB_DOT11D;
+ break;
+ case OID_80211H_ENABLE:
+ snmp->sub_command = MLAN_OID_SNMP_MIB_DOT11H;
+ break;
+ default:
+ PRINTM(MERROR, "%s: Unsupported SNMP_MIB OID (%d).\n", __FUNCTION__,
+ param.oid);
+ goto done;
+ }
+
+ if (!param.action) {
+ /* Get mib value from MLAN */
+ ioctl_req->action = MLAN_ACT_GET;
+ } else {
+ /* Set mib value to MLAN */
+ ioctl_req->action = MLAN_ACT_SET;
+ snmp->param.oid_value = *(t_u32 *) value;
+ }
+ if (MLAN_STATUS_SUCCESS !=
+ woal_request_ioctl(priv, ioctl_req, MOAL_IOCTL_WAIT)) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ /* Copy to user */
+ if (copy_to_user(req->ifr_data, &param, sizeof(param))) {
+ PRINTM(MERROR, "Copy to user failed!\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ if (!param.action) { /* GET */
+ if (copy_to_user(req->ifr_data + sizeof(param), &snmp->param.oid_value,
+ MIN(param.oid_val_len, sizeof(t_u32)))) {
+ PRINTM(MERROR, "Copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ }
+
+ done:
+ if (ioctl_req)
+ kfree(ioctl_req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief configure domain info
+ *
+ * @param dev A pointer to net_device structure
+ * @param req A pointer to ifreq structure
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_uap_domain_info(struct net_device *dev, struct ifreq *req)
+{
+ moal_private *priv = (moal_private *) netdev_priv(dev);
+ mlan_ioctl_req *ioctl_req = NULL;
+ mlan_ds_11d_cfg *cfg11d = NULL;
+ domain_info_para param;
+ t_u8 tlv[MAX_DOMAIN_TLV_LEN];
+ t_u16 tlv_data_len = 0;
+ int ret = 0;
+
+ ENTER();
+ memset(&param, 0, sizeof(param));
+ memset(tlv, 0, MAX_DOMAIN_TLV_LEN);
+
+ /* Sanity check */
+ if (req->ifr_data == NULL) {
+ PRINTM(MERROR, "woal_uap_domain_info() corrupt data\n");
+ ret = -EFAULT;
+ goto done;
+ }
+
+ /* Copy from user */
+ if (copy_from_user(&param, req->ifr_data, sizeof(param))) {
+ PRINTM(MERROR, "Copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ DBG_HEXDUMP(MCMD_D, "domain_info_para", (t_u8 *) & param, sizeof(param));
+ if (param.action) {
+ /* get tlv header */
+ if (copy_from_user(tlv, req->ifr_data + sizeof(param), TLV_HEADER_LEN)) {
+ PRINTM(MERROR, "Copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ tlv_data_len = ((t_u16 *) (tlv))[1];
+ if ((TLV_HEADER_LEN + tlv_data_len) > sizeof(tlv)) {
+ PRINTM(MERROR, "TLV buffer is overflowed");
+ ret = -EINVAL;
+ goto done;
+ }
+ /* get full tlv */
+ if (copy_from_user(tlv, req->ifr_data + sizeof(param),
+ TLV_HEADER_LEN + tlv_data_len)) {
+ PRINTM(MERROR, "Copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ DBG_HEXDUMP(MCMD_D, "domain_info_para tlv", tlv,
+ TLV_HEADER_LEN + tlv_data_len);
+ }
+
+ ioctl_req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_11d_cfg));
+ if (ioctl_req == NULL) {
+ LEAVE();
+ return -ENOMEM;
+ }
+ cfg11d = (mlan_ds_11d_cfg *) ioctl_req->pbuf;
+ ioctl_req->req_id = MLAN_IOCTL_11D_CFG;
+ cfg11d->sub_command = MLAN_OID_11D_DOMAIN_INFO;
+
+ if (!param.action) {
+ /* Get mib value from MLAN */
+ ioctl_req->action = MLAN_ACT_GET;
+ } else {
+ /* Set mib value to MLAN */
+ ioctl_req->action = MLAN_ACT_SET;
+ memcpy(cfg11d->param.domain_tlv, tlv,
+ MIN(MAX_IE_SIZE, (TLV_HEADER_LEN + tlv_data_len)));
+ }
+ if (MLAN_STATUS_SUCCESS !=
+ woal_request_ioctl(priv, ioctl_req, MOAL_IOCTL_WAIT)) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ /* Copy to user */
+ if (copy_to_user(req->ifr_data, &param, sizeof(param))) {
+ PRINTM(MERROR, "Copy to user failed!\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ if (!param.action) { /* GET */
+ tlv_data_len = ((t_u16 *) (cfg11d->param.domain_tlv))[1];
+ if (copy_to_user
+ (req->ifr_data + sizeof(param), &cfg11d->param.domain_tlv,
+ TLV_HEADER_LEN + tlv_data_len)) {
+ PRINTM(MERROR, "Copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ }
+
+ done:
+ if (ioctl_req)
+ kfree(ioctl_req);
+ LEAVE();
+ return ret;
+}
+
+#if defined(DFS_TESTING_SUPPORT)
+/**
+ * @brief configure dfs testing settings
+ *
+ * @param dev A pointer to net_device structure
+ * @param req A pointer to ifreq structure
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_uap_dfs_testing(struct net_device *dev, struct ifreq *req)
+{
+ moal_private *priv = (moal_private *) netdev_priv(dev);
+ mlan_ioctl_req *ioctl_req = NULL;
+ mlan_ds_11h_cfg *cfg11h = NULL;
+ dfs_testing_para param;
+ int ret = 0;
+
+ ENTER();
+ memset(&param, 0, sizeof(param));
+
+ /* Sanity check */
+ if (req->ifr_data == NULL) {
+ PRINTM(MERROR, "woal_uap_dfs_testing() corrupt data\n");
+ ret = -EFAULT;
+ goto done;
+ }
+
+ /* Copy from user */
+ if (copy_from_user(&param, req->ifr_data, sizeof(param))) {
+ PRINTM(MERROR, "Copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ DBG_HEXDUMP(MCMD_D, "dfs_testing_para", (t_u8 *) & param, sizeof(param));
+
+ ioctl_req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_11h_cfg));
+ if (ioctl_req == NULL) {
+ LEAVE();
+ return -ENOMEM;
+ }
+ cfg11h = (mlan_ds_11h_cfg *) ioctl_req->pbuf;
+ ioctl_req->req_id = MLAN_IOCTL_11H_CFG;
+ cfg11h->sub_command = MLAN_OID_11H_DFS_TESTING;
+
+ if (!param.action) {
+ /* Get mib value from MLAN */
+ ioctl_req->action = MLAN_ACT_GET;
+ } else {
+ /* Set mib value to MLAN */
+ ioctl_req->action = MLAN_ACT_SET;
+ cfg11h->param.dfs_testing.usr_cac_period_msec = param.usr_cac_period;
+ cfg11h->param.dfs_testing.usr_nop_period_sec = param.usr_nop_period;
+ cfg11h->param.dfs_testing.usr_no_chan_change = param.no_chan_change;
+ cfg11h->param.dfs_testing.usr_fixed_new_chan = param.fixed_new_chan;
+ priv->phandle->cac_period_jiffies = param.usr_cac_period * HZ / 1000;
+ }
+ if (MLAN_STATUS_SUCCESS !=
+ woal_request_ioctl(priv, ioctl_req, MOAL_IOCTL_WAIT)) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ if (!param.action) { /* GET */
+ param.usr_cac_period = cfg11h->param.dfs_testing.usr_cac_period_msec;
+ param.usr_nop_period = cfg11h->param.dfs_testing.usr_nop_period_sec;
+ param.no_chan_change = cfg11h->param.dfs_testing.usr_no_chan_change;
+ param.fixed_new_chan = cfg11h->param.dfs_testing.usr_fixed_new_chan;
+ }
+ /* Copy to user */
+ if (copy_to_user(req->ifr_data, &param, sizeof(param))) {
+ PRINTM(MERROR, "Copy to user failed!\n");
+ ret = -EFAULT;
+ goto done;
+ }
+
+ done:
+ if (ioctl_req)
+ kfree(ioctl_req);
+ LEAVE();
+ return ret;
+}
+#endif
+
+/**
+ * @brief Configure TX beamforming support
+ *
+ * @param dev A pointer to net_device structure
+ * @param req A pointer to ifreq structure
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_uap_tx_bf_cfg(struct net_device *dev, struct ifreq *req)
+{
+ int ret = 0;
+ moal_private *priv = (moal_private *) netdev_priv(dev);
+ mlan_ds_11n_tx_bf_cfg bf_cfg;
+ tx_bf_cfg_para_hdr param;
+ t_u16 action = 0;
+
+ ENTER();
+
+ memset(&param, 0, sizeof(param));
+ memset(&bf_cfg, 0, sizeof(bf_cfg));
+
+ /* Sanity check */
+ if (req->ifr_data == NULL) {
+ PRINTM(MERROR, "woal_uap_tx_bf_cfg corrupt data\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ if (copy_from_user(&param, req->ifr_data, sizeof(param))) {
+ PRINTM(MERROR, "Copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ if (!param.action) {
+ /* Get BF configurations */
+ action = MLAN_ACT_GET;
+ } else {
+ /* Set BF configurations */
+ action = MLAN_ACT_SET;
+ }
+ if (copy_from_user(&bf_cfg, req->ifr_data + sizeof(tx_bf_cfg_para_hdr),
+ sizeof(bf_cfg))) {
+ PRINTM(MERROR, "Copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ DBG_HEXDUMP(MCMD_D, "bf_cfg", (t_u8 *) & bf_cfg, sizeof(bf_cfg));
+
+ if (MLAN_STATUS_SUCCESS != woal_set_get_tx_bf_cfg(priv, action, &bf_cfg)) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ /* Copy to user */
+ if (copy_to_user(req->ifr_data + sizeof(tx_bf_cfg_para_hdr),
+ &bf_cfg, sizeof(bf_cfg))) {
+ PRINTM(MERROR, "Copy to user failed!\n");
+ ret = -EFAULT;
+ goto done;
+ }
+
+ done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief uap hs_cfg ioctl handler
+ *
+ * @param dev A pointer to net_device structure
+ * @param req A pointer to ifreq structure
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_uap_hs_cfg(struct net_device *dev, struct ifreq *req,
+ BOOLEAN invoke_hostcmd)
+{
+ moal_private *priv = (moal_private *) netdev_priv(dev);
+ mlan_ds_hs_cfg hscfg;
+ ds_hs_cfg hs_cfg;
+ mlan_bss_info bss_info;
+ t_u16 action;
+ int ret = 0;
+
+ ENTER();
+
+ memset(&hscfg, 0, sizeof(mlan_ds_hs_cfg));
+ memset(&hs_cfg, 0, sizeof(ds_hs_cfg));
+
+ /* Sanity check */
+ if (req->ifr_data == NULL) {
+ PRINTM(MERROR, "uap_hs_cfg() corrupt data\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ if (copy_from_user(&hs_cfg, req->ifr_data, sizeof(ds_hs_cfg))) {
+ PRINTM(MERROR, "Copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+
+ PRINTM(MIOCTL, "ioctl hscfg: flags=0x%x condition=0x%x gpio=%d gap=0x%x\n",
+ hs_cfg.flags, hs_cfg.conditions, (int) hs_cfg.gpio, hs_cfg.gap);
+
+ /* HS config is blocked if HS is already activated */
+ if ((hs_cfg.flags & HS_CFG_FLAG_CONDITION) &&
+ (hs_cfg.conditions != HOST_SLEEP_CFG_CANCEL ||
+ invoke_hostcmd == MFALSE)) {
+ memset(&bss_info, 0, sizeof(bss_info));
+ woal_get_bss_info(priv, MOAL_IOCTL_WAIT, &bss_info);
+ if (bss_info.is_hs_configured) {
+ PRINTM(MERROR, "HS already configured\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ }
+
+ if (hs_cfg.flags & HS_CFG_FLAG_SET) {
+ action = MLAN_ACT_SET;
+ if (hs_cfg.flags != HS_CFG_FLAG_ALL) {
+ woal_set_get_hs_params(priv, MLAN_ACT_GET, MOAL_IOCTL_WAIT, &hscfg);
+ }
+ if (hs_cfg.flags & HS_CFG_FLAG_CONDITION)
+ hscfg.conditions = hs_cfg.conditions;
+ if (hs_cfg.flags & HS_CFG_FLAG_GPIO)
+ hscfg.gpio = hs_cfg.gpio;
+ if (hs_cfg.flags & HS_CFG_FLAG_GAP)
+ hscfg.gap = hs_cfg.gap;
+
+ if (invoke_hostcmd == MTRUE) {
+ /* Issue IOCTL to set up parameters */
+ hscfg.is_invoke_hostcmd = MFALSE;
+ if (MLAN_STATUS_SUCCESS !=
+ woal_set_get_hs_params(priv, action, MOAL_IOCTL_WAIT, &hscfg)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ }
+ } else {
+ action = MLAN_ACT_GET;
+ }
+
+ /* Issue IOCTL to invoke hostcmd */
+ hscfg.is_invoke_hostcmd = invoke_hostcmd;
+ if (MLAN_STATUS_SUCCESS !=
+ woal_set_get_hs_params(priv, action, MOAL_IOCTL_WAIT, &hscfg)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ if (!(hs_cfg.flags & HS_CFG_FLAG_SET)) {
+ hs_cfg.flags =
+ HS_CFG_FLAG_CONDITION | HS_CFG_FLAG_GPIO | HS_CFG_FLAG_GAP;
+ hs_cfg.conditions = hscfg.conditions;
+ hs_cfg.gpio = hscfg.gpio;
+ hs_cfg.gap = hscfg.gap;
+ /* Copy to user */
+ if (copy_to_user(req->ifr_data, &hs_cfg, sizeof(ds_hs_cfg))) {
+ PRINTM(MERROR, "Copy to user failed!\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ }
+
+ done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set Host Sleep parameters
+ *
+ * @param priv A pointer to moal_private structure
+ * @param wrq A pointer to iwreq structure
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_uap_hs_set_para(struct net_device *dev, struct ifreq *req)
+{
+ int ret = 0;
+
+ ENTER();
+
+ if (req->ifr_data != NULL) {
+ ret = woal_uap_hs_cfg(dev, req, MFALSE);
+ goto done;
+ } else {
+ PRINTM(MERROR, "Invalid data\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief uap mgmt_frame_control ioctl handler
+ *
+ * @param dev A pointer to net_device structure
+ * @param req A pointer to ifreq structure
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_uap_mgmt_frame_control(struct net_device *dev, struct ifreq *req)
+{
+ moal_private *priv = (moal_private *) netdev_priv(dev);
+ int ret = 0;
+ t_u16 action = 0;
+ mgmt_frame_ctrl param;
+ mlan_uap_bss_param sys_config;
+
+ ENTER();
+
+ /* Sanity check */
+ if (req->ifr_data == NULL) {
+ PRINTM(MERROR, "uap_mgmt_frame_ctrl() corrupt data\n");
+ ret = -EFAULT;
+ goto done;
+ }
+
+ /* Get user data */
+ if (copy_from_user(&param, req->ifr_data, sizeof(param))) {
+ PRINTM(MERROR, "Copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ if (param.action) {
+ action = MLAN_ACT_SET;
+ } else {
+ action = MLAN_ACT_GET;
+ }
+ if (action == MLAN_ACT_SET) {
+ /* Initialize the invalid values so that the correct values below are
+ downloaded to firmware */
+ woal_set_sys_config_invalid_data(&sys_config);
+ sys_config.mgmt_ie_passthru_mask = param.mask;
+ }
+
+ if (MLAN_STATUS_SUCCESS !=
+ woal_set_get_sys_config(priv, action, MOAL_IOCTL_WAIT, &sys_config)) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ if (action == MLAN_ACT_GET) {
+ param.mask = sys_config.mgmt_ie_passthru_mask;
+ if (copy_to_user(req->ifr_data, &param, sizeof(param))) {
+ PRINTM(MERROR, "Copy to user failed\n");
+ ret = -EFAULT;
+ }
+ }
+ done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set/Get tx rate
+ *
+ * @param dev A pointer to net_device structure
+ * @param req A pointer to ifreq structure
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_uap_tx_rate_cfg(struct net_device *dev, struct ifreq *req)
+{
+ moal_private *priv = (moal_private *) netdev_priv(dev);
+ int ret = 0, i = 0;
+ mlan_ds_rate *rate = NULL;
+ mlan_ioctl_req *mreq = NULL;
+ tx_rate_cfg_t tx_rate_config;
+
+ ENTER();
+
+ /* Sanity check */
+ if (req->ifr_data == NULL) {
+ PRINTM(MERROR, "uap_tx_rate_cfg() corrupt data\n");
+ ret = -EFAULT;
+ goto done;
+ }
+
+ memset(&tx_rate_config, 0, sizeof(tx_rate_cfg_t));
+ /* Get user data */
+ if (copy_from_user(&tx_rate_config, req->ifr_data, sizeof(tx_rate_cfg_t))) {
+ PRINTM(MERROR, "Copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+
+ mreq = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_rate));
+ if (mreq == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+ rate = (mlan_ds_rate *) mreq->pbuf;
+ rate->param.rate_cfg.rate_type = MLAN_RATE_INDEX;
+ rate->sub_command = MLAN_OID_RATE_CFG;
+ mreq->req_id = MLAN_IOCTL_RATE;
+ if (!(tx_rate_config.action))
+ mreq->action = MLAN_ACT_GET;
+ else {
+ mreq->action = MLAN_ACT_SET;
+ if (tx_rate_config.rate == AUTO_RATE)
+ rate->param.rate_cfg.is_rate_auto = 1;
+ else {
+ if ((tx_rate_config.rate != MLAN_RATE_INDEX_MCS32) &&
+ ((tx_rate_config.rate < 0) ||
+ (tx_rate_config.rate > MLAN_RATE_INDEX_MCS15))) {
+ ret = -EINVAL;
+ goto done;
+ }
+ }
+ rate->param.rate_cfg.rate = tx_rate_config.rate;
+ }
+
+ if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, mreq, MOAL_IOCTL_WAIT)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ if (tx_rate_config.action) {
+ priv->rate_index = tx_rate_config.action;
+ } else {
+ if (rate->param.rate_cfg.is_rate_auto)
+ tx_rate_config.rate = AUTO_RATE;
+ else
+ tx_rate_config.rate = rate->param.rate_cfg.rate;
+ for (i = 0; i < MAX_BITMAP_RATES_SIZE; i++) {
+ tx_rate_config.bitmap_rates[i] =
+ rate->param.rate_cfg.bitmap_rates[i];
+ }
+
+ if (copy_to_user(req->ifr_data, &tx_rate_config, sizeof(tx_rate_cfg_t))) {
+ PRINTM(MERROR, "Copy to user failed\n");
+ ret = -EFAULT;
+ }
+ }
+ done:
+ if (mreq)
+ kfree(mreq);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set/Get RF antenna mode
+ *
+ * @param dev A pointer to net_device structure
+ * @param req A pointer to ifreq structure
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_uap_antenna_cfg(struct net_device *dev, struct ifreq *req)
+{
+ moal_private *priv = (moal_private *) netdev_priv(dev);
+ int ret = 0;
+ mlan_ds_radio_cfg *radio = NULL;
+ mlan_ioctl_req *mreq = NULL;
+ ant_cfg_t antenna_config;
+
+ ENTER();
+
+ /* Sanity check */
+ if (req->ifr_data == NULL) {
+ PRINTM(MERROR, "uap_antenna_cfg() corrupt data\n");
+ ret = -EFAULT;
+ goto done;
+ }
+
+ memset(&antenna_config, 0, sizeof(ant_cfg_t));
+ /* Get user data */
+ if (copy_from_user(&antenna_config, req->ifr_data, sizeof(ant_cfg_t))) {
+ PRINTM(MERROR, "Copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ mreq = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_radio_cfg));
+ if (mreq == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+ radio = (mlan_ds_radio_cfg *) mreq->pbuf;
+ radio->sub_command = MLAN_OID_ANT_CFG;
+ mreq->req_id = MLAN_IOCTL_RADIO_CFG;
+ if (!(antenna_config.action))
+ mreq->action = MLAN_ACT_GET;
+ else {
+ mreq->action = MLAN_ACT_SET;
+ radio->param.ant_cfg.tx_antenna = antenna_config.tx_mode;
+ radio->param.ant_cfg.rx_antenna = antenna_config.rx_mode;
+ }
+
+ if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, mreq, MOAL_IOCTL_WAIT)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ if (mreq->action == MLAN_ACT_GET) {
+ antenna_config.tx_mode = radio->param.ant_cfg.tx_antenna;
+ antenna_config.rx_mode = radio->param.ant_cfg.rx_antenna;
+ if (copy_to_user(req->ifr_data, &antenna_config, sizeof(ant_cfg_t))) {
+ PRINTM(MERROR, "Copy to user failed\n");
+ ret = -EFAULT;
+ }
+ }
+ done:
+ if (mreq)
+ kfree(mreq);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief uap ioctl handler
+ *
+ * @param dev A pointer to net_device structure
+ * @param req A pointer to ifreq structure
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_uap_ioctl(struct net_device *dev, struct ifreq *req)
+{
+ int ret = 0;
+ t_u32 subcmd = 0;
+ ENTER();
+ /* Sanity check */
+ if (req->ifr_data == NULL) {
+ PRINTM(MERROR, "uap_ioctl() corrupt data\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ if (copy_from_user(&subcmd, req->ifr_data, sizeof(subcmd))) {
+ PRINTM(MERROR, "Copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+
+ PRINTM(MIOCTL, "ioctl subcmd=%d\n", (int) subcmd);
+ switch (subcmd) {
+ case UAP_ADDBA_PARA:
+ ret = woal_uap_addba_param(dev, req);
+ break;
+ case UAP_AGGR_PRIOTBL:
+ ret = woal_uap_aggr_priotbl(dev, req);
+ break;
+ case UAP_ADDBA_REJECT:
+ ret = woal_uap_addba_reject(dev, req);
+ break;
+ case UAP_FW_INFO:
+ ret = woal_uap_get_fw_info(dev, req);
+ break;
+ case UAP_DEEP_SLEEP:
+ ret = woal_uap_deep_sleep(dev, req);
+ break;
+ case UAP_TX_DATA_PAUSE:
+ ret = woal_uap_txdatapause(dev, req);
+ break;
+ case UAP_SDCMD52_RW:
+ ret = woal_uap_sdcmd52_rw(dev, req);
+ break;
+ case UAP_SNMP_MIB:
+ ret = woal_uap_snmp_mib(dev, req);
+ break;
+ case UAP_DOMAIN_INFO:
+ ret = woal_uap_domain_info(dev, req);
+ break;
+#ifdef DFS_TESTING_SUPPORT
+ case UAP_DFS_TESTING:
+ ret = woal_uap_dfs_testing(dev, req);
+ break;
+#endif
+ case UAP_TX_BF_CFG:
+ ret = woal_uap_tx_bf_cfg(dev, req);
+ break;
+ case UAP_HS_CFG:
+ ret = woal_uap_hs_cfg(dev, req, MTRUE);
+ break;
+ case UAP_HS_SET_PARA:
+ ret = woal_uap_hs_set_para(dev, req);
+ break;
+ case UAP_MGMT_FRAME_CONTROL:
+ ret = woal_uap_mgmt_frame_control(dev, req);
+ break;
+ case UAP_TX_RATE_CFG:
+ ret = woal_uap_tx_rate_cfg(dev, req);
+ break;
+ case UAP_ANTENNA_CFG:
+ ret = woal_uap_antenna_cfg(dev, req);
+ break;
+ default:
+ break;
+ }
+ done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief uap station deauth ioctl handler
+ *
+ * @param dev A pointer to net_device structure
+ * @param req A pointer to ifreq structure
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_uap_sta_deauth_ioctl(struct net_device *dev, struct ifreq *req)
+{
+ moal_private *priv = (moal_private *) netdev_priv(dev);
+ mlan_ioctl_req *ioctl_req = NULL;
+ mlan_ds_bss *bss = NULL;
+ mlan_deauth_param deauth_param;
+ int ret = 0;
+
+ ENTER();
+
+ memset(&deauth_param, 0, sizeof(mlan_deauth_param));
+ /* Sanity check */
+ if (req->ifr_data == NULL) {
+ PRINTM(MERROR, "uap_sta_deauth_ioctl() corrupt data\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ if (copy_from_user(&deauth_param, req->ifr_data, sizeof(mlan_deauth_param))) {
+ PRINTM(MERROR, "Copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+
+ PRINTM(MIOCTL,
+ "ioctl deauth station: %02x:%02x:%02x:%02x:%02x:%02x, reason=%d\n",
+ deauth_param.mac_addr[0], deauth_param.mac_addr[1],
+ deauth_param.mac_addr[2], deauth_param.mac_addr[3],
+ deauth_param.mac_addr[4], deauth_param.mac_addr[5],
+ deauth_param.reason_code);
+
+ ioctl_req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_bss));
+ if (ioctl_req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+ bss = (mlan_ds_bss *) ioctl_req->pbuf;
+
+ bss->sub_command = MLAN_OID_UAP_DEAUTH_STA;
+ ioctl_req->req_id = MLAN_IOCTL_BSS;
+ ioctl_req->action = MLAN_ACT_SET;
+
+ memcpy(&bss->param.deauth_param, &deauth_param, sizeof(mlan_deauth_param));
+ if (MLAN_STATUS_SUCCESS !=
+ woal_request_ioctl(priv, ioctl_req, MOAL_IOCTL_WAIT)) {
+ ret = -EFAULT;
+ if (copy_to_user(req->ifr_data, &ioctl_req->status_code, sizeof(t_u32)))
+ PRINTM(MERROR, "Copy to user failed!\n");
+ goto done;
+ }
+
+ done:
+ if (ioctl_req)
+ kfree(ioctl_req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set/Get radio
+ *
+ * @param dev A pointer to net_device structure
+ * @param req A pointer to ifreq structure
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_uap_radio_ctl(struct net_device *dev, struct ifreq *req)
+{
+ moal_private *priv = (moal_private *) netdev_priv(dev);
+ int ret = 0;
+ mlan_ds_radio_cfg *radio = NULL;
+ mlan_ioctl_req *mreq = NULL;
+ int data[2] = { 0, 0 };
+ mlan_bss_info bss_info;
+
+ ENTER();
+
+ /* Sanity check */
+ if (req->ifr_data == NULL) {
+ PRINTM(MERROR, "uap_radio_ctl() corrupt data\n");
+ ret = -EFAULT;
+ goto done;
+ }
+
+ /* Get user data */
+ if (copy_from_user(&data, req->ifr_data, sizeof(data))) {
+ PRINTM(MERROR, "Copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+
+ if (data[0]) {
+ mreq = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_radio_cfg));
+ if (mreq == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+ radio = (mlan_ds_radio_cfg *) mreq->pbuf;
+ radio->sub_command = MLAN_OID_RADIO_CTRL;
+ mreq->req_id = MLAN_IOCTL_RADIO_CFG;
+ mreq->action = MLAN_ACT_SET;
+ radio->param.radio_on_off = (t_u32) data[1];
+ if (MLAN_STATUS_SUCCESS !=
+ woal_request_ioctl(priv, mreq, MOAL_IOCTL_WAIT)) {
+ ret = -EFAULT;
+ }
+ if (mreq)
+ kfree(mreq);
+ } else {
+ /* Get radio status */
+ memset(&bss_info, 0, sizeof(bss_info));
+ woal_get_bss_info(priv, MOAL_IOCTL_WAIT, &bss_info);
+
+ data[1] = bss_info.radio_on;
+ if (copy_to_user(req->ifr_data, data, sizeof(data))) {
+ PRINTM(MERROR, "Copy to user failed\n");
+ ret = -EFAULT;
+ }
+ }
+ done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief uap bss control ioctl handler
+ *
+ * @param dev A pointer to net_device structure
+ * @param req A pointer to ifreq structure
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_uap_bss_ctrl_ioctl(struct net_device *dev, struct ifreq *req)
+{
+ moal_private *priv = (moal_private *) netdev_priv(dev);
+ int ret = 0, data = 0;
+
+ ENTER();
+
+ /* Sanity check */
+ if (req->ifr_data == NULL) {
+ PRINTM(MERROR, "uap_bss_ctrl() corrupt data\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ if (copy_from_user(&data, req->ifr_data, sizeof(data))) {
+ PRINTM(MERROR, "Copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+
+ ret = woal_uap_bss_ctrl(priv, MOAL_IOCTL_WAIT, data);
+
+ done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief uap power mode ioctl handler
+ *
+ * @param dev A pointer to net_device structure
+ * @param req A pointer to ifreq structure
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_uap_power_mode_ioctl(struct net_device *dev, struct ifreq *req)
+{
+ moal_private *priv = (moal_private *) netdev_priv(dev);
+ mlan_ioctl_req *ioctl_req = NULL;
+ mlan_ds_pm_cfg *pm_cfg = NULL;
+ mlan_ds_ps_mgmt ps_mgmt;
+ int ret = 0;
+
+ ENTER();
+
+ memset(&ps_mgmt, 0, sizeof(mlan_ds_ps_mgmt));
+
+ /* Sanity check */
+ if (req->ifr_data == NULL) {
+ PRINTM(MERROR, "uap_power_mode_ioctl() corrupt data\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ if (copy_from_user(&ps_mgmt, req->ifr_data, sizeof(mlan_ds_ps_mgmt))) {
+ PRINTM(MERROR, "Copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+
+ PRINTM(MIOCTL,
+ "ioctl power: flag=0x%x ps_mode=%d ctrl_bitmap=%d min_sleep=%d max_sleep=%d "
+ "inact_to=%d min_awake=%d max_awake=%d\n", ps_mgmt.flags,
+ (int) ps_mgmt.ps_mode, (int) ps_mgmt.sleep_param.ctrl_bitmap,
+ (int) ps_mgmt.sleep_param.min_sleep,
+ (int) ps_mgmt.sleep_param.max_sleep,
+ (int) ps_mgmt.inact_param.inactivity_to,
+ (int) ps_mgmt.inact_param.min_awake,
+ (int) ps_mgmt.inact_param.max_awake);
+
+ if (ps_mgmt.
+ flags & ~(PS_FLAG_PS_MODE | PS_FLAG_SLEEP_PARAM |
+ PS_FLAG_INACT_SLEEP_PARAM)) {
+ PRINTM(MERROR, "Invalid parameter: flags = 0x%x\n", ps_mgmt.flags);
+ ret = -EINVAL;
+ goto done;
+ }
+
+ if (ps_mgmt.ps_mode > PS_MODE_INACTIVITY) {
+ PRINTM(MERROR, "Invalid parameter: ps_mode = %d\n",
+ (int) ps_mgmt.flags);
+ ret = -EINVAL;
+ goto done;
+ }
+
+ ioctl_req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_pm_cfg));
+ if (ioctl_req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+ pm_cfg = (mlan_ds_pm_cfg *) ioctl_req->pbuf;
+ pm_cfg->sub_command = MLAN_OID_PM_CFG_PS_MODE;
+ ioctl_req->req_id = MLAN_IOCTL_PM_CFG;
+ if (ps_mgmt.flags) {
+ ioctl_req->action = MLAN_ACT_SET;
+ memcpy(&pm_cfg->param.ps_mgmt, &ps_mgmt, sizeof(mlan_ds_ps_mgmt));
+ } else {
+ ioctl_req->action = MLAN_ACT_GET;
+ }
+
+ if (MLAN_STATUS_SUCCESS !=
+ woal_request_ioctl(priv, ioctl_req, MOAL_IOCTL_WAIT)) {
+ ret = -EFAULT;
+ if (copy_to_user(req->ifr_data, &ioctl_req->status_code, sizeof(t_u32)))
+ PRINTM(MERROR, "Copy to user failed!\n");
+ goto done;
+ }
+ if (!ps_mgmt.flags) {
+ /* Copy to user */
+ if (copy_to_user
+ (req->ifr_data, &pm_cfg->param.ps_mgmt, sizeof(mlan_ds_ps_mgmt))) {
+ PRINTM(MERROR, "Copy to user failed!\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ }
+ done:
+ if (ioctl_req)
+ kfree(ioctl_req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief uap BSS config ioctl handler
+ *
+ * @param dev A pointer to net_device structure
+ * @param req A pointer to ifreq structure
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_uap_bss_cfg_ioctl(struct net_device *dev, struct ifreq *req)
+{
+ moal_private *priv = (moal_private *) netdev_priv(dev);
+ int ret = 0;
+ mlan_ds_bss *bss = NULL;
+ mlan_ioctl_req *ioctl_req = NULL;
+ int offset = 0;
+ t_u32 action = 0;
+
+ ENTER();
+
+ /* Sanity check */
+ if (req->ifr_data == NULL) {
+ PRINTM(MERROR, "uap_bss_cfg_ioctl() corrupt data\n");
+ ret = -EFAULT;
+ goto done;
+ }
+
+ /* Get action */
+ if (copy_from_user(&action, req->ifr_data + offset, sizeof(action))) {
+ PRINTM(MERROR, "Copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ offset += sizeof(action);
+
+ /* Allocate an IOCTL request buffer */
+ ioctl_req =
+ (mlan_ioctl_req *) woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_bss));
+ if (ioctl_req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ bss = (mlan_ds_bss *) ioctl_req->pbuf;
+ bss->sub_command = MLAN_OID_UAP_BSS_CONFIG;
+ ioctl_req->req_id = MLAN_IOCTL_BSS;
+ if (action == 1) {
+ ioctl_req->action = MLAN_ACT_SET;
+ } else {
+ ioctl_req->action = MLAN_ACT_GET;
+ }
+
+ if (ioctl_req->action == MLAN_ACT_SET) {
+ /* Get the BSS config from user */
+ if (copy_from_user
+ (&bss->param.bss_config, req->ifr_data + offset,
+ sizeof(mlan_uap_bss_param))) {
+ PRINTM(MERROR, "Copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ }
+
+ if (MLAN_STATUS_SUCCESS !=
+ woal_request_ioctl(priv, ioctl_req, MOAL_IOCTL_WAIT)) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ if (ioctl_req->action == MLAN_ACT_GET) {
+ offset = sizeof(action);
+
+ /* Copy to user : BSS config */
+ if (copy_to_user
+ (req->ifr_data + offset, &bss->param.bss_config,
+ sizeof(mlan_uap_bss_param))) {
+ PRINTM(MERROR, "Copy to user failed!\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ }
+ done:
+ if (ioctl_req)
+ kfree(ioctl_req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief uap get station list handler
+ *
+ * @param dev A pointer to net_device structure
+ * @param req A pointer to ifreq structure
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_uap_get_sta_list_ioctl(struct net_device *dev, struct ifreq *req)
+{
+ moal_private *priv = (moal_private *) netdev_priv(dev);
+ int ret = 0;
+ mlan_ds_get_info *info = NULL;
+ mlan_ioctl_req *ioctl_req = NULL;
+
+ ENTER();
+
+ /* Sanity check */
+ if (req->ifr_data == NULL) {
+ PRINTM(MERROR, "uap_get_sta_list_ioctl() corrupt data\n");
+ ret = -EFAULT;
+ goto done;
+ }
+
+ /* Allocate an IOCTL request buffer */
+ ioctl_req =
+ (mlan_ioctl_req *) woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_get_info));
+ if (ioctl_req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ info = (mlan_ds_get_info *) ioctl_req->pbuf;
+ info->sub_command = MLAN_OID_UAP_STA_LIST;
+ ioctl_req->req_id = MLAN_IOCTL_GET_INFO;
+ ioctl_req->action = MLAN_ACT_GET;
+
+ if (MLAN_STATUS_SUCCESS !=
+ woal_request_ioctl(priv, ioctl_req, MOAL_IOCTL_WAIT)) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ if (ioctl_req->action == MLAN_ACT_GET) {
+ /* Copy to user : sta_list */
+ if (copy_to_user
+ (req->ifr_data, &info->param.sta_list, sizeof(mlan_ds_sta_list))) {
+ PRINTM(MERROR, "Copy to user failed!\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ }
+ done:
+ if (ioctl_req)
+ kfree(ioctl_req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief uAP set WAPI key ioctl
+ *
+ * @param priv A pointer to moal_private structure
+ * @param msg A pointer to wapi_msg structure
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_uap_set_wapi_key_ioctl(moal_private * priv, wapi_msg * msg)
+{
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_sec_cfg *sec = NULL;
+ int ret = 0;
+ wapi_key_msg *key_msg = NULL;
+ t_u8 bcast_addr[] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
+
+ ENTER();
+ if (msg->msg_len != sizeof(wapi_key_msg)) {
+ ret = -EINVAL;
+ goto done;
+ }
+ key_msg = (wapi_key_msg *) msg->msg;
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_sec_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+ sec = (mlan_ds_sec_cfg *) req->pbuf;
+ sec->sub_command = MLAN_OID_SEC_CFG_ENCRYPT_KEY;
+ req->req_id = MLAN_IOCTL_SEC_CFG;
+ req->action = MLAN_ACT_SET;
+
+ sec->param.encrypt_key.is_wapi_key = MTRUE;
+ sec->param.encrypt_key.key_len = MLAN_MAX_KEY_LENGTH;
+ memcpy(sec->param.encrypt_key.mac_addr, key_msg->mac_addr, ETH_ALEN);
+ sec->param.encrypt_key.key_index = key_msg->key_id;
+ if (0 == memcmp(key_msg->mac_addr, bcast_addr, ETH_ALEN))
+ sec->param.encrypt_key.key_flags = KEY_FLAG_GROUP_KEY;
+ else
+ sec->param.encrypt_key.key_flags = KEY_FLAG_SET_TX_KEY;
+ memcpy(sec->param.encrypt_key.key_material, key_msg->key,
+ sec->param.encrypt_key.key_len);
+
+ if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT))
+ ret = -EFAULT;
+ done:
+ if (req)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Enable/Disable wapi in firmware
+ *
+ * @param priv A pointer to moal_private structure
+ * @param enable MTRUE/MFALSE
+ *
+ * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING -- success, otherwise fail
+ */
+static mlan_status
+woal_enable_wapi(moal_private * priv, t_u8 enable)
+{
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_bss *bss = NULL;
+ mlan_status status;
+
+ ENTER();
+
+ /* Allocate an IOCTL request buffer */
+ req = (mlan_ioctl_req *) woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_bss));
+ if (req == NULL) {
+ status = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ /* Fill request buffer */
+ bss = (mlan_ds_bss *) req->pbuf;
+ bss->sub_command = MLAN_OID_UAP_BSS_CONFIG;
+ req->req_id = MLAN_IOCTL_BSS;
+ req->action = MLAN_ACT_GET;
+
+ /* Send IOCTL request to MLAN */
+ status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
+ if (status != MLAN_STATUS_SUCCESS) {
+ PRINTM(MERROR, "Get AP setting failed! status=%d, error_code=0x%x\n",
+ status, req->status_code);
+ }
+
+ /* Change AP default setting */
+ req->action = MLAN_ACT_SET;
+ if (enable == MFALSE) {
+ bss->param.bss_config.auth_mode = MLAN_AUTH_MODE_OPEN;
+ bss->param.bss_config.protocol = PROTOCOL_NO_SECURITY;
+ } else {
+ bss->param.bss_config.auth_mode = MLAN_AUTH_MODE_OPEN;
+ bss->param.bss_config.protocol = PROTOCOL_WAPI;
+ }
+
+ /* Send IOCTL request to MLAN */
+ status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
+ if (status != MLAN_STATUS_SUCCESS) {
+ PRINTM(MERROR, "Set AP setting failed! status=%d, error_code=0x%x\n",
+ status, req->status_code);
+ }
+ if (enable)
+ woal_uap_bss_ctrl(priv, MOAL_IOCTL_WAIT, UAP_BSS_START);
+ done:
+ if (req)
+ kfree(req);
+ LEAVE();
+ return status;
+}
+
+/**
+ * @brief uAP set WAPI flag ioctl
+ *
+ * @param priv A pointer to moal_private structure
+ * @param msg A pointer to wapi_msg structure
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_uap_set_wapi_flag_ioctl(moal_private * priv, wapi_msg * msg)
+{
+ t_u8 wapi_psk_ie[] =
+ { 0x44, 0x14, 0x01, 0x00, 0x01, 0x00, 0x00, 0x14, 0x72, 0x02,
+ 0x01, 0x00, 0x00, 0x14, 0x72, 0x01, 0x00, 0x14, 0x72, 0x01,
+ 0x00, 0x00
+ };
+ t_u8 wapi_cert_ie[] =
+ { 0x44, 0x14, 0x01, 0x00, 0x01, 0x00, 0x00, 0x14, 0x72, 0x01,
+ 0x01, 0x00, 0x00, 0x14, 0x72, 0x01, 0x00, 0x14, 0x72, 0x01,
+ 0x00, 0x00
+ };
+ mlan_ds_misc_cfg *misc = NULL;
+ mlan_ioctl_req *req = NULL;
+ int ret = 0;
+
+ ENTER();
+
+ woal_uap_bss_ctrl(priv, MOAL_IOCTL_WAIT, UAP_BSS_STOP);
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+ misc = (mlan_ds_misc_cfg *) req->pbuf;
+ misc->sub_command = MLAN_OID_MISC_GEN_IE;
+ req->req_id = MLAN_IOCTL_MISC_CFG;
+ req->action = MLAN_ACT_SET;
+
+ misc->param.gen_ie.type = MLAN_IE_TYPE_GEN_IE;
+ misc->param.gen_ie.len = sizeof(wapi_psk_ie);
+ if (msg->msg[0] & WAPI_MODE_PSK) {
+ memcpy(misc->param.gen_ie.ie_data, wapi_psk_ie, misc->param.gen_ie.len);
+ } else if (msg->msg[0] & WAPI_MODE_CERT) {
+ memcpy(misc->param.gen_ie.ie_data, wapi_cert_ie,
+ misc->param.gen_ie.len);
+ } else if (msg->msg[0] == 0) {
+ /* disable WAPI in driver */
+ if (MLAN_STATUS_SUCCESS !=
+ woal_set_wapi_enable(priv, MOAL_IOCTL_WAIT, 0))
+ ret = -EFAULT;
+ woal_enable_wapi(priv, MFALSE);
+ goto done;
+ } else {
+ ret = -EINVAL;
+ goto done;
+ }
+ if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ woal_enable_wapi(priv, MTRUE);
+ done:
+ if (req)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief set wapi ioctl function
+ *
+ * @param dev A pointer to net_device structure
+ * @param req A pointer to ifreq structure
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_uap_set_wapi(struct net_device *dev, struct ifreq *req)
+{
+ moal_private *priv = (moal_private *) netdev_priv(dev);
+ wapi_msg msg;
+ int ret = 0;
+
+ ENTER();
+
+ /* Sanity check */
+ if (req->ifr_data == NULL) {
+ PRINTM(MERROR, "uap_set_wapi() corrupt data\n");
+ ret = -EFAULT;
+ goto done;
+ }
+
+ memset(&msg, 0, sizeof(msg));
+
+ if (copy_from_user(&msg, req->ifr_data, sizeof(msg))) {
+ PRINTM(MERROR, "Copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+
+ PRINTM(MIOCTL, "set wapi msg_type = %d, msg_len=%d\n", msg.msg_type,
+ msg.msg_len);
+ DBG_HEXDUMP(MCMD_D, "wapi msg", msg.msg, MIN(msg.msg_len, sizeof(msg.msg)));
+
+ switch (msg.msg_type) {
+ case P80211_PACKET_WAPIFLAG:
+ ret = woal_uap_set_wapi_flag_ioctl(priv, &msg);
+ break;
+ case P80211_PACKET_SETKEY:
+ ret = woal_uap_set_wapi_key_ioctl(priv, &msg);
+ break;
+ default:
+ ret = -EOPNOTSUPP;
+ break;
+ }
+ done:
+ LEAVE();
+ return ret;
+}
+
+/********************************************************
+ Global Functions
+********************************************************/
+/**
+ * @brief Initialize the members of mlan_uap_bss_param
+ * which are uploaded from firmware
+ *
+ * @param priv A pointer to moal_private structure
+ * @param sys_cfg A pointer to mlan_uap_bss_param structure
+ * @param wait_option Wait option
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status
+woal_uap_get_bss_param(moal_private * priv, mlan_uap_bss_param * sys_cfg,
+ t_u8 wait_option)
+{
+ mlan_ds_bss *info = NULL;
+ mlan_ioctl_req *req = NULL;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_bss));
+ if (req == NULL) {
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+
+ info = (mlan_ds_bss *) req->pbuf;
+ info->sub_command = MLAN_OID_UAP_BSS_CONFIG;
+ req->req_id = MLAN_IOCTL_BSS;
+ req->action = MLAN_ACT_GET;
+
+ status = woal_request_ioctl(priv, req, wait_option);
+ if (status != MLAN_STATUS_SUCCESS) {
+ PRINTM(MERROR, "Get bss info failed!\n");
+ status = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ memcpy(sys_cfg, &info->param.bss_config, sizeof(mlan_uap_bss_param));
+
+ done:
+ if (req && (status != MLAN_STATUS_PENDING))
+ kfree(req);
+
+ LEAVE();
+ return status;
+}
+
+/**
+ * @brief Set 11n status based on the configured security mode
+ *
+ * @param sys_cfg A pointer to mlan_uap_bss_param structure
+ * @param action MLAN_ACT_DISABLE or MLAN_ACT_ENABLE
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status
+woal_uap_set_11n_status(mlan_uap_bss_param * sys_cfg, t_u8 action)
+{
+ mlan_status status = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+ if (action == MLAN_ACT_DISABLE) {
+ if ((sys_cfg->supported_mcs_set[0] == 0)
+ && (sys_cfg->supported_mcs_set[4] == 0)
+ && (sys_cfg->supported_mcs_set[1] == 0)
+ ) {
+ goto done;
+ } else {
+ sys_cfg->supported_mcs_set[0] = 0;
+ sys_cfg->supported_mcs_set[4] = 0;
+ sys_cfg->supported_mcs_set[1] = 0;
+ }
+ }
+
+ if (action == MLAN_ACT_ENABLE) {
+ if ((sys_cfg->supported_mcs_set[0] != 0)
+ || (sys_cfg->supported_mcs_set[4] != 0)
+ || (sys_cfg->supported_mcs_set[1] != 0)
+ ) {
+ goto done;
+ } else {
+ sys_cfg->supported_mcs_set[0] = 0xFF;
+ sys_cfg->supported_mcs_set[4] = 0x01;
+ sys_cfg->supported_mcs_set[1] = 0xFF;
+ }
+ }
+
+ done:
+ LEAVE();
+ return status;
+}
+
+/**
+ * @brief Parse AP configuration from ASCII string
+ *
+ * @param ap_cfg A pointer to mlan_uap_bss_param structure
+ * @param buf A pointer to user data
+ *
+ * @return 0 --success, otherwise fail
+ */
+int
+woal_uap_ap_cfg_parse_data(mlan_uap_bss_param * ap_cfg, t_s8 * buf)
+{
+ int ret = 0, atoi_ret;
+ int set_sec = 0, set_key = 0, set_chan = 0;
+ int set_preamble = 0, set_scb = 0, set_ssid = 0;
+ t_s8 *begin = buf, *value = NULL, *opt = NULL;
+
+ ENTER();
+
+ while (begin) {
+ value = woal_strsep(&begin, ',', '/');
+ opt = woal_strsep(&value, '=', '/');
+ if (opt && !strncmp(opt, "END", strlen("END"))) {
+ if (!ap_cfg->ssid.ssid_len) {
+ PRINTM(MERROR, "Minimum option required is SSID\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ PRINTM(MINFO, "Parsing terminated by string END\n");
+ break;
+ }
+ if (!opt || !value || !value[0]) {
+ PRINTM(MERROR, "Invalid option\n");
+ ret = -EINVAL;
+ goto done;
+ } else if (!strncmp(opt, "ASCII_CMD", strlen("ASCII_CMD"))) {
+ if (strncmp(value, "AP_CFG", strlen("AP_CFG"))) {
+ PRINTM(MERROR, "ASCII_CMD: %s not matched with AP_CFG\n",
+ value);
+ ret = -EFAULT;
+ goto done;
+ }
+ value = woal_strsep(&begin, ',', '/');
+ opt = woal_strsep(&value, '=', '/');
+ if (!opt || !value || !value[0]) {
+ PRINTM(MERROR, "Minimum option required is SSID\n");
+ ret = -EINVAL;
+ goto done;
+ } else if (!strncmp(opt, "SSID", strlen("SSID"))) {
+ if (set_ssid) {
+ PRINTM(MWARN, "Skipping SSID, found again!\n");
+ continue;
+ }
+ if (strlen(value) > MLAN_MAX_SSID_LENGTH) {
+ PRINTM(MERROR, "SSID length exceeds max length\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ ap_cfg->ssid.ssid_len = strlen(value);
+ strncpy((char *) ap_cfg->ssid.ssid, value, strlen(value));
+ PRINTM(MINFO, "ssid=%s, len=%d\n", ap_cfg->ssid.ssid,
+ (int) ap_cfg->ssid.ssid_len);
+ set_ssid = 1;
+ } else {
+ PRINTM(MERROR, "AP_CFG: Invalid option %s, "
+ "expect SSID\n", opt);
+ ret = -EINVAL;
+ goto done;
+ }
+ } else if (!strncmp(opt, "SEC", strlen("SEC"))) {
+ if (set_sec) {
+ PRINTM(MWARN, "Skipping SEC, found again!\n");
+ continue;
+ }
+ if (!strnicmp(value, "open", strlen("open"))) {
+ ap_cfg->auth_mode = MLAN_AUTH_MODE_OPEN;
+ if (set_key)
+ ap_cfg->wpa_cfg.length = 0;
+ ap_cfg->key_mgmt = KEY_MGMT_NONE;
+ ap_cfg->protocol = PROTOCOL_NO_SECURITY;
+ } else if (!strnicmp(value, "wpa2-psk", strlen("wpa2-psk"))) {
+ ap_cfg->auth_mode = MLAN_AUTH_MODE_OPEN;
+ ap_cfg->protocol = PROTOCOL_WPA2;
+ ap_cfg->key_mgmt = KEY_MGMT_PSK;
+ ap_cfg->wpa_cfg.pairwise_cipher_wpa = CIPHER_AES_CCMP;
+ ap_cfg->wpa_cfg.pairwise_cipher_wpa2 = CIPHER_AES_CCMP;
+ ap_cfg->wpa_cfg.group_cipher = CIPHER_AES_CCMP;
+ } else if (!strnicmp(value, "wpa-psk", strlen("wpa-psk"))) {
+ ap_cfg->auth_mode = MLAN_AUTH_MODE_OPEN;
+ ap_cfg->protocol = PROTOCOL_WPA;
+ ap_cfg->key_mgmt = KEY_MGMT_PSK;
+ ap_cfg->wpa_cfg.pairwise_cipher_wpa = CIPHER_TKIP;
+ ap_cfg->wpa_cfg.group_cipher = CIPHER_TKIP;
+ } else if (!strnicmp(value, "wep128", strlen("wep128"))) {
+ ap_cfg->auth_mode = MLAN_AUTH_MODE_OPEN;
+ if (set_key)
+ ap_cfg->wpa_cfg.length = 0;
+ ap_cfg->key_mgmt = KEY_MGMT_NONE;
+ ap_cfg->protocol = PROTOCOL_STATIC_WEP;
+ } else {
+ PRINTM(MERROR, "AP_CFG: Invalid value=%s for %s\n", value, opt);
+ ret = -EFAULT;
+ goto done;
+ }
+ set_sec = 1;
+ } else if (!strncmp(opt, "KEY", strlen("KEY"))) {
+ if (set_key) {
+ PRINTM(MWARN, "Skipping KEY, found again!\n");
+ continue;
+ }
+ if (set_sec && ap_cfg->protocol == PROTOCOL_STATIC_WEP) {
+ if (strlen(value) != MAX_WEP_KEY_SIZE) {
+ PRINTM(MERROR, "Invalid WEP KEY length\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ ap_cfg->wep_cfg.key0.key_index = 0;
+ ap_cfg->wep_cfg.key0.is_default = 1;
+ ap_cfg->wep_cfg.key0.length = strlen(value);
+ memcpy(ap_cfg->wep_cfg.key0.key, value, strlen(value));
+ set_key = 1;
+ continue;
+ }
+ if (set_sec && ap_cfg->protocol != PROTOCOL_WPA2
+ && ap_cfg->protocol != PROTOCOL_WPA) {
+ PRINTM(MWARN, "Warning! No KEY for open mode\n");
+ set_key = 1;
+ continue;
+ }
+ if (strlen(value) < MLAN_MIN_PASSPHRASE_LENGTH ||
+ strlen(value) > MLAN_PMK_HEXSTR_LENGTH) {
+ PRINTM(MERROR, "Invalid PSK/PMK length\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ ap_cfg->wpa_cfg.length = strlen(value);
+ memcpy(ap_cfg->wpa_cfg.passphrase, value, strlen(value));
+ set_key = 1;
+ } else if (!strncmp(opt, "CHANNEL", strlen("CHANNEL"))) {
+ if (set_chan) {
+ PRINTM(MWARN, "Skipping CHANNEL, found again!\n");
+ continue;
+ }
+ if (woal_atoi(&atoi_ret, value)) {
+ ret = -EINVAL;
+ goto done;
+ }
+ if (atoi_ret < 1 || atoi_ret > MLAN_MAX_CHANNEL) {
+ PRINTM(MERROR, "AP_CFG: Channel must be between 1 and %d"
+ "(both included)\n", MLAN_MAX_CHANNEL);
+ ret = -EINVAL;
+ goto done;
+ }
+ ap_cfg->channel = atoi_ret;
+ set_chan = 1;
+ } else if (!strncmp(opt, "PREAMBLE", strlen("PREAMBLE"))) {
+ if (set_preamble) {
+ PRINTM(MWARN, "Skipping PREAMBLE, found again!\n");
+ continue;
+ }
+ if (woal_atoi(&atoi_ret, value)) {
+ ret = -EINVAL;
+ goto done;
+ }
+ /* This is a READ only value from FW, so we can not set this and
+ pass it successfully */
+ set_preamble = 1;
+ } else if (!strncmp(opt, "MAX_SCB", strlen("MAX_SCB"))) {
+ if (set_scb) {
+ PRINTM(MWARN, "Skipping MAX_SCB, found again!\n");
+ continue;
+ }
+ if (woal_atoi(&atoi_ret, value)) {
+ ret = -EINVAL;
+ goto done;
+ }
+ if (atoi_ret < 1 || atoi_ret > MAX_STA_COUNT) {
+ PRINTM(MERROR, "AP_CFG: MAX_SCB must be between 1 to %d "
+ "(both included)\n", MAX_STA_COUNT);
+ ret = -EINVAL;
+ goto done;
+ }
+ ap_cfg->max_sta_count = (t_u16) atoi_ret;
+ set_scb = 1;
+ } else {
+ PRINTM(MERROR, "Invalid option %s\n", opt);
+ ret = -EINVAL;
+ goto done;
+ }
+ }
+
+ done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set AP configuration
+ *
+ * @param priv A pointer to moal_private structure
+ * @param data A pointer to user data
+ * @param len Length of buf
+ *
+ * @return 0 --success, otherwise fail
+ */
+int
+woal_uap_set_ap_cfg(moal_private * priv, t_u8 * data, int len)
+{
+ int ret = 0;
+ static t_s8 buf[MAX_BUF_LEN];
+ mlan_uap_bss_param sys_config;
+ int restart = 0;
+
+ ENTER();
+
+#define MIN_AP_CFG_CMD_LEN 16 /* strlen("ASCII_CMD=AP_CFG") */
+ if ((len - 1) <= MIN_AP_CFG_CMD_LEN) {
+ PRINTM(MERROR, "Invalid length of command\n");
+ ret = -EINVAL;
+ goto done;
+ }
+
+ memset(buf, 0, MAX_BUF_LEN);
+ memcpy(buf, data, len);
+
+ /* Initialize the uap bss values which are uploaded from firmware */
+ woal_uap_get_bss_param(priv, &sys_config, MOAL_IOCTL_WAIT);
+
+ /* Setting the default values */
+ sys_config.channel = 6;
+ sys_config.preamble_type = 0;
+
+ if ((ret = woal_uap_ap_cfg_parse_data(&sys_config, buf)))
+ goto done;
+
+ /* If BSS already started stop it first and restart after changing the
+ setting */
+ if (priv->bss_started == MTRUE) {
+ if ((ret = woal_uap_bss_ctrl(priv, MOAL_IOCTL_WAIT, UAP_BSS_STOP)))
+ goto done;
+ restart = 1;
+ }
+
+ /* If the security mode is configured as WEP or WPA-PSK, it will disable
+ 11n automatically, and if configured as open(off) or wpa2-psk, it will
+ automatically enable 11n */
+ if ((sys_config.protocol == PROTOCOL_STATIC_WEP) ||
+ (sys_config.protocol == PROTOCOL_WPA)) {
+ if (MLAN_STATUS_SUCCESS !=
+ woal_uap_set_11n_status(&sys_config, MLAN_ACT_DISABLE)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ } else {
+ if (MLAN_STATUS_SUCCESS !=
+ woal_uap_set_11n_status(&sys_config, MLAN_ACT_ENABLE)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ }
+
+ if (MLAN_STATUS_SUCCESS !=
+ woal_set_get_sys_config(priv, MLAN_ACT_SET, MOAL_IOCTL_WAIT,
+ &sys_config)) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ /* Start the BSS after successful configuration */
+ if (restart)
+ ret = woal_uap_bss_ctrl(priv, MOAL_IOCTL_WAIT, UAP_BSS_START);
+
+ done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief uap BSS control ioctl handler
+ *
+ * @param priv A pointer to moal_private structure
+ * @param wait_option Wait option
+ * @param data BSS control type
+ * @return 0 --success, otherwise fail
+ */
+int
+woal_uap_bss_ctrl(moal_private * priv, t_u8 wait_option, int data)
+{
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_bss *bss = NULL;
+ int ret = 0;
+
+ ENTER();
+
+ PRINTM(MIOCTL, "ioctl bss ctrl=%d\n", data);
+ if ((data != UAP_BSS_START) && (data != UAP_BSS_STOP) &&
+ (data != UAP_BSS_RESET)) {
+ PRINTM(MERROR, "Invalid parameter: %d\n", data);
+ ret = -EINVAL;
+ goto done;
+ }
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_bss));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+ bss = (mlan_ds_bss *) req->pbuf;
+ switch (data) {
+ case UAP_BSS_START:
+ if (priv->bss_started == MTRUE) {
+ PRINTM(MWARN, "Warning: BSS already started!\n");
+ // goto done;
+ } else {
+ /* about to start bss: issue channel check */
+ woal_11h_channel_check_ioctl(priv);
+ }
+ bss->sub_command = MLAN_OID_BSS_START;
+ break;
+ case UAP_BSS_STOP:
+ if (priv->bss_started == MFALSE) {
+ PRINTM(MWARN, "Warning: BSS already stopped!\n");
+ // goto done;
+ }
+ bss->sub_command = MLAN_OID_BSS_STOP;
+ break;
+ case UAP_BSS_RESET:
+ bss->sub_command = MLAN_OID_UAP_BSS_RESET;
+ woal_cancel_cac_block(priv);
+ break;
+ }
+ req->req_id = MLAN_IOCTL_BSS;
+ req->action = MLAN_ACT_SET;
+
+ if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ if (data == UAP_BSS_STOP || data == UAP_BSS_RESET)
+ priv->bss_started = MFALSE;
+
+ done:
+ if (req)
+ kfree(req);
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function sets multicast addresses to firmware
+ *
+ * @param dev A pointer to net_device structure
+ * @return N/A
+ */
+void
+woal_uap_set_multicast_list(struct net_device *dev)
+{
+ ENTER();
+
+ LEAVE();
+}
+
+/**
+ * @brief ioctl function - entry point
+ *
+ * @param dev A pointer to net_device structure
+ * @param req A pointer to ifreq structure
+ * @param cmd Command
+ *
+ * @return 0 --success, otherwise fail
+ */
+int
+woal_uap_do_ioctl(struct net_device *dev, struct ifreq *req, int cmd)
+{
+ int ret = 0;
+ ENTER();
+ PRINTM(MIOCTL, "uap_do_ioctl: ioctl cmd = 0x%x\n", cmd);
+ switch (cmd) {
+ case UAP_HOSTCMD:
+ ret = woal_hostcmd_ioctl(dev, req);
+ break;
+ case UAP_IOCTL_CMD:
+ ret = woal_uap_ioctl(dev, req);
+ break;
+ case UAP_POWER_MODE:
+ ret = woal_uap_power_mode_ioctl(dev, req);
+ break;
+ case UAP_BSS_CTRL:
+ ret = woal_uap_bss_ctrl_ioctl(dev, req);
+ break;
+ case UAP_WAPI_MSG:
+ ret = woal_uap_set_wapi(dev, req);
+ break;
+ case UAP_BSS_CONFIG:
+ ret = woal_uap_bss_cfg_ioctl(dev, req);
+ break;
+ case UAP_STA_DEAUTH:
+ ret = woal_uap_sta_deauth_ioctl(dev, req);
+ break;
+ case UAP_RADIO_CTL:
+ ret = woal_uap_radio_ctl(dev, req);
+ break;
+ case UAP_GET_STA_LIST:
+ ret = woal_uap_get_sta_list_ioctl(dev, req);
+ break;
+ case UAP_CUSTOM_IE:
+ ret = woal_custom_ie_ioctl(dev, req);
+ break;
+ case UAP_GET_BSS_TYPE:
+ ret = woal_get_bss_type(dev, req);
+ break;
+ case WOAL_ANDROID_PRIV_CMD:
+ ret = woal_android_priv_cmd(dev, req);
+ break;
+ default:
+#ifdef UAP_WEXT
+ ret = woal_uap_do_priv_ioctl(dev, req, cmd);
+#else
+ ret = -EOPNOTSUPP;
+#endif
+ break;
+ }
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Get version
+ *
+ * @param priv A pointer to moal_private structure
+ * @param version A pointer to version buffer
+ * @param max_len max length of version buffer
+ *
+ * @return N/A
+ */
+void
+woal_uap_get_version(moal_private * priv, char *version, int max_len)
+{
+ mlan_ds_get_info *info = NULL;
+ mlan_ioctl_req *req = NULL;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_get_info));
+ if (req == NULL) {
+ LEAVE();
+ return;
+ }
+
+ info = (mlan_ds_get_info *) req->pbuf;
+ info->sub_command = MLAN_OID_GET_VER_EXT;
+ req->req_id = MLAN_IOCTL_GET_INFO;
+ req->action = MLAN_ACT_GET;
+
+ status = woal_request_ioctl(priv, req, MOAL_PROC_WAIT);
+ if (status == MLAN_STATUS_SUCCESS) {
+ PRINTM(MINFO, "MOAL UAP VERSION: %s\n",
+ info->param.ver_ext.version_str);
+ snprintf(version, max_len, driver_version,
+ info->param.ver_ext.version_str);
+ }
+
+ if (req && (status != MLAN_STATUS_PENDING))
+ kfree(req);
+
+ LEAVE();
+ return;
+}
+
+/**
+ * @brief Get uap statistics
+ *
+ * @param priv A pointer to moal_private structure
+ * @param wait_option Wait option
+ * @param ustats A pointer to mlan_ds_uap_stats structure
+ *
+ * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING -- success, otherwise fail
+ */
+mlan_status
+woal_uap_get_stats(moal_private * priv, t_u8 wait_option,
+ mlan_ds_uap_stats * ustats)
+{
+ mlan_ds_get_info *info = NULL;
+ mlan_ioctl_req *req = NULL;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_get_info));
+ if (req == NULL) {
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+
+ info = (mlan_ds_get_info *) req->pbuf;
+ info->sub_command = MLAN_OID_GET_STATS;
+ req->req_id = MLAN_IOCTL_GET_INFO;
+ req->action = MLAN_ACT_GET;
+
+ status = woal_request_ioctl(priv, req, wait_option);
+ if (status == MLAN_STATUS_SUCCESS) {
+ if (ustats)
+ memcpy(ustats, &info->param.ustats, sizeof(mlan_ds_uap_stats));
+#ifdef UAP_WEXT
+ priv->w_stats.discard.fragment = info->param.ustats.fcs_error_count;
+ priv->w_stats.discard.retries = info->param.ustats.retry_count;
+ priv->w_stats.discard.misc = info->param.ustats.ack_failure_count;
+#endif
+ }
+
+ if (req && (status != MLAN_STATUS_PENDING))
+ kfree(req);
+
+ LEAVE();
+ return status;
+}
+
+/**
+ * @brief Set/Get system configuration parameters
+ *
+ * @param priv A pointer to moal_private structure
+ * @param action MLAN_ACT_SET or MLAN_ACT_GET
+ * @param wait_option Wait option
+ * @param sys_cfg A pointer to mlan_uap_bss_param structure
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status
+woal_set_get_sys_config(moal_private * priv, t_u16 action, t_u8 wait_option,
+ mlan_uap_bss_param * sys_cfg)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_ds_bss *bss = NULL;
+ mlan_ioctl_req *req = NULL;
+
+ ENTER();
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_bss));
+ if (req == NULL) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ bss = (mlan_ds_bss *) req->pbuf;
+ bss->sub_command = MLAN_OID_UAP_BSS_CONFIG;
+ req->req_id = MLAN_IOCTL_BSS;
+ req->action = action;
+
+ if (action == MLAN_ACT_SET) {
+ memcpy(&bss->param.bss_config, sys_cfg, sizeof(mlan_uap_bss_param));
+ }
+
+ if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, wait_option)) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ if (action == MLAN_ACT_GET) {
+ memcpy(sys_cfg, &bss->param.bss_config, sizeof(mlan_uap_bss_param));
+ }
+
+ done:
+ if (req)
+ kfree(req);
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set invalid data for each member of mlan_uap_bss_param
+ * structure
+ *
+ * @param config A pointer to mlan_uap_bss_param structure
+ *
+ * @return N/A
+ */
+void
+woal_set_sys_config_invalid_data(mlan_uap_bss_param * config)
+{
+ ENTER();
+
+ memset(config, 0, sizeof(mlan_uap_bss_param));
+ config->bcast_ssid_ctl = 0x7F;
+ config->radio_ctl = 0x7F;
+ config->dtim_period = 0x7F;
+ config->beacon_period = 0x7FFF;
+ config->tx_data_rate = 0x7FFF;
+ config->mcbc_data_rate = 0x7FFF;
+ config->tx_power_level = 0x7F;
+ config->tx_antenna = 0x7F;
+ config->rx_antenna = 0x7F;
+ config->pkt_forward_ctl = 0x7F;
+ config->max_sta_count = 0x7FFF;
+ config->auth_mode = 0x7F;
+ config->sta_ageout_timer = 0x7FFFFFFF;
+ config->pairwise_update_timeout = 0x7FFFFFFF;
+ config->pwk_retries = 0x7FFFFFFF;
+ config->groupwise_update_timeout = 0x7FFFFFFF;
+ config->gwk_retries = 0x7FFFFFFF;
+ config->mgmt_ie_passthru_mask = 0x7FFFFFFF;
+ config->ps_sta_ageout_timer = 0x7FFFFFFF;
+ config->rts_threshold = 0x7FFF;
+ config->frag_threshold = 0x7FFF;
+ config->retry_limit = 0x7FFF;
+ config->filter.filter_mode = 0x7FFF;
+ config->filter.mac_count = 0x7FFF;
+ config->wpa_cfg.rsn_protection = 0x7F;
+ config->wpa_cfg.gk_rekey_time = 0x7FFFFFFF;
+ config->enable_2040coex = 0x7F;
+ config->wmm_para.qos_info = 0x7F;
+
+ LEAVE();
+}
diff --git a/drivers/net/wireless/sd8797/mlinux/moal_uap.h b/drivers/net/wireless/sd8797/mlinux/moal_uap.h
new file mode 100644
index 000000000000..a30d0ceec87f
--- /dev/null
+++ b/drivers/net/wireless/sd8797/mlinux/moal_uap.h
@@ -0,0 +1,410 @@
+/** @file moal_uap.h
+ *
+ * @brief This file contains uap driver specific defines etc.
+ *
+ * Copyright (C) 2009-2011, Marvell International Ltd.
+ *
+ * This software file (the "File") is distributed by Marvell International
+ * Ltd. under the terms of the GNU General Public License Version 2, June 1991
+ * (the "License"). You may use, redistribute and/or modify this File in
+ * accordance with the terms and conditions of the License, a copy of which
+ * is available by writing to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
+ * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
+ *
+ * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
+ * ARE EXPRESSLY DISCLAIMED. The License provides additional details about
+ * this warranty disclaimer.
+ *
+ */
+
+/********************************************************
+Change log:
+ 02/02/2009: initial version
+********************************************************/
+
+#ifndef _MOAL_UAP_H
+#define _MOAL_UAP_H
+
+/** Maximum buffer length for WOAL_UAP_SET_GET_256_CHAR */
+#define MAX_BUF_LEN 256
+
+/** Private command ID to Host command */
+#define UAP_HOSTCMD (SIOCDEVPRIVATE + 1)
+/** Private command ID to send ioctl */
+#define UAP_IOCTL_CMD (SIOCDEVPRIVATE + 2)
+/** Updating ADDBA variables */
+#define UAP_ADDBA_PARA 0
+/** Updating priority table for AMPDU/AMSDU */
+#define UAP_AGGR_PRIOTBL 1
+/** Updating addbareject table */
+#define UAP_ADDBA_REJECT 2
+/** Get FW INFO */
+#define UAP_FW_INFO 4
+/** Updating Deep sleep variables */
+#define UAP_DEEP_SLEEP 3
+/** Tx data pause subcommand */
+#define UAP_TX_DATA_PAUSE 5
+/** sdcmd52 read write subcommand */
+#define UAP_SDCMD52_RW 6
+/** snmp mib subcommand */
+#define UAP_SNMP_MIB 7
+/** domain info subcommand */
+#define UAP_DOMAIN_INFO 8
+/** TX beamforming configuration */
+#define UAP_TX_BF_CFG 9
+#ifdef DFS_TESTING_SUPPORT
+/** dfs testing subcommand */
+#define UAP_DFS_TESTING 10
+#endif
+/** sub command ID to set/get Host Sleep configuration */
+#define UAP_HS_CFG 11
+/** sub command ID to set/get Host Sleep Parameters */
+#define UAP_HS_SET_PARA 12
+
+/** Management Frame Control Mask */
+#define UAP_MGMT_FRAME_CONTROL 13
+
+#define UAP_TX_RATE_CFG 14
+
+/** Subcommand ID to set/get antenna configuration */
+#define UAP_ANTENNA_CFG 15
+
+/** Private command ID to Power Mode */
+#define UAP_POWER_MODE (SIOCDEVPRIVATE + 3)
+
+/** Private command id to start/stop/reset bss */
+#define UAP_BSS_CTRL (SIOCDEVPRIVATE + 4)
+/** BSS START */
+#define UAP_BSS_START 0
+/** BSS STOP */
+#define UAP_BSS_STOP 1
+/** BSS RESET */
+#define UAP_BSS_RESET 2
+/** Band config 5GHz */
+#define BAND_CONFIG_5GHZ 0x01
+
+/** wapi_msg */
+typedef struct _wapi_msg
+{
+ /** message type */
+ t_u16 msg_type;
+ /** message len */
+ t_u16 msg_len;
+ /** message */
+ t_u8 msg[96];
+} wapi_msg;
+
+/* wapi key msg */
+typedef struct _wapi_key_msg
+{
+ /** mac address */
+ t_u8 mac_addr[MLAN_MAC_ADDR_LENGTH];
+ /** pad */
+ t_u8 pad;
+ /** key id */
+ t_u8 key_id;
+ /** key */
+ t_u8 key[32];
+} wapi_key_msg;
+
+typedef struct _tx_rate_cfg_t
+{
+ /** sub command */
+ int subcmd;
+ /** Action */
+ int action;
+ /** Rate configured */
+ int rate;
+ /** Rate bitmap */
+ t_u16 bitmap_rates[MAX_BITMAP_RATES_SIZE];
+} tx_rate_cfg_t;
+
+/** ant_cfg structure */
+typedef struct _ant_cfg_t
+{
+ /** Subcommand */
+ int subcmd;
+ /** Action */
+ int action;
+ /** TX mode configured */
+ int tx_mode;
+ /** RX mode configured */
+ int rx_mode;
+} ant_cfg_t;
+
+/** Private command ID to set wapi info */
+#define UAP_WAPI_MSG (SIOCDEVPRIVATE + 10)
+/** set wapi flag */
+#define P80211_PACKET_WAPIFLAG 0x0001
+/** set wapi key */
+#define P80211_PACKET_SETKEY 0x0003
+/** wapi mode psk */
+#define WAPI_MODE_PSK 0x04
+/** wapi mode certificate */
+#define WAPI_MODE_CERT 0x08
+
+/** radio control command */
+#define UAP_RADIO_CTL (SIOCDEVPRIVATE + 5)
+
+/** Private command ID to BSS config */
+#define UAP_BSS_CONFIG (SIOCDEVPRIVATE + 6)
+
+/** deauth station */
+#define UAP_STA_DEAUTH (SIOCDEVPRIVATE + 7)
+
+/** uap get station list */
+#define UAP_GET_STA_LIST (SIOCDEVPRIVATE + 11)
+
+/** Private command ID to set/get custom IE buffer */
+#define UAP_CUSTOM_IE (SIOCDEVPRIVATE + 13)
+
+/** HS WAKE UP event id */
+#define UAP_EVENT_ID_HS_WAKEUP 0x80000001
+/** HS_ACTIVATED event id */
+#define UAP_EVENT_ID_DRV_HS_ACTIVATED 0x80000002
+/** HS DEACTIVATED event id */
+#define UAP_EVENT_ID_DRV_HS_DEACTIVATED 0x80000003
+
+/** Host sleep flag set */
+#define HS_CFG_FLAG_GET 0
+/** Host sleep flag get */
+#define HS_CFG_FLAG_SET 1
+/** Host sleep flag for condition */
+#define HS_CFG_FLAG_CONDITION 2
+/** Host sleep flag for GPIO */
+#define HS_CFG_FLAG_GPIO 4
+/** Host sleep flag for Gap */
+#define HS_CFG_FLAG_GAP 8
+/** Host sleep flag for all */
+#define HS_CFG_FLAG_ALL 0x0f
+/** Host sleep mask to get condition */
+#define HS_CFG_CONDITION_MASK 0x0f
+
+/** ds_hs_cfg */
+typedef struct _ds_hs_cfg
+{
+ /** subcmd */
+ t_u32 subcmd;
+ /** Bit0: 0 - Get, 1 Set
+ * Bit1: 1 - conditions is valid
+ * Bit2: 2 - gpio is valid
+ * Bit3: 3 - gap is valid
+ */
+ t_u32 flags;
+ /** Host sleep config condition */
+ /** Bit0: non-unicast data
+ * Bit1: unicast data
+ * Bit2: mac events
+ * Bit3: magic packet
+ */
+ t_u32 conditions;
+ /** GPIO */
+ t_u32 gpio;
+ /** Gap in milliseconds */
+ t_u32 gap;
+} ds_hs_cfg;
+
+/** Private command ID to get BSS type */
+#define UAP_GET_BSS_TYPE (SIOCDEVPRIVATE + 15)
+
+/** addba_param */
+typedef struct _addba_param
+{
+ /** subcmd */
+ t_u32 subcmd;
+ /** Set/Get */
+ t_u32 action;
+ /** block ack timeout for ADDBA request */
+ t_u32 timeout;
+ /** Buffer size for ADDBA request */
+ t_u32 txwinsize;
+ /** Buffer size for ADDBA response */
+ t_u32 rxwinsize;
+ /** amsdu for ADDBA request */
+ t_u8 txamsdu;
+ /** amsdu for ADDBA response */
+ t_u8 rxamsdu;
+} addba_param;
+
+/** aggr_prio_tbl */
+typedef struct _aggr_prio_tbl
+{
+ /** subcmd */
+ t_u32 subcmd;
+ /** Set/Get */
+ t_u32 action;
+ /** ampdu priority table */
+ t_u8 ampdu[MAX_NUM_TID];
+ /** amsdu priority table */
+ t_u8 amsdu[MAX_NUM_TID];
+} aggr_prio_tbl;
+
+/** addba_reject parameters */
+typedef struct _addba_reject_para
+{
+ /** subcmd */
+ t_u32 subcmd;
+ /** Set/Get */
+ t_u32 action;
+ /** BA Reject paramters */
+ t_u8 addba_reject[MAX_NUM_TID];
+} addba_reject_para;
+
+/** fw_info */
+typedef struct _fw_info
+{
+ /** subcmd */
+ t_u32 subcmd;
+ /** Get */
+ t_u32 action;
+ /** Firmware release number */
+ t_u32 fw_release_number;
+ /** Device support for MIMO abstraction of MCSs */
+ t_u8 hw_dev_mcs_support;
+} fw_info;
+
+typedef struct _tx_bf_cfg_para_hdr
+{
+ /** Sub command */
+ t_u32 subcmd;
+ /** Action: Set/Get */
+ t_u32 action;
+} tx_bf_cfg_para_hdr;
+
+/** sdcmd52rw parameters */
+typedef struct _sdcmd52_para
+{
+ /** subcmd */
+ t_u32 subcmd;
+ /** Write /Read */
+ t_u32 action;
+ /** Command 52 paramters */
+ t_u8 cmd52_params[3];
+} sdcmd52_para;
+
+/** deep_sleep parameters */
+typedef struct _deep_sleep_para
+{
+ /** subcmd */
+ t_u32 subcmd;
+ /** Set/Get */
+ t_u32 action;
+ /** enable/disable deepsleep*/
+ t_u16 deep_sleep;
+ /** idle_time */
+ t_u16 idle_time;
+} deep_sleep_para;
+
+/** tx_data_pause parameters */
+typedef struct _tx_data_pause_para
+{
+ /** subcmd */
+ t_u32 subcmd;
+ /** Set/Get */
+ t_u32 action;
+ /** enable/disable Tx data pause*/
+ t_u16 txpause;
+ /** Max number of TX buffer allowed for all PS client*/
+ t_u16 txbufcnt;
+} tx_data_pause_para;
+
+/** mgmt_frame_ctrl */
+typedef struct _mgmt_frame_ctrl
+{
+ /** subcmd */
+ t_u32 subcmd;
+ /** Set/Get */
+ t_u32 action;
+ /** mask */
+ t_u32 mask;
+} mgmt_frame_ctrl;
+
+typedef struct _snmp_mib_para
+{
+ /** subcmd */
+ t_u32 subcmd;
+ /** Set/Get */
+ t_u32 action;
+ /** oid to set/get */
+ t_u16 oid;
+ /** length of oid value */
+ t_u16 oid_val_len;
+ /** oid value to set/get */
+ t_u8 oid_value[0];
+} snmp_mib_para;
+
+/** Max length for oid_value field */
+#define MAX_SNMP_VALUE_SIZE 128
+
+/** Oid for 802.11D enable/disable */
+#define OID_80211D_ENABLE 0x0009
+/** Oid for 802.11H enable/disable */
+#define OID_80211H_ENABLE 0x000a
+
+/** domain_info parameters */
+typedef struct _domain_info_param
+{
+ /** subcmd */
+ t_u32 subcmd;
+ /** Set/Get */
+ t_u32 action;
+ /** domain_param TLV (incl. header) */
+ t_u8 tlv[0];
+} domain_info_para;
+
+/** DOMAIN_INFO param sizes */
+#define TLV_HEADER_LEN (2 + 2)
+#define SUB_BAND_LEN 3
+#define MAX_SUB_BANDS 40
+
+/** MAX domain TLV length */
+#define MAX_DOMAIN_TLV_LEN (TLV_HEADER_LEN + COUNTRY_CODE_LEN \
+ + (SUB_BAND_LEN * MAX_SUB_BANDS))
+
+#ifdef DFS_TESTING_SUPPORT
+/** dfs_testing parameters */
+typedef struct _dfs_testing_param
+{
+ /** subcmd */
+ t_u32 subcmd;
+ /** Set/Get */
+ t_u32 action;
+ /** user CAC period (msec) */
+ t_u16 usr_cac_period;
+ /** user NOP period (sec) */
+ t_u16 usr_nop_period;
+ /** don't change channel on radar */
+ t_u8 no_chan_change;
+ /** fixed channel to change to on radar */
+ t_u8 fixed_new_chan;
+} dfs_testing_para;
+#endif
+
+void woal_uap_set_multicast_list(struct net_device *dev);
+int woal_uap_do_ioctl(struct net_device *dev, struct ifreq *req, int cmd);
+int woal_uap_bss_ctrl(moal_private * priv, t_u8 wait_option, int data);
+void woal_uap_get_version(moal_private * priv, char *version, int max_len);
+mlan_status woal_uap_get_stats(moal_private * priv, t_u8 wait_option,
+ mlan_ds_uap_stats * ustats);
+#if defined(UAP_WEXT) || defined(UAP_CFG80211)
+extern struct iw_handler_def woal_uap_handler_def;
+struct iw_statistics *woal_get_uap_wireless_stats(struct net_device *dev);
+/** IOCTL function for wireless private IOCTLs */
+int woal_uap_do_priv_ioctl(struct net_device *dev, struct ifreq *req, int cmd);
+#endif
+/** Set invalid data for each member of mlan_uap_bss_param */
+void woal_set_sys_config_invalid_data(mlan_uap_bss_param * config);
+/** Set/Get system configuration parameters */
+mlan_status woal_set_get_sys_config(moal_private * priv,
+ t_u16 action, t_u8 wait_option,
+ mlan_uap_bss_param * sys_cfg);
+int woal_uap_set_ap_cfg(moal_private * priv, t_u8 * data, int len);
+mlan_status woal_uap_set_11n_status(mlan_uap_bss_param * sys_cfg, t_u8 action);
+#ifdef UAP_WEXT
+void woal_ioctl_get_uap_info_resp(moal_private * priv, mlan_ds_get_info * info);
+int woal_set_get_custom_ie(moal_private * priv, t_u16 mask, t_u8 * ie,
+ int ie_len);
+#endif /* UAP_WEXT */
+#endif /* _MOAL_UAP_H */
diff --git a/drivers/net/wireless/sd8797/mlinux/moal_uap_cfg80211.c b/drivers/net/wireless/sd8797/mlinux/moal_uap_cfg80211.c
new file mode 100644
index 000000000000..e83d4de4d282
--- /dev/null
+++ b/drivers/net/wireless/sd8797/mlinux/moal_uap_cfg80211.c
@@ -0,0 +1,1762 @@
+/** @file moal_uap_cfg80211.c
+ *
+ * @brief This file contains the functions for uAP CFG80211.
+ *
+ * Copyright (C) 2011-2012, Marvell International Ltd.
+ *
+ * This software file (the "File") is distributed by Marvell International
+ * Ltd. under the terms of the GNU General Public License Version 2, June 1991
+ * (the "License"). You may use, redistribute and/or modify this File in
+ * accordance with the terms and conditions of the License, a copy of which
+ * is available by writing to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
+ * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
+ *
+ * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
+ * ARE EXPRESSLY DISCLAIMED. The License provides additional details about
+ * this warranty disclaimer.
+ *
+ */
+
+#include "moal_cfg80211.h"
+#include "moal_uap_cfg80211.h"
+
+/* these 3 function will be called in woal_cfg80211_wifi_direct_ops */
+int woal_cfg80211_add_beacon(struct wiphy *wiphy,
+ struct net_device *dev,
+ struct beacon_parameters *params);
+
+int woal_cfg80211_set_beacon(struct wiphy *wiphy,
+ struct net_device *dev,
+ struct beacon_parameters *params);
+
+int woal_cfg80211_del_beacon(struct wiphy *wiphy, struct net_device *dev);
+
+static int woal_uap_cfg80211_scan(struct wiphy *wiphy, struct net_device *dev,
+ struct cfg80211_scan_request *request);
+
+static int woal_uap_cfg80211_connect(struct wiphy *wiphy,
+ struct net_device *dev,
+ struct cfg80211_connect_params *sme);
+
+static int woal_uap_cfg80211_disconnect(struct wiphy *wiphy,
+ struct net_device *dev,
+ t_u16 reason_code);
+
+int woal_uap_cfg80211_get_station(struct wiphy *wiphy, struct net_device *dev,
+ u8 * mac, struct station_info *stainfo);
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,37) || defined(COMPAT_WIRELESS)
+static const struct ieee80211_txrx_stypes
+ ieee80211_uap_mgmt_stypes[NUM_NL80211_IFTYPES] = {
+ [NL80211_IFTYPE_ADHOC] = {
+ .tx = 0x0000,
+ .rx = 0x0000,
+ },
+ [NL80211_IFTYPE_STATION] = {
+ .tx = BIT(IEEE80211_STYPE_ACTION >> 4),
+ .rx = BIT(IEEE80211_STYPE_ACTION >> 4),
+ },
+ [NL80211_IFTYPE_AP] = {
+ .tx = 0xffff,
+ .rx = BIT(IEEE80211_STYPE_ASSOC_REQ >> 4) |
+ BIT(IEEE80211_STYPE_REASSOC_REQ >> 4) |
+ BIT(IEEE80211_STYPE_PROBE_REQ >> 4) |
+ BIT(IEEE80211_STYPE_DISASSOC >> 4) |
+ BIT(IEEE80211_STYPE_AUTH >> 4) |
+ BIT(IEEE80211_STYPE_DEAUTH >> 4) |
+ BIT(IEEE80211_STYPE_ACTION >> 4),
+ },
+ [NL80211_IFTYPE_AP_VLAN] = {
+ .tx = 0x0000,
+ .rx = 0x0000,
+ },
+ [NL80211_IFTYPE_P2P_CLIENT] = {
+ .tx = 0x0000,
+ .rx = 0x0000,
+ },
+ [NL80211_IFTYPE_P2P_GO] = {
+ .tx = 0x0000,
+ .rx = 0x0000,
+ },
+ [NL80211_IFTYPE_MESH_POINT] = {
+ .tx = 0x0000,
+ .rx = 0x0000,
+ },
+};
+#endif
+
+/** cfg80211 uAP operations */
+static struct cfg80211_ops woal_cfg80211_uap_ops = {
+ .add_virtual_intf = woal_cfg80211_add_virtual_intf,
+ .del_virtual_intf = woal_cfg80211_del_virtual_intf,
+ .set_channel = woal_cfg80211_set_channel,
+ .scan = woal_uap_cfg80211_scan,
+ .connect = woal_uap_cfg80211_connect,
+ .disconnect = woal_uap_cfg80211_disconnect,
+ .set_wiphy_params = woal_cfg80211_set_wiphy_params,
+ .change_virtual_intf = woal_cfg80211_change_virtual_intf,
+ .add_key = woal_cfg80211_add_key,
+ .del_key = woal_cfg80211_del_key,
+ .set_default_key = woal_cfg80211_set_default_key,
+ .add_beacon = woal_cfg80211_add_beacon,
+ .set_beacon = woal_cfg80211_set_beacon,
+ .del_beacon = woal_cfg80211_del_beacon,
+ .get_station = woal_uap_cfg80211_get_station,
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,37) || defined(COMPAT_WIRELESS)
+ .mgmt_frame_register = woal_cfg80211_mgmt_frame_register,
+ .mgmt_tx = woal_cfg80211_mgmt_tx,
+#endif
+};
+
+/********************************************************
+ Local Variables
+********************************************************/
+
+/********************************************************
+ Global Variables
+********************************************************/
+
+/********************************************************
+ Local Functions
+********************************************************/
+
+/********************************************************
+ Global Functions
+********************************************************/
+/**
+ * @brief Filter specific IE in ie buf
+ *
+ * @param ie Pointer to IEs
+ * @param len Total length of ie
+ * @param ie_out Pointer to out IE buf
+ *
+ * @return out IE length
+ */
+static t_u16
+woal_filter_beacon_ies(const t_u8 * ie, int len, t_u8 * ie_out)
+{
+ int left_len = len;
+ const t_u8 *pos = ie;
+ int length;
+ t_u8 id = 0;
+ t_u16 out_len = 0;
+
+ /* ERP_INFO and RSN IE will be fileter out */
+ while (left_len >= 2) {
+ length = *(pos + 1);
+ id = *pos;
+ if ((length + 2) > left_len)
+ break;
+ switch (id) {
+ case ERP_INFO:
+ case RSN_IE:
+ break;
+ default:
+ memcpy(ie_out + out_len, pos, length + 2);
+ out_len += length + 2;
+ break;
+ }
+ pos += (length + 2);
+ left_len -= (length + 2);
+ }
+ return out_len;
+}
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(3,2,0) && !defined(COMPAT_WIRELESS)
+/**
+ * @brief Verify RSN IE
+ *
+ * @param rsn_ie Pointer RSN IE
+ * @param sys_config Pointer to mlan_uap_bss_param structure
+ *
+ * @return MTRUE/MFALSE
+ */
+static t_u8
+woal_check_rsn_ie(IEEEtypes_Rsn_t * rsn_ie, mlan_uap_bss_param * sys_config)
+{
+ int left = 0;
+ int count = 0;
+ int i = 0;
+ wpa_suite_auth_key_mgmt_t *key_mgmt = NULL;
+ left = rsn_ie->len + 2;
+ if (left < sizeof(IEEEtypes_Rsn_t))
+ return MFALSE;
+ sys_config->wpa_cfg.group_cipher = 0;
+ sys_config->wpa_cfg.pairwise_cipher_wpa2 = 0;
+ /* check the group cipher */
+ switch (rsn_ie->group_cipher.type) {
+ case WPA_CIPHER_TKIP:
+ sys_config->wpa_cfg.group_cipher = CIPHER_TKIP;
+ break;
+ case WPA_CIPHER_AES_CCM:
+ sys_config->wpa_cfg.group_cipher = CIPHER_AES_CCMP;
+ break;
+ default:
+ break;
+ }
+ count = le16_to_cpu(rsn_ie->pairwise_cipher.count);
+ for (i = 0; i < count; i++) {
+ switch (rsn_ie->pairwise_cipher.list[i].type) {
+ case WPA_CIPHER_TKIP:
+ sys_config->wpa_cfg.pairwise_cipher_wpa2 |= CIPHER_TKIP;
+ break;
+ case WPA_CIPHER_AES_CCM:
+ sys_config->wpa_cfg.pairwise_cipher_wpa2 |= CIPHER_AES_CCMP;
+ break;
+ default:
+ break;
+ }
+ }
+ left -= sizeof(IEEEtypes_Rsn_t) + (count - 1) * sizeof(wpa_suite);
+ if (left < sizeof(wpa_suite_auth_key_mgmt_t))
+ return MFALSE;
+ key_mgmt =
+ (wpa_suite_auth_key_mgmt_t *) ((u8 *) rsn_ie + sizeof(IEEEtypes_Rsn_t) +
+ (count - 1) * sizeof(wpa_suite));
+ count = le16_to_cpu(key_mgmt->count);
+ if (left <
+ (sizeof(wpa_suite_auth_key_mgmt_t) + (count - 1) * sizeof(wpa_suite)))
+ return MFALSE;
+
+ for (i = 0; i < count; i++) {
+ switch (key_mgmt->list[i].type) {
+ case RSN_AKM_8021X:
+ sys_config->key_mgmt = KEY_MGMT_EAP;
+ break;
+ case RSN_AKM_PSK:
+ sys_config->key_mgmt = KEY_MGMT_PSK;
+ break;
+ }
+ }
+ return MTRUE;
+}
+
+/**
+ * @brief Verify WPA IE
+ *
+ * @param wpa_ie Pointer WPA IE
+ * @param sys_config Pointer to mlan_uap_bss_param structure
+ *
+ * @return MTRUE/MFALSE
+ */
+static t_u8
+woal_check_wpa_ie(IEEEtypes_Wpa_t * wpa_ie, mlan_uap_bss_param * sys_config)
+{
+ int left = 0;
+ int count = 0;
+ int i = 0;
+ wpa_suite_auth_key_mgmt_t *key_mgmt = NULL;
+ left = wpa_ie->len + 2;
+ if (left < sizeof(IEEEtypes_Wpa_t))
+ return MFALSE;
+ sys_config->wpa_cfg.group_cipher = 0;
+ sys_config->wpa_cfg.pairwise_cipher_wpa = 0;
+ switch (wpa_ie->group_cipher.type) {
+ case WPA_CIPHER_TKIP:
+ sys_config->wpa_cfg.group_cipher = CIPHER_TKIP;
+ break;
+ case WPA_CIPHER_AES_CCM:
+ sys_config->wpa_cfg.group_cipher = CIPHER_AES_CCMP;
+ break;
+ default:
+ break;
+ }
+ count = le16_to_cpu(wpa_ie->pairwise_cipher.count);
+ for (i = 0; i < count; i++) {
+ switch (wpa_ie->pairwise_cipher.list[i].type) {
+ case WPA_CIPHER_TKIP:
+ sys_config->wpa_cfg.pairwise_cipher_wpa |= CIPHER_TKIP;
+ break;
+ case WPA_CIPHER_AES_CCM:
+ sys_config->wpa_cfg.pairwise_cipher_wpa |= CIPHER_AES_CCMP;
+ break;
+ default:
+ break;
+ }
+ }
+ left -= sizeof(IEEEtypes_Wpa_t) + (count - 1) * sizeof(wpa_suite);
+ if (left < sizeof(wpa_suite_auth_key_mgmt_t))
+ return MFALSE;
+ key_mgmt =
+ (wpa_suite_auth_key_mgmt_t *) ((u8 *) wpa_ie + sizeof(IEEEtypes_Wpa_t) +
+ (count - 1) * sizeof(wpa_suite));
+ count = le16_to_cpu(key_mgmt->count);
+ if (left <
+ (sizeof(wpa_suite_auth_key_mgmt_t) + (count - 1) * sizeof(wpa_suite)))
+ return MFALSE;
+ for (i = 0; i < count; i++) {
+ switch (key_mgmt->list[i].type) {
+ case RSN_AKM_8021X:
+ sys_config->key_mgmt = KEY_MGMT_EAP;
+ break;
+ case RSN_AKM_PSK:
+ sys_config->key_mgmt = KEY_MGMT_PSK;
+ break;
+ }
+ }
+ return MTRUE;
+}
+
+/**
+ * @brief Find RSN/WPA IES
+ *
+ * @param ie Pointer IE buffer
+ * @param sys_config Pointer to mlan_uap_bss_param structure
+ *
+ * @return MTRUE/MFALSE
+ */
+static t_u8
+woal_find_wpa_ies(t_u8 * ie, int len, mlan_uap_bss_param * sys_config)
+{
+ int bytes_left = len;
+ t_u8 *pcurrent_ptr = ie;
+ t_u16 total_ie_len;
+ t_u8 element_len;
+ t_u8 wpa2 = 0;
+ t_u8 wpa = 0;
+ t_u8 ret = MFALSE;
+ IEEEtypes_ElementId_e element_id;
+ IEEEtypes_VendorSpecific_t *pvendor_ie;
+ const t_u8 wpa_oui[4] = { 0x00, 0x50, 0xf2, 0x01 };
+
+ while (bytes_left >= 2) {
+ element_id = (IEEEtypes_ElementId_e) (*((t_u8 *) pcurrent_ptr));
+ element_len = *((t_u8 *) pcurrent_ptr + 1);
+ total_ie_len = element_len + sizeof(IEEEtypes_Header_t);
+ if (bytes_left < total_ie_len) {
+ PRINTM(MERROR, "InterpretIE: Error in processing IE, "
+ "bytes left < IE length\n");
+ bytes_left = 0;
+ continue;
+ }
+ switch (element_id) {
+ case RSN_IE:
+ wpa2 =
+ woal_check_rsn_ie((IEEEtypes_Rsn_t *) pcurrent_ptr, sys_config);
+ break;
+ case VENDOR_SPECIFIC_221:
+ pvendor_ie = (IEEEtypes_VendorSpecific_t *) pcurrent_ptr;
+ if (!memcmp(pvendor_ie->vend_hdr.oui, wpa_oui, sizeof(wpa_oui)))
+ wpa =
+ woal_check_wpa_ie((IEEEtypes_Wpa_t *) pcurrent_ptr,
+ sys_config);
+ break;
+ default:
+ break;
+ }
+ pcurrent_ptr += element_len + 2;
+ /* Need to account for IE ID and IE Len */
+ bytes_left -= (element_len + 2);
+ }
+ if (wpa && wpa2) {
+ sys_config->protocol = PROTOCOL_WPA | PROTOCOL_WPA2;
+ ret = MTRUE;
+ } else if (wpa2) {
+ sys_config->protocol = PROTOCOL_WPA2;
+ ret = MTRUE;
+ } else if (wpa) {
+ sys_config->protocol = PROTOCOL_WPA;
+ ret = MTRUE;
+ }
+ return ret;
+}
+#endif
+
+/**
+ * @brief Look up specific IE in a buf
+ *
+ * @param ie Pointer to IEs
+ * @param len Total length of ie
+ * @param id Element id to lookup
+ *
+ * @return Pointer of the specific IE -- success, NULL -- fail
+ */
+static const t_u8 *
+woal_parse_ie_tlv(const t_u8 * ie, int len, t_u8 id)
+{
+ int left_len = len;
+ const t_u8 *pos = ie;
+ int length;
+
+ /* IE format: | u8 | id | | u8 | len | | var | data | */
+ while (left_len >= 2) {
+ length = *(pos + 1);
+ if ((*pos == id) && (length + 2) <= left_len)
+ return pos;
+ pos += (length + 2);
+ left_len -= (length + 2);
+ }
+
+ return NULL;
+}
+
+/**
+ * @brief Add custom ie to mgmt frames.
+ *
+ * @param priv A pointer to moal private structure
+ * @param beacon_ies_data Beacon ie
+ * @param beacon_index The index for beacon when auto index
+ * @param proberesp_ies_data Probe resp ie
+ * @param proberesp_index The index for probe resp when auto index
+ * @param assocresp_ies_data Assoc resp ie
+ * @param assocresp_index The index for assoc resp when auto index
+ * @param probereq_ies_data Probe req ie
+ * @param probereq_index The index for probe req when auto index *
+ *
+ * @return 0 -- success, otherwise fail
+ */
+static int
+woal_cfg80211_custom_ie(moal_private * priv,
+ custom_ie * beacon_ies_data, t_u16 * beacon_index,
+ custom_ie * proberesp_ies_data, t_u16 * proberesp_index,
+ custom_ie * assocresp_ies_data, t_u16 * assocresp_index,
+ custom_ie * probereq_ies_data, t_u16 * probereq_index)
+{
+ mlan_ioctl_req *ioctl_req = NULL;
+ mlan_ds_misc_cfg *misc = NULL;
+ mlan_ds_misc_custom_ie *custom_ie = NULL;
+ t_u8 *pos = NULL;
+ t_u16 len = 0;
+ int ret = 0;
+
+ ENTER();
+
+ if (!(custom_ie = kmalloc(sizeof(mlan_ds_misc_custom_ie), GFP_KERNEL))) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ memset(custom_ie, 0x00, sizeof(mlan_ds_misc_custom_ie));
+ custom_ie->type = TLV_TYPE_MGMT_IE;
+
+ pos = (t_u8 *) custom_ie->ie_data_list;
+ if (beacon_ies_data) {
+ len = sizeof(*beacon_ies_data) - MAX_IE_SIZE
+ + beacon_ies_data->ie_length;
+ memcpy(pos, beacon_ies_data, len);
+ pos += len;
+ custom_ie->len += len;
+ }
+
+ if (proberesp_ies_data) {
+ len = sizeof(*proberesp_ies_data) - MAX_IE_SIZE
+ + proberesp_ies_data->ie_length;
+ memcpy(pos, proberesp_ies_data, len);
+ pos += len;
+ custom_ie->len += len;
+ }
+
+ if (assocresp_ies_data) {
+ len = sizeof(*assocresp_ies_data) - MAX_IE_SIZE
+ + assocresp_ies_data->ie_length;
+ memcpy(pos, assocresp_ies_data, len);
+ custom_ie->len += len;
+ }
+
+ if (probereq_ies_data) {
+ len = sizeof(*probereq_ies_data) - MAX_IE_SIZE
+ + probereq_ies_data->ie_length;
+ memcpy(pos, probereq_ies_data, len);
+ pos += len;
+ custom_ie->len += len;
+ }
+
+ ioctl_req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
+ if (ioctl_req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ misc = (mlan_ds_misc_cfg *) ioctl_req->pbuf;
+ misc->sub_command = MLAN_OID_MISC_CUSTOM_IE;
+ ioctl_req->req_id = MLAN_IOCTL_MISC_CFG;
+ ioctl_req->action = MLAN_ACT_SET;
+
+ memcpy(&misc->param.cust_ie, custom_ie, sizeof(mlan_ds_misc_custom_ie));
+
+ if (MLAN_STATUS_SUCCESS !=
+ woal_request_ioctl(priv, ioctl_req, MOAL_IOCTL_WAIT)) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ /* get the assigned index */
+ pos = (t_u8 *) (&misc->param.cust_ie.ie_data_list[0].ie_index);
+ if (beacon_ies_data && beacon_ies_data->ie_length
+ && beacon_ies_data->ie_index == MLAN_CUSTOM_IE_AUTO_IDX_MASK) {
+ /* save beacon ie index after auto-indexing */
+ *beacon_index = misc->param.cust_ie.ie_data_list[0].ie_index;
+ len = sizeof(*beacon_ies_data) - MAX_IE_SIZE
+ + beacon_ies_data->ie_length;
+ pos += len;
+ }
+
+ if (proberesp_ies_data && proberesp_ies_data->ie_length
+ && proberesp_ies_data->ie_index == MLAN_CUSTOM_IE_AUTO_IDX_MASK) {
+ /* save probe resp ie index after auto-indexing */
+ *proberesp_index = *((t_u16 *) pos);
+ len = sizeof(*proberesp_ies_data) - MAX_IE_SIZE
+ + proberesp_ies_data->ie_length;
+ pos += len;
+ }
+
+ if (assocresp_ies_data && assocresp_ies_data->ie_length
+ && assocresp_ies_data->ie_index == MLAN_CUSTOM_IE_AUTO_IDX_MASK) {
+ /* save assoc resp ie index after auto-indexing */
+ *assocresp_index = *((t_u16 *) pos);
+ len = sizeof(*assocresp_ies_data) - MAX_IE_SIZE
+ + assocresp_ies_data->ie_length;
+ pos += len;
+ }
+ if (probereq_ies_data && probereq_ies_data->ie_length
+ && probereq_ies_data->ie_index == MLAN_CUSTOM_IE_AUTO_IDX_MASK) {
+ /* save probe resp ie index after auto-indexing */
+ *probereq_index = *((t_u16 *) pos);
+ len = sizeof(*probereq_ies_data) - MAX_IE_SIZE
+ + probereq_ies_data->ie_length;
+ pos += len;
+ }
+
+ if (ioctl_req->status_code == MLAN_ERROR_IOCTL_FAIL)
+ ret = -EFAULT;
+
+ done:
+ if (ioctl_req)
+ kfree(ioctl_req);
+ if (custom_ie)
+ kfree(custom_ie);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function returns priv
+ * based on mgmt ie index
+ *
+ * @param handle A pointer to moal_handle
+ * @param index mgmt ie index
+ *
+ * @return Pointer to moal_private
+ */
+static moal_private *
+woal_get_priv_by_mgmt_index(moal_handle * handle, t_u16 index)
+{
+ int i;
+
+ for (i = 0; i < MIN(handle->priv_num, MLAN_MAX_BSS_NUM); i++) {
+ if (handle->priv[i]) {
+ if (handle->priv[i]->probereq_index == index)
+ return (handle->priv[i]);
+ }
+ }
+ return NULL;
+}
+
+/**
+ * @brief config AP or GO for mgmt frame ies.
+ *
+ * @param priv A pointer to moal private structure
+ * @param beacon_ies A pointer to beacon ies
+ * @param beacon_ies_len Beacon ies length
+ * @param proberesp_ies A pointer to probe resp ies
+ * @param proberesp_ies_len Probe resp ies length
+ * @param assocresp_ies A pointer to probe resp ies
+ * @param assocresp_ies_len Assoc resp ies length
+ * @param probereq_ies A pointer to probe req ies
+ * @param probereq_ies_len Probe req ies length *
+ * @param mask Mgmt frame mask
+ *
+ * @return 0 -- success, otherwise fail
+ */
+int
+woal_cfg80211_mgmt_frame_ie(moal_private * priv,
+ const t_u8 * beacon_ies, size_t beacon_ies_len,
+ const t_u8 * proberesp_ies,
+ size_t proberesp_ies_len,
+ const t_u8 * assocresp_ies,
+ size_t assocresp_ies_len, const t_u8 * probereq_ies,
+ size_t probereq_ies_len, t_u16 mask)
+{
+ int ret = 0;
+ t_u8 *pos = NULL;
+ custom_ie *beacon_ies_data = NULL;
+ custom_ie *proberesp_ies_data = NULL;
+ custom_ie *assocresp_ies_data = NULL;
+ custom_ie *probereq_ies_data = NULL;
+
+ /* static variables for mgmt frame ie auto-indexing */
+ static t_u16 beacon_index = MLAN_CUSTOM_IE_AUTO_IDX_MASK;
+ static t_u16 proberesp_index = MLAN_CUSTOM_IE_AUTO_IDX_MASK;
+ static t_u16 assocresp_index = MLAN_CUSTOM_IE_AUTO_IDX_MASK;
+ static t_u16 probereq_index = MLAN_CUSTOM_IE_AUTO_IDX_MASK;
+ moal_private *pmpriv = NULL;
+ static t_u16 rsn_index = MLAN_CUSTOM_IE_AUTO_IDX_MASK;
+ const t_u8 *rsn_ie;
+
+ ENTER();
+
+ if (mask & MGMT_MASK_BEACON) {
+ if (!(beacon_ies_data = kmalloc(sizeof(custom_ie), GFP_KERNEL))) {
+ ret = -ENOMEM;
+ goto done;
+ }
+ if (beacon_ies && beacon_ies_len) {
+ rsn_ie =
+ woal_parse_ie_tlv((t_u8 *) beacon_ies, (int) beacon_ies_len,
+ RSN_IE);
+ if (rsn_ie) {
+ beacon_ies_data->ie_index = rsn_index;
+ beacon_ies_data->mgmt_subtype_mask =
+ MGMT_MASK_BEACON | MGMT_MASK_PROBE_RESP |
+ MGMT_MASK_ASSOC_RESP;
+ beacon_ies_data->ie_length = rsn_ie[1] + 2;
+ memcpy(beacon_ies_data->ie_buffer, rsn_ie, rsn_ie[1] + 2);
+ if (MLAN_STATUS_SUCCESS !=
+ woal_cfg80211_custom_ie(priv, beacon_ies_data, &rsn_index,
+ NULL, &proberesp_index, NULL,
+ &assocresp_index, NULL,
+ &probereq_index)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ }
+ } else {
+ /* clear rsn_ie */
+ if (rsn_index <= MAX_MGMT_IE_INDEX) {
+ beacon_ies_data->ie_index = rsn_index;
+ beacon_ies_data->mgmt_subtype_mask = MLAN_CUSTOM_IE_DELETE_MASK;
+ beacon_ies_data->ie_length = 0;
+ rsn_index = MLAN_CUSTOM_IE_AUTO_IDX_MASK;
+ if (MLAN_STATUS_SUCCESS !=
+ woal_cfg80211_custom_ie(priv, beacon_ies_data, &rsn_index,
+ NULL, &proberesp_index, NULL,
+ &assocresp_index, NULL,
+ &probereq_index)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ }
+ }
+ }
+
+ if (mask & MGMT_MASK_PROBE_RESP) {
+ if (!(proberesp_ies_data = kmalloc(sizeof(custom_ie), GFP_KERNEL))) {
+ ret = -ENOMEM;
+ goto done;
+ }
+ }
+
+ if (mask & MGMT_MASK_ASSOC_RESP) {
+ if (!(assocresp_ies_data = kmalloc(sizeof(custom_ie), GFP_KERNEL))) {
+ ret = -ENOMEM;
+ goto done;
+ }
+ }
+ if (mask & MGMT_MASK_PROBE_REQ) {
+ if (!(probereq_ies_data = kmalloc(sizeof(custom_ie), GFP_KERNEL))) {
+ ret = -ENOMEM;
+ goto done;
+ }
+ }
+
+ if (beacon_ies_data) {
+ memset(beacon_ies_data, 0x00, sizeof(custom_ie));
+ if (beacon_ies && beacon_ies_len) {
+ /* set the beacon ies */
+ beacon_ies_data->ie_index = beacon_index;
+ beacon_ies_data->mgmt_subtype_mask = MGMT_MASK_BEACON;
+ beacon_ies_data->mgmt_subtype_mask |= MGMT_MASK_ASSOC_RESP;
+ beacon_ies_data->ie_length = woal_filter_beacon_ies(beacon_ies,
+ beacon_ies_len,
+ beacon_ies_data->
+ ie_buffer);
+ } else {
+ /* clear the beacon ies */
+ if (beacon_index > MAX_MGMT_IE_INDEX) {
+ PRINTM(MERROR, "Invalid beacon index for mgmt frame ie.\n");
+ goto done;
+ }
+
+ beacon_ies_data->ie_index = beacon_index;
+ beacon_ies_data->mgmt_subtype_mask = MLAN_CUSTOM_IE_DELETE_MASK;
+ beacon_ies_data->ie_length = 0;
+ beacon_index = MLAN_CUSTOM_IE_AUTO_IDX_MASK;
+ }
+ }
+
+ if (proberesp_ies_data) {
+ memset(proberesp_ies_data, 0x00, sizeof(custom_ie));
+ if (proberesp_ies && proberesp_ies_len) {
+ /* set the probe response ies */
+ // proberesp_ies_data->ie_index = MLAN_CUSTOM_IE_AUTO_IDX_MASK;
+ proberesp_ies_data->ie_index = proberesp_index;
+ proberesp_ies_data->mgmt_subtype_mask = MGMT_MASK_PROBE_RESP;
+ proberesp_ies_data->ie_length = proberesp_ies_len;
+ pos = proberesp_ies_data->ie_buffer;
+ memcpy(pos, proberesp_ies, proberesp_ies_len);
+ } else {
+ /* clear the probe response ies */
+ if (proberesp_index > MAX_MGMT_IE_INDEX) {
+ PRINTM(MERROR, "Invalid probe resp index for mgmt frame ie.\n");
+ goto done;
+ }
+
+ proberesp_ies_data->ie_index = proberesp_index;
+ proberesp_ies_data->mgmt_subtype_mask = MLAN_CUSTOM_IE_DELETE_MASK;
+ proberesp_ies_data->ie_length = 0;
+ proberesp_index = MLAN_CUSTOM_IE_AUTO_IDX_MASK;
+ }
+ }
+ if (assocresp_ies_data) {
+ memset(assocresp_ies_data, 0x00, sizeof(custom_ie));
+ if (assocresp_ies && assocresp_ies_len) {
+ /* set the assoc response ies */
+ assocresp_ies_data->ie_index = assocresp_index;
+ assocresp_ies_data->mgmt_subtype_mask = MGMT_MASK_ASSOC_RESP;
+ assocresp_ies_data->ie_length = assocresp_ies_len;
+ pos = assocresp_ies_data->ie_buffer;
+ memcpy(pos, assocresp_ies, assocresp_ies_len);
+ } else {
+ /* clear the assoc response ies */
+ if (assocresp_index > MAX_MGMT_IE_INDEX) {
+ PRINTM(MERROR, "Invalid assoc resp index for mgmt frame ie.\n");
+ goto done;
+ }
+
+ assocresp_ies_data->ie_index = assocresp_index;
+ assocresp_ies_data->mgmt_subtype_mask = MLAN_CUSTOM_IE_DELETE_MASK;
+ assocresp_ies_data->ie_length = 0;
+ assocresp_index = MLAN_CUSTOM_IE_AUTO_IDX_MASK;
+ }
+ }
+
+ if (probereq_ies_data) {
+ memset(probereq_ies_data, 0x00, sizeof(custom_ie));
+ if ((probereq_index != MLAN_CUSTOM_IE_AUTO_IDX_MASK) &&
+ (priv->probereq_index != probereq_index)) {
+ pmpriv = woal_get_priv_by_mgmt_index(priv->phandle, probereq_index);
+ if (pmpriv) {
+ probereq_ies_data->ie_index = probereq_index;
+ probereq_ies_data->mgmt_subtype_mask =
+ MLAN_CUSTOM_IE_DELETE_MASK;
+ probereq_ies_data->ie_length = 0;
+ probereq_index = MLAN_CUSTOM_IE_AUTO_IDX_MASK;
+ pmpriv->probereq_index = MLAN_CUSTOM_IE_AUTO_IDX_MASK;
+ if (MLAN_STATUS_SUCCESS !=
+ woal_cfg80211_custom_ie(pmpriv, NULL, &beacon_index,
+ NULL, &proberesp_index,
+ NULL, &assocresp_index,
+ probereq_ies_data,
+ &probereq_index)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ memset(probereq_ies_data, 0x00, sizeof(custom_ie));
+ }
+ }
+ if (probereq_ies && probereq_ies_len) {
+ /* set the probe req ies */
+ probereq_ies_data->ie_index = probereq_index;
+ probereq_ies_data->mgmt_subtype_mask = MGMT_MASK_PROBE_REQ;
+ probereq_ies_data->ie_length = probereq_ies_len;
+ pos = probereq_ies_data->ie_buffer;
+ memcpy(pos, probereq_ies, probereq_ies_len);
+ } else {
+ /* clear the probe req ies */
+ if (probereq_index > MAX_MGMT_IE_INDEX) {
+ PRINTM(MERROR, "Invalid probe resp index for mgmt frame ie.\n");
+ goto done;
+ }
+ probereq_ies_data->ie_index = probereq_index;
+ probereq_ies_data->mgmt_subtype_mask = MLAN_CUSTOM_IE_DELETE_MASK;
+ probereq_ies_data->ie_length = 0;
+ probereq_index = MLAN_CUSTOM_IE_AUTO_IDX_MASK;
+ }
+ }
+
+ if (MLAN_STATUS_SUCCESS !=
+ woal_cfg80211_custom_ie(priv, beacon_ies_data, &beacon_index,
+ proberesp_ies_data, &proberesp_index,
+ assocresp_ies_data, &assocresp_index,
+ probereq_ies_data, &probereq_index)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ if (probereq_ies_data)
+ priv->probereq_index = probereq_index;
+
+ done:
+ if (beacon_ies_data)
+ kfree(beacon_ies_data);
+ if (proberesp_ies_data)
+ kfree(proberesp_ies_data);
+ if (assocresp_ies_data)
+ kfree(assocresp_ies_data);
+
+ LEAVE();
+
+ return ret;
+}
+
+/**
+ * @brief initialize AP or GO bss config
+ *
+ * @param priv A pointer to moal private structure
+ * @param params A pointer to beacon_parameters structure
+ * @return 0 -- success, otherwise fail
+ */
+static int
+woal_cfg80211_beacon_config(moal_private * priv,
+ struct beacon_parameters *params)
+{
+ int ret = 0;
+ mlan_uap_bss_param sys_config;
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,2,0) || defined(COMPAT_WIRELESS)
+ int i = 0;
+#else
+ const t_u8 *ssid_ie = NULL;
+ struct ieee80211_mgmt *head = NULL;
+ t_u16 capab_info = 0;
+#endif
+
+ ENTER();
+
+ if (params == NULL) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ if (priv->bss_type != MLAN_BSS_TYPE_UAP
+#ifdef WIFI_DIRECT_SUPPORT
+ && priv->bss_type != MLAN_BSS_TYPE_WIFIDIRECT
+#endif
+ ) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ /* Initialize the uap bss values which are uploaded from firmware */
+ if (MLAN_STATUS_SUCCESS != woal_set_get_sys_config(priv,
+ MLAN_ACT_GET,
+ MOAL_IOCTL_WAIT,
+ &sys_config)) {
+ PRINTM(MERROR, "Error getting AP confiruration\n");
+ ret = -EFAULT;
+ goto done;
+ }
+
+ /* Setting the default values */
+ sys_config.channel = 6;
+ sys_config.preamble_type = 0;
+
+ if (priv->bss_type == MLAN_BSS_TYPE_UAP) {
+ if (params->interval)
+ sys_config.beacon_period = params->interval;
+ if (params->dtim_period)
+ sys_config.dtim_period = params->dtim_period;
+ }
+ if (priv->channel)
+ sys_config.channel = priv->channel;
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,2,0) || defined(COMPAT_WIRELESS)
+ if (!params->ssid || !params->ssid_len) {
+ ret = -EINVAL;
+ goto done;
+ }
+ memcpy(sys_config.ssid.ssid, params->ssid,
+ MIN(MLAN_MAX_SSID_LENGTH, params->ssid_len));
+ sys_config.ssid.ssid_len = MIN(MLAN_MAX_SSID_LENGTH, params->ssid_len);
+ if (params->hidden_ssid)
+ sys_config.bcast_ssid_ctl = 0;
+ else
+ sys_config.bcast_ssid_ctl = 1;
+ if (params->auth_type == NL80211_AUTHTYPE_SHARED_KEY)
+ sys_config.auth_mode = MLAN_AUTH_MODE_SHARED;
+ else
+ sys_config.auth_mode = MLAN_AUTH_MODE_OPEN;
+
+ for (i = 0; i < params->crypto.n_akm_suites; i++) {
+ switch (params->crypto.akm_suites[i]) {
+ case WLAN_AKM_SUITE_8021X:
+ sys_config.key_mgmt = KEY_MGMT_EAP;
+ if ((params->crypto.wpa_versions & NL80211_WPA_VERSION_1) &&
+ (params->crypto.wpa_versions & NL80211_WPA_VERSION_2))
+ sys_config.protocol = PROTOCOL_WPA | PROTOCOL_WPA2;
+ else if (params->crypto.wpa_versions & NL80211_WPA_VERSION_2)
+ sys_config.protocol = PROTOCOL_WPA2;
+ else if (params->crypto.wpa_versions & NL80211_WPA_VERSION_1)
+ sys_config.protocol = PROTOCOL_WPA;
+ break;
+ case WLAN_AKM_SUITE_PSK:
+ sys_config.key_mgmt = KEY_MGMT_PSK;
+ if ((params->crypto.wpa_versions & NL80211_WPA_VERSION_1) &&
+ (params->crypto.wpa_versions & NL80211_WPA_VERSION_2))
+ sys_config.protocol = PROTOCOL_WPA | PROTOCOL_WPA2;
+ else if (params->crypto.wpa_versions & NL80211_WPA_VERSION_2)
+ sys_config.protocol = PROTOCOL_WPA2;
+ else if (params->crypto.wpa_versions & NL80211_WPA_VERSION_1)
+ sys_config.protocol = PROTOCOL_WPA;
+ break;
+ }
+ }
+ sys_config.wpa_cfg.pairwise_cipher_wpa = 0;
+ sys_config.wpa_cfg.pairwise_cipher_wpa2 = 0;
+ for (i = 0; i < params->crypto.n_ciphers_pairwise; i++) {
+ switch (params->crypto.ciphers_pairwise[i]) {
+ case WLAN_CIPHER_SUITE_WEP40:
+ case WLAN_CIPHER_SUITE_WEP104:
+ break;
+ case WLAN_CIPHER_SUITE_TKIP:
+ if (params->crypto.wpa_versions & NL80211_WPA_VERSION_1)
+ sys_config.wpa_cfg.pairwise_cipher_wpa |= CIPHER_TKIP;
+ if (params->crypto.wpa_versions & NL80211_WPA_VERSION_2)
+ sys_config.wpa_cfg.pairwise_cipher_wpa2 |= CIPHER_TKIP;
+ break;
+ case WLAN_CIPHER_SUITE_CCMP:
+ if (params->crypto.wpa_versions & NL80211_WPA_VERSION_1)
+ sys_config.wpa_cfg.pairwise_cipher_wpa |= CIPHER_AES_CCMP;
+ if (params->crypto.wpa_versions & NL80211_WPA_VERSION_2)
+ sys_config.wpa_cfg.pairwise_cipher_wpa2 |= CIPHER_AES_CCMP;
+ break;
+ }
+ }
+ switch (params->crypto.cipher_group) {
+ case WLAN_CIPHER_SUITE_WEP40:
+ case WLAN_CIPHER_SUITE_WEP104:
+ if ((priv->cipher == WLAN_CIPHER_SUITE_WEP40) ||
+ (priv->cipher == WLAN_CIPHER_SUITE_WEP104)) {
+ sys_config.protocol = PROTOCOL_STATIC_WEP;
+ sys_config.key_mgmt = KEY_MGMT_NONE;
+ sys_config.wpa_cfg.length = 0;
+ sys_config.wep_cfg.key0.key_index = priv->key_index;
+ sys_config.wep_cfg.key0.is_default = 1;
+ sys_config.wep_cfg.key0.length = priv->key_len;
+ memcpy(sys_config.wep_cfg.key0.key, priv->key_material,
+ priv->key_len);
+ }
+ break;
+ case WLAN_CIPHER_SUITE_TKIP:
+ sys_config.wpa_cfg.group_cipher = CIPHER_TKIP;
+ break;
+ case WLAN_CIPHER_SUITE_CCMP:
+ sys_config.wpa_cfg.group_cipher = CIPHER_AES_CCMP;
+ break;
+ }
+#else
+ /* Since in Android ICS 4.0.1's wpa_supplicant, there is no way to set ssid
+ when GO (AP) starts up, so get it from beacon head parameter TODO: right
+ now use hard code 24 -- ieee80211 header lenth, 12 -- fixed element
+ length for beacon */
+#define BEACON_IE_OFFSET 36
+ /* Find SSID in head SSID IE id: 0, right now use hard code */
+ ssid_ie = woal_parse_ie_tlv(params->head + BEACON_IE_OFFSET,
+ params->head_len - BEACON_IE_OFFSET, 0);
+ if (!ssid_ie) {
+ PRINTM(MERROR, "No ssid IE found.\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ if (*(ssid_ie + 1) > 32) {
+ PRINTM(MERROR, "ssid len error: %d\n", *(ssid_ie + 1));
+ ret = -EFAULT;
+ goto done;
+ }
+ memcpy(sys_config.ssid.ssid, ssid_ie + 2, *(ssid_ie + 1));
+ sys_config.ssid.ssid_len = *(ssid_ie + 1);
+ head = (struct ieee80211_mgmt *) params->head;
+ capab_info = le16_to_cpu(head->u.beacon.capab_info);
+ PRINTM(MIOCTL, "capab_info=0x%x\n", head->u.beacon.capab_info);
+ sys_config.auth_mode = MLAN_AUTH_MODE_OPEN;
+ /** For ICS, we don't support OPEN mode */
+ if ((priv->cipher == WLAN_CIPHER_SUITE_WEP40) ||
+ (priv->cipher == WLAN_CIPHER_SUITE_WEP104)) {
+ sys_config.protocol = PROTOCOL_STATIC_WEP;
+ sys_config.key_mgmt = KEY_MGMT_NONE;
+ sys_config.wpa_cfg.length = 0;
+ sys_config.wep_cfg.key0.key_index = priv->key_index;
+ sys_config.wep_cfg.key0.is_default = 1;
+ sys_config.wep_cfg.key0.length = priv->key_len;
+ memcpy(sys_config.wep_cfg.key0.key, priv->key_material, priv->key_len);
+ } else {
+ /** Get cipher and key_mgmt from RSN/WPA IE */
+ if (capab_info & WLAN_CAPABILITY_PRIVACY) {
+ if (MFALSE ==
+ woal_find_wpa_ies(params->tail, params->tail_len,
+ &sys_config)) {
+ /* hard code setting to wpa2-psk */
+ sys_config.protocol = PROTOCOL_WPA2;
+ sys_config.key_mgmt = KEY_MGMT_PSK;
+ sys_config.wpa_cfg.pairwise_cipher_wpa2 = CIPHER_AES_CCMP;
+ sys_config.wpa_cfg.group_cipher = CIPHER_AES_CCMP;
+ }
+ }
+ }
+#endif /* COMPAT_WIRELESS */
+ /* If the security mode is configured as WEP or WPA-PSK, it will disable
+ 11n automatically, and if configured as open(off) or wpa2-psk, it will
+ automatically enable 11n */
+ if ((sys_config.protocol == PROTOCOL_STATIC_WEP) ||
+ (sys_config.protocol == PROTOCOL_WPA))
+ woal_uap_set_11n_status(&sys_config, MLAN_ACT_DISABLE);
+ else
+ woal_uap_set_11n_status(&sys_config, MLAN_ACT_ENABLE);
+ if (MLAN_STATUS_SUCCESS != woal_set_get_sys_config(priv,
+ MLAN_ACT_SET,
+ MOAL_IOCTL_WAIT,
+ &sys_config)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ done:
+ LEAVE();
+ return ret;
+}
+
+static int
+woal_mon_open(struct net_device *ndev)
+{
+ ENTER();
+ LEAVE();
+ return 0;
+}
+
+static int
+woal_mon_close(struct net_device *ndev)
+{
+ ENTER();
+ LEAVE();
+ return 0;
+}
+
+static int
+woal_mon_set_mac_address(struct net_device *ndev, void *addr)
+{
+ ENTER();
+ LEAVE();
+ return 0;
+}
+
+static void
+woal_mon_set_multicast_list(struct net_device *ndev)
+{
+ ENTER();
+ LEAVE();
+}
+
+static int
+woal_mon_hard_start_xmit(struct sk_buff *skb, struct net_device *ndev)
+{
+ int len_rthdr;
+ int qos_len = 0;
+ int dot11_hdr_len = 24;
+ int snap_len = 6;
+ unsigned char *pdata;
+ unsigned short fc;
+ unsigned char src_mac_addr[6];
+ unsigned char dst_mac_addr[6];
+ struct ieee80211_hdr *dot11_hdr;
+ struct ieee80211_radiotap_header *prthdr =
+ (struct ieee80211_radiotap_header *) skb->data;
+ monitor_iface *mon_if = netdev_priv(ndev);
+
+ if (mon_if == NULL || mon_if->base_ndev == NULL) {
+ goto fail;
+ }
+
+ ENTER();
+ /* check for not even having the fixed radiotap header part */
+ if (unlikely(skb->len < sizeof(struct ieee80211_radiotap_header))) {
+ PRINTM(MERROR, "Invalid radiotap hdr length,"
+ "skb->len: %d\n", skb->len);
+ goto fail; /* too short to be possibly valid */
+ }
+
+ /* is it a header version we can trust to find length from? */
+ if (unlikely(prthdr->it_version))
+ goto fail; /* only version 0 is supported */
+
+ /* then there must be a radiotap header with a length we can use */
+ len_rthdr = ieee80211_get_radiotap_len(skb->data);
+
+ /* does the skb contain enough to deliver on the alleged length? */
+ if (unlikely(skb->len < len_rthdr)) {
+ PRINTM(MERROR, "Invalid data length," "skb->len: %d\n", skb->len);
+ goto fail; /* skb too short for claimed rt header extent */
+ }
+
+ /* Skip the ratiotap header */
+ skb_pull(skb, len_rthdr);
+
+ dot11_hdr = (struct ieee80211_hdr *) skb->data;
+ fc = le16_to_cpu(dot11_hdr->frame_control);
+ if ((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA) {
+ /* Check if this ia a Wireless Distribution System (WDS) frame which
+ has 4 MAC addresses */
+ if (dot11_hdr->frame_control & 0x0080)
+ qos_len = 2;
+ if ((dot11_hdr->frame_control & 0x0300) == 0x0300)
+ dot11_hdr_len += 6;
+
+ memcpy(dst_mac_addr, dot11_hdr->addr1, sizeof(dst_mac_addr));
+ memcpy(src_mac_addr, dot11_hdr->addr2, sizeof(src_mac_addr));
+
+ /* Skip the 802.11 header, QoS (if any) and SNAP, but leave spaces for
+ for two MAC addresses */
+ skb_pull(skb,
+ dot11_hdr_len + qos_len + snap_len - sizeof(src_mac_addr) * 2);
+ pdata = (unsigned char *) skb->data;
+ memcpy(pdata, dst_mac_addr, sizeof(dst_mac_addr));
+ memcpy(pdata + sizeof(dst_mac_addr), src_mac_addr,
+ sizeof(src_mac_addr));
+
+ LEAVE();
+ return woal_hard_start_xmit(skb, mon_if->base_ndev);
+ }
+
+ fail:
+ dev_kfree_skb(skb);
+ return NETDEV_TX_OK;
+}
+
+static const struct net_device_ops woal_cfg80211_mon_if_ops = {
+ .ndo_open = woal_mon_open,
+ .ndo_start_xmit = woal_mon_hard_start_xmit,
+ .ndo_stop = woal_mon_close,
+ .ndo_set_mac_address = woal_mon_set_mac_address,
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,2,0)
+ .ndo_set_rx_mode = woal_mon_set_multicast_list,
+#else
+ .ndo_set_multicast_list = woal_mon_set_multicast_list,
+#endif
+};
+
+static void
+woal_mon_if_setup(struct net_device *dev)
+{
+ ENTER();
+ ether_setup(dev);
+ dev->netdev_ops = &woal_cfg80211_mon_if_ops;
+ dev->destructor = free_netdev;
+ LEAVE();
+}
+
+/**
+ * @brief Request the driver to add a monitor interface
+ *
+ * @param wiphy A pointer to wiphy structure
+ * @param name Virtual interface name
+ * @param flags Flags for the virtual interface
+ * @param params A pointer to vif_params structure
+ * @param new_dev Netdevice to be passed out
+ *
+ * @return A pointer to net_device -- success, otherwise null
+ */
+static int
+woal_cfg80211_add_mon_if(struct wiphy *wiphy, char *name,
+ u32 * flags, struct vif_params *params,
+ struct net_device **new_dev)
+{
+ int ret;
+ struct net_device *ndev;
+ monitor_iface *mon_if;
+ moal_private *priv;
+
+ ENTER();
+
+ ASSERT_RTNL();
+
+ priv = (moal_private *) woal_get_wiphy_priv(wiphy);
+
+ ndev = alloc_netdev_mq(sizeof(*mon_if), name, woal_mon_if_setup, 1);
+ if (!ndev) {
+ PRINTM(MFATAL, "Init virtual ethernet device failed\n");
+ ret = -EFAULT;
+ goto fail;
+ }
+
+ dev_net_set(ndev, wiphy_net(wiphy));
+
+ ret = dev_alloc_name(ndev, ndev->name);
+ if (ret < 0) {
+ PRINTM(MFATAL, "Net device alloc name fail.\n");
+ goto fail;
+ }
+
+ memcpy(ndev->perm_addr, wiphy->perm_addr, ETH_ALEN);
+ memcpy(ndev->dev_addr, ndev->perm_addr, ETH_ALEN);
+ SET_NETDEV_DEV(ndev, wiphy_dev(wiphy));
+
+ mon_if = netdev_priv(ndev);
+ ndev->ieee80211_ptr = &mon_if->wdev;
+ mon_if->wdev.iftype = NL80211_IFTYPE_MONITOR;
+ mon_if->wdev.wiphy = wiphy;
+ memcpy(mon_if->ifname, ndev->name, IFNAMSIZ);
+
+ ndev->type = ARPHRD_IEEE80211_RADIOTAP;
+ ndev->netdev_ops = &woal_cfg80211_mon_if_ops;
+
+ mon_if->priv = priv;
+ mon_if->mon_ndev = ndev;
+ mon_if->base_ndev = priv->netdev;
+ mon_if->radiotap_enabled = 1;
+ mon_if->flag = 1;
+
+ ret = register_netdevice(ndev);
+ if (ret) {
+ PRINTM(MFATAL, "register net_device failed, ret=%d\n", ret);
+ goto fail;
+ }
+
+ if (new_dev)
+ *new_dev = ndev;
+
+ fail:
+ if (ret && ndev)
+ free_netdev(ndev);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Request the driver to add a virtual interface
+ *
+ * @param wiphy A pointer to wiphy structure
+ * @param name Virtual interface name
+ * @param type Virtual interface type
+ * @param flags Flags for the virtual interface
+ * @param params A pointer to vif_params structure
+ *
+ * @return A pointer to net_device -- success, otherwise null
+ */
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,37) || defined(COMPAT_WIRELESS)
+struct net_device *
+woal_cfg80211_add_virtual_intf(struct wiphy *wiphy,
+ char *name, enum nl80211_iftype type,
+ u32 * flags, struct vif_params *params)
+#else
+int
+woal_cfg80211_add_virtual_intf(struct wiphy *wiphy,
+ char *name, enum nl80211_iftype type,
+ u32 * flags, struct vif_params *params)
+#endif
+{
+ struct net_device *ndev = NULL;
+ int ret = 0;
+
+ ENTER();
+ PRINTM(MIOCTL, "add virtual intf: %d\n", type);
+ switch (type) {
+ case NL80211_IFTYPE_MONITOR:
+ ret = woal_cfg80211_add_mon_if(wiphy, name, flags, params, &ndev);
+ break;
+ default:
+ PRINTM(MWARN, "Not supported if type: %d\n", type);
+ ret = -EFAULT;
+ break;
+ }
+ LEAVE();
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,37) || defined(COMPAT_WIRELESS)
+ if (ret)
+ return NULL;
+ else
+ return ndev;
+#else
+ return ret;
+#endif
+}
+
+/**
+ * @brief Request the driver to del a virtual interface
+ *
+ * @param wiphy A pointer to wiphy structure
+ * @param dev The pointer to net_device
+ *
+ * @return 0 -- success, otherwise fail
+ */
+int
+woal_cfg80211_del_virtual_intf(struct wiphy *wiphy, struct net_device *dev)
+{
+ ENTER();
+
+ PRINTM(MIOCTL, "del virtual intf\n");
+ ASSERT_RTNL();
+ unregister_netdevice(dev);
+
+ LEAVE();
+ return 0;
+}
+
+static int
+woal_uap_cfg80211_scan(struct wiphy *wiphy, struct net_device *dev,
+ struct cfg80211_scan_request *request)
+{
+ ENTER();
+
+ cfg80211_scan_done(request, MTRUE);
+
+ LEAVE();
+ return 0;
+}
+
+static int
+woal_uap_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev,
+ struct cfg80211_connect_params *sme)
+{
+ ENTER();
+ LEAVE();
+ return 0;
+}
+
+static int
+woal_uap_cfg80211_disconnect(struct wiphy *wiphy, struct net_device *dev,
+ t_u16 reason_code)
+{
+ ENTER();
+ LEAVE();
+ return 0;
+}
+
+/**
+ * @brief initialize AP or GO parameters
+
+ *
+ * @param wiphy A pointer to wiphy structure
+ * @param dev A pointer to net_device structure
+ * @param params A pointer to beacon_parameters structure
+ * @return 0 -- success, otherwise fail
+ */
+int
+woal_cfg80211_add_beacon(struct wiphy *wiphy,
+ struct net_device *dev,
+ struct beacon_parameters *params)
+{
+ moal_private *priv = (moal_private *) woal_get_wiphy_priv(wiphy);
+ int ret = 0;
+
+ ENTER();
+
+ PRINTM(MIOCTL, "add beacon\n");
+ if (params != NULL) {
+ /* bss config */
+ if (MLAN_STATUS_SUCCESS != woal_cfg80211_beacon_config(priv, params)) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ /* set mgmt frame ies */
+ if (MLAN_STATUS_SUCCESS != woal_cfg80211_mgmt_frame_ie(priv,
+#if LINUX_VERSION_CODE < KERNEL_VERSION(3,2,0) && !defined(COMPAT_WIRELESS)
+ params->tail,
+ params->tail_len,
+ NULL, 0, NULL, 0,
+ NULL, 0,
+ MGMT_MASK_BEACON
+#else
+ params->tail,
+ params->tail_len,
+ params->
+ proberesp_ies,
+ params->
+ proberesp_ies_len,
+ params->
+ assocresp_ies,
+ params->
+ assocresp_ies_len,
+ NULL, 0,
+ MGMT_MASK_BEACON
+ |
+ MGMT_MASK_PROBE_RESP
+ |
+ MGMT_MASK_ASSOC_RESP
+#endif
+ )) {
+ ret = -EFAULT;
+ goto done;
+ }
+ }
+
+ /* if the bss is stopped, then start it */
+ if (priv->bss_started == MFALSE) {
+ if (MLAN_STATUS_SUCCESS !=
+ woal_uap_bss_ctrl(priv, MOAL_IOCTL_WAIT, UAP_BSS_START)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ }
+
+ done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief set AP or GO parameter
+ *
+ * @param wiphy A pointer to wiphy structure
+ * @param dev A pointer to net_device structure
+ * @param params A pointer to beacon_parameters structure
+ * @return 0 -- success, otherwise fail
+ */
+int
+woal_cfg80211_set_beacon(struct wiphy *wiphy,
+ struct net_device *dev,
+ struct beacon_parameters *params)
+{
+ moal_private *priv = (moal_private *) woal_get_wiphy_priv(wiphy);
+ int ret = 0;
+
+ ENTER();
+
+ PRINTM(MIOCTL, "set beacon\n");
+ if (params != NULL) {
+#if LINUX_VERSION_CODE < KERNEL_VERSION(3,2,0) && !defined(COMPAT_WIRELESS)
+ if (params->tail && params->tail_len) {
+ if (MLAN_STATUS_SUCCESS !=
+ woal_cfg80211_mgmt_frame_ie(priv,
+ params->tail, params->tail_len,
+ NULL, 0, NULL, 0, NULL, 0,
+ MGMT_MASK_BEACON)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ }
+#else
+ if (params->beacon_ies && params->beacon_ies_len) {
+ if (MLAN_STATUS_SUCCESS !=
+ woal_cfg80211_mgmt_frame_ie(priv, params->tail,
+ params->tail_len, NULL, 0, NULL, 0,
+ NULL, 0, MGMT_MASK_BEACON)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ }
+
+ if (params->proberesp_ies && params->proberesp_ies_len) {
+ if (MLAN_STATUS_SUCCESS !=
+ woal_cfg80211_mgmt_frame_ie(priv, NULL, 0,
+ params->proberesp_ies,
+ params->proberesp_ies_len, NULL, 0,
+ NULL, 0, MGMT_MASK_PROBE_RESP)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ }
+
+ if (params->assocresp_ies && params->assocresp_ies_len) {
+ if (MLAN_STATUS_SUCCESS !=
+ woal_cfg80211_mgmt_frame_ie(priv, NULL, 0, NULL, 0,
+ params->assocresp_ies,
+ params->assocresp_ies_len, NULL, 0,
+ MGMT_MASK_ASSOC_RESP)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ }
+#endif
+ }
+
+ done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief reset AP or GO parameters
+ *
+ * @param wiphy A pointer to wiphy structure
+ * @param dev A pointer to net_device structure
+ *
+ * @return 0 -- success, otherwise fail
+ */
+int
+woal_cfg80211_del_beacon(struct wiphy *wiphy, struct net_device *dev)
+{
+ moal_private *priv = (moal_private *) woal_get_wiphy_priv(wiphy);
+ int ret = 0;
+
+ ENTER();
+
+ PRINTM(MIOCTL, "del beacon\n");
+ /* if the bss is still running, then stop it */
+ if (priv->bss_started == MTRUE) {
+ if (MLAN_STATUS_SUCCESS !=
+ woal_uap_bss_ctrl(priv, MOAL_IOCTL_WAIT, UAP_BSS_STOP)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ if (MLAN_STATUS_SUCCESS !=
+ woal_uap_bss_ctrl(priv, MOAL_IOCTL_WAIT, UAP_BSS_RESET)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ }
+
+ /* clear mgmt frame ies */
+ if (MLAN_STATUS_SUCCESS !=
+ woal_cfg80211_mgmt_frame_ie(priv, NULL, 0, NULL, 0, NULL, 0, NULL, 0,
+ MGMT_MASK_BEACON | MGMT_MASK_PROBE_RESP |
+ MGMT_MASK_ASSOC_RESP)) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ priv->cipher = 0;
+ priv->key_len = 0;
+ done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Get station info
+ *
+ * @param wiphy A pointer to wiphy structure
+ * @param dev A pointer to net_device structure
+ * @param mac A pointer to station mac address
+ * @param stainfo A pointer to station_info structure
+ *
+ * @return 0 -- success, otherwise fail
+ */
+int
+woal_uap_cfg80211_get_station(struct wiphy *wiphy, struct net_device *dev,
+ u8 * mac, struct station_info *stainfo)
+{
+ moal_private *priv = (moal_private *) woal_get_wiphy_priv(wiphy);
+ int ret = -EFAULT;
+ int i = 0;
+ mlan_ds_get_info *info = NULL;
+ mlan_ioctl_req *ioctl_req = NULL;
+
+ ENTER();
+ if (priv->media_connected == MFALSE) {
+ PRINTM(MINFO, "cfg80211: Media not connected!\n");
+ LEAVE();
+ return -ENOENT;
+ }
+
+ /* Allocate an IOCTL request buffer */
+ ioctl_req =
+ (mlan_ioctl_req *) woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_get_info));
+ if (ioctl_req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ info = (mlan_ds_get_info *) ioctl_req->pbuf;
+ info->sub_command = MLAN_OID_UAP_STA_LIST;
+ ioctl_req->req_id = MLAN_IOCTL_GET_INFO;
+ ioctl_req->action = MLAN_ACT_GET;
+
+ if (MLAN_STATUS_SUCCESS !=
+ woal_request_ioctl(priv, ioctl_req, MOAL_IOCTL_WAIT)) {
+ goto done;
+ }
+ for (i = 0; i < info->param.sta_list.sta_count; i++) {
+ if (!memcmp(info->param.sta_list.info[i].mac_address, mac, ETH_ALEN)) {
+ PRINTM(MIOCTL,
+ "Get station: %02x:%02x:%02x:%02x:%02x:%02x RSSI=%d\n",
+ mac[0], mac[1], mac[2], mac[3], mac[4], mac[5],
+ (int) info->param.sta_list.info[i].rssi);
+ stainfo->filled = STATION_INFO_INACTIVE_TIME | STATION_INFO_SIGNAL;
+ stainfo->inactive_time = 0;
+ stainfo->signal = info->param.sta_list.info[i].rssi;
+ ret = 0;
+ break;
+ }
+ }
+ done:
+ if (ioctl_req)
+ kfree(ioctl_req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Sets up the CFG802.11 specific HT capability fields
+ * with default values
+ *
+ * @param ht_info A pointer to ieee80211_sta_ht_cap structure
+ * @param ap_cfg A pointer to mlan_uap_bss_param
+ *
+ * @return N/A
+ */
+static void
+woal_cfg80211_setup_uap_ht_cap(struct ieee80211_sta_ht_cap *ht_info,
+ mlan_uap_bss_param * ap_cfg)
+{
+ ENTER();
+
+ ht_info->ht_supported = true;
+ ht_info->ampdu_factor = ap_cfg->ampdu_param & (MBIT(1) | MBIT(0));
+ ht_info->ampdu_density =
+ ap_cfg->ampdu_param & (MBIT(4) | MBIT(3) | MBIT(2));
+
+ memset(&ht_info->mcs, 0, sizeof(ht_info->mcs));
+ memcpy(ht_info->mcs.rx_mask, ap_cfg->supported_mcs_set,
+ sizeof(ht_info->mcs.rx_mask));
+
+ ht_info->cap = 0;
+ if (ap_cfg->ht_cap_info & MBIT(1)) /* 20/40 Mhz enable */
+ ht_info->cap |= IEEE80211_HT_CAP_SUP_WIDTH_20_40;
+ if (ap_cfg->ht_cap_info & MBIT(4)) /* Green field supported */
+ ht_info->cap |= IEEE80211_HT_CAP_GRN_FLD;
+ if (ap_cfg->ht_cap_info & MBIT(5)) /* Short GI @ 20Mhz supported */
+ ht_info->cap |= IEEE80211_HT_CAP_SGI_20;
+ if (ap_cfg->ht_cap_info & MBIT(6)) /* Short GI @ 40Mhz supported */
+ ht_info->cap |= IEEE80211_HT_CAP_SGI_40;
+ if (ap_cfg->ht_cap_info & MBIT(12)) /* DSS/CCK mode in 40MHz enable */
+ ht_info->cap |= IEEE80211_HT_CAP_DSSSCCK40;
+ ht_info->mcs.tx_params = IEEE80211_HT_MCS_TX_DEFINED;
+
+ LEAVE();
+}
+
+/**
+ * @brief Initialize the uAP wiphy
+ *
+ * @param priv A pointer to moal_private structure
+ * @param wait_option Wait option
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status
+woal_cfg80211_uap_init_wiphy(moal_private * priv, t_u8 wait_option)
+{
+ struct wiphy *wiphy = priv->wdev->wiphy;
+ mlan_uap_bss_param ap_cfg;
+
+ ENTER();
+
+ if (MLAN_STATUS_SUCCESS != woal_set_get_sys_config(priv,
+ MLAN_ACT_GET,
+ wait_option, &ap_cfg)) {
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+
+ /* Initialize parameters for 2GHz and 5GHz bands */
+ woal_cfg80211_setup_uap_ht_cap(&wiphy->bands[IEEE80211_BAND_2GHZ]->ht_cap,
+ &ap_cfg);
+ if (wiphy->bands[IEEE80211_BAND_5GHZ])
+ woal_cfg80211_setup_uap_ht_cap(&wiphy->bands[IEEE80211_BAND_5GHZ]->
+ ht_cap, &ap_cfg);
+
+ /* Set retry limit count to wiphy */
+ wiphy->retry_long = (t_u8) ap_cfg.retry_limit;
+ wiphy->retry_short = (t_u8) ap_cfg.retry_limit;
+ wiphy->max_scan_ie_len = MAX_IE_SIZE;
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,37) || defined(COMPAT_WIRELESS)
+ wiphy->mgmt_stypes = ieee80211_uap_mgmt_stypes;
+#endif
+ /* Set RTS threshold to wiphy */
+ wiphy->rts_threshold = (t_u32) ap_cfg.rts_threshold;
+
+ /* Set fragment threshold to wiphy */
+ wiphy->frag_threshold = (t_u32) ap_cfg.frag_threshold;
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief Register the device with cfg80211
+ *
+ * @param dev A pointer to net_device structure
+ * @param bss_type BSS type
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status
+woal_register_uap_cfg80211(struct net_device * dev, t_u8 bss_type)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ moal_private *priv = (moal_private *) netdev_priv(dev);
+ void *wdev_priv = NULL;
+ struct wireless_dev *wdev = NULL;
+ mlan_fw_info fw_info;
+
+ ENTER();
+
+ /* Allocate wireless device */
+ wdev = kzalloc(sizeof(struct wireless_dev), GFP_KERNEL);
+ if (!wdev) {
+ PRINTM(MERROR, "Could not allocate wireless device\n");
+ ret = MLAN_STATUS_FAILURE;
+ goto err_wdev;
+ }
+
+ /* Allocate wiphy */
+ wdev->wiphy = wiphy_new(&woal_cfg80211_uap_ops, sizeof(moal_private *));
+ if (!wdev->wiphy) {
+ PRINTM(MERROR, "Could not allocate wiphy device\n");
+ ret = MLAN_STATUS_FAILURE;
+ goto err_wdev;
+ }
+ if (bss_type == MLAN_BSS_TYPE_UAP) {
+ dev_set_name(&wdev->wiphy->dev, dev->name);
+ wdev->iftype = NL80211_IFTYPE_AP;
+ wdev->wiphy->interface_modes =
+ MBIT(NL80211_IFTYPE_AP) | MBIT(NL80211_IFTYPE_STATION) |
+ MBIT(NL80211_IFTYPE_MONITOR);
+ wdev->wiphy->max_scan_ssids = 10;
+ }
+
+ /* Make this wiphy known to this driver only */
+ wdev->wiphy->privid = mrvl_wiphy_privid;
+
+ /* Supported bands */
+ wdev->wiphy->bands[IEEE80211_BAND_2GHZ] = &cfg80211_band_2ghz;
+ if (MLAN_STATUS_SUCCESS ==
+ woal_request_get_fw_info(priv, MOAL_CMD_WAIT, &fw_info)) {
+ if (fw_info.fw_bands & BAND_A)
+ wdev->wiphy->bands[IEEE80211_BAND_5GHZ] = &cfg80211_band_5ghz;
+ }
+
+ /* Initialize cipher suits */
+ wdev->wiphy->cipher_suites = cfg80211_cipher_suites;
+ wdev->wiphy->n_cipher_suites = ARRAY_SIZE(cfg80211_cipher_suites);
+
+ wdev->wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM;
+
+ /* We are using custom domains */
+ wdev->wiphy->flags |= WIPHY_FLAG_CUSTOM_REGULATORY;
+
+ wdev->wiphy->reg_notifier = NULL; // TODO: woal_cfg80211_reg_notifier;
+
+ /* Set moal_private pointer in wiphy_priv */
+ wdev_priv = wiphy_priv(wdev->wiphy);
+
+ *(unsigned long *) wdev_priv = (unsigned long) priv;
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,39) || defined(COMPAT_WIRELESS)
+ set_wiphy_dev(wdev->wiphy, (struct device *) priv->phandle->hotplug_device);
+#endif
+
+ if (wiphy_register(wdev->wiphy) < 0) {
+ PRINTM(MERROR, "Wiphy device registration failed!\n");
+ ret = MLAN_STATUS_FAILURE;
+ goto err_wdev;
+ }
+
+ dev_net_set(dev, wiphy_net(wdev->wiphy));
+ dev->ieee80211_ptr = wdev;
+ SET_NETDEV_DEV(dev, wiphy_dev(wdev->wiphy));
+ priv->wdev = wdev;
+
+ if (ret != MLAN_STATUS_SUCCESS) {
+ PRINTM(MERROR, "Wiphy device registration failed!\n");
+ } else {
+ PRINTM(MINFO, "Successfully registered wiphy device\n");
+ LEAVE();
+ return ret;
+ }
+
+ wiphy_unregister(wdev->wiphy);
+ err_wdev:
+ dev->ieee80211_ptr = NULL;
+ if (wdev && wdev->wiphy)
+ wiphy_free(wdev->wiphy);
+ kfree(wdev);
+ LEAVE();
+ return ret;
+}
diff --git a/drivers/net/wireless/sd8797/mlinux/moal_uap_cfg80211.h b/drivers/net/wireless/sd8797/mlinux/moal_uap_cfg80211.h
new file mode 100644
index 000000000000..74c6f1a4e59b
--- /dev/null
+++ b/drivers/net/wireless/sd8797/mlinux/moal_uap_cfg80211.h
@@ -0,0 +1,30 @@
+/** @file moal_uap_cfg80211.h
+ *
+ * @brief This file contains the uAP CFG80211 specific defines.
+ *
+ * Copyright (C) 2011, Marvell International Ltd.
+ *
+ * This software file (the "File") is distributed by Marvell International
+ * Ltd. under the terms of the GNU General Public License Version 2, June 1991
+ * (the "License"). You may use, redistribute and/or modify this File in
+ * accordance with the terms and conditions of the License, a copy of which
+ * is available by writing to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
+ * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
+ *
+ * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
+ * ARE EXPRESSLY DISCLAIMED. The License provides additional details about
+ * this warranty disclaimer.
+ *
+ */
+
+#ifndef _MOAL_UAP_CFG80211_H_
+#define _MOAL_UAP_CFG80211_H_
+
+#include "moal_uap.h"
+
+mlan_status woal_register_uap_cfg80211(struct net_device *dev, t_u8 bss_type);
+mlan_status woal_cfg80211_uap_init_wiphy(moal_private * priv, t_u8 wait_option);
+
+#endif /* _MOAL_UAP_CFG80211_H_ */
diff --git a/drivers/net/wireless/sd8797/mlinux/moal_uap_priv.c b/drivers/net/wireless/sd8797/mlinux/moal_uap_priv.c
new file mode 100644
index 000000000000..dd06e03ecb1e
--- /dev/null
+++ b/drivers/net/wireless/sd8797/mlinux/moal_uap_priv.c
@@ -0,0 +1,175 @@
+/** @file moal_uap_priv.c
+ *
+ * @brief This file contains standard ioctl functions
+ *
+ * Copyright (C) 2010-2011, Marvell International Ltd.
+ *
+ * This software file (the "File") is distributed by Marvell International
+ * Ltd. under the terms of the GNU General Public License Version 2, June 1991
+ * (the "License"). You may use, redistribute and/or modify this File in
+ * accordance with the terms and conditions of the License, a copy of which
+ * is available by writing to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
+ * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
+ *
+ * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
+ * ARE EXPRESSLY DISCLAIMED. The License provides additional details about
+ * this warranty disclaimer.
+ *
+ */
+
+/************************************************************************
+Change log:
+ 08/06/2010: initial version
+************************************************************************/
+
+#include "moal_main.h"
+#include "moal_uap.h"
+#include "moal_uap_priv.h"
+
+/********************************************************
+ Local Variables
+********************************************************/
+
+/********************************************************
+ Global Variables
+********************************************************/
+
+/********************************************************
+ Local Functions
+********************************************************/
+
+/********************************************************
+ Global Functions
+********************************************************/
+
+/**
+ * @brief ioctl function for wireless IOCTLs
+ *
+ * @param dev A pointer to net_device structure
+ * @param req A pointer to ifreq structure
+ * @param cmd Command
+ *
+ * @return 0 --success, otherwise fail
+ */
+int
+woal_uap_do_priv_ioctl(struct net_device *dev, struct ifreq *req, int cmd)
+{
+ moal_private *priv = (moal_private *) netdev_priv(dev);
+ struct iwreq *wrq = (struct iwreq *) req;
+ int ret = 0;
+
+ ENTER();
+
+ switch (cmd) {
+ case WOAL_UAP_SETNONE_GETNONE:
+ switch (wrq->u.data.flags) {
+ case WOAL_UAP_START:
+ break;
+ case WOAL_UAP_STOP:
+ ret = woal_uap_bss_ctrl(priv, MOAL_IOCTL_WAIT, UAP_BSS_STOP);
+ break;
+ case WOAL_AP_BSS_START:
+ ret = woal_uap_bss_ctrl(priv, MOAL_IOCTL_WAIT, UAP_BSS_START);
+ break;
+ case WOAL_AP_BSS_STOP:
+ ret = woal_uap_bss_ctrl(priv, MOAL_IOCTL_WAIT, UAP_BSS_STOP);
+ break;
+ default:
+ ret = -EINVAL;
+ break;
+ }
+ break;
+ case WOAL_UAP_SETONEINT_GETWORDCHAR:
+ switch (wrq->u.data.flags) {
+ case WOAL_UAP_VERSION:
+ ret = woal_get_driver_version(priv, req);
+ break;
+ case WOAL_UAP_VEREXT:
+ ret = woal_get_driver_verext(priv, req);
+ break;
+ default:
+ ret = -EOPNOTSUPP;
+ break;
+ }
+ break;
+ case WOAL_UAP_SET_GET_256_CHAR:
+ switch (wrq->u.data.flags) {
+ case WOAL_WL_FW_RELOAD:
+ break;
+ case WOAL_AP_SET_CFG:
+ ret = woal_uap_set_ap_cfg(priv, wrq->u.data.pointer,
+ wrq->u.data.length);
+ break;
+ default:
+ ret = -EINVAL;
+ break;
+ }
+ break;
+#if defined(WIFI_DIRECT_SUPPORT)
+#if defined(STA_SUPPORT) && defined(UAP_SUPPORT)
+ case WOAL_UAP_SETONEINT_GETONEINT:
+ switch (wrq->u.data.flags) {
+ case WOAL_UAP_SET_GET_BSS_ROLE:
+ ret = woal_set_get_bss_role(priv, wrq);
+ break;
+ default:
+ ret = -EINVAL;
+ break;
+ }
+ break;
+#endif
+#endif
+ case WOAL_UAP_HOST_CMD:
+ ret = woal_host_command(priv, wrq);
+ break;
+ case WOAL_UAP_FROYO_START:
+ break;
+ case WOAL_UAP_FROYO_STOP:
+ ret = woal_uap_bss_ctrl(priv, MOAL_IOCTL_WAIT, UAP_BSS_STOP);
+ break;
+ case WOAL_UAP_FROYO_AP_BSS_START:
+ ret = woal_uap_bss_ctrl(priv, MOAL_IOCTL_WAIT, UAP_BSS_START);
+ break;
+ case WOAL_UAP_FROYO_AP_BSS_STOP:
+ ret = woal_uap_bss_ctrl(priv, MOAL_IOCTL_WAIT, UAP_BSS_STOP);
+ break;
+ case WOAL_UAP_FROYO_WL_FW_RELOAD:
+ break;
+ case WOAL_UAP_FROYO_AP_SET_CFG:
+ ret = woal_uap_set_ap_cfg(priv, wrq->u.data.pointer,
+ wrq->u.data.length);
+ break;
+ default:
+ ret = -EINVAL;
+ break;
+ }
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Handle get info resp
+ *
+ * @param priv Pointer to moal_private structure
+ * @param info Pointer to mlan_ds_get_info structure
+ *
+ * @return N/A
+ */
+void
+woal_ioctl_get_uap_info_resp(moal_private * priv, mlan_ds_get_info * info)
+{
+ ENTER();
+ switch (info->sub_command) {
+ case MLAN_OID_GET_STATS:
+ priv->w_stats.discard.fragment = info->param.ustats.fcs_error_count;
+ priv->w_stats.discard.retries = info->param.ustats.retry_count;
+ priv->w_stats.discard.misc = info->param.ustats.ack_failure_count;
+ break;
+ default:
+ break;
+ }
+ LEAVE();
+}
diff --git a/drivers/net/wireless/sd8797/mlinux/moal_uap_priv.h b/drivers/net/wireless/sd8797/mlinux/moal_uap_priv.h
new file mode 100644
index 000000000000..fcd811efb168
--- /dev/null
+++ b/drivers/net/wireless/sd8797/mlinux/moal_uap_priv.h
@@ -0,0 +1,194 @@
+/** @file moal_uap_priv.h
+ *
+ * @brief This file contains definition for extended private IOCTL call.
+ *
+ * Copyright (C) 2010-2011, Marvell International Ltd.
+ *
+ * This software file (the "File") is distributed by Marvell International
+ * Ltd. under the terms of the GNU General Public License Version 2, June 1991
+ * (the "License"). You may use, redistribute and/or modify this File in
+ * accordance with the terms and conditions of the License, a copy of which
+ * is available by writing to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
+ * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
+ *
+ * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
+ * ARE EXPRESSLY DISCLAIMED. The License provides additional details about
+ * this warranty disclaimer.
+ *
+ */
+
+/************************************************************************
+Change log:
+ 08/06/2010: initial version
+************************************************************************/
+
+#ifndef _MOAL_UAP_PRIV_H_
+#define _MOAL_UAP_PRIV_H_
+
+/** Private command ID */
+#define WOAL_UAP_IOCTL 0x8BE0
+
+/** Private command to get/set 256 chars */
+#define WOAL_UAP_SET_GET_256_CHAR (WOAL_UAP_IOCTL + 1)
+/** Private command ID to FW reload */
+#define WOAL_WL_FW_RELOAD 1
+/** Private command ID to set AP configuration */
+#define WOAL_AP_SET_CFG 2
+
+/** Private command ID to set/get none */
+#define WOAL_UAP_SETNONE_GETNONE (WOAL_UAP_IOCTL + 2)
+/** Private command ID to start UAP */
+#define WOAL_UAP_START 1
+/** Private command ID to stop UAP */
+#define WOAL_UAP_STOP 2
+/** Private command ID to start AP BSS */
+#define WOAL_AP_BSS_START 3
+/** Private command ID to stop AP BSS */
+#define WOAL_AP_BSS_STOP 4
+
+/** Private command ID to set one int/get word char */
+#define WOAL_UAP_SETONEINT_GETWORDCHAR (WOAL_UAP_IOCTL + 3)
+/** Private command ID to get version */
+#define WOAL_UAP_VERSION 1
+/** Private command ID to get extended version */
+#define WOAL_UAP_VEREXT 2
+
+#if defined(WIFI_DIRECT_SUPPORT)
+#if defined(STA_SUPPORT) && defined(UAP_SUPPORT)
+/** Private command ID to set one int/get one int */
+#define WOAL_UAP_SETONEINT_GETONEINT (WOAL_UAP_IOCTL + 5)
+/** Private command ID for set/get BSS role */
+#define WOAL_UAP_SET_GET_BSS_ROLE 1
+#endif
+#endif
+
+/** Private command ID for hostcmd */
+#define WOAL_UAP_HOST_CMD (WOAL_UAP_IOCTL + 17)
+
+/** The following command IDs are for Froyo app */
+/** Private command ID to start AP BSS */
+#define WOAL_UAP_FROYO_AP_BSS_START (WOAL_UAP_IOCTL + 24)
+/** Private command ID to stop AP BSS */
+#define WOAL_UAP_FROYO_AP_BSS_STOP (WOAL_UAP_IOCTL + 26)
+/** Private command ID to set AP config */
+#define WOAL_UAP_FROYO_AP_SET_CFG (WOAL_UAP_IOCTL + 27)
+/** Private command ID to start driver */
+#define WOAL_UAP_FROYO_START (WOAL_UAP_IOCTL + 28)
+/** Private command ID to reload FW */
+#define WOAL_UAP_FROYO_WL_FW_RELOAD (WOAL_UAP_IOCTL + 29)
+/** Private command ID to stop driver */
+#define WOAL_UAP_FROYO_STOP (WOAL_UAP_IOCTL + 30)
+
+/**
+ * iwpriv ioctl handlers
+ */
+static const struct iw_priv_args woal_uap_priv_args[] = {
+ {
+ WOAL_UAP_SETNONE_GETNONE,
+ IW_PRIV_TYPE_NONE,
+ IW_PRIV_TYPE_NONE,
+ ""},
+ {
+ WOAL_UAP_START,
+ IW_PRIV_TYPE_NONE,
+ IW_PRIV_TYPE_NONE,
+ "start"},
+ {
+ WOAL_UAP_STOP,
+ IW_PRIV_TYPE_NONE,
+ IW_PRIV_TYPE_NONE,
+ "stop"},
+ {
+ WOAL_AP_BSS_START,
+ IW_PRIV_TYPE_NONE,
+ IW_PRIV_TYPE_NONE,
+ "bssstart"},
+ {
+ WOAL_AP_BSS_STOP,
+ IW_PRIV_TYPE_NONE,
+ IW_PRIV_TYPE_NONE,
+ "bssstop"},
+ {
+ WOAL_UAP_SETONEINT_GETWORDCHAR,
+ IW_PRIV_TYPE_INT | 1,
+ IW_PRIV_TYPE_CHAR | 128,
+ ""},
+ {
+ WOAL_UAP_VERSION,
+ IW_PRIV_TYPE_INT | 1,
+ IW_PRIV_TYPE_CHAR | 128,
+ "version"},
+ {
+ WOAL_UAP_VEREXT,
+ IW_PRIV_TYPE_INT | 1,
+ IW_PRIV_TYPE_CHAR | 128,
+ "verext"},
+#if defined(WIFI_DIRECT_SUPPORT)
+#if defined(STA_SUPPORT) && defined(UAP_SUPPORT)
+ {
+ WOAL_UAP_SETONEINT_GETONEINT,
+ IW_PRIV_TYPE_INT | 1,
+ IW_PRIV_TYPE_INT | 1,
+ ""},
+ {
+ WOAL_UAP_SET_GET_BSS_ROLE,
+ IW_PRIV_TYPE_INT | 1,
+ IW_PRIV_TYPE_INT | 1,
+ "bssrole"},
+#endif
+#endif
+ {
+ WOAL_UAP_SET_GET_256_CHAR,
+ IW_PRIV_TYPE_CHAR | 256,
+ IW_PRIV_TYPE_CHAR | 256,
+ ""},
+ {
+ WOAL_WL_FW_RELOAD,
+ IW_PRIV_TYPE_CHAR | 256,
+ IW_PRIV_TYPE_CHAR | 256,
+ "fwreload"},
+ {
+ WOAL_AP_SET_CFG,
+ IW_PRIV_TYPE_CHAR | 256,
+ IW_PRIV_TYPE_CHAR | 256,
+ "apcfg"},
+ {
+ WOAL_UAP_HOST_CMD,
+ IW_PRIV_TYPE_BYTE | 2047,
+ IW_PRIV_TYPE_BYTE | 2047,
+ "hostcmd"},
+ {
+ WOAL_UAP_FROYO_START,
+ IW_PRIV_TYPE_NONE,
+ IW_PRIV_TYPE_NONE,
+ "START"},
+ {
+ WOAL_UAP_FROYO_STOP,
+ IW_PRIV_TYPE_NONE,
+ IW_PRIV_TYPE_NONE,
+ "STOP"},
+ {
+ WOAL_UAP_FROYO_AP_BSS_START,
+ IW_PRIV_TYPE_NONE,
+ IW_PRIV_TYPE_NONE,
+ "AP_BSS_START"},
+ {
+ WOAL_UAP_FROYO_AP_BSS_STOP,
+ IW_PRIV_TYPE_NONE,
+ IW_PRIV_TYPE_NONE,
+ "AP_BSS_STOP"},
+ {
+ WOAL_UAP_FROYO_WL_FW_RELOAD,
+ IW_PRIV_TYPE_CHAR | 256,
+ IW_PRIV_TYPE_CHAR | 256,
+ "WL_FW_RELOAD"},
+ {
+ WOAL_UAP_FROYO_AP_SET_CFG,
+ IW_PRIV_TYPE_CHAR | 256,
+ IW_PRIV_TYPE_CHAR | 256,
+ "AP_SET_CFG"},
+};
+
+#endif /* _MOAL_UAP_PRIV_H_ */
diff --git a/drivers/net/wireless/sd8797/mlinux/moal_uap_wext.c b/drivers/net/wireless/sd8797/mlinux/moal_uap_wext.c
new file mode 100644
index 000000000000..0426a28339cb
--- /dev/null
+++ b/drivers/net/wireless/sd8797/mlinux/moal_uap_wext.c
@@ -0,0 +1,1766 @@
+/** @file moal_uap_wext.c
+ *
+ * @brief This file contains wireless extension standard ioctl functions
+ *
+ * Copyright (C) 2010-2011, Marvell International Ltd.
+ *
+ * This software file (the "File") is distributed by Marvell International
+ * Ltd. under the terms of the GNU General Public License Version 2, June 1991
+ * (the "License"). You may use, redistribute and/or modify this File in
+ * accordance with the terms and conditions of the License, a copy of which
+ * is available by writing to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
+ * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
+ *
+ * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
+ * ARE EXPRESSLY DISCLAIMED. The License provides additional details about
+ * this warranty disclaimer.
+ *
+ */
+
+/************************************************************************
+Change log:
+ 08/06/2010: initial version
+************************************************************************/
+
+#include "moal_main.h"
+#include "moal_uap.h"
+#include "moal_wext.h"
+#include "moal_uap_priv.h"
+
+/********************************************************
+ Global Variables
+********************************************************/
+typedef struct _chan_to_freq_t
+{
+ /** Channel */
+ t_u16 channel;
+ /** Frequency */
+ t_u32 freq;
+ /** Band */
+ t_u8 band;
+} chan_to_freq_t;
+
+const chan_to_freq_t chan_to_freq[] = {
+ {1, 2412, 0},
+ {2, 2417, 0},
+ {3, 2422, 0},
+ {4, 2427, 0},
+ {5, 2432, 0},
+ {6, 2437, 0},
+ {7, 2442, 0},
+ {8, 2447, 0},
+ {9, 2452, 0},
+ {10, 2457, 0},
+ {11, 2462, 0},
+ {12, 2467, 0},
+ {13, 2472, 0},
+ {14, 2484, 0},
+ {183, 4915, 1},
+ {184, 4920, 1},
+ {185, 4925, 1},
+ {187, 4935, 1},
+ {188, 4940, 1},
+ {189, 4945, 1},
+ {192, 4960, 1},
+ {196, 4980, 1},
+ {7, 5035, 1},
+ {8, 5040, 1},
+ {9, 5045, 1},
+ {11, 5055, 1},
+ {12, 5060, 1},
+ {16, 5080, 1},
+ {34, 5170, 1},
+ {36, 5180, 1},
+ {38, 5190, 1},
+ {40, 5200, 1},
+ {42, 5210, 1},
+ {44, 5220, 1},
+ {46, 5230, 1},
+ {48, 5240, 1},
+ {52, 5260, 1},
+ {56, 5280, 1},
+ {60, 5300, 1},
+ {64, 5320, 1},
+ {100, 5500, 1},
+ {104, 5520, 1},
+ {108, 5540, 1},
+ {112, 5560, 1},
+ {116, 5580, 1},
+ {120, 5600, 1},
+ {124, 5620, 1},
+ {128, 5640, 1},
+ {132, 5660, 1},
+ {136, 5680, 1},
+ {140, 5700, 1},
+ {149, 5745, 1},
+ {153, 5765, 1},
+ {157, 5785, 1},
+ {161, 5805, 1},
+ {165, 5825, 1},
+};
+
+/** Convertion from frequency to channel */
+#define freq_to_chan(x) ((((x) - 2412) / 5) + 1)
+
+/********************************************************
+ Local Functions
+********************************************************/
+
+/**
+ * @brief Sort Channels
+ *
+ * @param freq A pointer to iw_freq structure
+ * @param num Number of Channels
+ *
+ * @return N/A
+ */
+static inline void
+woal_sort_channels(struct iw_freq *freq, int num)
+{
+ int i, j;
+ struct iw_freq temp;
+
+ for (i = 0; i < num; i++)
+ for (j = i + 1; j < num; j++)
+ if (freq[i].i > freq[j].i) {
+ temp.i = freq[i].i;
+ temp.m = freq[i].m;
+
+ freq[i].i = freq[j].i;
+ freq[i].m = freq[j].m;
+
+ freq[j].i = temp.i;
+ freq[j].m = temp.m;
+ }
+}
+
+/**
+ * @brief Get frequency for channel in given band
+ *
+ * @param channel channel
+ * @param band band
+ *
+ * @return freq
+ */
+static int
+channel_to_frequency(t_u16 channel, t_u8 band)
+{
+ int i = 0;
+
+ ENTER();
+ for (i = 0; i < sizeof(chan_to_freq) / sizeof(chan_to_freq_t); i++) {
+ if (channel == chan_to_freq[i].channel && band == chan_to_freq[i].band) {
+ LEAVE();
+ return chan_to_freq[i].freq;
+ }
+ }
+ LEAVE();
+ return 0;
+}
+
+/**
+ * @brief Commit handler: called after a bunch of SET operations
+ *
+ * @param dev A pointer to net_device structure
+ * @param info A pointer to iw_request_info structure
+ * @param cwrq A pointer to char buffer
+ * @param extra A pointer to extra data buf
+ *
+ * @return 0 --success
+ */
+static int
+woal_config_commit(struct net_device *dev,
+ struct iw_request_info *info, char *cwrq, char *extra)
+{
+ ENTER();
+
+ LEAVE();
+ return 0;
+}
+
+/**
+ * @brief Get name
+ *
+ * @param dev A pointer to net_device structure
+ * @param info A pointer to iw_request_info structure
+ * @param cwrq A pointer to char buffer
+ * @param extra A pointer to extra data buf
+ *
+ * @return 0 --success
+ */
+static int
+woal_get_name(struct net_device *dev, struct iw_request_info *info,
+ char *cwrq, char *extra)
+{
+ ENTER();
+ strcpy(cwrq, "IEEE 802.11-DS");
+ LEAVE();
+ return 0;
+}
+
+/**
+ * @brief Get current BSSID
+ *
+ * @param dev A pointer to net_device structure
+ * @param info A pointer to iw_request_info structure
+ * @param awrq A pointer to sockaddr structure
+ * @param extra A pointer to extra data buf
+ *
+ * @return 0 --success
+ */
+static int
+woal_get_wap(struct net_device *dev, struct iw_request_info *info,
+ struct sockaddr *awrq, char *extra)
+{
+ moal_private *priv = (moal_private *) netdev_priv(dev);
+ int ret = 0;
+
+ ENTER();
+
+ if (priv->bss_started) {
+ memcpy(awrq->sa_data, priv->current_addr, MLAN_MAC_ADDR_LENGTH);
+ } else {
+ memset(awrq->sa_data, 0, MLAN_MAC_ADDR_LENGTH);
+ }
+ awrq->sa_family = ARPHRD_ETHER;
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Change the AP BSSID
+ *
+ * @param dev A pointer to net_device structure
+ * @param info A pointer to iw_request_info structure
+ * @param awrq A pointer to iw_param structure
+ * @param extra A pointer to extra data buf
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_set_wap(struct net_device *dev, struct iw_request_info *info,
+ struct sockaddr *awrq, char *extra)
+{
+ int ret = 0;
+ moal_private *priv = (moal_private *) netdev_priv(dev);
+ const t_u8 zero_mac[MLAN_MAC_ADDR_LENGTH] = { 0, 0, 0, 0, 0, 0 };
+
+ ENTER();
+
+ if (awrq->sa_family != ARPHRD_ETHER) {
+ ret = -EINVAL;
+ goto done;
+ }
+
+ PRINTM(MINFO, "ASSOC: WAP: uAP bss : %02x:%02x:%02x:%02x:%02x:%02x\n",
+ (t_u8) awrq->sa_data[0], (t_u8) awrq->sa_data[1],
+ (t_u8) awrq->sa_data[2], (t_u8) awrq->sa_data[3],
+ (t_u8) awrq->sa_data[4], (t_u8) awrq->sa_data[5]);
+
+ /*
+ * Using this ioctl to start/stop the BSS, return if bss
+ * is already started/stopped.
+ */
+ if (memcmp(zero_mac, awrq->sa_data, MLAN_MAC_ADDR_LENGTH)) {
+ if (priv->bss_started == MFALSE)
+ ret = woal_uap_bss_ctrl(priv, MOAL_IOCTL_WAIT, UAP_BSS_START);
+ else
+ PRINTM(MINFO, "BSS is already started.\n");
+ } else {
+ /* zero_mac means bss_stop */
+ if (priv->bss_started == MTRUE)
+ ret = woal_uap_bss_ctrl(priv, MOAL_IOCTL_WAIT, UAP_BSS_STOP);
+ else
+ PRINTM(MINFO, "BSS is already stopped.\n");
+ }
+
+ done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set frequency/channel
+ *
+ * @param dev A pointer to net_device structure
+ * @param info A pointer to iw_request_info structure
+ * @param fwrq A pointer to iw_freq structure
+ * @param extra A pointer to extra data buf
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_set_freq(struct net_device *dev, struct iw_request_info *info,
+ struct iw_freq *fwrq, char *extra)
+{
+ moal_private *priv = (moal_private *) netdev_priv(dev);
+ mlan_uap_bss_param *sys_cfg = NULL, *ap_cfg = NULL;
+ int ret = 0, chan = 0, i = 0;
+
+ ENTER();
+
+ ap_cfg = kmalloc(sizeof(mlan_uap_bss_param), GFP_KERNEL);
+ if (ap_cfg == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ sys_cfg = kmalloc(sizeof(mlan_uap_bss_param), GFP_KERNEL);
+ if (sys_cfg == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ if (MLAN_STATUS_SUCCESS != woal_set_get_sys_config(priv,
+ MLAN_ACT_GET,
+ MOAL_IOCTL_WAIT,
+ ap_cfg)) {
+ PRINTM(MERROR, "Error getting AP confiruration\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ i = ap_cfg->num_of_chan;
+
+ /* Initialize the invalid values so that the correct values below are
+ downloaded to firmware */
+ woal_set_sys_config_invalid_data(sys_cfg);
+
+ /* If setting by frequency, convert to a channel */
+ if (fwrq->e == 1)
+ chan = freq_to_chan(fwrq->m / 100000);
+ else
+ chan = fwrq->m;
+ if (chan > 0 && chan < MLAN_MAX_CHANNEL)
+ sys_cfg->channel = chan;
+ else {
+ ret = -EINVAL;
+ goto done;
+ }
+ for (i = 0; i < ap_cfg->num_of_chan; i++)
+ if (ap_cfg->chan_list[i].chan_number == chan)
+ break;
+ if (i == ap_cfg->num_of_chan) {
+ PRINTM(MERROR, "Channel %d is not supported\n", chan);
+ ret = -EINVAL;
+ goto done;
+ }
+
+ if (MLAN_STATUS_SUCCESS != woal_set_get_sys_config(priv,
+ MLAN_ACT_SET,
+ MOAL_IOCTL_WAIT,
+ sys_cfg)) {
+ PRINTM(MERROR, "Error setting AP confiruration\n");
+ ret = -EFAULT;
+ goto done;
+ }
+
+ done:
+ if (sys_cfg)
+ kfree(sys_cfg);
+ if (ap_cfg)
+ kfree(ap_cfg);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Get frequency and channel
+ *
+ * @param dev A pointer to net_device structure
+ * @param info A pointer to iw_request_info structure
+ * @param fwrq A pointer to iw_freq structure
+ * @param extra A pointer to extra data buf
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_get_freq(struct net_device *dev, struct iw_request_info *info,
+ struct iw_freq *fwrq, char *extra)
+{
+ moal_private *priv = (moal_private *) netdev_priv(dev);
+ mlan_uap_bss_param ap_cfg;
+ t_u8 band = 0;
+ int ret = 0;
+
+ ENTER();
+
+ if (MLAN_STATUS_SUCCESS != woal_set_get_sys_config(priv,
+ MLAN_ACT_GET,
+ MOAL_IOCTL_WAIT,
+ &ap_cfg)) {
+ PRINTM(MERROR, "Error getting AP confiruration\n");
+ LEAVE();
+ return -EFAULT;
+ }
+ band = ap_cfg.band_cfg & BAND_CONFIG_5GHZ;
+ fwrq->i = (long) ap_cfg.channel;
+ fwrq->m = (long) (channel_to_frequency(ap_cfg.channel, band)) * 100000;
+ fwrq->e = 1;
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set wlan mode
+ *
+ * @param dev A pointer to net_device structure
+ * @param info A pointer to iw_request_info structure
+ * @param uwrq A pointer to t_u32 string
+ * @param extra A pointer to extra data buf
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_set_bss_mode(struct net_device *dev, struct iw_request_info *info,
+ t_u32 * uwrq, char *extra)
+{
+ int ret = 0;
+ ENTER();
+
+ switch (*uwrq) {
+ case IW_MODE_AUTO:
+ case IW_MODE_MASTER:
+ PRINTM(MINFO, "This is correct mode in AP mode\n");
+ break;
+ default:
+ PRINTM(MERROR, "Invalid mode for AP\n");
+ ret = -EINVAL;
+ }
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Get wlan mode
+ *
+ * @param dev A pointer to net_device structure
+ * @param info A pointer to iw_request_info structure
+ * @param uwrq A pointer to t_u32 string
+ * @param extra A pointer to extra data buf
+ *
+ * @return 0 --success
+ */
+static int
+woal_get_bss_mode(struct net_device *dev, struct iw_request_info *info,
+ t_u32 * uwrq, char *extra)
+{
+ ENTER();
+
+ *uwrq = IW_MODE_MASTER;
+
+ LEAVE();
+ return 0;
+}
+
+/**
+ * @brief Set encryption key
+ *
+ * @param dev A pointer to net_device structure
+ * @param info A pointer to iw_request_info structure
+ * @param dwrq A pointer to iw_point structure
+ * @param extra A pointer to extra data buf
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_set_encode(struct net_device *dev, struct iw_request_info *info,
+ struct iw_point *dwrq, char *extra)
+{
+ int ret = 0;
+ moal_private *priv = (moal_private *) netdev_priv(dev);
+ mlan_uap_bss_param *sys_cfg = NULL, *ap_cfg = NULL;
+ wep_key *pkey = NULL;
+ int key_index = 0;
+
+ ENTER();
+
+ /* Check index */
+ key_index = (dwrq->flags & IW_ENCODE_INDEX) - 1;
+ if (key_index > 3) {
+ PRINTM(MERROR, "Key index #%d out of range\n", key_index);
+ ret = -EINVAL;
+ goto done;
+ }
+
+ ap_cfg = kmalloc(sizeof(mlan_uap_bss_param), GFP_KERNEL);
+ if (ap_cfg == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ sys_cfg = kmalloc(sizeof(mlan_uap_bss_param), GFP_KERNEL);
+ if (sys_cfg == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ if (MLAN_STATUS_SUCCESS != woal_set_get_sys_config(priv,
+ MLAN_ACT_GET,
+ MOAL_IOCTL_WAIT,
+ ap_cfg)) {
+ PRINTM(MERROR, "Error getting AP confiruration\n");
+ ret = -EFAULT;
+ goto done;
+ }
+
+ /* Initialize the invalid values so that the correct values below are
+ downloaded to firmware */
+ woal_set_sys_config_invalid_data(sys_cfg);
+ sys_cfg->wep_cfg.key0.key_index = 0;
+ sys_cfg->wep_cfg.key1.key_index = 1;
+ sys_cfg->wep_cfg.key2.key_index = 2;
+ sys_cfg->wep_cfg.key3.key_index = 3;
+
+ if (key_index >= 0 && key_index <= 3) {
+ if (key_index == 0)
+ pkey = &sys_cfg->wep_cfg.key0;
+ else if (key_index == 1)
+ pkey = &sys_cfg->wep_cfg.key1;
+ else if (key_index == 2)
+ pkey = &sys_cfg->wep_cfg.key2;
+ else if (key_index == 3)
+ pkey = &sys_cfg->wep_cfg.key3;
+ }
+
+ if (!(dwrq->flags & IW_ENCODE_NOKEY) && dwrq->length) {
+ if (dwrq->length > MAX_WEP_KEY_SIZE) {
+ PRINTM(MERROR, "Key length (%d) out of range\n", dwrq->length);
+ ret = -E2BIG;
+ goto done;
+ }
+ if (key_index < 0) {
+ /* Get current default key index */
+ if (ap_cfg->wep_cfg.key0.is_default)
+ pkey = &sys_cfg->wep_cfg.key0;
+ if (ap_cfg->wep_cfg.key1.is_default)
+ pkey = &sys_cfg->wep_cfg.key1;
+ if (ap_cfg->wep_cfg.key2.is_default)
+ pkey = &sys_cfg->wep_cfg.key2;
+ if (ap_cfg->wep_cfg.key3.is_default)
+ pkey = &sys_cfg->wep_cfg.key3;
+ }
+
+ sys_cfg->protocol = PROTOCOL_STATIC_WEP;
+ memcpy(pkey->key, extra, dwrq->length);
+ /* Set the length */
+ if (dwrq->length > MIN_WEP_KEY_SIZE)
+ pkey->length = MAX_WEP_KEY_SIZE;
+ else
+ pkey->length = MIN_WEP_KEY_SIZE;
+ /* Set current key index as default */
+ pkey->is_default = MTRUE;
+ } else {
+ /*
+ * No key provided so it is either enable key,
+ * on or off
+ */
+ if (dwrq->flags & IW_ENCODE_DISABLED) {
+ PRINTM(MINFO, "*** iwconfig mlanX key off ***\n");
+ sys_cfg->protocol = PROTOCOL_NO_SECURITY;
+ } else {
+ /*
+ * iwconfig mlanX key [n]
+ * iwconfig mlanX key on
+ * Do we want to just set the transmit key index ?
+ */
+ if (key_index < 0) {
+ PRINTM(MINFO, "*** iwconfig mlanX key on ***\n");
+ } else {
+ /* Get current key configuration at key_index */
+ if (key_index == 0)
+ memcpy(pkey, &ap_cfg->wep_cfg.key0, sizeof(wep_key));
+ if (key_index == 1)
+ memcpy(pkey, &ap_cfg->wep_cfg.key1, sizeof(wep_key));
+ if (key_index == 2)
+ memcpy(pkey, &ap_cfg->wep_cfg.key2, sizeof(wep_key));
+ if (key_index == 3)
+ memcpy(pkey, &ap_cfg->wep_cfg.key3, sizeof(wep_key));
+ /* Set current key index as default */
+ pkey->is_default = MTRUE;
+ }
+ }
+ }
+ if (dwrq->flags & (IW_ENCODE_RESTRICTED | IW_ENCODE_OPEN)) {
+ switch (dwrq->flags & 0xf000) {
+ case IW_ENCODE_RESTRICTED:
+ /* iwconfig mlanX restricted key [1] */
+ sys_cfg->auth_mode = MLAN_AUTH_MODE_SHARED;
+ PRINTM(MINFO, "Auth mode restricted!\n");
+ break;
+ case IW_ENCODE_OPEN:
+ /* iwconfig mlanX key [2] open */
+ sys_cfg->auth_mode = MLAN_AUTH_MODE_OPEN;
+ PRINTM(MINFO, "Auth mode open!\n");
+ break;
+ case IW_ENCODE_RESTRICTED | IW_ENCODE_OPEN:
+ default:
+ /* iwconfig mlanX key [2] open restricted */
+ PRINTM(MINFO, "Auth mode auto!\n");
+ break;
+ }
+ }
+
+ if (MLAN_STATUS_SUCCESS != woal_set_get_sys_config(priv,
+ MLAN_ACT_SET,
+ MOAL_IOCTL_WAIT,
+ sys_cfg)) {
+ PRINTM(MERROR, "Error setting AP confiruration\n");
+ ret = -EFAULT;
+ goto done;
+ }
+
+ done:
+ if (sys_cfg)
+ kfree(sys_cfg);
+ if (ap_cfg)
+ kfree(ap_cfg);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Get encryption key
+ *
+ * @param dev A pointer to net_device structure
+ * @param info A pointer to iw_request_info structure
+ * @param dwrq A pointer to iw_point structure
+ * @param extra A pointer to extra data buf
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_get_encode(struct net_device *dev, struct iw_request_info *info,
+ struct iw_point *dwrq, char *extra)
+{
+ moal_private *priv = (moal_private *) netdev_priv(dev);
+ int index = (dwrq->flags & IW_ENCODE_INDEX);
+ wep_key *pkey = NULL;
+ mlan_uap_bss_param ap_cfg;
+ int ret = 0;
+
+ ENTER();
+ if (index < 0 || index > 4) {
+ PRINTM(MERROR, "Key index #%d out of range\n", index);
+ ret = -EINVAL;
+ goto done;
+ }
+ if (MLAN_STATUS_SUCCESS != woal_set_get_sys_config(priv,
+ MLAN_ACT_GET,
+ MOAL_IOCTL_WAIT,
+ &ap_cfg)) {
+ PRINTM(MERROR, "Error getting AP confiruration\n");
+ ret = -EFAULT;
+ goto done;
+ }
+
+ dwrq->flags = 0;
+ /*
+ * Check encryption mode
+ */
+ switch (ap_cfg.auth_mode) {
+ case MLAN_AUTH_MODE_OPEN:
+ dwrq->flags = IW_ENCODE_OPEN;
+ break;
+ case MLAN_AUTH_MODE_SHARED:
+ case MLAN_AUTH_MODE_NETWORKEAP:
+ dwrq->flags = IW_ENCODE_RESTRICTED;
+ break;
+ default:
+ dwrq->flags = IW_ENCODE_DISABLED | IW_ENCODE_OPEN;
+ break;
+ }
+
+ switch (ap_cfg.protocol) {
+ case PROTOCOL_NO_SECURITY:
+ dwrq->flags |= IW_ENCODE_DISABLED;
+ break;
+ case PROTOCOL_STATIC_WEP:
+ if (ap_cfg.wep_cfg.key0.is_default)
+ pkey = &ap_cfg.wep_cfg.key0;
+ else if (ap_cfg.wep_cfg.key1.is_default)
+ pkey = &ap_cfg.wep_cfg.key1;
+ else if (ap_cfg.wep_cfg.key2.is_default)
+ pkey = &ap_cfg.wep_cfg.key2;
+ else if (ap_cfg.wep_cfg.key3.is_default)
+ pkey = &ap_cfg.wep_cfg.key3;
+ if (pkey) {
+ dwrq->flags |= (pkey->key_index + 1);
+ dwrq->length = pkey->length;
+ memcpy(extra, pkey->key, pkey->length);
+ dwrq->flags &= ~IW_ENCODE_DISABLED;
+ } else {
+ ret = -EFAULT;
+ }
+ break;
+ case PROTOCOL_WPA:
+ case PROTOCOL_WPA2:
+ case PROTOCOL_WPA2_MIXED:
+ memcpy(extra, ap_cfg.wpa_cfg.passphrase, ap_cfg.wpa_cfg.length);
+ dwrq->length = ap_cfg.wpa_cfg.length;
+ dwrq->flags |= 1;
+ dwrq->flags &= ~IW_ENCODE_DISABLED;
+ break;
+ default:
+ dwrq->flags &= ~IW_ENCODE_DISABLED;
+ break;
+ }
+ dwrq->flags |= IW_ENCODE_NOKEY;
+
+ done:
+ LEAVE();
+ return ret;
+}
+
+#if (WIRELESS_EXT >= 18)
+/**
+ * @brief Get IE
+ *
+ * @param dev A pointer to net_device structure
+ * @param info A pointer to iw_request_info structure
+ * @param dwrq A pointer to iw_point structure
+ * @param extra A pointer to extra data buf
+ *
+ * @return -EOPNOTSUPP
+ */
+static int
+woal_get_gen_ie(struct net_device *dev, struct iw_request_info *info,
+ struct iw_point *dwrq, char *extra)
+{
+ ENTER();
+ LEAVE();
+ return -EOPNOTSUPP;
+}
+
+/**
+ * @brief Set IE
+ *
+ * Pass an opaque block of data, expected to be IEEE IEs, to the driver
+ * for eventual passthrough to the firmware in an associate/join
+ * (and potentially start) command.
+ *
+ * @param dev A pointer to net_device structure
+ * @param info A pointer to iw_request_info structure
+ * @param dwrq A pointer to iw_point structure
+ * @param extra A pointer to extra data buf
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_set_gen_ie(struct net_device *dev, struct iw_request_info *info,
+ struct iw_point *dwrq, char *extra)
+{
+ moal_private *priv = (moal_private *) netdev_priv(dev);
+ mlan_uap_bss_param sys_cfg;
+ IEEEtypes_Header_t *tlv = NULL;
+ int tlv_hdr_len = sizeof(IEEEtypes_Header_t), tlv_buf_left = 0;
+ int ret = 0;
+
+ ENTER();
+
+ /* Initialize the invalid values so that the correct values below are
+ downloaded to firmware */
+ woal_set_sys_config_invalid_data(&sys_cfg);
+
+ tlv_buf_left = dwrq->length;
+ tlv = (IEEEtypes_Header_t *) extra;
+ while (tlv_buf_left >= tlv_hdr_len) {
+ if (tlv->element_id == WPA_IE) {
+ sys_cfg.protocol |= PROTOCOL_WPA;
+ if (priv->pairwise_cipher == CIPHER_TKIP) {
+ sys_cfg.wpa_cfg.pairwise_cipher_wpa = CIPHER_TKIP;
+ PRINTM(MINFO, "Set IE Cipher TKIP\n");
+ }
+ if (priv->pairwise_cipher == CIPHER_AES_CCMP) {
+ sys_cfg.wpa_cfg.pairwise_cipher_wpa = CIPHER_AES_CCMP;
+ PRINTM(MINFO, "Set IE Cipher CCMP\n");
+ }
+ if (priv->pairwise_cipher == (CIPHER_TKIP | CIPHER_AES_CCMP)) {
+ sys_cfg.wpa_cfg.pairwise_cipher_wpa =
+ CIPHER_TKIP | CIPHER_AES_CCMP;
+ PRINTM(MINFO, "Set IE Cipher TKIP + CCMP\n");
+ }
+ memcpy(priv->bcn_ie_buf + priv->bcn_ie_len,
+ ((t_u8 *) tlv), sizeof(IEEEtypes_Header_t) + tlv->len);
+ priv->bcn_ie_len += sizeof(IEEEtypes_Header_t) + tlv->len;
+ }
+ if (tlv->element_id == RSN_IE) {
+ sys_cfg.protocol |= PROTOCOL_WPA2;
+ if (priv->pairwise_cipher == CIPHER_TKIP) {
+ sys_cfg.wpa_cfg.pairwise_cipher_wpa2 = CIPHER_TKIP;
+ }
+ if (priv->pairwise_cipher == CIPHER_AES_CCMP) {
+ sys_cfg.wpa_cfg.pairwise_cipher_wpa2 = CIPHER_AES_CCMP;
+ }
+ if (priv->pairwise_cipher == (CIPHER_TKIP | CIPHER_AES_CCMP)) {
+ sys_cfg.wpa_cfg.pairwise_cipher_wpa2 =
+ (CIPHER_TKIP | CIPHER_AES_CCMP);
+ }
+ memcpy(priv->bcn_ie_buf + priv->bcn_ie_len,
+ ((t_u8 *) tlv), sizeof(IEEEtypes_Header_t) + tlv->len);
+ priv->bcn_ie_len += sizeof(IEEEtypes_Header_t) + tlv->len;
+ }
+ if (priv->group_cipher == CIPHER_TKIP)
+ sys_cfg.wpa_cfg.group_cipher = CIPHER_TKIP;
+ if (priv->group_cipher == CIPHER_AES_CCMP)
+ sys_cfg.wpa_cfg.group_cipher = CIPHER_AES_CCMP;
+ tlv_buf_left -= (tlv_hdr_len + tlv->len);
+ tlv = (IEEEtypes_Header_t *) ((t_u8 *) tlv + tlv_hdr_len + tlv->len);
+ }
+ sys_cfg.key_mgmt = priv->uap_key_mgmt;
+ if (sys_cfg.key_mgmt & KEY_MGMT_PSK)
+ sys_cfg.key_mgmt_operation |= 0x01;
+ if (sys_cfg.key_mgmt & KEY_MGMT_EAP)
+ sys_cfg.key_mgmt_operation |= 0x03;
+
+ if (sys_cfg.protocol) {
+ if (MLAN_STATUS_SUCCESS != woal_set_get_sys_config(priv,
+ MLAN_ACT_SET,
+ MOAL_IOCTL_WAIT,
+ &sys_cfg)) {
+ PRINTM(MERROR, "Error setting AP configuration\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ priv->pairwise_cipher = 0;
+ priv->group_cipher = 0;
+
+ /* custom IE command to set priv->bcn_ie_buf */
+ if (MLAN_STATUS_SUCCESS !=
+#define UAP_RSN_MASK (BIT(8) | BIT(5) | BIT(1) | BIT(3))
+ woal_set_get_custom_ie(priv, UAP_RSN_MASK, priv->bcn_ie_buf,
+ priv->bcn_ie_len)) {
+ PRINTM(MERROR, "Error setting wpa-rsn IE\n");
+ ret = -EFAULT;
+ }
+ } else if (dwrq->length == 0) {
+ /* custom IE command to re-set priv->bcn_ie_buf */
+ if (MLAN_STATUS_SUCCESS !=
+ woal_set_get_custom_ie(priv, 0, priv->bcn_ie_buf,
+ priv->bcn_ie_len)) {
+ PRINTM(MERROR, "Error resetting wpa-rsn IE\n");
+ ret = -EFAULT;
+ }
+ priv->bcn_ie_len = 0;
+ }
+
+ done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Extended version of encoding configuration
+ *
+ * @param dev A pointer to net_device structure
+ * @param info A pointer to iw_request_info structure
+ * @param dwrq A pointer to iw_point structure
+ * @param extra A pointer to extra data buf
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_set_encode_ext(struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_point *dwrq, char *extra)
+{
+ struct iw_encode_ext *ext = (struct iw_encode_ext *) extra;
+ moal_private *priv = (moal_private *) netdev_priv(dev);
+ int key_index;
+ t_u8 *pkey_material = NULL;
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_sec_cfg *sec = NULL;
+ mlan_uap_bss_param sys_cfg;
+ wep_key *pwep_key = NULL;
+ int ret = 0;
+
+ ENTER();
+
+ key_index = (dwrq->flags & IW_ENCODE_INDEX) - 1;
+ if (key_index < 0 || key_index > 3) {
+ ret = -EINVAL;
+ goto done;
+ }
+ if (ext->key_len > (dwrq->length - sizeof(struct iw_encode_ext))) {
+ ret = -EINVAL;
+ goto done;
+ }
+
+ /* Initialize the invalid values so that the correct values below are
+ downloaded to firmware */
+ woal_set_sys_config_invalid_data(&sys_cfg);
+
+ pkey_material = (t_u8 *) (ext + 1);
+ /* Disable Key */
+ if ((dwrq->flags & IW_ENCODE_DISABLED) && !ext->key_len) {
+ sys_cfg.protocol = PROTOCOL_NO_SECURITY;
+ } else if (ext->alg == IW_ENCODE_ALG_WEP) {
+ sys_cfg.protocol = PROTOCOL_STATIC_WEP;
+ /* Set WEP key */
+ switch (key_index) {
+ case 0:
+ pwep_key = &sys_cfg.wep_cfg.key0;
+ break;
+ case 1:
+ pwep_key = &sys_cfg.wep_cfg.key1;
+ break;
+ case 2:
+ pwep_key = &sys_cfg.wep_cfg.key2;
+ break;
+ case 3:
+ pwep_key = &sys_cfg.wep_cfg.key3;
+ break;
+ }
+ pwep_key->key_index = key_index;
+ pwep_key->is_default = MTRUE;
+ pwep_key->length = ext->key_len;
+ memcpy(pwep_key->key, pkey_material, ext->key_len);
+ } else {
+ /* Set GTK/PTK key */
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_sec_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+ sec = (mlan_ds_sec_cfg *) req->pbuf;
+ sec->sub_command = MLAN_OID_SEC_CFG_ENCRYPT_KEY;
+ req->req_id = MLAN_IOCTL_SEC_CFG;
+ req->action = MLAN_ACT_SET;
+ sec->param.encrypt_key.key_len = ext->key_len;
+ sec->param.encrypt_key.key_index = key_index;
+ memcpy(sec->param.encrypt_key.key_material, pkey_material,
+ ext->key_len);
+ memcpy(sec->param.encrypt_key.mac_addr, ext->addr.sa_data, ETH_ALEN);
+ sec->param.encrypt_key.key_flags = ext->ext_flags;
+ if (ext->ext_flags & IW_ENCODE_EXT_RX_SEQ_VALID) {
+ memcpy(sec->param.encrypt_key.pn, (t_u8 *) ext->rx_seq,
+ SEQ_MAX_SIZE);
+ DBG_HEXDUMP(MCMD_D, "Uap Rx PN", sec->param.encrypt_key.pn,
+ SEQ_MAX_SIZE);
+ }
+ if (ext->ext_flags & IW_ENCODE_EXT_TX_SEQ_VALID) {
+ memcpy(sec->param.encrypt_key.pn, (t_u8 *) ext->tx_seq,
+ SEQ_MAX_SIZE);
+ DBG_HEXDUMP(MCMD_D, "Uap Tx PN", sec->param.encrypt_key.pn,
+ SEQ_MAX_SIZE);
+ }
+ PRINTM(MIOCTL,
+ "set uap wpa key key_index=%d, key_len=%d key_flags=0x%x %02x:%02x:%02x:%02x:%02x:%02x\n",
+ key_index, ext->key_len, sec->param.encrypt_key.key_flags,
+ sec->param.encrypt_key.mac_addr[0],
+ sec->param.encrypt_key.mac_addr[1],
+ sec->param.encrypt_key.mac_addr[2],
+ sec->param.encrypt_key.mac_addr[3],
+ sec->param.encrypt_key.mac_addr[4],
+ sec->param.encrypt_key.mac_addr[5]);
+ DBG_HEXDUMP(MCMD_D, "uap wpa key", pkey_material, ext->key_len);
+
+ if (MLAN_STATUS_SUCCESS !=
+ woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) {
+ ret = -EFAULT;
+ }
+ /* Cipher set will be done in set generic IE */
+ priv->pairwise_cipher = ext->alg;
+ priv->group_cipher = ext->alg;
+ goto done; /* No AP configuration */
+ }
+ if (MLAN_STATUS_SUCCESS != woal_set_get_sys_config(priv,
+ MLAN_ACT_SET,
+ MOAL_IOCTL_WAIT,
+ &sys_cfg)) {
+ PRINTM(MERROR, "Error setting AP confiruration\n");
+ ret = -EFAULT;
+ goto done;
+ }
+
+ done:
+ if (req)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Extended version of encoding configuration
+ *
+ * @param dev A pointer to net_device structure
+ * @param info A pointer to iw_request_info structure
+ * @param dwrq A pointer to iw_point structure
+ * @param extra A pointer to extra data buf
+ *
+ * @return -EOPNOTSUPP
+ */
+static int
+woal_get_encode_ext(struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_point *dwrq, char *extra)
+{
+ ENTER();
+ LEAVE();
+ return -EOPNOTSUPP;
+}
+
+/**
+ * @brief Request MLME operation
+ *
+ * @param dev A pointer to net_device structure
+ * @param info A pointer to iw_request_info structure
+ * @param dwrq A pointer to iw_point structure
+ * @param extra A pointer to extra data buf
+ *
+ * @return 0--success, otherwise fail
+ */
+static int
+woal_set_mlme(struct net_device *dev,
+ struct iw_request_info *info, struct iw_point *dwrq, char *extra)
+{
+ struct iw_mlme *mlme = (struct iw_mlme *) extra;
+ moal_private *priv = (moal_private *) netdev_priv(dev);
+ mlan_ds_bss *bss = NULL;
+ mlan_ds_get_info *pinfo = NULL;
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_sta_list *sta_list = NULL;
+ const t_u8 bc_addr[] = { 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF };
+ t_u8 sta_addr[ETH_ALEN];
+ int ret = 0, i;
+
+ ENTER();
+
+ memset(sta_addr, 0, ETH_ALEN);
+ if ((mlme->cmd == IW_MLME_DEAUTH) || (mlme->cmd == IW_MLME_DISASSOC)) {
+ memcpy(sta_addr, (t_u8 *) mlme->addr.sa_data, ETH_ALEN);
+ PRINTM(MIOCTL, "Deauth station: %02x:%02x:%02x:%02x:%02x:%02x, "
+ "reason=%d\n", sta_addr[0], sta_addr[1], sta_addr[2],
+ sta_addr[3], sta_addr[4], sta_addr[5], mlme->reason_code);
+
+ /* FIXME: For flushing all stations we need to use zero MAC, but right
+ now the FW does not support this. So, manually delete each one
+ individually. */
+ /* If deauth all station, get the connected STA list first */
+ if (!memcmp(bc_addr, sta_addr, ETH_ALEN)) {
+ PRINTM(MIOCTL, "Deauth all stations\n");
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_get_info));
+ if (req == NULL) {
+ LEAVE();
+ return -ENOMEM;
+ }
+ pinfo = (mlan_ds_get_info *) req->pbuf;
+ pinfo->sub_command = MLAN_OID_UAP_STA_LIST;
+ req->req_id = MLAN_IOCTL_GET_INFO;
+ req->action = MLAN_ACT_GET;
+ if (MLAN_STATUS_SUCCESS !=
+ woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ sta_list =
+ (mlan_ds_sta_list *) kmalloc(sizeof(mlan_ds_sta_list),
+ GFP_KERNEL);
+ if (sta_list == NULL) {
+ PRINTM(MERROR, "Memory allocation failed!\n");
+ ret = -ENOMEM;
+ goto done;
+ }
+ memcpy(sta_list, &pinfo->param.sta_list, sizeof(mlan_ds_sta_list));
+ if (req)
+ kfree(req);
+ }
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_bss));
+ if (req == NULL) {
+ LEAVE();
+ return -ENOMEM;
+ }
+ bss = (mlan_ds_bss *) req->pbuf;
+ bss->sub_command = MLAN_OID_UAP_DEAUTH_STA;
+ req->req_id = MLAN_IOCTL_BSS;
+ req->action = MLAN_ACT_SET;
+
+ if (!memcmp(bc_addr, sta_addr, ETH_ALEN)) {
+ for (i = 0; i < sta_list->sta_count; i++) {
+ memcpy(bss->param.deauth_param.mac_addr,
+ sta_list->info[i].mac_address, ETH_ALEN);
+ bss->param.deauth_param.reason_code = mlme->reason_code;
+
+ if (MLAN_STATUS_SUCCESS !=
+ woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ }
+ } else {
+ memcpy(bss->param.deauth_param.mac_addr, sta_addr, ETH_ALEN);
+ bss->param.deauth_param.reason_code = mlme->reason_code;
+
+ if (MLAN_STATUS_SUCCESS !=
+ woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ }
+ }
+
+ done:
+ if (req)
+ kfree(req);
+ if (sta_list)
+ kfree(sta_list);
+
+ LEAVE();
+ return ret;
+}
+
+/** @brief Set authentication mode parameters
+ *
+ * @param dev A pointer to net_device structure
+ * @param info A pointer to iw_request_info structure
+ * @param vwrq A pointer to iw_param structure
+ * @param extra A pointer to extra data buf
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_set_auth(struct net_device *dev, struct iw_request_info *info,
+ struct iw_param *vwrq, char *extra)
+{
+ int ret = 0;
+ moal_private *priv = (moal_private *) netdev_priv(dev);
+ mlan_uap_bss_param sys_cfg;
+
+ ENTER();
+
+ /* Initialize the invalid values so that the correct values below are
+ downloaded to firmware */
+ woal_set_sys_config_invalid_data(&sys_cfg);
+
+ switch (vwrq->flags & IW_AUTH_INDEX) {
+ case IW_AUTH_CIPHER_PAIRWISE:
+ /* Rest are not supported now */
+ if (vwrq->value & IW_AUTH_CIPHER_NONE);
+ else if (vwrq->value & IW_AUTH_CIPHER_WEP40);
+ else if (vwrq->value & IW_AUTH_CIPHER_WEP104);
+ else if (vwrq->value == IW_AUTH_CIPHER_TKIP) {
+ sys_cfg.wpa_cfg.pairwise_cipher_wpa = CIPHER_TKIP;
+ sys_cfg.wpa_cfg.pairwise_cipher_wpa2 = CIPHER_TKIP;
+ priv->pairwise_cipher = CIPHER_TKIP;
+ if (!priv->uap_key_mgmt)
+ priv->uap_key_mgmt = KEY_MGMT_PSK;
+ PRINTM(MINFO, "Set Auth Cipher TKIP\n");
+ } else if (vwrq->value == IW_AUTH_CIPHER_CCMP) {
+ sys_cfg.wpa_cfg.pairwise_cipher_wpa = CIPHER_AES_CCMP;
+ sys_cfg.wpa_cfg.pairwise_cipher_wpa2 = CIPHER_AES_CCMP;
+ priv->pairwise_cipher = CIPHER_AES_CCMP;
+ if (!priv->uap_key_mgmt)
+ priv->uap_key_mgmt = KEY_MGMT_PSK;
+ PRINTM(MINFO, "Set Auth Cipher CCMP\n");
+ } else if (vwrq->value == (IW_AUTH_CIPHER_TKIP | IW_AUTH_CIPHER_CCMP)) {
+ sys_cfg.wpa_cfg.pairwise_cipher_wpa =
+ (CIPHER_TKIP | CIPHER_AES_CCMP);
+ sys_cfg.wpa_cfg.pairwise_cipher_wpa2 =
+ (CIPHER_TKIP | CIPHER_AES_CCMP);
+ priv->pairwise_cipher = (CIPHER_TKIP | CIPHER_AES_CCMP);
+ if (!priv->uap_key_mgmt)
+ priv->uap_key_mgmt = KEY_MGMT_PSK;
+ PRINTM(MINFO, "Set Auth Cipher TKIP + CCMP\n");
+ }
+ break;
+ case IW_AUTH_CIPHER_GROUP:
+ /* Rest are not supported now */
+ if (vwrq->value & IW_AUTH_CIPHER_NONE);
+ else if (vwrq->value & IW_AUTH_CIPHER_WEP40);
+ else if (vwrq->value & IW_AUTH_CIPHER_WEP104);
+ else if (vwrq->value & IW_AUTH_CIPHER_TKIP) {
+ sys_cfg.wpa_cfg.group_cipher = CIPHER_TKIP;
+ priv->group_cipher = CIPHER_TKIP;
+ if (!priv->uap_key_mgmt)
+ priv->uap_key_mgmt = KEY_MGMT_PSK;
+ PRINTM(MINFO, "Set Auth Cipher TKIP\n");
+ } else if (vwrq->value & IW_AUTH_CIPHER_CCMP) {
+ sys_cfg.wpa_cfg.group_cipher = CIPHER_AES_CCMP;
+ priv->group_cipher = CIPHER_AES_CCMP;
+ if (!priv->uap_key_mgmt)
+ priv->uap_key_mgmt = KEY_MGMT_PSK;
+ PRINTM(MINFO, "Set Auth Cipher CCMP\n");
+ }
+ break;
+ case IW_AUTH_80211_AUTH_ALG:
+ switch (vwrq->value) {
+ case IW_AUTH_ALG_SHARED_KEY:
+ PRINTM(MINFO, "Auth mode shared key!\n");
+ sys_cfg.auth_mode = MLAN_AUTH_MODE_SHARED;
+ break;
+ case IW_AUTH_ALG_LEAP:
+ break;
+ case IW_AUTH_ALG_OPEN_SYSTEM:
+ PRINTM(MINFO, "Auth mode open!\n");
+ sys_cfg.auth_mode = MLAN_AUTH_MODE_OPEN;
+ break;
+ default:
+ PRINTM(MINFO, "Auth mode auto!\n");
+ break;
+ }
+ break;
+ case IW_AUTH_WPA_VERSION:
+ switch (vwrq->value) {
+ case IW_AUTH_WPA_VERSION_DISABLED:
+ sys_cfg.protocol = PROTOCOL_NO_SECURITY;
+ break;
+ case IW_AUTH_WPA_VERSION_WPA:
+ sys_cfg.protocol = PROTOCOL_WPA;
+ break;
+ case IW_AUTH_WPA_VERSION_WPA2:
+ sys_cfg.protocol = PROTOCOL_WPA2;
+ break;
+ case IW_AUTH_WPA_VERSION_WPA | IW_AUTH_WPA_VERSION_WPA2:
+ sys_cfg.protocol = PROTOCOL_WPA2_MIXED;
+ break;
+ default:
+ break;
+ }
+ priv->uap_protocol = sys_cfg.protocol;
+ break;
+ case IW_AUTH_KEY_MGMT:
+ switch (vwrq->value) {
+ case IW_AUTH_KEY_MGMT_802_1X:
+ sys_cfg.key_mgmt |= KEY_MGMT_EAP;
+ priv->uap_key_mgmt |= KEY_MGMT_EAP;
+ break;
+ case IW_AUTH_KEY_MGMT_PSK:
+ sys_cfg.key_mgmt |= KEY_MGMT_PSK;
+ priv->uap_key_mgmt |= KEY_MGMT_PSK;
+ break;
+ default:
+ break;
+ }
+ break;
+ case IW_AUTH_WPA_ENABLED:
+ case IW_AUTH_TKIP_COUNTERMEASURES:
+ case IW_AUTH_DROP_UNENCRYPTED:
+ case IW_AUTH_RX_UNENCRYPTED_EAPOL:
+ case IW_AUTH_ROAMING_CONTROL:
+ case IW_AUTH_PRIVACY_INVOKED:
+ default:
+ LEAVE();
+ return -EOPNOTSUPP; /* No AP configuration */
+ }
+ if (!sys_cfg.key_mgmt)
+ sys_cfg.key_mgmt = priv->uap_key_mgmt;
+ if (sys_cfg.key_mgmt & KEY_MGMT_PSK)
+ sys_cfg.key_mgmt_operation |= 0x01;
+ if (sys_cfg.key_mgmt & KEY_MGMT_EAP)
+ sys_cfg.key_mgmt_operation |= 0x03;
+ if (!sys_cfg.protocol)
+ sys_cfg.protocol = priv->uap_protocol;
+
+ /* Set AP configuration */
+ if (MLAN_STATUS_SUCCESS != woal_set_get_sys_config(priv,
+ MLAN_ACT_SET,
+ MOAL_IOCTL_WAIT,
+ &sys_cfg)) {
+ PRINTM(MERROR, "Error setting AP confiruration\n");
+ ret = -EFAULT;
+ goto done;
+ }
+
+ done:
+ LEAVE();
+ return 0;
+}
+
+/**
+ * @brief Get authentication mode parameters
+ *
+ * @param dev A pointer to net_device structure
+ * @param info A pointer to iw_request_info structure
+ * @param vwrq A pointer to iw_param structure
+ * @param extra A pointer to extra data buf
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_get_auth(struct net_device *dev, struct iw_request_info *info,
+ struct iw_param *vwrq, char *extra)
+{
+ moal_private *priv = (moal_private *) netdev_priv(dev);
+ mlan_uap_bss_param ap_cfg;
+
+ ENTER();
+
+ if (MLAN_STATUS_SUCCESS != woal_set_get_sys_config(priv,
+ MLAN_ACT_GET,
+ MOAL_IOCTL_WAIT,
+ &ap_cfg)) {
+ PRINTM(MERROR, "Error getting AP confiruration\n");
+ LEAVE();
+ return -EFAULT;
+ }
+ switch (vwrq->flags & IW_AUTH_INDEX) {
+ case IW_AUTH_CIPHER_PAIRWISE:
+ if (ap_cfg.wpa_cfg.pairwise_cipher_wpa == CIPHER_TKIP ||
+ ap_cfg.wpa_cfg.pairwise_cipher_wpa2 == CIPHER_TKIP)
+ vwrq->value = IW_AUTH_CIPHER_TKIP;
+ else if (ap_cfg.wpa_cfg.pairwise_cipher_wpa == CIPHER_AES_CCMP ||
+ ap_cfg.wpa_cfg.pairwise_cipher_wpa2 == CIPHER_AES_CCMP)
+ vwrq->value = IW_AUTH_CIPHER_CCMP;
+ else
+ vwrq->value = IW_AUTH_CIPHER_NONE;
+ break;
+ case IW_AUTH_CIPHER_GROUP:
+ if (ap_cfg.wpa_cfg.group_cipher == CIPHER_TKIP)
+ vwrq->value = IW_AUTH_CIPHER_TKIP;
+ else if (ap_cfg.wpa_cfg.group_cipher == CIPHER_AES_CCMP)
+ vwrq->value = IW_AUTH_CIPHER_CCMP;
+ else
+ vwrq->value = IW_AUTH_CIPHER_NONE;
+ break;
+ case IW_AUTH_80211_AUTH_ALG:
+ if (ap_cfg.auth_mode == MLAN_AUTH_MODE_SHARED)
+ vwrq->value = IW_AUTH_ALG_SHARED_KEY;
+ else if (ap_cfg.auth_mode == MLAN_AUTH_MODE_NETWORKEAP)
+ vwrq->value = IW_AUTH_ALG_LEAP;
+ else
+ vwrq->value = IW_AUTH_ALG_OPEN_SYSTEM;
+ break;
+ case IW_AUTH_WPA_ENABLED:
+ if (ap_cfg.protocol == PROTOCOL_WPA ||
+ ap_cfg.protocol == PROTOCOL_WPA2 ||
+ ap_cfg.protocol == PROTOCOL_WPA2_MIXED)
+ vwrq->value = 1;
+ else
+ vwrq->value = 0;
+ break;
+ case IW_AUTH_KEY_MGMT:
+ if (ap_cfg.key_mgmt & KEY_MGMT_EAP)
+ vwrq->value |= IW_AUTH_KEY_MGMT_802_1X;
+ if (ap_cfg.key_mgmt & KEY_MGMT_PSK)
+ vwrq->value |= IW_AUTH_KEY_MGMT_PSK;
+ break;
+ case IW_AUTH_WPA_VERSION:
+ case IW_AUTH_TKIP_COUNTERMEASURES:
+ case IW_AUTH_DROP_UNENCRYPTED:
+ case IW_AUTH_RX_UNENCRYPTED_EAPOL:
+ case IW_AUTH_ROAMING_CONTROL:
+ case IW_AUTH_PRIVACY_INVOKED:
+ default:
+ LEAVE();
+ return -EOPNOTSUPP;
+ }
+
+ LEAVE();
+ return 0;
+}
+#endif /* WE >= 18 */
+
+/* Data rate listing
+ * MULTI_BANDS:
+ * abg a b b/g
+ * Infra G(12) A(8) B(4) G(12)
+ * Adhoc A+B(12) A(8) B(4) B(4)
+ * non-MULTI_BANDS:
+ b b/g
+ * Infra B(4) G(12)
+ * Adhoc B(4) B(4)
+ */
+/**
+ * @brief Get Range Info
+ *
+ * @param dev A pointer to net_device structure
+ * @param info A pointer to iw_request_info structure
+ * @param dwrq A pointer to iw_point structure
+ * @param extra A pointer to extra data buf
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_get_range(struct net_device *dev, struct iw_request_info *info,
+ struct iw_point *dwrq, char *extra)
+{
+ moal_private *priv = (moal_private *) netdev_priv(dev);
+ mlan_uap_bss_param ap_cfg;
+ struct iw_range *range = (struct iw_range *) extra;
+ t_u8 band = 0;
+ int i;
+
+ ENTER();
+
+ if (MLAN_STATUS_SUCCESS != woal_set_get_sys_config(priv,
+ MLAN_ACT_GET,
+ MOAL_IOCTL_WAIT,
+ &ap_cfg)) {
+ PRINTM(MERROR, "Error getting AP confiruration\n");
+ LEAVE();
+ return -EFAULT;
+ }
+ dwrq->length = sizeof(struct iw_range);
+ memset(range, 0, sizeof(struct iw_range));
+
+ range->min_nwid = 0;
+ range->max_nwid = 0;
+
+ range->num_bitrates = MAX_DATA_RATES;
+ for (i = 0; i < MIN(MAX_DATA_RATES, IW_MAX_BITRATES) &&
+ ap_cfg.rates[i]; i++) {
+ range->bitrate[i] = (ap_cfg.rates[i] & 0x7f) * 500000;
+ }
+ range->num_bitrates = i;
+ PRINTM(MINFO, "IW_MAX_BITRATES=%d num_bitrates=%d\n",
+ IW_MAX_BITRATES, range->num_bitrates);
+
+ range->num_frequency = MIN(ap_cfg.num_of_chan, IW_MAX_FREQUENCIES);
+
+ for (i = 0; i < range->num_frequency; i++) {
+ range->freq[i].i = (long) ap_cfg.chan_list[i].chan_number;
+ band = ap_cfg.chan_list[i].band_config_type & BAND_CONFIG_5GHZ;
+ range->freq[i].m =
+ (long) channel_to_frequency(ap_cfg.chan_list[i].chan_number,
+ band) * 100000;
+ range->freq[i].e = 1;
+ }
+
+ PRINTM(MINFO, "IW_MAX_FREQUENCIES=%d num_frequency=%d\n",
+ IW_MAX_FREQUENCIES, range->num_frequency);
+
+ range->num_channels = range->num_frequency;
+
+ woal_sort_channels(&range->freq[0], range->num_frequency);
+
+ /*
+ * Set an indication of the max TCP throughput in bit/s that we can
+ * expect using this interface
+ */
+ if (i > 2)
+ range->throughput = 5000 * 1000;
+ else
+ range->throughput = 1500 * 1000;
+
+ range->min_rts = MLAN_RTS_MIN_VALUE;
+ range->max_rts = MLAN_RTS_MAX_VALUE;
+ range->min_frag = MLAN_FRAG_MIN_VALUE;
+ range->max_frag = MLAN_FRAG_MAX_VALUE;
+
+ range->encoding_size[0] = 5;
+ range->encoding_size[1] = 13;
+ range->num_encoding_sizes = 2;
+ range->max_encoding_tokens = 4;
+
+/** Minimum power period */
+#define IW_POWER_PERIOD_MIN 1000000 /* 1 sec */
+/** Maximum power period */
+#define IW_POWER_PERIOD_MAX 120000000 /* 2 min */
+/** Minimum power timeout value */
+#define IW_POWER_TIMEOUT_MIN 1000 /* 1 ms */
+/** Maximim power timeout value */
+#define IW_POWER_TIMEOUT_MAX 1000000 /* 1 sec */
+
+ /* Power Management duration & timeout */
+ range->min_pmp = IW_POWER_PERIOD_MIN;
+ range->max_pmp = IW_POWER_PERIOD_MAX;
+ range->min_pmt = IW_POWER_TIMEOUT_MIN;
+ range->max_pmt = IW_POWER_TIMEOUT_MAX;
+ range->pmp_flags = IW_POWER_PERIOD;
+ range->pmt_flags = IW_POWER_TIMEOUT;
+ range->pm_capa = IW_POWER_PERIOD | IW_POWER_TIMEOUT | IW_POWER_ALL_R;
+
+ /*
+ * Minimum version we recommend
+ */
+ range->we_version_source = 15;
+
+ /*
+ * Version we are compiled with
+ */
+ range->we_version_compiled = WIRELESS_EXT;
+
+ range->retry_capa = IW_RETRY_LIMIT;
+ range->retry_flags = IW_RETRY_LIMIT | IW_RETRY_MAX;
+
+ range->min_retry = MLAN_TX_RETRY_MIN;
+ range->max_retry = MLAN_TX_RETRY_MAX;
+
+#if (WIRELESS_EXT >= 18)
+ if (ap_cfg.protocol & PROTOCOL_WPA)
+ range->enc_capa |= IW_ENC_CAPA_WPA;
+ if (ap_cfg.protocol & PROTOCOL_WPA2)
+ range->enc_capa |= IW_ENC_CAPA_WPA2;
+ if (ap_cfg.wpa_cfg.pairwise_cipher_wpa == CIPHER_TKIP ||
+ ap_cfg.wpa_cfg.pairwise_cipher_wpa2 == CIPHER_TKIP ||
+ ap_cfg.wpa_cfg.group_cipher == CIPHER_TKIP)
+ range->enc_capa |= IW_ENC_CAPA_CIPHER_TKIP;
+ if (ap_cfg.wpa_cfg.pairwise_cipher_wpa == CIPHER_AES_CCMP ||
+ ap_cfg.wpa_cfg.pairwise_cipher_wpa2 == CIPHER_AES_CCMP ||
+ ap_cfg.wpa_cfg.group_cipher == CIPHER_AES_CCMP)
+ range->enc_capa |= IW_ENC_CAPA_CIPHER_CCMP;
+#endif
+
+ LEAVE();
+ return 0;
+}
+
+/**
+ * @brief Set priv command
+ *
+ * @param dev A pointer to net_device structure
+ * @param info A pointer to iw_request_info structure
+ * @param dwrq A pointer to iw_point structure
+ * @param extra A pointer to extra data buf
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_set_priv(struct net_device *dev, struct iw_request_info *info,
+ struct iw_point *dwrq, char *extra)
+{
+ ENTER();
+ LEAVE();
+ return -EOPNOTSUPP;
+}
+
+/**
+ * @brief Set essid
+ *
+ * @param dev A pointer to net_device structure
+ * @param info A pointer to iw_request_info structure
+ * @param dwrq A pointer to iw_point structure
+ * @param extra A pointer to extra data buf
+ *
+ * @return 0--success, otherwise fail
+ */
+static int
+woal_set_essid(struct net_device *dev, struct iw_request_info *info,
+ struct iw_point *dwrq, char *extra)
+{
+ moal_private *priv = (moal_private *) netdev_priv(dev);
+ mlan_uap_bss_param sys_cfg;
+ int ret = 0;
+
+ ENTER();
+
+ /* Check the size of the string */
+ if (dwrq->length > IW_ESSID_MAX_SIZE + 1) {
+ ret = -E2BIG;
+ goto done;
+ }
+
+ /* Initialize the invalid values so that the correct values below are
+ downloaded to firmware */
+ woal_set_sys_config_invalid_data(&sys_cfg);
+
+ /* Set the SSID */
+#if WIRELESS_EXT > 20
+ sys_cfg.ssid.ssid_len = dwrq->length;
+#else
+ sys_cfg.ssid.ssid_len = dwrq->length - 1;
+#endif
+
+ memcpy(sys_cfg.ssid.ssid, extra,
+ MIN(sys_cfg.ssid.ssid_len, MLAN_MAX_SSID_LENGTH));
+ if (!sys_cfg.ssid.ssid_len || sys_cfg.ssid.ssid[0] < 0x20) {
+ PRINTM(MERROR, "Invalid SSID - aborting set_essid\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ PRINTM(MINFO, "Requested new SSID = %s\n",
+ (sys_cfg.ssid.ssid_len > 0) ? (char *) sys_cfg.ssid.ssid : "NULL");
+
+ /* Set AP configuration */
+ if (MLAN_STATUS_SUCCESS != woal_set_get_sys_config(priv,
+ MLAN_ACT_SET,
+ MOAL_IOCTL_WAIT,
+ &sys_cfg)) {
+ PRINTM(MERROR, "Error setting AP confiruration\n");
+ ret = -EFAULT;
+ goto done;
+ }
+
+ done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Get current essid
+ *
+ * @param dev A pointer to net_device structure
+ * @param info A pointer to iw_request_info structure
+ * @param dwrq A pointer to iw_point structure
+ * @param extra A pointer to extra data buf
+ *
+ * @return 0--success, otherwise fail
+ */
+static int
+woal_get_essid(struct net_device *dev, struct iw_request_info *info,
+ struct iw_point *dwrq, char *extra)
+{
+ moal_private *priv = (moal_private *) netdev_priv(dev);
+ mlan_uap_bss_param ap_cfg;
+
+ ENTER();
+
+ if (MLAN_STATUS_SUCCESS != woal_set_get_sys_config(priv,
+ MLAN_ACT_GET,
+ MOAL_IOCTL_WAIT,
+ &ap_cfg)) {
+ PRINTM(MERROR, "Error getting AP confiruration\n");
+ LEAVE();
+ return -EFAULT;
+ }
+
+ if (priv->bss_started) {
+ dwrq->length = MIN(dwrq->length, ap_cfg.ssid.ssid_len);
+ memcpy(extra, ap_cfg.ssid.ssid, dwrq->length);
+ } else
+ dwrq->length = 0;
+
+ dwrq->flags = 1;
+
+ LEAVE();
+ return 0;
+}
+
+/**
+ * iwconfig settable callbacks
+ */
+static const iw_handler woal_handler[] = {
+ (iw_handler) woal_config_commit, /* SIOCSIWCOMMIT */
+ (iw_handler) woal_get_name, /* SIOCGIWNAME */
+ (iw_handler) NULL, /* SIOCSIWNWID */
+ (iw_handler) NULL, /* SIOCGIWNWID */
+ (iw_handler) woal_set_freq, /* SIOCSIWFREQ */
+ (iw_handler) woal_get_freq, /* SIOCGIWFREQ */
+ (iw_handler) woal_set_bss_mode, /* SIOCSIWMODE */
+ (iw_handler) woal_get_bss_mode, /* SIOCGIWMODE */
+ (iw_handler) NULL, /* SIOCSIWSENS */
+ (iw_handler) NULL, /* SIOCGIWSENS */
+ (iw_handler) NULL, /* SIOCSIWRANGE */
+ (iw_handler) woal_get_range, /* SIOCGIWRANGE */
+ (iw_handler) woal_set_priv, /* SIOCSIWPRIV */
+ (iw_handler) NULL, /* SIOCGIWPRIV */
+ (iw_handler) NULL, /* SIOCSIWSTATS */
+ (iw_handler) NULL, /* SIOCGIWSTATS */
+#if WIRELESS_EXT > 15
+ iw_handler_set_spy, /* SIOCSIWSPY */
+ iw_handler_get_spy, /* SIOCGIWSPY */
+ iw_handler_set_thrspy, /* SIOCSIWTHRSPY */
+ iw_handler_get_thrspy, /* SIOCGIWTHRSPY */
+#else /* WIRELESS_EXT > 15 */
+#ifdef WIRELESS_SPY
+ (iw_handler) NULL, /* SIOCSIWSPY */
+ (iw_handler) NULL, /* SIOCGIWSPY */
+#else /* WIRELESS_SPY */
+ (iw_handler) NULL, /* SIOCSIWSPY */
+ (iw_handler) NULL, /* SIOCGIWSPY */
+#endif /* WIRELESS_SPY */
+ (iw_handler) NULL, /* -- hole -- */
+ (iw_handler) NULL, /* -- hole -- */
+#endif /* WIRELESS_EXT > 15 */
+ (iw_handler) woal_set_wap, /* SIOCSIWAP */
+ (iw_handler) woal_get_wap, /* SIOCGIWAP */
+#if WIRELESS_EXT >= 18
+ (iw_handler) woal_set_mlme, /* SIOCSIWMLME */
+#else
+ (iw_handler) NULL, /* -- hole -- */
+#endif
+ /* (iw_handler) wlan_get_aplist, *//* SIOCGIWAPLIST */
+ NULL, /* SIOCGIWAPLIST */
+#if WIRELESS_EXT > 13
+ (iw_handler) NULL, /* SIOCSIWSCAN */
+ (iw_handler) NULL, /* SIOCGIWSCAN */
+#else /* WIRELESS_EXT > 13 */
+ (iw_handler) NULL, /* SIOCSIWSCAN */
+ (iw_handler) NULL, /* SIOCGIWSCAN */
+#endif /* WIRELESS_EXT > 13 */
+ (iw_handler) woal_set_essid, /* SIOCSIWESSID */
+ (iw_handler) woal_get_essid, /* SIOCGIWESSID */
+ (iw_handler) NULL, /* SIOCSIWNICKN */
+ (iw_handler) NULL, /* SIOCGIWNICKN */
+ (iw_handler) NULL, /* -- hole -- */
+ (iw_handler) NULL, /* -- hole -- */
+ (iw_handler) NULL, /* SIOCSIWRATE */
+ (iw_handler) NULL, /* SIOCGIWRATE */
+ (iw_handler) NULL, /* SIOCSIWRTS */
+ (iw_handler) NULL, /* SIOCGIWRTS */
+ (iw_handler) NULL, /* SIOCSIWFRAG */
+ (iw_handler) NULL, /* SIOCGIWFRAG */
+ (iw_handler) NULL, /* SIOCSIWTXPOW */
+ (iw_handler) NULL, /* SIOCGIWTXPOW */
+ (iw_handler) NULL, /* SIOCSIWRETRY */
+ (iw_handler) NULL, /* SIOCGIWRETRY */
+ (iw_handler) woal_set_encode, /* SIOCSIWENCODE */
+ (iw_handler) woal_get_encode, /* SIOCGIWENCODE */
+ (iw_handler) NULL, /* SIOCSIWPOWER */
+ (iw_handler) NULL, /* SIOCGIWPOWER */
+#if (WIRELESS_EXT >= 18)
+ (iw_handler) NULL, /* -- hole -- */
+ (iw_handler) NULL, /* -- hole -- */
+ (iw_handler) woal_set_gen_ie, /* SIOCSIWGENIE */
+ (iw_handler) woal_get_gen_ie, /* SIOCGIWGENIE */
+ (iw_handler) woal_set_auth, /* SIOCSIWAUTH */
+ (iw_handler) woal_get_auth, /* SIOCGIWAUTH */
+ (iw_handler) woal_set_encode_ext, /* SIOCSIWENCODEEXT */
+ (iw_handler) woal_get_encode_ext, /* SIOCGIWENCODEEXT */
+#endif /* WIRELESSS_EXT >= 18 */
+};
+
+/**
+ * iwpriv settable callbacks
+ */
+static const iw_handler woal_private_handler[] = {
+ NULL, /* SIOCIWFIRSTPRIV */
+};
+
+/********************************************************
+ Global Functions
+********************************************************/
+
+/** wlan_handler_def */
+struct iw_handler_def woal_uap_handler_def = {
+ num_standard:sizeof(woal_handler) / sizeof(iw_handler),
+ num_private:sizeof(woal_private_handler) / sizeof(iw_handler),
+ num_private_args:sizeof(woal_uap_priv_args) /
+ sizeof(struct iw_priv_args),
+ standard:(iw_handler *) woal_handler,
+ private:(iw_handler *) woal_private_handler,
+ private_args:(struct iw_priv_args *) woal_uap_priv_args,
+#if WIRELESS_EXT > 20
+ get_wireless_stats:woal_get_uap_wireless_stats,
+#endif
+};
+
+/**
+ * @brief Get wireless statistics
+ *
+ * @param dev A pointer to net_device structure
+ *
+ * @return A pointer to iw_statistics buf
+ */
+struct iw_statistics *
+woal_get_uap_wireless_stats(struct net_device *dev)
+{
+ moal_private *priv = (moal_private *) netdev_priv(dev);
+ t_u16 wait_option = MOAL_NO_WAIT;
+
+ ENTER();
+
+ /*
+ * Since schedule() is not allowed from an atomic context
+ * such as when dev_base_lock for netdevices is acquired
+ * for reading/writing in kernel before this call, HostCmd
+ * is issued in non-blocking way in such contexts and
+ * blocking in other cases.
+ */
+ if (write_can_lock(&dev_base_lock)
+ && (!in_atomic() || current->exit_state))
+ wait_option = MOAL_WSTATS_WAIT;
+
+ priv->w_stats.qual.qual = 0;
+ priv->w_stats.qual.level = 0;
+ priv->w_stats.discard.code = 0;
+ priv->w_stats.status = IW_MODE_MASTER;
+ woal_uap_get_stats(priv, wait_option, NULL);
+
+ LEAVE();
+ return &priv->w_stats;
+}
diff --git a/drivers/net/wireless/sd8797/mlinux/moal_wext.c b/drivers/net/wireless/sd8797/mlinux/moal_wext.c
new file mode 100644
index 000000000000..9b5ce1333ee8
--- /dev/null
+++ b/drivers/net/wireless/sd8797/mlinux/moal_wext.c
@@ -0,0 +1,3048 @@
+/** @file moal_wext.c
+ *
+ * @brief This file contains wireless extension standard ioctl functions
+ *
+ * Copyright (C) 2008-2011, Marvell International Ltd.
+ *
+ * This software file (the "File") is distributed by Marvell International
+ * Ltd. under the terms of the GNU General Public License Version 2, June 1991
+ * (the "License"). You may use, redistribute and/or modify this File in
+ * accordance with the terms and conditions of the License, a copy of which
+ * is available by writing to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
+ * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
+ *
+ * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
+ * ARE EXPRESSLY DISCLAIMED. The License provides additional details about
+ * this warranty disclaimer.
+ *
+ */
+
+/************************************************************************
+Change log:
+ 10/21/2008: initial version
+************************************************************************/
+
+#include "moal_main.h"
+
+#ifdef STA_SUPPORT
+/** Approximate amount of data needed to pass a scan result back to iwlist */
+#define MAX_SCAN_CELL_SIZE (IW_EV_ADDR_LEN \
+ + MLAN_MAX_SSID_LENGTH \
+ + IW_EV_UINT_LEN \
+ + IW_EV_FREQ_LEN \
+ + IW_EV_QUAL_LEN \
+ + MLAN_MAX_SSID_LENGTH \
+ + IW_EV_PARAM_LEN \
+ + 40) /* 40 for WPAIE */
+/** Macro for minimum size of scan buffer */
+#define MIN_ACCEPTED_GET_SCAN_BUF 8000
+
+/********************************************************
+ Global Variables
+********************************************************/
+
+/********************************************************
+ Local Functions
+********************************************************/
+/**
+ * @brief This function validates a SSID as being able to be printed
+ *
+ * @param pssid SSID structure to validate
+ *
+ * @return MTRUE or MFALSE
+ */
+static BOOLEAN
+woal_ssid_valid(mlan_802_11_ssid * pssid)
+{
+#ifdef ASCII_SSID_CHECK
+ unsigned int ssid_idx;
+
+ ENTER();
+
+ for (ssid_idx = 0; ssid_idx < pssid->ssid_len; ssid_idx++) {
+ if ((pssid->ssid[ssid_idx] < 0x20) || (pssid->ssid[ssid_idx] > 0x7e)) {
+ LEAVE();
+ return MFALSE;
+ }
+ }
+ LEAVE();
+#endif
+ return MTRUE;
+}
+
+/**
+ * @brief Compare two SSIDs
+ *
+ * @param ssid1 A pointer to ssid to compare
+ * @param ssid2 A pointer to ssid to compare
+ *
+ * @return 0--ssid is same, otherwise is different
+ */
+static t_s32
+woal_ssid_cmp(mlan_802_11_ssid * ssid1, mlan_802_11_ssid * ssid2)
+{
+ ENTER();
+
+ if (!ssid1 || !ssid2) {
+ LEAVE();
+ return -1;
+ }
+ if (ssid1->ssid_len != ssid2->ssid_len) {
+ LEAVE();
+ return -1;
+ }
+
+ LEAVE();
+ return memcmp(ssid1->ssid, ssid2->ssid, ssid1->ssid_len);
+}
+
+/**
+ * @brief Sort Channels
+ *
+ * @param freq A pointer to iw_freq structure
+ * @param num Number of Channels
+ *
+ * @return N/A
+ */
+static inline void
+woal_sort_channels(struct iw_freq *freq, int num)
+{
+ int i, j;
+ struct iw_freq temp;
+
+ for (i = 0; i < num; i++)
+ for (j = i + 1; j < num; j++)
+ if (freq[i].i > freq[j].i) {
+ temp.i = freq[i].i;
+ temp.m = freq[i].m;
+
+ freq[i].i = freq[j].i;
+ freq[i].m = freq[j].m;
+
+ freq[j].i = temp.i;
+ freq[j].m = temp.m;
+ }
+}
+
+/**
+ * @brief Convert RSSI to quality
+ *
+ * @param rssi RSSI in dBm
+ *
+ * @return Quality of the link (0-5)
+ */
+static t_u8
+woal_rssi_to_quality(t_s16 rssi)
+{
+/** Macro for RSSI range */
+#define MOAL_RSSI_NO_SIGNAL -90
+#define MOAL_RSSI_VERY_LOW -80
+#define MOAL_RSSI_LOW -70
+#define MOAL_RSSI_GOOD -60
+#define MOAL_RSSI_VERY_GOOD -50
+#define MOAL_RSSI_INVALID 0
+ if (rssi <= MOAL_RSSI_NO_SIGNAL || rssi == MOAL_RSSI_INVALID)
+ return 0;
+ else if (rssi <= MOAL_RSSI_VERY_LOW)
+ return 1;
+ else if (rssi <= MOAL_RSSI_LOW)
+ return 2;
+ else if (rssi <= MOAL_RSSI_GOOD)
+ return 3;
+ else if (rssi <= MOAL_RSSI_VERY_GOOD)
+ return 4;
+ else
+ return 5;
+}
+
+/**
+ * @brief Set Adapter Node Name
+ *
+ * @param dev A pointer to net_device structure
+ * @param info A pointer to iw_request_info structure
+ * @param dwrq A pointer to iw_point structure
+ * @param extra A pointer to extra data buf
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_set_nick(struct net_device *dev, struct iw_request_info *info,
+ struct iw_point *dwrq, char *extra)
+{
+ moal_private *priv = (moal_private *) netdev_priv(dev);
+ ENTER();
+ /*
+ * Check the size of the string
+ */
+ if (dwrq->length > 16) {
+ LEAVE();
+ return -E2BIG;
+ }
+ memset(priv->nick_name, 0, sizeof(priv->nick_name));
+ memcpy(priv->nick_name, extra, dwrq->length);
+ LEAVE();
+ return 0;
+}
+
+/**
+ * @brief Get Adapter Node Name
+ *
+ * @param dev A pointer to net_device structure
+ * @param info A pointer to iw_request_info structure
+ * @param dwrq A pointer to iw_point structure
+ * @param extra A pointer to extra data buf
+ *
+ * @return 0 --success
+ */
+static int
+woal_get_nick(struct net_device *dev, struct iw_request_info *info,
+ struct iw_point *dwrq, char *extra)
+{
+ moal_private *priv = (moal_private *) netdev_priv(dev);
+ ENTER();
+ /*
+ * Get the Nick Name saved
+ */
+ strncpy(extra, (char *) priv->nick_name, 16);
+ extra[16] = '\0';
+ /*
+ * If none, we may want to get the one that was set
+ */
+
+ /*
+ * Push it out !
+ */
+ dwrq->length = strlen(extra) + 1;
+ LEAVE();
+ return 0;
+}
+
+/**
+ * @brief Commit handler: called after a bunch of SET operations
+ *
+ * @param dev A pointer to net_device structure
+ * @param info A pointer to iw_request_info structure
+ * @param cwrq A pointer to char buffer
+ * @param extra A pointer to extra data buf
+ *
+ * @return 0 --success
+ */
+static int
+woal_config_commit(struct net_device *dev,
+ struct iw_request_info *info, char *cwrq, char *extra)
+{
+ ENTER();
+
+ LEAVE();
+ return 0;
+}
+
+/**
+ * @brief Get name
+ *
+ * @param dev A pointer to net_device structure
+ * @param info A pointer to iw_request_info structure
+ * @param cwrq A pointer to char buffer
+ * @param extra A pointer to extra data buf
+ *
+ * @return 0 --success
+ */
+static int
+woal_get_name(struct net_device *dev, struct iw_request_info *info,
+ char *cwrq, char *extra)
+{
+ ENTER();
+ strcpy(cwrq, "IEEE 802.11-DS");
+ LEAVE();
+ return 0;
+}
+
+/**
+ * @brief Set frequency
+ *
+ * @param dev A pointer to net_device structure
+ * @param info A pointer to iw_request_info structure
+ * @param fwrq A pointer to iw_freq structure
+ * @param extra A pointer to extra data buf
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_set_freq(struct net_device *dev, struct iw_request_info *info,
+ struct iw_freq *fwrq, char *extra)
+{
+ int ret = 0;
+ moal_private *priv = (moal_private *) netdev_priv(dev);
+ mlan_ds_bss *bss = NULL;
+ mlan_ioctl_req *req = NULL;
+
+ ENTER();
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_bss));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+ bss = (mlan_ds_bss *) req->pbuf;
+ /*
+ * If setting by frequency, convert to a channel
+ */
+ if (fwrq->e == 1) {
+ long f = fwrq->m / 100000;
+ bss->param.bss_chan.freq = f;
+ } else
+ bss->param.bss_chan.channel = fwrq->m;
+
+ bss->sub_command = MLAN_OID_BSS_CHANNEL;
+ req->req_id = MLAN_IOCTL_BSS;
+ req->action = MLAN_ACT_SET;
+ if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ if (MLAN_STATUS_SUCCESS !=
+ woal_change_adhoc_chan(priv, bss->param.bss_chan.channel))
+ ret = -EFAULT;
+
+ done:
+ if (req)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Get frequency
+ *
+ * @param dev A pointer to net_device structure
+ * @param info A pointer to iw_request_info structure
+ * @param fwrq A pointer to iw_freq structure
+ * @param extra A pointer to extra data buf
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_get_freq(struct net_device *dev, struct iw_request_info *info,
+ struct iw_freq *fwrq, char *extra)
+{
+ int ret = 0;
+ moal_private *priv = (moal_private *) netdev_priv(dev);
+ mlan_ds_bss *bss = NULL;
+ mlan_ioctl_req *req = NULL;
+
+ ENTER();
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_bss));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+ bss = (mlan_ds_bss *) req->pbuf;
+ bss->sub_command = MLAN_OID_BSS_CHANNEL;
+ req->req_id = MLAN_IOCTL_BSS;
+ req->action = MLAN_ACT_GET;
+ if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ fwrq->m = (long) bss->param.bss_chan.freq * 100000;
+ fwrq->i = (long) bss->param.bss_chan.channel;
+ fwrq->e = 1;
+ fwrq->flags = IW_FREQ_FIXED;
+ done:
+ if (req)
+ kfree(req);
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set wlan mode
+ *
+ * @param dev A pointer to net_device structure
+ * @param info A pointer to iw_request_info structure
+ * @param uwrq Wireless mode to set
+ * @param extra A pointer to extra data buf
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_set_bss_mode(struct net_device *dev, struct iw_request_info *info,
+ t_u32 * uwrq, char *extra)
+{
+ int ret = 0;
+ moal_private *priv = (moal_private *) netdev_priv(dev);
+ mlan_ds_bss *bss = NULL;
+ mlan_ioctl_req *req = NULL;
+
+ ENTER();
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_bss));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+ bss = (mlan_ds_bss *) req->pbuf;
+ bss->sub_command = MLAN_OID_BSS_MODE;
+ req->req_id = MLAN_IOCTL_BSS;
+ req->action = MLAN_ACT_SET;
+
+ switch (*uwrq) {
+ case IW_MODE_INFRA:
+ bss->param.bss_mode = MLAN_BSS_MODE_INFRA;
+ break;
+ case IW_MODE_ADHOC:
+ bss->param.bss_mode = MLAN_BSS_MODE_IBSS;
+ break;
+ case IW_MODE_AUTO:
+ bss->param.bss_mode = MLAN_BSS_MODE_AUTO;
+ break;
+ default:
+ ret = -EINVAL;
+ break;
+ }
+ if (ret)
+ goto done;
+ if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ done:
+ if (req)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Get current BSSID
+ *
+ * @param dev A pointer to net_device structure
+ * @param info A pointer to iw_request_info structure
+ * @param awrq A pointer to sockaddr structure
+ * @param extra A pointer to extra data buf
+ *
+ * @return 0 --success
+ */
+static int
+woal_get_wap(struct net_device *dev, struct iw_request_info *info,
+ struct sockaddr *awrq, char *extra)
+{
+ int ret = 0;
+ moal_private *priv = (moal_private *) netdev_priv(dev);
+ mlan_bss_info bss_info;
+
+ ENTER();
+
+ memset(&bss_info, 0, sizeof(bss_info));
+
+ woal_get_bss_info(priv, MOAL_IOCTL_WAIT, &bss_info);
+
+ if (bss_info.media_connected == MTRUE) {
+ memcpy(awrq->sa_data, &bss_info.bssid, MLAN_MAC_ADDR_LENGTH);
+ } else {
+ memset(awrq->sa_data, 0, MLAN_MAC_ADDR_LENGTH);
+ }
+ awrq->sa_family = ARPHRD_ETHER;
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Connect to the AP or Ad-hoc Network with specific bssid
+ *
+ * NOTE: Scan should be issued by application before this function is called
+ *
+ * @param dev A pointer to net_device structure
+ * @param info A pointer to iw_request_info structure
+ * @param awrq A pointer to iw_param structure
+ * @param extra A pointer to extra data buf
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_set_wap(struct net_device *dev, struct iw_request_info *info,
+ struct sockaddr *awrq, char *extra)
+{
+ int ret = 0;
+ const t_u8 bcast[MLAN_MAC_ADDR_LENGTH] = { 255, 255, 255, 255, 255, 255 };
+ const t_u8 zero_mac[MLAN_MAC_ADDR_LENGTH] = { 0, 0, 0, 0, 0, 0 };
+ moal_private *priv = (moal_private *) netdev_priv(dev);
+ mlan_ssid_bssid ssid_bssid;
+ mlan_bss_info bss_info;
+
+ ENTER();
+
+ if (awrq->sa_family != ARPHRD_ETHER) {
+ ret = -EINVAL;
+ goto done;
+ }
+
+ PRINTM(MINFO, "ASSOC: WAP: sa_data: %02x:%02x:%02x:%02x:%02x:%02x\n",
+ (t_u8) awrq->sa_data[0], (t_u8) awrq->sa_data[1],
+ (t_u8) awrq->sa_data[2], (t_u8) awrq->sa_data[3],
+ (t_u8) awrq->sa_data[4], (t_u8) awrq->sa_data[5]);
+
+ if (MLAN_STATUS_SUCCESS !=
+ woal_get_bss_info(priv, MOAL_IOCTL_WAIT, &bss_info)) {
+ ret = -EFAULT;
+ goto done;
+ }
+#ifdef REASSOCIATION
+ /* Cancel re-association */
+ priv->reassoc_required = MFALSE;
+#endif
+
+ /* zero_mac means disconnect */
+ if (!memcmp(zero_mac, awrq->sa_data, MLAN_MAC_ADDR_LENGTH)) {
+ woal_disconnect(priv, MOAL_IOCTL_WAIT, NULL);
+ goto done;
+ }
+
+ /* Broadcast MAC means search for best network */
+ memset(&ssid_bssid, 0, sizeof(mlan_ssid_bssid));
+
+ if (memcmp(bcast, awrq->sa_data, MLAN_MAC_ADDR_LENGTH)) {
+ /* Check if we are already assoicated to the AP */
+ if (bss_info.media_connected == MTRUE) {
+ if (!memcmp(awrq->sa_data, &bss_info.bssid, ETH_ALEN))
+ goto done;
+ /* disconnect before try to assoicate to the new AP */
+ woal_disconnect(priv, MOAL_IOCTL_WAIT, NULL);
+ }
+ memcpy(&ssid_bssid.bssid, awrq->sa_data, ETH_ALEN);
+ }
+
+ if (MLAN_STATUS_SUCCESS != woal_find_best_network(priv,
+ MOAL_IOCTL_WAIT,
+ &ssid_bssid)) {
+ PRINTM(MERROR, "ASSOC: WAP: MAC address not found in BSSID List\n");
+ ret = -ENETUNREACH;
+ goto done;
+ }
+ /* Zero SSID implies use BSSID to connect */
+ memset(&ssid_bssid.ssid, 0, sizeof(mlan_802_11_ssid));
+ if (MLAN_STATUS_SUCCESS != woal_bss_start(priv,
+ MOAL_IOCTL_WAIT, &ssid_bssid)) {
+ ret = -EFAULT;
+ goto done;
+ }
+#ifdef REASSOCIATION
+ memset(&bss_info, 0, sizeof(bss_info));
+ if (MLAN_STATUS_SUCCESS != woal_get_bss_info(priv,
+ MOAL_IOCTL_WAIT, &bss_info)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ memcpy(&priv->prev_ssid_bssid.ssid, &bss_info.ssid,
+ sizeof(mlan_802_11_ssid));
+ memcpy(&priv->prev_ssid_bssid.bssid, &bss_info.bssid, MLAN_MAC_ADDR_LENGTH);
+#endif /* REASSOCIATION */
+
+ done:
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Get wlan mode
+ *
+ * @param dev A pointer to net_device structure
+ * @param info A pointer to iw_request_info structure
+ * @param uwrq A pointer to t_u32 string
+ * @param extra A pointer to extra data buf
+ *
+ * @return 0 --success
+ */
+static int
+woal_get_bss_mode(struct net_device *dev, struct iw_request_info *info,
+ t_u32 * uwrq, char *extra)
+{
+ moal_private *priv = (moal_private *) netdev_priv(dev);
+ ENTER();
+ *uwrq = woal_get_mode(priv, MOAL_IOCTL_WAIT);
+ LEAVE();
+ return 0;
+}
+
+/**
+ * @brief Set sensitivity
+ *
+ * @param dev A pointer to net_device structure
+ * @param info A pointer to iw_request_info structure
+ * @param vwrq A pointer to iw_param structure
+ * @param extra A pointer to extra data buf
+ *
+ * @return 0 --success
+ */
+static int
+woal_set_sens(struct net_device *dev, struct iw_request_info *info,
+ struct iw_param *vwrq, char *extra)
+{
+ int ret = 0;
+
+ ENTER();
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Get sensitivity
+ *
+ * @param dev A pointer to net_device structure
+ * @param info A pointer to iw_request_info structure
+ * @param vwrq A pointer to iw_param structure
+ * @param extra A pointer to extra data buf
+ *
+ * @return -1
+ */
+static int
+woal_get_sens(struct net_device *dev, struct iw_request_info *info,
+ struct iw_param *vwrq, char *extra)
+{
+ int ret = -1;
+
+ ENTER();
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set Tx power
+ *
+ * @param dev A pointer to net_device structure
+ * @param info A pointer to iw_request_info structure
+ * @param vwrq A pointer to iw_param structure
+ * @param extra A pointer to extra data buf
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_set_txpow(struct net_device *dev, struct iw_request_info *info,
+ struct iw_param *vwrq, char *extra)
+{
+ int ret = 0;
+ moal_private *priv = (moal_private *) netdev_priv(dev);
+ mlan_power_cfg_t power_cfg;
+
+ ENTER();
+ if (vwrq->disabled) {
+ woal_set_radio(priv, 0);
+ goto done;
+ }
+ woal_set_radio(priv, 1);
+
+ if (!vwrq->fixed)
+ power_cfg.is_power_auto = 1;
+ else {
+ power_cfg.is_power_auto = 0;
+ power_cfg.power_level = vwrq->value;
+ }
+
+ if (MLAN_STATUS_SUCCESS !=
+ woal_set_get_tx_power(priv, MLAN_ACT_SET, &power_cfg)) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Get Tx power
+ *
+ * @param dev A pointer to net_device structure
+ * @param info A pointer to iw_request_info structure
+ * @param vwrq A pointer to iw_param structure
+ * @param extra A pointer to extra data buf
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_get_txpow(struct net_device *dev, struct iw_request_info *info,
+ struct iw_param *vwrq, char *extra)
+{
+ int ret = 0;
+ moal_private *priv = (moal_private *) netdev_priv(dev);
+ mlan_power_cfg_t power_cfg;
+ mlan_bss_info bss_info;
+
+ ENTER();
+
+ memset(&power_cfg, 0, sizeof(mlan_power_cfg_t));
+ memset(&bss_info, 0, sizeof(bss_info));
+ woal_get_bss_info(priv, MOAL_IOCTL_WAIT, &bss_info);
+
+ if (MLAN_STATUS_SUCCESS !=
+ woal_set_get_tx_power(priv, MLAN_ACT_GET, &power_cfg)) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ vwrq->value = power_cfg.power_level;
+ if (power_cfg.is_power_auto)
+ vwrq->fixed = 0;
+ else
+ vwrq->fixed = 1;
+ if (bss_info.radio_on) {
+ vwrq->disabled = 0;
+ vwrq->flags = IW_TXPOW_DBM;
+ } else {
+ vwrq->disabled = 1;
+ }
+
+ done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set power management
+ *
+ * @param dev A pointer to net_device structure
+ * @param info A pointer to iw_request_info structure
+ * @param vwrq A pointer to iw_param structure
+ * @param extra A pointer to extra data buf
+ *
+ * @return MLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static int
+woal_set_power(struct net_device *dev, struct iw_request_info *info,
+ struct iw_param *vwrq, char *extra)
+{
+ int ret = 0, disabled;
+ moal_private *priv = (moal_private *) netdev_priv(dev);
+
+ ENTER();
+
+ disabled = vwrq->disabled;
+
+ if (MLAN_STATUS_SUCCESS != woal_set_get_power_mgmt(priv,
+ MLAN_ACT_SET, &disabled,
+ vwrq->flags)) {
+ ret = -EFAULT;
+ }
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Get power management
+ *
+ * @param dev A pointer to net_device structure
+ * @param info A pointer to iw_request_info structure
+ * @param vwrq A pointer to iw_param structure
+ * @param extra A pointer to extra data buf
+ *
+ * @return MLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static int
+woal_get_power(struct net_device *dev, struct iw_request_info *info,
+ struct iw_param *vwrq, char *extra)
+{
+ int ret = 0, ps_mode;
+ moal_private *priv = (moal_private *) netdev_priv(dev);
+
+ ENTER();
+
+ if (MLAN_STATUS_SUCCESS != woal_set_get_power_mgmt(priv,
+ MLAN_ACT_GET, &ps_mode,
+ 0)) {
+ ret = -EFAULT;
+ }
+
+ if (ps_mode)
+ vwrq->disabled = 0;
+ else
+ vwrq->disabled = 1;
+
+ vwrq->value = 0;
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set Tx retry count
+ *
+ * @param dev A pointer to net_device structure
+ * @param info A pointer to iw_request_info structure
+ * @param vwrq A pointer to iw_param structure
+ * @param extra A pointer to extra data buf
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_set_retry(struct net_device *dev, struct iw_request_info *info,
+ struct iw_param *vwrq, char *extra)
+{
+ int ret = 0, retry_val = vwrq->value;
+ moal_private *priv = (moal_private *) netdev_priv(dev);
+
+ ENTER();
+
+ if (vwrq->flags == IW_RETRY_LIMIT) {
+ /*
+ * The MAC has a 4-bit Total_Tx_Count register
+ * Total_Tx_Count = 1 + Tx_Retry_Count
+ */
+
+ if (MLAN_STATUS_SUCCESS !=
+ woal_set_get_retry(priv, MLAN_ACT_SET,
+ MOAL_IOCTL_WAIT, &retry_val)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ } else {
+ ret = -EOPNOTSUPP;
+ goto done;
+ }
+
+ done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Get Tx retry count
+ *
+ * @param dev A pointer to net_device structure
+ * @param info A pointer to iw_request_info structure
+ * @param vwrq A pointer to iw_param structure
+ * @param extra A pointer to extra data buf
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_get_retry(struct net_device *dev, struct iw_request_info *info,
+ struct iw_param *vwrq, char *extra)
+{
+ int retry_val, ret = 0;
+ moal_private *priv = (moal_private *) netdev_priv(dev);
+
+ ENTER();
+
+ if (MLAN_STATUS_SUCCESS !=
+ woal_set_get_retry(priv, MLAN_ACT_GET, MOAL_IOCTL_WAIT, &retry_val)) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ vwrq->disabled = 0;
+ if (!vwrq->flags) {
+ vwrq->flags = IW_RETRY_LIMIT;
+ /* Get Tx retry count */
+ vwrq->value = retry_val;
+ }
+
+ done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set encryption key
+ *
+ * @param dev A pointer to net_device structure
+ * @param info A pointer to iw_request_info structure
+ * @param dwrq A pointer to iw_point structure
+ * @param extra A pointer to extra data buf
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_set_encode(struct net_device *dev, struct iw_request_info *info,
+ struct iw_point *dwrq, char *extra)
+{
+ int ret = 0;
+ moal_private *priv = (moal_private *) netdev_priv(dev);
+ mlan_ds_sec_cfg *sec = NULL;
+ mlan_ioctl_req *req = NULL;
+ int index = 0;
+ t_u32 auth_mode = 0;
+
+ ENTER();
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_sec_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+ sec = (mlan_ds_sec_cfg *) req->pbuf;
+ sec->sub_command = MLAN_OID_SEC_CFG_ENCRYPT_KEY;
+ req->req_id = MLAN_IOCTL_SEC_CFG;
+ req->action = MLAN_ACT_SET;
+
+ /* Check index */
+ index = (dwrq->flags & IW_ENCODE_INDEX) - 1;
+ if (index > 3) {
+ PRINTM(MERROR, "Key index #%d out of range\n", index);
+ ret = -EINVAL;
+ goto done;
+ }
+
+ sec->param.encrypt_key.key_len = 0;
+ if (!(dwrq->flags & IW_ENCODE_NOKEY) && dwrq->length) {
+ if (dwrq->length > MAX_WEP_KEY_SIZE) {
+ PRINTM(MERROR, "Key length (%d) out of range\n", dwrq->length);
+ ret = -EINVAL;
+ goto done;
+ }
+ if (index < 0)
+ sec->param.encrypt_key.key_index = MLAN_KEY_INDEX_DEFAULT;
+ else
+ sec->param.encrypt_key.key_index = index;
+ memcpy(sec->param.encrypt_key.key_material, extra, dwrq->length);
+ /* Set the length */
+ if (dwrq->length > MIN_WEP_KEY_SIZE)
+ sec->param.encrypt_key.key_len = MAX_WEP_KEY_SIZE;
+ else
+ sec->param.encrypt_key.key_len = MIN_WEP_KEY_SIZE;
+ } else {
+ /*
+ * No key provided so it is either enable key,
+ * on or off
+ */
+ if (dwrq->flags & IW_ENCODE_DISABLED) {
+ PRINTM(MINFO, "*** iwconfig mlanX key off ***\n");
+ sec->param.encrypt_key.key_disable = MTRUE;
+ } else {
+ /*
+ * iwconfig mlanX key [n]
+ * iwconfig mlanX key on
+ * iwconfig mlanX key open
+ * iwconfig mlanX key restricted
+ * Do we want to just set the transmit key index ?
+ */
+ if (index < 0) {
+ PRINTM(MINFO, "*** iwconfig mlanX key on ***\n");
+ sec->param.encrypt_key.key_index = MLAN_KEY_INDEX_DEFAULT;
+ } else
+ sec->param.encrypt_key.key_index = index;
+ sec->param.encrypt_key.is_current_wep_key = MTRUE;
+ }
+ }
+ if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ if (dwrq->flags & (IW_ENCODE_RESTRICTED | IW_ENCODE_OPEN)) {
+ switch (dwrq->flags & 0xf000) {
+ case IW_ENCODE_RESTRICTED:
+ /* iwconfig mlanX restricted key [1] */
+ auth_mode = MLAN_AUTH_MODE_SHARED;
+ PRINTM(MINFO, "Auth mode restricted!\n");
+ break;
+ case IW_ENCODE_OPEN:
+ /* iwconfig mlanX key [2] open */
+ auth_mode = MLAN_AUTH_MODE_OPEN;
+ PRINTM(MINFO, "Auth mode open!\n");
+ break;
+ case IW_ENCODE_RESTRICTED | IW_ENCODE_OPEN:
+ default:
+ /* iwconfig mlanX key [2] open restricted */
+ auth_mode = MLAN_AUTH_MODE_AUTO;
+ PRINTM(MINFO, "Auth mode auto!\n");
+ break;
+ }
+ if (MLAN_STATUS_SUCCESS !=
+ woal_set_auth_mode(priv, MOAL_IOCTL_WAIT, auth_mode))
+ ret = -EFAULT;
+ }
+ done:
+ if (req)
+ kfree(req);
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Get encryption key
+ *
+ * @param dev A pointer to net_device structure
+ * @param info A pointer to iw_request_info structure
+ * @param dwrq A pointer to iw_point structure
+ * @param extra A pointer to extra data buf
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_get_encode(struct net_device *dev, struct iw_request_info *info,
+ struct iw_point *dwrq, char *extra)
+{
+ int ret = 0;
+ moal_private *priv = (moal_private *) netdev_priv(dev);
+ mlan_ds_sec_cfg *sec = NULL;
+ mlan_ioctl_req *req = NULL;
+ t_u32 auth_mode;
+ int index = (dwrq->flags & IW_ENCODE_INDEX);
+
+ ENTER();
+ if (index < 0 || index > 4) {
+ PRINTM(MERROR, "Key index #%d out of range\n", index);
+ ret = -EINVAL;
+ goto done;
+ }
+ if (MLAN_STATUS_SUCCESS !=
+ woal_get_auth_mode(priv, MOAL_IOCTL_WAIT, &auth_mode)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ dwrq->flags = 0;
+ /*
+ * Check encryption mode
+ */
+ switch (auth_mode) {
+ case MLAN_AUTH_MODE_OPEN:
+ dwrq->flags = IW_ENCODE_OPEN;
+ break;
+
+ case MLAN_AUTH_MODE_SHARED:
+ case MLAN_AUTH_MODE_NETWORKEAP:
+ dwrq->flags = IW_ENCODE_RESTRICTED;
+ break;
+
+ case MLAN_AUTH_MODE_AUTO:
+ dwrq->flags = IW_ENCODE_OPEN | IW_ENCODE_RESTRICTED;
+ break;
+
+ default:
+ dwrq->flags = IW_ENCODE_DISABLED | IW_ENCODE_OPEN;
+ break;
+ }
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_sec_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ sec = (mlan_ds_sec_cfg *) req->pbuf;
+ sec->sub_command = MLAN_OID_SEC_CFG_ENCRYPT_KEY;
+ req->req_id = MLAN_IOCTL_SEC_CFG;
+ req->action = MLAN_ACT_GET;
+
+ if (!index)
+ sec->param.encrypt_key.key_index = MLAN_KEY_INDEX_DEFAULT;
+ else
+ sec->param.encrypt_key.key_index = index - 1;
+
+ if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ memset(extra, 0, 16);
+ if (sec->param.encrypt_key.key_len) {
+ memcpy(extra, sec->param.encrypt_key.key_material,
+ sec->param.encrypt_key.key_len);
+ dwrq->length = sec->param.encrypt_key.key_len;
+ dwrq->flags |= (sec->param.encrypt_key.key_index + 1);
+ dwrq->flags &= ~IW_ENCODE_DISABLED;
+ } else if (sec->param.encrypt_key.key_disable)
+ dwrq->flags |= IW_ENCODE_DISABLED;
+ else
+ dwrq->flags &= ~IW_ENCODE_DISABLED;
+
+ dwrq->flags |= IW_ENCODE_NOKEY;
+ done:
+ if (req)
+ kfree(req);
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set data rate
+ *
+ * @param dev A pointer to net_device structure
+ * @param info A pointer to iw_request_info structure
+ * @param vwrq A pointer to iw_param structure
+ * @param extra A pointer to extra data buf
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_set_rate(struct net_device *dev, struct iw_request_info *info,
+ struct iw_param *vwrq, char *extra)
+{
+ int ret = 0;
+ moal_private *priv = (moal_private *) netdev_priv(dev);
+ mlan_rate_cfg_t rate_cfg;
+
+ ENTER();
+
+ if (vwrq->value == -1) {
+ rate_cfg.is_rate_auto = 1;
+ } else {
+ rate_cfg.is_rate_auto = 0;
+ rate_cfg.rate_type = MLAN_RATE_VALUE;
+ rate_cfg.rate = vwrq->value / 500000;
+ }
+ if (MLAN_STATUS_SUCCESS != woal_set_get_data_rate(priv,
+ MLAN_ACT_SET,
+ &rate_cfg)) {
+ ret = -EFAULT;
+ }
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Get data rate
+ *
+ * @param dev A pointer to net_device structure
+ * @param info A pointer to iw_request_info structure
+ * @param vwrq A pointer to iw_param structure
+ * @param extra A pointer to extra data buf
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_get_rate(struct net_device *dev, struct iw_request_info *info,
+ struct iw_param *vwrq, char *extra)
+{
+ int ret = 0;
+ moal_private *priv = (moal_private *) netdev_priv(dev);
+ mlan_rate_cfg_t rate_cfg;
+
+ ENTER();
+
+ if (MLAN_STATUS_SUCCESS != woal_set_get_data_rate(priv,
+ MLAN_ACT_GET,
+ &rate_cfg)) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ if (rate_cfg.is_rate_auto)
+ vwrq->fixed = 0;
+ else
+ vwrq->fixed = 1;
+ vwrq->value = rate_cfg.rate * 500000;
+ done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set RTS threshold
+ *
+ * @param dev A pointer to net_device structure
+ * @param info A pointer to iw_request_info structure
+ * @param vwrq A pointer to iw_param structure
+ * @param extra A pointer to extra data buf
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_set_rts(struct net_device *dev, struct iw_request_info *info,
+ struct iw_param *vwrq, char *extra)
+{
+ int ret = 0;
+ moal_private *priv = (moal_private *) netdev_priv(dev);
+ int rthr = vwrq->value;
+
+ ENTER();
+
+ if (vwrq->disabled) {
+ rthr = MLAN_RTS_MAX_VALUE;
+ } else {
+ if (rthr < MLAN_RTS_MIN_VALUE || rthr > MLAN_RTS_MAX_VALUE) {
+ ret = -EINVAL;
+ goto done;
+ }
+ }
+
+ if (MLAN_STATUS_SUCCESS !=
+ woal_set_get_rts(priv, MLAN_ACT_SET, MOAL_IOCTL_WAIT, &rthr)) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Get RTS threshold
+ *
+ * @param dev A pointer to net_device structure
+ * @param info A pointer to iw_request_info structure
+ * @param vwrq A pointer to iw_param structure
+ * @param extra A pointer to extra data buf
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_get_rts(struct net_device *dev, struct iw_request_info *info,
+ struct iw_param *vwrq, char *extra)
+{
+ int rthr, ret = 0;
+ moal_private *priv = (moal_private *) netdev_priv(dev);
+
+ ENTER();
+
+ if (MLAN_STATUS_SUCCESS !=
+ woal_set_get_rts(priv, MLAN_ACT_GET, MOAL_IOCTL_WAIT, &rthr)) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ vwrq->value = rthr;
+ vwrq->disabled = ((vwrq->value < MLAN_RTS_MIN_VALUE)
+ || (vwrq->value > MLAN_RTS_MAX_VALUE));
+ vwrq->fixed = 1;
+
+ done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set Fragment threshold
+ *
+ * @param dev A pointer to net_device structure
+ * @param info A pointer to iw_request_info structure
+ * @param vwrq A pointer to iw_param structure
+ * @param extra A pointer to extra data buf
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_set_frag(struct net_device *dev, struct iw_request_info *info,
+ struct iw_param *vwrq, char *extra)
+{
+ int ret = 0;
+ moal_private *priv = (moal_private *) netdev_priv(dev);
+ int fthr = vwrq->value;
+
+ ENTER();
+
+ if (vwrq->disabled) {
+ fthr = MLAN_FRAG_MAX_VALUE;
+ } else {
+ if (fthr < MLAN_FRAG_MIN_VALUE || fthr > MLAN_FRAG_MAX_VALUE) {
+ ret = -EINVAL;
+ goto done;
+ }
+ }
+
+ if (MLAN_STATUS_SUCCESS !=
+ woal_set_get_frag(priv, MLAN_ACT_SET, MOAL_IOCTL_WAIT, &fthr)) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Get Fragment threshold
+ *
+ * @param dev A pointer to net_device structure
+ * @param info A pointer to iw_request_info structure
+ * @param vwrq A pointer to iw_param structure
+ * @param extra A pointer to extra data buf
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_get_frag(struct net_device *dev, struct iw_request_info *info,
+ struct iw_param *vwrq, char *extra)
+{
+ int ret = 0, fthr;
+ moal_private *priv = (moal_private *) netdev_priv(dev);
+
+ ENTER();
+
+ if (MLAN_STATUS_SUCCESS !=
+ woal_set_get_frag(priv, MLAN_ACT_GET, MOAL_IOCTL_WAIT, &fthr)) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ vwrq->value = fthr;
+ vwrq->disabled = ((vwrq->value < MLAN_FRAG_MIN_VALUE)
+ || (vwrq->value > MLAN_FRAG_MAX_VALUE));
+ vwrq->fixed = 1;
+
+ done:
+ LEAVE();
+ return ret;
+}
+
+#if (WIRELESS_EXT >= 18)
+/**
+ * @brief Get IE
+ *
+ * @param dev A pointer to net_device structure
+ * @param info A pointer to iw_request_info structure
+ * @param dwrq A pointer to iw_point structure
+ * @param extra A pointer to extra data buf
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_get_gen_ie(struct net_device *dev, struct iw_request_info *info,
+ struct iw_point *dwrq, char *extra)
+{
+ int ret = 0;
+ moal_private *priv = (moal_private *) netdev_priv(dev);
+ int copy_size = 0, ie_len;
+ t_u8 ie[MAX_IE_SIZE];
+
+ ENTER();
+
+ if (MLAN_STATUS_SUCCESS !=
+ woal_set_get_gen_ie(priv, MLAN_ACT_GET, ie, &ie_len)) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ copy_size = MIN(ie_len, dwrq->length);
+ memcpy(extra, ie, copy_size);
+ dwrq->length = copy_size;
+
+ done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set IE
+ *
+ * Pass an opaque block of data, expected to be IEEE IEs, to the driver
+ * for eventual passthrough to the firmware in an associate/join
+ * (and potentially start) command.
+ *
+ * @param dev A pointer to net_device structure
+ * @param info A pointer to iw_request_info structure
+ * @param dwrq A pointer to iw_point structure
+ * @param extra A pointer to extra data buf
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_set_gen_ie(struct net_device *dev, struct iw_request_info *info,
+ struct iw_point *dwrq, char *extra)
+{
+ int ret = 0;
+ moal_private *priv = (moal_private *) netdev_priv(dev);
+ int ie_len = dwrq->length;
+ const t_u8 wps_oui[] = { 0x00, 0x50, 0xf2, 0x04 };
+ mlan_ds_wps_cfg *pwps = NULL;
+ mlan_ioctl_req *req = NULL;
+
+ ENTER();
+
+ /* extra + 2 to skip element id and length */
+ if (!memcmp((t_u8 *) (extra + 2), wps_oui, sizeof(wps_oui))) {
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_wps_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ pwps = (mlan_ds_wps_cfg *) req->pbuf;
+ req->req_id = MLAN_IOCTL_WPS_CFG;
+ req->action = MLAN_ACT_SET;
+ pwps->sub_command = MLAN_OID_WPS_CFG_SESSION;
+ pwps->param.wps_session = MLAN_WPS_CFG_SESSION_START;
+
+ if (MLAN_STATUS_SUCCESS !=
+ woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ }
+
+ if (MLAN_STATUS_SUCCESS !=
+ woal_set_get_gen_ie(priv, MLAN_ACT_SET, (t_u8 *) extra, &ie_len)) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ done:
+ if (req)
+ kfree(req);
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Extended version of encoding configuration
+ *
+ * @param dev A pointer to net_device structure
+ * @param info A pointer to iw_request_info structure
+ * @param dwrq A pointer to iw_point structure
+ * @param extra A pointer to extra data buf
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_set_encode_ext(struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_point *dwrq, char *extra)
+{
+ struct iw_encode_ext *ext = (struct iw_encode_ext *) extra;
+ moal_private *priv = (moal_private *) netdev_priv(dev);
+ int key_index;
+ t_u8 *pkey_material = NULL;
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_sec_cfg *sec = NULL;
+ int ret = 0;
+
+ ENTER();
+ key_index = (dwrq->flags & IW_ENCODE_INDEX) - 1;
+ if (key_index < 0 || key_index > 3) {
+ ret = -EINVAL;
+ goto done;
+ }
+ if (ext->key_len > (dwrq->length - sizeof(struct iw_encode_ext))) {
+ ret = -EINVAL;
+ goto done;
+ }
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_sec_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+ sec = (mlan_ds_sec_cfg *) req->pbuf;
+ sec->sub_command = MLAN_OID_SEC_CFG_ENCRYPT_KEY;
+ req->req_id = MLAN_IOCTL_SEC_CFG;
+ req->action = MLAN_ACT_SET;
+ pkey_material = (t_u8 *) (ext + 1);
+ sec->param.encrypt_key.key_len = ext->key_len;
+ memcpy(sec->param.encrypt_key.mac_addr, (u8 *) ext->addr.sa_data, ETH_ALEN);
+ /* Disable and Remove Key */
+ if ((dwrq->flags & IW_ENCODE_DISABLED) && !ext->key_len) {
+ sec->param.encrypt_key.key_remove = MTRUE;
+ sec->param.encrypt_key.key_index = key_index;
+ sec->param.encrypt_key.key_flags = KEY_FLAG_REMOVE_KEY;
+ PRINTM(MIOCTL,
+ "Remove key key_index=%d, dwrq->flags=0x%x %02x:%02x:%02x:%02x:%02x:%02x\n",
+ key_index, dwrq->flags, sec->param.encrypt_key.mac_addr[0],
+ sec->param.encrypt_key.mac_addr[1],
+ sec->param.encrypt_key.mac_addr[2],
+ sec->param.encrypt_key.mac_addr[3],
+ sec->param.encrypt_key.mac_addr[4],
+ sec->param.encrypt_key.mac_addr[5]);
+ } else if (ext->key_len <= MAX_WEP_KEY_SIZE) {
+ /* Set WEP key */
+ sec->param.encrypt_key.key_index = key_index;
+ sec->param.encrypt_key.key_flags = ext->ext_flags;
+ memcpy(sec->param.encrypt_key.key_material, pkey_material,
+ ext->key_len);
+ if (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY)
+ sec->param.encrypt_key.is_current_wep_key = MTRUE;
+ } else {
+ /* Set WPA key */
+ sec->param.encrypt_key.key_index = key_index;
+ sec->param.encrypt_key.key_flags = ext->ext_flags;
+ if (ext->ext_flags & IW_ENCODE_EXT_RX_SEQ_VALID) {
+ memcpy(sec->param.encrypt_key.pn, (t_u8 *) ext->rx_seq,
+ SEQ_MAX_SIZE);
+ DBG_HEXDUMP(MCMD_D, "Rx PN", sec->param.encrypt_key.pn,
+ SEQ_MAX_SIZE);
+ }
+ if (ext->ext_flags & IW_ENCODE_EXT_TX_SEQ_VALID) {
+ memcpy(sec->param.encrypt_key.pn, (t_u8 *) ext->tx_seq,
+ SEQ_MAX_SIZE);
+ DBG_HEXDUMP(MCMD_D, "Tx PN", sec->param.encrypt_key.pn,
+ SEQ_MAX_SIZE);
+ }
+ memcpy(sec->param.encrypt_key.key_material, pkey_material,
+ ext->key_len);
+ PRINTM(MIOCTL,
+ "set wpa key key_index=%d, key_len=%d key_flags=0x%x %02x:%02x:%02x:%02x:%02x:%02x\n",
+ key_index, ext->key_len, sec->param.encrypt_key.key_flags,
+ sec->param.encrypt_key.mac_addr[0],
+ sec->param.encrypt_key.mac_addr[1],
+ sec->param.encrypt_key.mac_addr[2],
+ sec->param.encrypt_key.mac_addr[3],
+ sec->param.encrypt_key.mac_addr[4],
+ sec->param.encrypt_key.mac_addr[5]);
+ DBG_HEXDUMP(MCMD_D, "wpa key", pkey_material, ext->key_len);
+#define IW_ENCODE_ALG_SMS4 0x20
+ /* Set WAPI key */
+ if (ext->alg == IW_ENCODE_ALG_SMS4) {
+ sec->param.encrypt_key.is_wapi_key = MTRUE;
+ memcpy(sec->param.encrypt_key.pn, (t_u8 *) ext->tx_seq,
+ SEQ_MAX_SIZE);
+ memcpy(&sec->param.encrypt_key.pn[SEQ_MAX_SIZE],
+ (t_u8 *) ext->rx_seq, SEQ_MAX_SIZE);
+ DBG_HEXDUMP(MCMD_D, "WAPI PN", sec->param.encrypt_key.pn, PN_SIZE);
+ }
+ }
+ if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT))
+ ret = -EFAULT;
+ done:
+ if (req)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Extended version of encoding configuration
+ *
+ * @param dev A pointer to net_device structure
+ * @param info A pointer to iw_request_info structure
+ * @param dwrq A pointer to iw_point structure
+ * @param extra A pointer to extra data buf
+ *
+ * @return -EOPNOTSUPP
+ */
+static int
+woal_get_encode_ext(struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_point *dwrq, char *extra)
+{
+ ENTER();
+ LEAVE();
+ return -EOPNOTSUPP;
+}
+
+/**
+ * @brief Request MLME operation
+ *
+ * @param dev A pointer to net_device structure
+ * @param info A pointer to iw_request_info structure
+ * @param dwrq A pointer to iw_point structure
+ * @param extra A pointer to extra data buf
+ *
+ * @return 0--success, otherwise fail
+ */
+static int
+woal_set_mlme(struct net_device *dev,
+ struct iw_request_info *info, struct iw_point *dwrq, char *extra)
+{
+ struct iw_mlme *mlme = (struct iw_mlme *) extra;
+ moal_private *priv = (moal_private *) netdev_priv(dev);
+ int ret = 0;
+
+ ENTER();
+ if ((mlme->cmd == IW_MLME_DEAUTH) || (mlme->cmd == IW_MLME_DISASSOC)) {
+
+ if (MLAN_STATUS_SUCCESS !=
+ woal_disconnect(priv, MOAL_IOCTL_WAIT, (t_u8 *) mlme->addr.sa_data))
+ ret = -EFAULT;
+ }
+ LEAVE();
+ return ret;
+}
+
+/** @brief Set authentication mode parameters
+ *
+ * @param dev A pointer to net_device structure
+ * @param info A pointer to iw_request_info structure
+ * @param vwrq A pointer to iw_param structure
+ * @param extra A pointer to extra data buf
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_set_auth(struct net_device *dev, struct iw_request_info *info,
+ struct iw_param *vwrq, char *extra)
+{
+ int ret = 0;
+ moal_private *priv = (moal_private *) netdev_priv(dev);
+ t_u32 auth_mode = 0;
+ t_u32 encrypt_mode = 0;
+ ENTER();
+
+ switch (vwrq->flags & IW_AUTH_INDEX) {
+ case IW_AUTH_CIPHER_PAIRWISE:
+ case IW_AUTH_CIPHER_GROUP:
+ if (vwrq->value & IW_AUTH_CIPHER_NONE)
+ encrypt_mode = MLAN_ENCRYPTION_MODE_NONE;
+ else if (vwrq->value & IW_AUTH_CIPHER_WEP40)
+ encrypt_mode = MLAN_ENCRYPTION_MODE_WEP40;
+ else if (vwrq->value & IW_AUTH_CIPHER_WEP104)
+ encrypt_mode = MLAN_ENCRYPTION_MODE_WEP104;
+ else if (vwrq->value & IW_AUTH_CIPHER_TKIP)
+ encrypt_mode = MLAN_ENCRYPTION_MODE_TKIP;
+ else if (vwrq->value & IW_AUTH_CIPHER_CCMP)
+ encrypt_mode = MLAN_ENCRYPTION_MODE_CCMP;
+ if (MLAN_STATUS_SUCCESS !=
+ woal_set_encrypt_mode(priv, MOAL_IOCTL_WAIT, encrypt_mode))
+ ret = -EFAULT;
+ break;
+ case IW_AUTH_80211_AUTH_ALG:
+ switch (vwrq->value) {
+ case IW_AUTH_ALG_SHARED_KEY:
+ PRINTM(MINFO, "Auth mode shared key!\n");
+ auth_mode = MLAN_AUTH_MODE_SHARED;
+ break;
+ case IW_AUTH_ALG_LEAP:
+ PRINTM(MINFO, "Auth mode LEAP!\n");
+ auth_mode = MLAN_AUTH_MODE_NETWORKEAP;
+ break;
+ case IW_AUTH_ALG_OPEN_SYSTEM:
+ PRINTM(MINFO, "Auth mode open!\n");
+ auth_mode = MLAN_AUTH_MODE_OPEN;
+ break;
+ case IW_AUTH_ALG_SHARED_KEY | IW_AUTH_ALG_OPEN_SYSTEM:
+ default:
+ PRINTM(MINFO, "Auth mode auto!\n");
+ auth_mode = MLAN_AUTH_MODE_AUTO;
+ break;
+ }
+ if (MLAN_STATUS_SUCCESS !=
+ woal_set_auth_mode(priv, MOAL_IOCTL_WAIT, auth_mode))
+ ret = -EFAULT;
+ break;
+ case IW_AUTH_WPA_ENABLED:
+ if (MLAN_STATUS_SUCCESS !=
+ woal_set_wpa_enable(priv, MOAL_IOCTL_WAIT, vwrq->value))
+ ret = -EFAULT;
+ break;
+#define IW_AUTH_WAPI_ENABLED 0x20
+ case IW_AUTH_WAPI_ENABLED:
+ if (MLAN_STATUS_SUCCESS !=
+ woal_set_wapi_enable(priv, MOAL_IOCTL_WAIT, vwrq->value))
+ ret = -EFAULT;
+ break;
+ case IW_AUTH_WPA_VERSION:
+ /* set WPA_VERSION_DISABLED/VERSION_WPA/VERSION_WP2 */
+ priv->wpa_version = vwrq->value;
+ break;
+ case IW_AUTH_KEY_MGMT:
+ /* set KEY_MGMT_802_1X/KEY_MGMT_PSK */
+ priv->key_mgmt = vwrq->value;
+ break;
+ case IW_AUTH_TKIP_COUNTERMEASURES:
+ case IW_AUTH_DROP_UNENCRYPTED:
+ case IW_AUTH_RX_UNENCRYPTED_EAPOL:
+ case IW_AUTH_ROAMING_CONTROL:
+ case IW_AUTH_PRIVACY_INVOKED:
+ break;
+ default:
+ ret = -EOPNOTSUPP;
+ break;
+ }
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Get authentication mode parameters
+ *
+ * @param dev A pointer to net_device structure
+ * @param info A pointer to iw_request_info structure
+ * @param vwrq A pointer to iw_param structure
+ * @param extra A pointer to extra data buf
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_get_auth(struct net_device *dev, struct iw_request_info *info,
+ struct iw_param *vwrq, char *extra)
+{
+ int ret = 0;
+ moal_private *priv = (moal_private *) netdev_priv(dev);
+ t_u32 encrypt_mode = 0;
+ t_u32 auth_mode;
+ t_u32 wpa_enable;
+ ENTER();
+ switch (vwrq->flags & IW_AUTH_INDEX) {
+ case IW_AUTH_CIPHER_PAIRWISE:
+ case IW_AUTH_CIPHER_GROUP:
+ if (MLAN_STATUS_SUCCESS !=
+ woal_get_encrypt_mode(priv, MOAL_IOCTL_WAIT, &encrypt_mode))
+ ret = -EFAULT;
+ else {
+ if (encrypt_mode == MLAN_ENCRYPTION_MODE_NONE)
+ vwrq->value = IW_AUTH_CIPHER_NONE;
+ else if (encrypt_mode == MLAN_ENCRYPTION_MODE_WEP40)
+ vwrq->value = IW_AUTH_CIPHER_WEP40;
+ else if (encrypt_mode == MLAN_ENCRYPTION_MODE_TKIP)
+ vwrq->value = IW_AUTH_CIPHER_TKIP;
+ else if (encrypt_mode == MLAN_ENCRYPTION_MODE_CCMP)
+ vwrq->value = IW_AUTH_CIPHER_CCMP;
+ else if (encrypt_mode == MLAN_ENCRYPTION_MODE_WEP104)
+ vwrq->value = IW_AUTH_CIPHER_WEP104;
+ }
+ break;
+ case IW_AUTH_80211_AUTH_ALG:
+ if (MLAN_STATUS_SUCCESS !=
+ woal_get_auth_mode(priv, MOAL_IOCTL_WAIT, &auth_mode))
+ ret = -EFAULT;
+ else {
+ if (auth_mode == MLAN_AUTH_MODE_SHARED)
+ vwrq->value = IW_AUTH_ALG_SHARED_KEY;
+ else if (auth_mode == MLAN_AUTH_MODE_NETWORKEAP)
+ vwrq->value = IW_AUTH_ALG_LEAP;
+ else
+ vwrq->value = IW_AUTH_ALG_OPEN_SYSTEM;
+ }
+ break;
+ case IW_AUTH_WPA_ENABLED:
+ if (MLAN_STATUS_SUCCESS !=
+ woal_get_wpa_enable(priv, MOAL_IOCTL_WAIT, &wpa_enable))
+ ret = -EFAULT;
+ else
+ vwrq->value = wpa_enable;
+ break;
+ case IW_AUTH_WPA_VERSION:
+ vwrq->value = priv->wpa_version;
+ break;
+ case IW_AUTH_KEY_MGMT:
+ vwrq->value = priv->key_mgmt;
+ break;
+ case IW_AUTH_TKIP_COUNTERMEASURES:
+ case IW_AUTH_DROP_UNENCRYPTED:
+ case IW_AUTH_RX_UNENCRYPTED_EAPOL:
+ case IW_AUTH_ROAMING_CONTROL:
+ case IW_AUTH_PRIVACY_INVOKED:
+ default:
+ ret = -EOPNOTSUPP;
+ goto done;
+ }
+
+ done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set PMKSA Cache
+ *
+ * @param dev A pointer to net_device structure
+ * @param info A pointer to iw_request_info structure
+ * @param vwrq A pointer to iw_param structure
+ * @param extra A pointer to extra data buf
+ *
+ * @return -EOPNOTSUPP
+ */
+static int
+woal_set_pmksa(struct net_device *dev, struct iw_request_info *info,
+ struct iw_param *vwrq, char *extra)
+{
+ ENTER();
+ LEAVE();
+ return -EOPNOTSUPP;
+}
+
+#endif /* WE >= 18 */
+
+/* Data rate listing
+ * MULTI_BANDS:
+ * abg a b b/g
+ * Infra G(12) A(8) B(4) G(12)
+ * Adhoc A+B(12) A(8) B(4) B(4)
+ * non-MULTI_BANDS:
+ b b/g
+ * Infra B(4) G(12)
+ * Adhoc B(4) B(4)
+ */
+/**
+ * @brief Get Range Info
+ *
+ * @param dev A pointer to net_device structure
+ * @param info A pointer to iw_request_info structure
+ * @param dwrq A pointer to iw_point structure
+ * @param extra A pointer to extra data buf
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_get_range(struct net_device *dev, struct iw_request_info *info,
+ struct iw_point *dwrq, char *extra)
+{
+ int i;
+ moal_private *priv = (moal_private *) netdev_priv(dev);
+ struct iw_range *range = (struct iw_range *) extra;
+ moal_802_11_rates rates;
+ mlan_chan_list *pchan_list = NULL;
+ mlan_bss_info bss_info;
+
+ ENTER();
+
+ if (!(pchan_list = kmalloc(sizeof(mlan_chan_list), GFP_KERNEL))) {
+ LEAVE();
+ return -ENOMEM;
+ }
+
+ dwrq->length = sizeof(struct iw_range);
+ memset(range, 0, sizeof(struct iw_range));
+
+ range->min_nwid = 0;
+ range->max_nwid = 0;
+
+ memset(&rates, 0, sizeof(rates));
+ woal_get_data_rates(priv, MOAL_IOCTL_WAIT, &rates);
+ range->num_bitrates = rates.num_of_rates;
+
+ for (i = 0; i < MIN(range->num_bitrates, IW_MAX_BITRATES) && rates.rates[i];
+ i++) {
+ range->bitrate[i] = (rates.rates[i] & 0x7f) * 500000;
+ }
+ range->num_bitrates = i;
+ PRINTM(MINFO, "IW_MAX_BITRATES=%d num_bitrates=%d\n", IW_MAX_BITRATES,
+ range->num_bitrates);
+
+ range->num_frequency = 0;
+
+ memset(pchan_list, 0, sizeof(mlan_chan_list));
+
+ woal_get_channel_list(priv, MOAL_IOCTL_WAIT, pchan_list);
+
+ range->num_frequency = MIN(pchan_list->num_of_chan, IW_MAX_FREQUENCIES);
+
+ for (i = 0; i < range->num_frequency; i++) {
+ range->freq[i].i = (long) pchan_list->cf[i].channel;
+ range->freq[i].m = (long) pchan_list->cf[i].freq * 100000;
+ range->freq[i].e = 1;
+ }
+ kfree(pchan_list);
+
+ PRINTM(MINFO, "IW_MAX_FREQUENCIES=%d num_frequency=%d\n",
+ IW_MAX_FREQUENCIES, range->num_frequency);
+
+ range->num_channels = range->num_frequency;
+
+ woal_sort_channels(&range->freq[0], range->num_frequency);
+
+ /*
+ * Set an indication of the max TCP throughput in bit/s that we can
+ * expect using this interface
+ */
+ if (i > 2)
+ range->throughput = 5000 * 1000;
+ else
+ range->throughput = 1500 * 1000;
+
+ range->min_rts = MLAN_RTS_MIN_VALUE;
+ range->max_rts = MLAN_RTS_MAX_VALUE;
+ range->min_frag = MLAN_FRAG_MIN_VALUE;
+ range->max_frag = MLAN_FRAG_MAX_VALUE;
+
+ range->encoding_size[0] = 5;
+ range->encoding_size[1] = 13;
+ range->num_encoding_sizes = 2;
+ range->max_encoding_tokens = 4;
+
+/** Minimum power period */
+#define IW_POWER_PERIOD_MIN 1000000 /* 1 sec */
+/** Maximum power period */
+#define IW_POWER_PERIOD_MAX 120000000 /* 2 min */
+/** Minimum power timeout value */
+#define IW_POWER_TIMEOUT_MIN 1000 /* 1 ms */
+/** Maximim power timeout value */
+#define IW_POWER_TIMEOUT_MAX 1000000 /* 1 sec */
+
+ /* Power Management duration & timeout */
+ range->min_pmp = IW_POWER_PERIOD_MIN;
+ range->max_pmp = IW_POWER_PERIOD_MAX;
+ range->min_pmt = IW_POWER_TIMEOUT_MIN;
+ range->max_pmt = IW_POWER_TIMEOUT_MAX;
+ range->pmp_flags = IW_POWER_PERIOD;
+ range->pmt_flags = IW_POWER_TIMEOUT;
+ range->pm_capa = IW_POWER_PERIOD | IW_POWER_TIMEOUT | IW_POWER_ALL_R;
+
+ /*
+ * Minimum version we recommend
+ */
+ range->we_version_source = 15;
+
+ /*
+ * Version we are compiled with
+ */
+ range->we_version_compiled = WIRELESS_EXT;
+
+ range->retry_capa = IW_RETRY_LIMIT;
+ range->retry_flags = IW_RETRY_LIMIT | IW_RETRY_MAX;
+
+ range->min_retry = MLAN_TX_RETRY_MIN;
+ range->max_retry = MLAN_TX_RETRY_MAX;
+
+ /*
+ * Set the qual, level and noise range values
+ */
+ /*
+ * need to put the right values here
+ */
+/** Maximum quality percentage */
+#define IW_MAX_QUAL_PERCENT 5
+/** Average quality percentage */
+#define IW_AVG_QUAL_PERCENT 3
+ range->max_qual.qual = IW_MAX_QUAL_PERCENT;
+ range->max_qual.level = 0;
+ range->max_qual.noise = 0;
+
+ range->avg_qual.qual = IW_AVG_QUAL_PERCENT;
+ range->avg_qual.level = 0;
+ range->avg_qual.noise = 0;
+
+ range->sensitivity = 0;
+
+ /*
+ * Setup the supported power level ranges
+ */
+ memset(range->txpower, 0, sizeof(range->txpower));
+
+ memset(&bss_info, 0, sizeof(bss_info));
+
+ woal_get_bss_info(priv, MOAL_IOCTL_WAIT, &bss_info);
+
+ range->txpower[0] = bss_info.min_power_level;
+ range->txpower[1] = bss_info.max_power_level;
+ range->num_txpower = 2;
+ range->txpower_capa = IW_TXPOW_DBM | IW_TXPOW_RANGE;
+
+ LEAVE();
+ return 0;
+}
+
+#ifdef MEF_CFG_RX_FILTER
+/**
+ * @brief Enable/disable Rx broadcast/multicast filter in non-HS mode
+ *
+ * @param priv A pointer to moal_private structure
+ * @param enable MTRUE/MFALSE: enable/disable
+ *
+ * @return 0 -- success, otherwise fail
+ */
+static int
+woal_set_rxfilter(moal_private * priv, BOOLEAN enable)
+{
+ int ret = 0;
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_misc_cfg *misc = NULL;
+ mlan_ds_misc_mef_cfg *mef_cfg = NULL;
+
+ ENTER();
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+ misc = (mlan_ds_misc_cfg *) req->pbuf;
+ mef_cfg = &misc->param.mef_cfg;
+ req->req_id = MLAN_IOCTL_MISC_CFG;
+ misc->sub_command = MLAN_OID_MISC_MEF_CFG;
+ req->action = MLAN_ACT_SET;
+
+ mef_cfg->sub_id = (enable ? MEF_CFG_RX_FILTER_ENABLE : MEF_CFG_DISABLE);
+ if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ done:
+ if (req)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+#endif
+
+/**
+ * @brief Set priv command
+ *
+ * @param dev A pointer to net_device structure
+ * @param info A pointer to iw_request_info structure
+ * @param dwrq A pointer to iw_point structure
+ * @param extra A pointer to extra data buf
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_set_priv(struct net_device *dev, struct iw_request_info *info,
+ struct iw_point *dwrq, char *extra)
+{
+ int ret = 0;
+ moal_private *priv = (moal_private *) netdev_priv(dev);
+ char *buf = NULL;
+ int power_mode = 0;
+ int band = 0;
+ char *pband = NULL;
+ mlan_bss_info bss_info;
+ mlan_ds_get_signal signal;
+ mlan_rate_cfg_t rate;
+ char *pdata;
+ t_u8 country_code[COUNTRY_CODE_LEN];
+ int len = 0;
+ ENTER();
+ if (!(buf = kmalloc(dwrq->length + 1, GFP_KERNEL))) {
+ ret = -ENOMEM;
+ goto done;
+ }
+ memset(buf, 0, dwrq->length + 1);
+ if (copy_from_user(buf, dwrq->pointer, dwrq->length)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ PRINTM(MIOCTL, "SIOCSIWPRIV requst = %s\n", buf);
+ if (strncmp(buf, "RSSILOW-THRESHOLD", strlen("RSSILOW-THRESHOLD")) == 0) {
+ pdata = buf + strlen("RSSILOW-THRESHOLD") + 1;
+ if (MLAN_STATUS_SUCCESS != woal_set_rssi_low_threshold(priv, pdata)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ len = sprintf(buf, "OK\n") + 1;
+ } else if (strncmp(buf, "RSSI", strlen("RSSI")) == 0) {
+ if (MLAN_STATUS_SUCCESS != woal_get_bss_info(priv,
+ MOAL_IOCTL_WAIT,
+ &bss_info)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ if (bss_info.media_connected) {
+ if (MLAN_STATUS_SUCCESS !=
+ woal_get_signal_info(priv, MOAL_IOCTL_WAIT, &signal)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ len =
+ sprintf(buf, "%s rssi %d\n", bss_info.ssid.ssid,
+ signal.bcn_rssi_avg) + 1;
+ } else {
+ len = sprintf(buf, "OK\n") + 1;
+ }
+ } else if (strncmp(buf, "LINKSPEED", strlen("LINKSPEED")) == 0) {
+ if (MLAN_STATUS_SUCCESS !=
+ woal_set_get_data_rate(priv, MLAN_ACT_GET, &rate)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ PRINTM(MIOCTL, "tx rate=%d\n", (int) rate.rate);
+ len =
+ sprintf(buf, "LinkSpeed %d\n",
+ (int) (rate.rate * 500000 / 1000000)) + 1;
+ } else if (strncmp(buf, "MACADDR", strlen("MACADDR")) == 0) {
+ len =
+ sprintf(buf, "Macaddr = %02X:%02X:%02X:%02X:%02X:%02X\n",
+ priv->current_addr[0], priv->current_addr[1],
+ priv->current_addr[2], priv->current_addr[3],
+ priv->current_addr[4], priv->current_addr[5]) + 1;
+ } else if (strncmp(buf, "GETPOWER", strlen("GETPOWER")) == 0) {
+ if (MLAN_STATUS_SUCCESS != woal_get_powermode(priv, &power_mode)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ len = sprintf(buf, "powermode = %d\n", power_mode) + 1;
+ } else if (strncmp(buf, "SCAN-ACTIVE", strlen("SCAN-ACTIVE")) == 0) {
+ if (MLAN_STATUS_SUCCESS !=
+ woal_set_scan_type(priv, MLAN_SCAN_TYPE_ACTIVE)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ priv->scan_type = MLAN_SCAN_TYPE_ACTIVE;
+ PRINTM(MIOCTL, "Set Active Scan\n");
+ len = sprintf(buf, "OK\n") + 1;
+ } else if (strncmp(buf, "SCAN-PASSIVE", strlen("SCAN-PASSIVE")) == 0) {
+ if (MLAN_STATUS_SUCCESS !=
+ woal_set_scan_type(priv, MLAN_SCAN_TYPE_PASSIVE)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ priv->scan_type = MLAN_SCAN_TYPE_PASSIVE;
+ PRINTM(MIOCTL, "Set Passive Scan\n");
+ len = sprintf(buf, "OK\n") + 1;
+ } else if (strncmp(buf, "POWERMODE", strlen("POWERMODE")) == 0) {
+ pdata = buf + strlen("POWERMODE") + 1;
+ if (MLAN_STATUS_SUCCESS != woal_set_powermode(priv, pdata)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ len = sprintf(buf, "OK\n") + 1;
+ } else if (strncmp(buf, "COUNTRY", strlen("COUNTRY")) == 0) {
+ memset(country_code, 0, sizeof(country_code));
+ memcpy(country_code, buf + strlen("COUNTRY") + 1,
+ strlen(buf) - strlen("COUNTRY") - 1);
+ PRINTM(MIOCTL, "Set COUNTRY %s\n", country_code);
+ if (MLAN_STATUS_SUCCESS != woal_set_region_code(priv, country_code)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ len = sprintf(buf, "OK\n") + 1;
+ } else if (memcmp(buf, WEXT_CSCAN_HEADER, WEXT_CSCAN_HEADER_SIZE) == 0) {
+ PRINTM(MIOCTL, "Set Combo Scan\n");
+ if (MLAN_STATUS_SUCCESS != woal_set_combo_scan(priv, buf, dwrq->length)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ len = sprintf(buf, "OK\n") + 1;
+ } else if (strncmp(buf, "GETBAND", strlen("GETBAND")) == 0) {
+ if (MLAN_STATUS_SUCCESS != woal_get_band(priv, &band)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ len = sprintf(buf, "Band %d\n", band) + 1;
+ } else if (strncmp(buf, "SETBAND", strlen("SETBAND")) == 0) {
+ pband = buf + strlen("SETBAND") + 1;
+ if (MLAN_STATUS_SUCCESS != woal_set_band(priv, pband)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ len = sprintf(buf, "OK\n") + 1;
+ } else if (strncmp(buf, "START", strlen("START")) == 0) {
+ len = sprintf(buf, "OK\n") + 1;
+ } else if (strncmp(buf, "STOP", strlen("STOP")) == 0) {
+ len = sprintf(buf, "OK\n") + 1;
+ } else if (strncmp(buf, "SETSUSPENDOPT", strlen("SETSUSPENDOPT")) == 0) {
+ /* it will be done by GUI */
+ len = sprintf(buf, "OK\n") + 1;
+ } else if (strncmp(buf, "BTCOEXMODE", strlen("BTCOEXMODE")) == 0) {
+ len = sprintf(buf, "OK\n") + 1;
+ } else if (strncmp(buf, "BTCOEXSCAN-START", strlen("BTCOEXSCAN-START")) ==
+ 0) {
+ len = sprintf(buf, "OK\n") + 1;
+ } else if (strncmp(buf, "BTCOEXSCAN-STOP", strlen("BTCOEXSCAN-STOP")) == 0) {
+ len = sprintf(buf, "OK\n") + 1;
+ } else if (strncmp(buf, "BTCOEXSCAN-START", strlen("BTCOEXSCAN-START")) ==
+ 0) {
+ len = sprintf(buf, "OK\n") + 1;
+ } else if (strncmp(buf, "BTCOEXSCAN-STOP", strlen("BTCOEXSCAN-STOP")) == 0) {
+ len = sprintf(buf, "OK\n") + 1;
+ } else if (strncmp(buf, "BGSCAN-START", strlen("BGSCAN-START")) == 0) {
+ len = sprintf(buf, "OK\n") + 1;
+ } else if (strncmp(buf, "BGSCAN-CONFIG", strlen("BGSCAN-CONFIG")) == 0) {
+ if (MLAN_STATUS_SUCCESS != woal_set_bg_scan(priv, buf, dwrq->length)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ priv->bg_scan_start = MTRUE;
+ priv->bg_scan_reported = MFALSE;
+ len = sprintf(buf, "OK\n") + 1;
+ } else if (strncmp(buf, "BGSCAN-STOP", strlen("BGSCAN-STOP")) == 0) {
+ if (MLAN_STATUS_SUCCESS != woal_stop_bg_scan(priv)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ priv->bg_scan_start = MFALSE;
+ priv->bg_scan_reported = MFALSE;
+ len = sprintf(buf, "OK\n") + 1;
+ } else if (strncmp(buf, "RXFILTER-START", strlen("RXFILTER-START")) == 0) {
+#ifdef MEF_CFG_RX_FILTER
+ if ((ret = woal_set_rxfilter(priv, MTRUE))) {
+ goto done;
+ }
+#endif
+ len = sprintf(buf, "OK\n") + 1;
+ } else if (strncmp(buf, "RXFILTER-STOP", strlen("RXFILTER-STOP")) == 0) {
+#ifdef MEF_CFG_RX_FILTER
+ if ((ret = woal_set_rxfilter(priv, MFALSE))) {
+ goto done;
+ }
+#endif
+ len = sprintf(buf, "OK\n") + 1;
+ } else if (strncmp(buf, "RXFILTER-ADD", strlen("RXFILTER-ADD")) == 0) {
+ pdata = buf + strlen("RXFILTER-ADD") + 1;
+ if (MLAN_STATUS_SUCCESS != woal_add_rxfilter(priv, pdata)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ len = sprintf(buf, "OK\n") + 1;
+ } else if (strncmp(buf, "RXFILTER-REMOVE", strlen("RXFILTER-REMOVE")) == 0) {
+ pdata = buf + strlen("RXFILTER-REMOVE") + 1;
+ if (MLAN_STATUS_SUCCESS != woal_remove_rxfilter(priv, pdata)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ len = sprintf(buf, "OK\n") + 1;
+ } else if (strncmp(buf, "QOSINFO", strlen("QOSINFO")) == 0) {
+ pdata = buf + strlen("QOSINFO") + 1;
+ if (MLAN_STATUS_SUCCESS != woal_set_qos_cfg(priv, pdata)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ len = sprintf(buf, "OK\n") + 1;
+ } else if (strncmp(buf, "SLEEPPD", strlen("SLEEPPD")) == 0) {
+ pdata = buf + strlen("SLEEPPD") + 1;
+ if (MLAN_STATUS_SUCCESS != woal_set_sleeppd(priv, pdata)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ len = sprintf(buf, "OK\n") + 1;
+ } else {
+ PRINTM(MIOCTL, "Unknow PRIVATE command: %s, ignored\n", buf);
+ ret = -EFAULT;
+ goto done;
+ }
+ PRINTM(MIOCTL, "PRIV Command return: %s, length=%d\n", buf, len);
+ dwrq->length = (t_u16) len;
+ if (copy_to_user(dwrq->pointer, buf, dwrq->length)) {
+ ret = -EFAULT;
+ }
+ done:
+ if (buf)
+ kfree(buf);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Scan Network
+ *
+ * @param dev A pointer to net_device structure
+ * @param info A pointer to iw_request_info structure
+ * @param vwrq A pointer to iw_param structure
+ * @param extra A pointer to extra data buf
+ *
+ * @return 0--success, otherwise fail
+ */
+static int
+woal_set_scan(struct net_device *dev, struct iw_request_info *info,
+ struct iw_param *vwrq, char *extra)
+{
+ int ret = 0;
+ moal_private *priv = (moal_private *) netdev_priv(dev);
+ moal_handle *handle = priv->phandle;
+#if WIRELESS_EXT >= 18
+ struct iw_scan_req *req;
+ struct iw_point *dwrq = (struct iw_point *) vwrq;
+#endif
+ mlan_802_11_ssid req_ssid;
+
+ ENTER();
+ if (handle->scan_pending_on_block == MTRUE) {
+ PRINTM(MINFO, "scan already in processing...\n");
+ LEAVE();
+ return ret;
+ }
+#ifdef REASSOCIATION
+ if (MOAL_ACQ_SEMAPHORE_BLOCK(&handle->reassoc_sem)) {
+ PRINTM(MERROR, "Acquire semaphore error, woal_set_scan\n");
+ LEAVE();
+ return -EBUSY;
+ }
+#endif /* REASSOCIATION */
+ priv->report_scan_result = MTRUE;
+
+ memset(&req_ssid, 0x00, sizeof(mlan_802_11_ssid));
+
+#if WIRELESS_EXT >= 18
+ if ((dwrq->flags & IW_SCAN_THIS_ESSID) &&
+ (dwrq->length == sizeof(struct iw_scan_req))) {
+ req = (struct iw_scan_req *) extra;
+
+ if (req->essid_len <= MLAN_MAX_SSID_LENGTH) {
+
+ req_ssid.ssid_len = req->essid_len;
+ memcpy(req_ssid.ssid, (t_u8 *) req->essid, req->essid_len);
+ if (MLAN_STATUS_SUCCESS !=
+ woal_request_scan(priv, MOAL_NO_WAIT, &req_ssid)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ }
+ } else {
+#endif
+ if (MLAN_STATUS_SUCCESS != woal_request_scan(priv, MOAL_NO_WAIT, NULL)) {
+ ret = -EFAULT;
+ goto done;
+ }
+#if WIRELESS_EXT >= 18
+ }
+#endif
+
+ if (priv->phandle->surprise_removed) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ done:
+#ifdef REASSOCIATION
+ MOAL_REL_SEMAPHORE(&handle->reassoc_sem);
+#endif
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set essid
+ *
+ * @param dev A pointer to net_device structure
+ * @param info A pointer to iw_request_info structure
+ * @param dwrq A pointer to iw_point structure
+ * @param extra A pointer to extra data buf
+ *
+ * @return 0--success, otherwise fail
+ */
+static int
+woal_set_essid(struct net_device *dev, struct iw_request_info *info,
+ struct iw_point *dwrq, char *extra)
+{
+ moal_private *priv = (moal_private *) netdev_priv(dev);
+ mlan_802_11_ssid req_ssid;
+ mlan_ssid_bssid ssid_bssid;
+#ifdef REASSOCIATION
+ moal_handle *handle = priv->phandle;
+ mlan_bss_info bss_info;
+#endif
+ int ret = 0;
+ t_u32 mode = 0;
+
+ ENTER();
+
+#ifdef REASSOCIATION
+ /* Cancel re-association */
+ priv->reassoc_required = MFALSE;
+
+ if (MOAL_ACQ_SEMAPHORE_BLOCK(&handle->reassoc_sem)) {
+ PRINTM(MERROR, "Acquire semaphore error, woal_set_essid\n");
+ LEAVE();
+ return -EBUSY;
+ }
+#endif /* REASSOCIATION */
+
+ /* Check the size of the string */
+ if (dwrq->length > IW_ESSID_MAX_SIZE + 1) {
+ ret = -E2BIG;
+ goto setessid_ret;
+ }
+ if (priv->scan_type == MLAN_SCAN_TYPE_PASSIVE)
+ woal_set_scan_type(priv, MLAN_SCAN_TYPE_ACTIVE);
+ memset(&req_ssid, 0, sizeof(mlan_802_11_ssid));
+ memset(&ssid_bssid, 0, sizeof(mlan_ssid_bssid));
+
+#if WIRELESS_EXT > 20
+ req_ssid.ssid_len = dwrq->length;
+#else
+ req_ssid.ssid_len = dwrq->length - 1;
+#endif
+
+ /*
+ * Check if we asked for `any' or 'particular'
+ */
+ if (!dwrq->flags) {
+
+ if (!req_ssid.ssid_len) {
+ memset(&priv->prev_ssid_bssid.ssid, 0x00, sizeof(mlan_802_11_ssid));
+ memset(&priv->prev_ssid_bssid.bssid, 0x00, MLAN_MAC_ADDR_LENGTH);
+ goto setessid_ret;
+ }
+
+ /* Do normal SSID scanning */
+ if (MLAN_STATUS_SUCCESS !=
+ woal_request_scan(priv, MOAL_IOCTL_WAIT, NULL)) {
+ ret = -EFAULT;
+ goto setessid_ret;
+ }
+ } else {
+ /* Set the SSID */
+ memcpy(req_ssid.ssid, extra,
+ MIN(req_ssid.ssid_len, MLAN_MAX_SSID_LENGTH));
+ if (!req_ssid.ssid_len || (MFALSE == woal_ssid_valid(&req_ssid))) {
+ PRINTM(MERROR, "Invalid SSID - aborting set_essid\n");
+ ret = -EINVAL;
+ goto setessid_ret;
+ }
+
+ PRINTM(MINFO, "Requested new SSID = %s\n", (char *) req_ssid.ssid);
+ memcpy(&ssid_bssid.ssid, &req_ssid, sizeof(mlan_802_11_ssid));
+ if (dwrq->flags != 0xFFFF) {
+ if (MLAN_STATUS_SUCCESS != woal_find_essid(priv, &ssid_bssid)) {
+ /* Do specific SSID scanning */
+ if (MLAN_STATUS_SUCCESS !=
+ woal_request_scan(priv, MOAL_IOCTL_WAIT, &req_ssid)) {
+ ret = -EFAULT;
+ goto setessid_ret;
+ }
+ }
+ }
+
+ }
+
+ /* disconnect before try to associate */
+ woal_disconnect(priv, MOAL_IOCTL_WAIT, NULL);
+ mode = woal_get_mode(priv, MOAL_IOCTL_WAIT);
+
+ if (mode != IW_MODE_ADHOC) {
+ if (MLAN_STATUS_SUCCESS !=
+ woal_find_best_network(priv, MOAL_IOCTL_WAIT, &ssid_bssid)) {
+ ret = -EFAULT;
+ goto setessid_ret;
+ }
+ } else if (MLAN_STATUS_SUCCESS !=
+ woal_find_best_network(priv, MOAL_IOCTL_WAIT, &ssid_bssid))
+ /* Adhoc start, Check the channel command */
+ woal_11h_channel_check_ioctl(priv);
+
+ /* Connect to BSS by ESSID */
+ memset(&ssid_bssid.bssid, 0, MLAN_MAC_ADDR_LENGTH);
+
+ if (MLAN_STATUS_SUCCESS != woal_bss_start(priv,
+ MOAL_IOCTL_WAIT, &ssid_bssid)) {
+ ret = -EFAULT;
+ goto setessid_ret;
+ }
+#ifdef REASSOCIATION
+ memset(&bss_info, 0, sizeof(bss_info));
+ if (MLAN_STATUS_SUCCESS != woal_get_bss_info(priv,
+ MOAL_IOCTL_WAIT, &bss_info)) {
+ ret = -EFAULT;
+ goto setessid_ret;
+ }
+ memcpy(&priv->prev_ssid_bssid.ssid, &bss_info.ssid,
+ sizeof(mlan_802_11_ssid));
+ memcpy(&priv->prev_ssid_bssid.bssid, &bss_info.bssid, MLAN_MAC_ADDR_LENGTH);
+#endif /* REASSOCIATION */
+
+ setessid_ret:
+ if (priv->scan_type == MLAN_SCAN_TYPE_PASSIVE)
+ woal_set_scan_type(priv, MLAN_SCAN_TYPE_PASSIVE);
+#ifdef REASSOCIATION
+ MOAL_REL_SEMAPHORE(&handle->reassoc_sem);
+#endif
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Get current essid
+ *
+ * @param dev A pointer to net_device structure
+ * @param info A pointer to iw_request_info structure
+ * @param dwrq A pointer to iw_point structure
+ * @param extra A pointer to extra data buf
+ *
+ * @return 0--success, otherwise fail
+ */
+static int
+woal_get_essid(struct net_device *dev, struct iw_request_info *info,
+ struct iw_point *dwrq, char *extra)
+{
+ moal_private *priv = (moal_private *) netdev_priv(dev);
+ mlan_bss_info bss_info;
+ int ret = 0;
+
+ ENTER();
+
+ memset(&bss_info, 0, sizeof(bss_info));
+
+ if (MLAN_STATUS_SUCCESS !=
+ woal_get_bss_info(priv, MOAL_IOCTL_WAIT, &bss_info)) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ if (bss_info.media_connected) {
+ dwrq->length = MIN(dwrq->length, bss_info.ssid.ssid_len);
+ memcpy(extra, bss_info.ssid.ssid, dwrq->length);
+ } else
+ dwrq->length = 0;
+
+ if (bss_info.scan_table_idx)
+ dwrq->flags = (bss_info.scan_table_idx + 1) & IW_ENCODE_INDEX;
+ else
+ dwrq->flags = 1;
+
+ done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Retrieve the scan table entries via wireless tools IOCTL call
+ *
+ * @param dev A pointer to net_device structure
+ * @param info A pointer to iw_request_info structure
+ * @param dwrq A pointer to iw_point structure
+ * @param extra A pointer to extra data buf
+ *
+ * @return 0--success, otherwise fail
+ */
+static int
+woal_get_scan(struct net_device *dev, struct iw_request_info *info,
+ struct iw_point *dwrq, char *extra)
+{
+ moal_private *priv = (moal_private *) netdev_priv(dev);
+ int ret = 0;
+ char *current_ev = extra;
+ char *end_buf = extra + IW_SCAN_MAX_DATA;
+ char *current_val; /* For rates */
+ struct iw_event iwe; /* Temporary buffer */
+ unsigned int i;
+ unsigned int j;
+ mlan_scan_resp scan_resp;
+ mlan_bss_info bss_info;
+ BSSDescriptor_t *scan_table;
+ mlan_ds_get_signal rssi;
+ t_u16 buf_size = 16 + 256 * 2;
+ char *buf = NULL;
+ char *ptr;
+#if WIRELESS_EXT >= 18
+ t_u8 *praw_data;
+#endif
+ int beacon_size;
+ t_u8 *pbeacon;
+ IEEEtypes_ElementId_e element_id;
+ t_u8 element_len;
+
+ ENTER();
+
+ if (priv->phandle->scan_pending_on_block == MTRUE) {
+ LEAVE();
+ return -EAGAIN;
+ }
+
+ if (!(buf = kmalloc((buf_size), GFP_KERNEL))) {
+ PRINTM(MERROR, "Cannot allocate buffer!\n");
+ ret = -EFAULT;
+ goto done;
+ }
+
+ memset(&bss_info, 0, sizeof(bss_info));
+ if (MLAN_STATUS_SUCCESS !=
+ woal_get_bss_info(priv, MOAL_IOCTL_WAIT, &bss_info)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ memset(&scan_resp, 0, sizeof(scan_resp));
+ if (MLAN_STATUS_SUCCESS != woal_get_scan_table(priv,
+ MOAL_IOCTL_WAIT,
+ &scan_resp)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ scan_table = (BSSDescriptor_t *) scan_resp.pscan_table;
+ if (dwrq->length)
+ end_buf = extra + dwrq->length;
+ if (priv->media_connected == MTRUE) {
+ PRINTM(MINFO, "Current Ssid: %-32s\n", bss_info.ssid.ssid);
+ }
+ PRINTM(MINFO, "Scan: Get: NumInScanTable = %d\n",
+ (int) scan_resp.num_in_scan_table);
+
+#if WIRELESS_EXT > 13
+ /* The old API using SIOCGIWAPLIST had a hard limit of IW_MAX_AP. The new
+ API using SIOCGIWSCAN is only limited by buffer size WE-14 -> WE-16 the
+ buffer is limited to IW_SCAN_MAX_DATA bytes which is 4096. */
+ for (i = 0; i < scan_resp.num_in_scan_table; i++) {
+ if ((current_ev + MAX_SCAN_CELL_SIZE) >= end_buf) {
+ PRINTM(MINFO, "i=%d break out: current_ev=%p end_buf=%p "
+ "MAX_SCAN_CELL_SIZE=%d\n",
+ i, current_ev, end_buf, (t_u32) MAX_SCAN_CELL_SIZE);
+ ret = -E2BIG;
+ break;
+ }
+ if (!scan_table[i].freq) {
+ PRINTM(MERROR, "Invalid channel number %d\n",
+ (int) scan_table[i].channel);
+ continue;
+ }
+ PRINTM(MINFO, "i=%d Ssid: %-32s\n", i, scan_table[i].ssid.ssid);
+
+ /* check ssid is valid or not, ex. hidden ssid will be filter out */
+ if (woal_ssid_valid(&scan_table[i].ssid) == MFALSE) {
+ continue;
+ }
+
+ /* First entry *MUST* be the AP MAC address */
+ iwe.cmd = SIOCGIWAP;
+ iwe.u.ap_addr.sa_family = ARPHRD_ETHER;
+ memcpy(iwe.u.ap_addr.sa_data, &scan_table[i].mac_address, ETH_ALEN);
+
+ iwe.len = IW_EV_ADDR_LEN;
+ current_ev =
+ IWE_STREAM_ADD_EVENT(info, current_ev, end_buf, &iwe, iwe.len);
+
+ /* Add the ESSID */
+ iwe.u.data.length = scan_table[i].ssid.ssid_len;
+
+ if (iwe.u.data.length > 32) {
+ iwe.u.data.length = 32;
+ }
+
+ iwe.cmd = SIOCGIWESSID;
+ iwe.u.essid.flags = (i + 1) & IW_ENCODE_INDEX;
+ iwe.len = IW_EV_POINT_LEN + iwe.u.data.length;
+ current_ev =
+ IWE_STREAM_ADD_POINT(info, current_ev, end_buf, &iwe,
+ (t_s8 *) scan_table[i].ssid.ssid);
+
+ /* Add mode */
+ iwe.cmd = SIOCGIWMODE;
+ if (scan_table[i].bss_mode == MLAN_BSS_MODE_IBSS)
+ iwe.u.mode = IW_MODE_ADHOC;
+ else if (scan_table[i].bss_mode == MLAN_BSS_MODE_INFRA)
+ iwe.u.mode = IW_MODE_MASTER;
+ else
+ iwe.u.mode = IW_MODE_AUTO;
+
+ iwe.len = IW_EV_UINT_LEN;
+ current_ev =
+ IWE_STREAM_ADD_EVENT(info, current_ev, end_buf, &iwe, iwe.len);
+
+ /* Frequency */
+ iwe.cmd = SIOCGIWFREQ;
+ iwe.u.freq.m = (long) scan_table[i].freq * 100000;
+ iwe.u.freq.e = 1;
+ iwe.u.freq.flags = IW_FREQ_FIXED;
+ iwe.len = IW_EV_FREQ_LEN;
+ current_ev =
+ IWE_STREAM_ADD_EVENT(info, current_ev, end_buf, &iwe, iwe.len);
+
+ memset(&iwe, 0, sizeof(iwe));
+ /* Add quality statistics */
+ iwe.cmd = IWEVQUAL;
+ iwe.u.qual.level = SCAN_RSSI(scan_table[i].rssi);
+ if (!bss_info.bcn_nf_last) {
+ iwe.u.qual.noise = MRVDRV_NF_DEFAULT_SCAN_VALUE;
+ } else {
+ iwe.u.qual.noise = bss_info.bcn_nf_last;
+ }
+ if ((bss_info.bss_mode == MLAN_BSS_MODE_IBSS) &&
+ !woal_ssid_cmp(&bss_info.ssid, &scan_table[i].ssid)
+ && bss_info.adhoc_state == ADHOC_STARTED) {
+ memset(&rssi, 0, sizeof(mlan_ds_get_signal));
+ if (MLAN_STATUS_SUCCESS !=
+ woal_get_signal_info(priv, MOAL_IOCTL_WAIT, &rssi)) {
+ ret = -EFAULT;
+ break;
+ }
+ iwe.u.qual.level = rssi.data_rssi_avg;
+ }
+ iwe.u.qual.qual =
+ woal_rssi_to_quality((t_s16) (iwe.u.qual.level - 0x100));
+ iwe.len = IW_EV_QUAL_LEN;
+ current_ev =
+ IWE_STREAM_ADD_EVENT(info, current_ev, end_buf, &iwe, iwe.len);
+
+ /* Add encryption capability */
+ iwe.cmd = SIOCGIWENCODE;
+ if (scan_table[i].privacy) {
+ iwe.u.data.flags = IW_ENCODE_ENABLED | IW_ENCODE_NOKEY;
+ } else {
+ iwe.u.data.flags = IW_ENCODE_DISABLED;
+ }
+ iwe.u.data.length = 0;
+ iwe.len = IW_EV_POINT_LEN + iwe.u.data.length;
+ current_ev =
+ IWE_STREAM_ADD_POINT(info, current_ev, end_buf, &iwe, NULL);
+
+ current_val = current_ev + IW_EV_LCP_LEN;
+
+ iwe.cmd = SIOCGIWRATE;
+
+ iwe.u.bitrate.fixed = 0;
+ iwe.u.bitrate.disabled = 0;
+ iwe.u.bitrate.value = 0;
+
+ /* Bit rate given in 500 kb/s units (+ 0x80) */
+ for (j = 0; j < sizeof(scan_table[i].supported_rates); j++) {
+ if (!scan_table[i].supported_rates[j]) {
+ break;
+ }
+
+ iwe.u.bitrate.value =
+ (scan_table[i].supported_rates[j] & 0x7f) * 500000;
+ iwe.len = IW_EV_PARAM_LEN;
+ current_val =
+ IWE_STREAM_ADD_VALUE(info, current_ev, current_val, end_buf,
+ &iwe, iwe.len);
+
+ }
+ if ((bss_info.bss_mode == MLAN_BSS_MODE_IBSS) &&
+ !woal_ssid_cmp(&bss_info.ssid, &scan_table[i].ssid)
+ && bss_info.adhoc_state == ADHOC_STARTED) {
+ iwe.u.bitrate.value = 22 * 500000;
+ iwe.len = IW_EV_PARAM_LEN;
+ current_val =
+ IWE_STREAM_ADD_VALUE(info, current_ev, current_val, end_buf,
+ &iwe, iwe.len);
+ }
+
+ /* Check if an event is added */
+ if ((unsigned int) (current_val - current_ev) >= IW_EV_PARAM_LEN)
+ current_ev = current_val;
+
+ /* Beacon Interval */
+ memset(&iwe, 0, sizeof(iwe));
+ memset(buf, 0, buf_size);
+ ptr = buf;
+ ptr += sprintf(ptr, "Beacon interval=%d", scan_table[i].beacon_period);
+
+ iwe.u.data.length = strlen(buf);
+ iwe.cmd = IWEVCUSTOM;
+ iwe.len = IW_EV_POINT_LEN + iwe.u.data.length;
+ current_ev = IWE_STREAM_ADD_POINT(info, current_ev, end_buf, &iwe, buf);
+ current_val = current_ev + IW_EV_LCP_LEN + strlen(buf);
+
+ /* Parse and send the IEs */
+ pbeacon = scan_table[i].pbeacon_buf;
+ beacon_size = scan_table[i].beacon_buf_size;
+
+ /* Skip time stamp, beacon interval and capability */
+ if (pbeacon) {
+ pbeacon += sizeof(scan_table[i].beacon_period) +
+ sizeof(scan_table[i].time_stamp) +
+ sizeof(scan_table[i].cap_info);
+ beacon_size -= sizeof(scan_table[i].beacon_period) +
+ sizeof(scan_table[i].time_stamp) +
+ sizeof(scan_table[i].cap_info);
+
+ while ((unsigned int) beacon_size >= sizeof(IEEEtypes_Header_t)) {
+ element_id = (IEEEtypes_ElementId_e) (*(t_u8 *) pbeacon);
+ element_len = *((t_u8 *) pbeacon + 1);
+ if ((unsigned int) beacon_size <
+ (unsigned int) element_len + sizeof(IEEEtypes_Header_t)) {
+ PRINTM(MERROR,
+ "Get scan: Error in processing IE, "
+ "bytes left < IE length\n");
+ break;
+ }
+
+ switch (element_id) {
+#if WIRELESS_EXT >= 18
+ case VENDOR_SPECIFIC_221:
+ case RSN_IE:
+ case WAPI_IE:
+ praw_data = (t_u8 *) pbeacon;
+ memset(&iwe, 0, sizeof(iwe));
+ memset(buf, 0, buf_size);
+ ptr = buf;
+ memcpy(buf, praw_data,
+ element_len + sizeof(IEEEtypes_Header_t));
+ iwe.cmd = IWEVGENIE;
+ iwe.u.data.length =
+ element_len + sizeof(IEEEtypes_Header_t);
+ iwe.len = IW_EV_POINT_LEN + iwe.u.data.length;
+ current_ev =
+ IWE_STREAM_ADD_POINT(info, current_ev, end_buf, &iwe,
+ buf);
+ current_val = current_ev + IW_EV_LCP_LEN + strlen(buf);
+ break;
+#endif
+ default:
+ break;
+ }
+ pbeacon += element_len + sizeof(IEEEtypes_Header_t);
+ beacon_size -= element_len + sizeof(IEEEtypes_Header_t);
+ }
+ }
+#if WIRELESS_EXT > 14
+ memset(&iwe, 0, sizeof(iwe));
+ memset(buf, 0, buf_size);
+ ptr = buf;
+ ptr += sprintf(ptr, "band=");
+ memset(&iwe, 0, sizeof(iwe));
+ if (scan_table[i].bss_band == BAND_A)
+ ptr += sprintf(ptr, "a");
+ else
+ ptr += sprintf(ptr, "bg");
+ iwe.u.data.length = strlen(buf);
+ PRINTM(MINFO, "iwe.u.data.length %d\n", iwe.u.data.length);
+ PRINTM(MINFO, "BUF: %s \n", buf);
+ iwe.cmd = IWEVCUSTOM;
+ iwe.len = IW_EV_POINT_LEN + iwe.u.data.length;
+ current_ev = IWE_STREAM_ADD_POINT(info, current_ev, end_buf, &iwe, buf);
+ current_val = current_ev + IW_EV_LCP_LEN + strlen(buf);
+#endif
+ current_val = current_ev + IW_EV_LCP_LEN;
+
+ /*
+ * Check if we added any event
+ */
+ if ((unsigned int) (current_val - current_ev) > IW_EV_LCP_LEN)
+ current_ev = current_val;
+ }
+
+ dwrq->length = (current_ev - extra);
+ dwrq->flags = 0;
+#endif
+
+ done:
+ if (buf)
+ kfree(buf);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * iwconfig settable callbacks
+ */
+static const iw_handler woal_handler[] = {
+ (iw_handler) woal_config_commit, /* SIOCSIWCOMMIT */
+ (iw_handler) woal_get_name, /* SIOCGIWNAME */
+ (iw_handler) NULL, /* SIOCSIWNWID */
+ (iw_handler) NULL, /* SIOCGIWNWID */
+ (iw_handler) woal_set_freq, /* SIOCSIWFREQ */
+ (iw_handler) woal_get_freq, /* SIOCGIWFREQ */
+ (iw_handler) woal_set_bss_mode, /* SIOCSIWMODE */
+ (iw_handler) woal_get_bss_mode, /* SIOCGIWMODE */
+ (iw_handler) woal_set_sens, /* SIOCSIWSENS */
+ (iw_handler) woal_get_sens, /* SIOCGIWSENS */
+ (iw_handler) NULL, /* SIOCSIWRANGE */
+ (iw_handler) woal_get_range, /* SIOCGIWRANGE */
+ (iw_handler) woal_set_priv, /* SIOCSIWPRIV */
+ (iw_handler) NULL, /* SIOCGIWPRIV */
+ (iw_handler) NULL, /* SIOCSIWSTATS */
+ (iw_handler) NULL, /* SIOCGIWSTATS */
+#if WIRELESS_EXT > 15
+ iw_handler_set_spy, /* SIOCSIWSPY */
+ iw_handler_get_spy, /* SIOCGIWSPY */
+ iw_handler_set_thrspy, /* SIOCSIWTHRSPY */
+ iw_handler_get_thrspy, /* SIOCGIWTHRSPY */
+#else /* WIRELESS_EXT > 15 */
+#ifdef WIRELESS_SPY
+ (iw_handler) NULL, /* SIOCSIWSPY */
+ (iw_handler) NULL, /* SIOCGIWSPY */
+#else /* WIRELESS_SPY */
+ (iw_handler) NULL, /* SIOCSIWSPY */
+ (iw_handler) NULL, /* SIOCGIWSPY */
+#endif /* WIRELESS_SPY */
+ (iw_handler) NULL, /* -- hole -- */
+ (iw_handler) NULL, /* -- hole -- */
+#endif /* WIRELESS_EXT > 15 */
+ (iw_handler) woal_set_wap, /* SIOCSIWAP */
+ (iw_handler) woal_get_wap, /* SIOCGIWAP */
+#if WIRELESS_EXT >= 18
+ (iw_handler) woal_set_mlme, /* SIOCSIWMLME */
+#else
+ (iw_handler) NULL, /* -- hole -- */
+#endif
+ /* (iw_handler) wlan_get_aplist, *//* SIOCGIWAPLIST */
+ NULL, /* SIOCGIWAPLIST */
+#if WIRELESS_EXT > 13
+ (iw_handler) woal_set_scan, /* SIOCSIWSCAN */
+ (iw_handler) woal_get_scan, /* SIOCGIWSCAN */
+#else /* WIRELESS_EXT > 13 */
+ (iw_handler) NULL, /* SIOCSIWSCAN */
+ (iw_handler) NULL, /* SIOCGIWSCAN */
+#endif /* WIRELESS_EXT > 13 */
+ (iw_handler) woal_set_essid, /* SIOCSIWESSID */
+ (iw_handler) woal_get_essid, /* SIOCGIWESSID */
+ (iw_handler) woal_set_nick, /* SIOCSIWNICKN */
+ (iw_handler) woal_get_nick, /* SIOCGIWNICKN */
+ (iw_handler) NULL, /* -- hole -- */
+ (iw_handler) NULL, /* -- hole -- */
+ (iw_handler) woal_set_rate, /* SIOCSIWRATE */
+ (iw_handler) woal_get_rate, /* SIOCGIWRATE */
+ (iw_handler) woal_set_rts, /* SIOCSIWRTS */
+ (iw_handler) woal_get_rts, /* SIOCGIWRTS */
+ (iw_handler) woal_set_frag, /* SIOCSIWFRAG */
+ (iw_handler) woal_get_frag, /* SIOCGIWFRAG */
+ (iw_handler) woal_set_txpow, /* SIOCSIWTXPOW */
+ (iw_handler) woal_get_txpow, /* SIOCGIWTXPOW */
+ (iw_handler) woal_set_retry, /* SIOCSIWRETRY */
+ (iw_handler) woal_get_retry, /* SIOCGIWRETRY */
+ (iw_handler) woal_set_encode, /* SIOCSIWENCODE */
+ (iw_handler) woal_get_encode, /* SIOCGIWENCODE */
+ (iw_handler) woal_set_power, /* SIOCSIWPOWER */
+ (iw_handler) woal_get_power, /* SIOCGIWPOWER */
+#if (WIRELESS_EXT >= 18)
+ (iw_handler) NULL, /* -- hole -- */
+ (iw_handler) NULL, /* -- hole -- */
+ (iw_handler) woal_set_gen_ie, /* SIOCSIWGENIE */
+ (iw_handler) woal_get_gen_ie, /* SIOCGIWGENIE */
+ (iw_handler) woal_set_auth, /* SIOCSIWAUTH */
+ (iw_handler) woal_get_auth, /* SIOCGIWAUTH */
+ (iw_handler) woal_set_encode_ext, /* SIOCSIWENCODEEXT */
+ (iw_handler) woal_get_encode_ext, /* SIOCGIWENCODEEXT */
+ (iw_handler) woal_set_pmksa, /* SIOCSIWPMKSA */
+#endif /* WIRELESSS_EXT >= 18 */
+};
+
+/**
+ * iwpriv settable callbacks
+ */
+static const iw_handler woal_private_handler[] = {
+ NULL, /* SIOCIWFIRSTPRIV */
+};
+#endif /* STA_SUPPORT */
+
+/********************************************************
+ Global Functions
+********************************************************/
+
+#if WIRELESS_EXT > 14
+
+/**
+ * @brief This function sends customized event to application.
+ *
+ * @param priv A pointer to moal_private structure
+ * @param str A pointer to event string
+ *
+ * @return N/A
+ */
+void
+woal_send_iwevcustom_event(moal_private * priv, t_s8 * str)
+{
+ union iwreq_data iwrq;
+ char buf[IW_CUSTOM_MAX];
+
+ ENTER();
+
+ memset(&iwrq, 0, sizeof(union iwreq_data));
+ memset(buf, 0, sizeof(buf));
+
+ snprintf(buf, sizeof(buf) - 1, "%s", str);
+
+ iwrq.data.pointer = buf;
+ iwrq.data.length = strlen(buf) + 1;
+
+ /* Send Event to upper layer */
+ wireless_send_event(priv->netdev, IWEVCUSTOM, &iwrq, buf);
+ PRINTM(MINFO, "Wireless event %s is sent to application\n", str);
+
+ LEAVE();
+ return;
+}
+#endif
+
+#if WIRELESS_EXT >= 18
+/**
+ * @brief This function sends mic error event to application.
+ *
+ * @param priv A pointer to moal_private structure
+ * @param event MIC MERROR EVENT.
+ *
+ * @return N/A
+ */
+void
+woal_send_mic_error_event(moal_private * priv, t_u32 event)
+{
+ union iwreq_data iwrq;
+ struct iw_michaelmicfailure mic;
+
+ ENTER();
+
+ memset(&iwrq, 0, sizeof(iwrq));
+ memset(&mic, 0, sizeof(mic));
+ if (event == MLAN_EVENT_ID_FW_MIC_ERR_UNI)
+ mic.flags = IW_MICFAILURE_PAIRWISE;
+ else
+ mic.flags = IW_MICFAILURE_GROUP;
+ iwrq.data.pointer = &mic;
+ iwrq.data.length = sizeof(mic);
+
+ wireless_send_event(priv->netdev, IWEVMICHAELMICFAILURE, &iwrq,
+ (char *) &mic);
+
+ LEAVE();
+ return;
+}
+#endif
+
+#ifdef STA_SUPPORT
+/**
+ * @brief Set Radio On/OFF
+ *
+ * @param priv A pointer to moal_private structure
+ * @param option Radio Option
+ *
+ * @return 0 --success, otherwise fail
+ */
+int
+woal_set_radio(moal_private * priv, t_u8 option)
+{
+ int ret = 0;
+ mlan_ds_radio_cfg *radio = NULL;
+ mlan_ioctl_req *req = NULL;
+ ENTER();
+ if ((option != 0) && (option != 1)) {
+ ret = -EINVAL;
+ goto done;
+ }
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_radio_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+ radio = (mlan_ds_radio_cfg *) req->pbuf;
+ radio->sub_command = MLAN_OID_RADIO_CTRL;
+ req->req_id = MLAN_IOCTL_RADIO_CFG;
+ req->action = MLAN_ACT_SET;
+ radio->param.radio_on_off = option;
+ if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ done:
+ if (req)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/** wlan_handler_def */
+struct iw_handler_def woal_handler_def = {
+ num_standard:sizeof(woal_handler) / sizeof(iw_handler),
+ num_private:sizeof(woal_private_handler) / sizeof(iw_handler),
+ num_private_args:sizeof(woal_private_args) / sizeof(struct iw_priv_args),
+ standard:(iw_handler *) woal_handler,
+ private:(iw_handler *) woal_private_handler,
+ private_args:(struct iw_priv_args *) woal_private_args,
+#if WIRELESS_EXT > 20
+ get_wireless_stats:woal_get_wireless_stats,
+#endif
+};
+
+/**
+ * @brief Get wireless statistics
+ *
+ * @param dev A pointer to net_device structure
+ *
+ * @return A pointer to iw_statistics buf
+ */
+struct iw_statistics *
+woal_get_wireless_stats(struct net_device *dev)
+{
+ moal_private *priv = (moal_private *) netdev_priv(dev);
+ t_u16 wait_option = MOAL_NO_WAIT;
+
+ ENTER();
+
+ /*
+ * Since schedule() is not allowed from an atomic context
+ * such as when dev_base_lock for netdevices is acquired
+ * for reading/writing in kernel before this call, HostCmd
+ * is issued in non-blocking way in such contexts and
+ * blocking in other cases.
+ */
+ if (write_can_lock(&dev_base_lock)
+ && (!in_atomic() || current->exit_state))
+ wait_option = MOAL_WSTATS_WAIT;
+
+ priv->w_stats.status = woal_get_mode(priv, wait_option);
+ priv->w_stats.discard.retries = priv->stats.tx_errors;
+ priv->w_stats.qual.qual = 0;
+
+ /* Send RSSI command to get beacon RSSI/NF, valid only if associated */
+ if (priv->media_connected == MTRUE) {
+ woal_get_signal_info(priv, wait_option, NULL);
+ priv->w_stats.qual.qual = woal_rssi_to_quality((t_s16)
+ (priv->w_stats.qual.
+ level - 0x100));
+ }
+#if WIRELESS_EXT > 18
+ priv->w_stats.qual.updated |= (IW_QUAL_ALL_UPDATED | IW_QUAL_DBM);
+#else
+ priv->w_stats.qual.updated |= 7;
+#endif
+ if (!priv->w_stats.qual.noise && priv->media_connected == MTRUE)
+ priv->w_stats.qual.noise = MRVDRV_NF_DEFAULT_SCAN_VALUE;
+
+ PRINTM(MINFO, "Link Quality = %#x\n", priv->w_stats.qual.qual);
+ PRINTM(MINFO, "Signal Level = %#x\n", priv->w_stats.qual.level);
+ PRINTM(MINFO, "Noise = %#x\n", priv->w_stats.qual.noise);
+ priv->w_stats.discard.code = 0;
+ woal_get_stats_info(priv, wait_option, NULL);
+
+ LEAVE();
+ return &priv->w_stats;
+}
+#endif /* STA_SUPPORT */
diff --git a/drivers/net/wireless/sd8797/mlinux/moal_wext.h b/drivers/net/wireless/sd8797/mlinux/moal_wext.h
new file mode 100644
index 000000000000..91f918e1b130
--- /dev/null
+++ b/drivers/net/wireless/sd8797/mlinux/moal_wext.h
@@ -0,0 +1,116 @@
+/** @file moal_wext.h
+ *
+ * @brief This file contains definition for wireless extension IOCTL call.
+ *
+ * Copyright (C) 2008-2011, Marvell International Ltd.
+ *
+ * This software file (the "File") is distributed by Marvell International
+ * Ltd. under the terms of the GNU General Public License Version 2, June 1991
+ * (the "License"). You may use, redistribute and/or modify this File in
+ * accordance with the terms and conditions of the License, a copy of which
+ * is available by writing to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
+ * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
+ *
+ * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
+ * ARE EXPRESSLY DISCLAIMED. The License provides additional details about
+ * this warranty disclaimer.
+ *
+ */
+
+/********************************************************
+Change log:
+ 10/21/2008: initial version
+********************************************************/
+
+#ifndef _WOAL_WEXT_H_
+#define _WOAL_WEXT_H_
+
+/** Custom event : AdHoc link sensed */
+#define CUS_EVT_ADHOC_LINK_SENSED "EVENT=ADHOC_LINK_SENSED"
+/** Custom event : AdHoc link lost */
+#define CUS_EVT_ADHOC_LINK_LOST "EVENT=ADHOC_LINK_LOST"
+/** Custom event : MIC failure, unicast */
+#define CUS_EVT_MLME_MIC_ERR_UNI "MLME-MICHAELMICFAILURE.indication unicast "
+/** Custom event : MIC failure, multicast */
+#define CUS_EVT_MLME_MIC_ERR_MUL "MLME-MICHAELMICFAILURE.indication multicast "
+/** Custom event : Beacon RSSI low */
+#define CUS_EVT_BEACON_RSSI_LOW "EVENT=BEACON_RSSI_LOW"
+/** Custom event : Beacon SNR low */
+#define CUS_EVT_BEACON_SNR_LOW "EVENT=BEACON_SNR_LOW"
+/** Custom event : Beacon RSSI high */
+#define CUS_EVT_BEACON_RSSI_HIGH "EVENT=BEACON_RSSI_HIGH"
+/** Custom event : Beacon SNR high */
+#define CUS_EVT_BEACON_SNR_HIGH "EVENT=BEACON_SNR_HIGH"
+/** Custom event : Max fail */
+#define CUS_EVT_MAX_FAIL "EVENT=MAX_FAIL"
+#define CUS_EVT_BG_SCAN "EVENT=BG_SCAN_REPORT"
+/** Custom event : Data RSSI low */
+#define CUS_EVT_DATA_RSSI_LOW "EVENT=DATA_RSSI_LOW"
+/** Custom event : Data SNR low */
+#define CUS_EVT_DATA_SNR_LOW "EVENT=DATA_SNR_LOW"
+/** Custom event : Data RSSI high */
+#define CUS_EVT_DATA_RSSI_HIGH "EVENT=DATA_RSSI_HIGH"
+/** Custom event : Data SNR high */
+#define CUS_EVT_DATA_SNR_HIGH "EVENT=DATA_SNR_HIGH"
+/** Custom event : Link Quality */
+#define CUS_EVT_LINK_QUALITY "EVENT=LINK_QUALITY"
+/** Custom event : Port Release */
+#define CUS_EVT_PORT_RELEASE "EVENT=PORT_RELEASE"
+/** Custom event : Pre-Beacon Lost */
+#define CUS_EVT_PRE_BEACON_LOST "EVENT=PRE_BEACON_LOST"
+
+/** Custom event : Deep Sleep awake */
+#define CUS_EVT_DEEP_SLEEP_AWAKE "EVENT=DS_AWAKE"
+
+/** Custom event : Host Sleep activated */
+#define CUS_EVT_HS_ACTIVATED "HS_ACTIVATED "
+/** Custom event : Host Sleep deactivated */
+#define CUS_EVT_HS_DEACTIVATED "HS_DEACTIVATED "
+/** Custom event : Host Sleep wakeup */
+#define CUS_EVT_HS_WAKEUP "HS_WAKEUP"
+
+/** Custom event : WEP ICV error */
+#define CUS_EVT_WEP_ICV_ERR "EVENT=WEP_ICV_ERR"
+
+/** Custom event : Channel Switch Announcment */
+#define CUS_EVT_CHANNEL_SWITCH_ANN "EVENT=CHANNEL_SWITCH_ANN"
+
+/** Custom event : BW changed */
+#define CUS_EVT_BW_CHANGED "EVENT=BW_CHANGED"
+/** Custom event : OBSS scan parameter */
+#define CUS_EVT_OBSS_SCAN_PARAM "EVENT=OBSS_SCAN_PARAM"
+/** Custom indiciation message sent to the application layer for WMM changes */
+#define WMM_CONFIG_CHANGE_INDICATION "WMM_CONFIG_CHANGE.indication"
+
+#ifdef UAP_SUPPORT
+#ifdef UAP_WEXT
+/** Custom event : STA connected */
+#define CUS_EVT_STA_CONNECTED "EVENT=STA_CONNECTED"
+/** Custom event : STA disconnected */
+#define CUS_EVT_STA_DISCONNECTED "EVENT=STA_DISCONNECTED"
+#endif
+#endif
+/** NF value for default scan */
+#define MRVDRV_NF_DEFAULT_SCAN_VALUE (-96)
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,26)
+/** Add event */
+#define IWE_STREAM_ADD_EVENT(i, c, e, w, l) iwe_stream_add_event((i), (c), (e), (w), (l))
+/** Add point */
+#define IWE_STREAM_ADD_POINT(i, c, e, w, p) iwe_stream_add_point((i), (c), (e), (w), (p))
+/** Add value */
+#define IWE_STREAM_ADD_VALUE(i, c, v, e, w, l) iwe_stream_add_value((i), (c), (v), (e), (w), (l))
+#else
+/** Add event */
+#define IWE_STREAM_ADD_EVENT(i, c, e, w, l) iwe_stream_add_event((c), (e), (w), (l))
+/** Add point */
+#define IWE_STREAM_ADD_POINT(i, c, e, w, p) iwe_stream_add_point((c), (e), (w), (p))
+/** Add value */
+#define IWE_STREAM_ADD_VALUE(i, c, v, e, w, l) iwe_stream_add_value((c), (v), (e), (w), (l))
+#endif
+
+extern struct iw_handler_def woal_handler_def;
+struct iw_statistics *woal_get_wireless_stats(struct net_device *dev);
+#endif /* _WOAL_WEXT_H_ */