From 33d9f8e4f3805144e74af0ec4e680d1a4b61b0bb Mon Sep 17 00:00:00 2001 From: Fugang Duan Date: Mon, 20 Apr 2020 00:54:27 +0800 Subject: [PATCH] mxm_wifiex: add nxp mxm_wifiex sdk Add initial MxM (multi-chip-multi-interface) wifi driver. The driver target is to support 88w8987/88w8997/88w9098, currently it only supports 88w8987. The MxM wifi driver is merged from below repo and applied some patches for block and build issues. ssh://git@bitbucket.sw.nxp.com/wcswrel/ rel-nxp-wifi-fp92-bt-fp85-linux-android-mxm4x17169-gpl.git The sdk only includes application, the driver already is merged into linux kernel. Signed-off-by: Fugang Duan --- mxm_wifiex/wlan_src/Makefile | 558 + mxm_wifiex/wlan_src/README | 1125 + mxm_wifiex/wlan_src/README_MLAN | 3972 +++ mxm_wifiex/wlan_src/gpl-2.0.txt | 339 + .../wlan_src/mapp/mlan2040coex/Makefile | 48 + .../wlan_src/mapp/mlan2040coex/mlan2040coex.c | 1387 ++ .../wlan_src/mapp/mlan2040coex/mlan2040coex.h | 239 + .../wlan_src/mapp/mlan2040coex/mlan2040misc.c | 286 + .../wlan_src/mapp/mlan2040coex/mlan2040misc.h | 449 + mxm_wifiex/wlan_src/mapp/mlanconfig/Makefile | 48 + .../mapp/mlanconfig/config/11axcfg.conf | 49 + .../mapp/mlanconfig/config/11n_2040coex.conf | 21 + .../mapp/mlanconfig/config/auto_tx.conf | 54 + .../mlanconfig/config/band_steer_cfg.conf | 16 + .../mapp/mlanconfig/config/bg_scan.conf | 157 + .../mlanconfig/config/bg_scan_wifidirect.conf | 88 + .../mapp/mlanconfig/config/crypto_test.conf | 58 + .../mapp/mlanconfig/config/cwmode.conf | 51 + .../mapp/mlanconfig/config/debug.conf | 89 + .../config/ed_mac_ctrl_V2_8887.conf | 29 + .../config/ed_mac_ctrl_V2_8897.conf | 29 + .../config/ed_mac_ctrl_V3_8977.conf | 23 + .../config/ed_mac_ctrl_V3_8978.conf | 23 + .../config/ed_mac_ctrl_V3_8987.conf | 23 + .../config/ed_mac_ctrl_V3_8997.conf | 23 + .../config/ed_mac_ctrl_V3_909x.conf | 23 + .../mapp/mlanconfig/config/init_cfg.conf | 14 + .../wlan_src/mapp/mlanconfig/config/mef.conf | 167 + .../mapp/mlanconfig/config/mef_mdns.conf | 204 + .../mlanconfig/config/mef_ws_discovery.conf | 204 + .../wlan_src/mapp/mlanconfig/config/mem.conf | 17 + .../mapp/mlanconfig/config/mgmt_frame.conf | 30 + .../mapp/mlanconfig/config/mgmtfilter.conf | 15 + .../mapp/mlanconfig/config/or_data.conf | 7 + .../mapp/mlanconfig/config/pad_cfg.conf | 29 + .../mapp/mlanconfig/config/requesttpc.conf | 15 + .../mapp/mlanconfig/config/robust_btc.conf | 211 + .../mlanconfig/config/rutxpower_limit.conf | 674 + .../mapp/mlanconfig/config/sdio_pulldown.conf | 27 + .../mapp/mlanconfig/config/small_debug.conf | 62 + .../wlan_src/mapp/mlanconfig/config/smc.conf | 124 + .../wlan_src/mapp/mlanconfig/config/ssu.conf | 13 + .../mapp/mlanconfig/config/subevent.conf | 103 + .../mapp/mlanconfig/config/tspecs.conf | 100 + .../mapp/mlanconfig/config/turbo_mode.conf | 12 + .../mapp/mlanconfig/config/tx_ctrl.conf | 58 + .../mlanconfig/config/txpwrlimit_cfg.conf | 617 + .../mapp/mlanconfig/config/txrate_cfg.conf | 172 + .../mapp/mlanconfig/config/wifi_mod_para.conf | 179 + .../wlan_src/mapp/mlanconfig/mlanconfig.c | 2970 +++ .../wlan_src/mapp/mlanconfig/mlanconfig.h | 254 + .../wlan_src/mapp/mlanconfig/mlanhostcmd.c | 928 + .../wlan_src/mapp/mlanconfig/mlanhostcmd.h | 390 + .../wlan_src/mapp/mlanconfig/mlanmisc.c | 1167 + .../wlan_src/mapp/mlanconfig/mlanmisc.h | 710 + mxm_wifiex/wlan_src/mapp/mlanevent/Makefile | 52 + .../wlan_src/mapp/mlanevent/mlanevent.c | 2572 ++ .../wlan_src/mapp/mlanevent/mlanevent.h | 1269 + mxm_wifiex/wlan_src/mapp/mlanutl/Makefile | 55 + .../wlan_src/mapp/mlanutl/mlanhostcmd.c | 900 + .../wlan_src/mapp/mlanutl/mlanhostcmd.h | 139 + .../wlan_src/mapp/mlanutl/mlanoffload.c | 3056 +++ .../wlan_src/mapp/mlanutl/mlanoffload.h | 519 + .../wlan_src/mapp/mlanutl/mlanregclass.c | 545 + .../wlan_src/mapp/mlanutl/mlanregclass.h | 105 + .../wlan_src/mapp/mlanutl/mlanroamagent.c | 3675 +++ .../wlan_src/mapp/mlanutl/mlanroamagent.h | 320 + .../wlan_src/mapp/mlanutl/mlanscanagent.c | 848 + .../wlan_src/mapp/mlanutl/mlanscanagent.h | 155 + mxm_wifiex/wlan_src/mapp/mlanutl/mlanutl.c | 20430 ++++++++++++++++ mxm_wifiex/wlan_src/mapp/mlanutl/mlanutl.h | 2891 +++ mxm_wifiex/wlan_src/mapp/mlanutl/timestamp.c | 420 + mxm_wifiex/wlan_src/mapp/mlanutl/timestamp.h | 60 + mxm_wifiex/wlan_src/mapp/uaputl/Makefile | 54 + .../mapp/uaputl/config/80211d_domain.conf | 45 + .../mapp/uaputl/config/embedded_dhcp.conf | 9 + .../config/sample_cal_data_bg_8688.conf | 42 + .../wlan_src/mapp/uaputl/config/uapcoex.conf | 22 + .../wlan_src/mapp/uaputl/config/uaputl.conf | 151 + .../mapp/uaputl/config/uaputl_wifidirect.conf | 80 + mxm_wifiex/wlan_src/mapp/uaputl/uapcmd.c | 7563 ++++++ mxm_wifiex/wlan_src/mapp/uaputl/uapcmd.h | 86 + mxm_wifiex/wlan_src/mapp/uaputl/uaphostcmd.c | 343 + mxm_wifiex/wlan_src/mapp/uaputl/uaputl.c | 14536 +++++++++++ mxm_wifiex/wlan_src/mapp/uaputl/uaputl.h | 2671 ++ .../wlan_src/mapp/wifidirectutl/Makefile | 57 + .../mapp/wifidirectutl/config/wifidirect.conf | 415 + .../mapp/wifidirectutl/wifidirectutl.c | 8338 +++++++ .../mapp/wifidirectutl/wifidirectutl.h | 1408 ++ mxm_wifiex/wlan_src/script/load | 16 + mxm_wifiex/wlan_src/script/unload | 20 + mxm_wifiex/wlan_src/script/usbconfig | Bin 0 -> 9098 bytes .../script/wifidirect/start_auto_go.sh | 30 + .../script/wifidirect/start_find_phase.sh | 25 + .../script/wifidirect/start_listen_state.sh | 18 + .../script/wifidirect/stop_auto_go.sh | 8 + .../wifidirect/stop_wifidirect_client.sh | 6 + .../wlan_src/script/wifidirect/update_mac.sh | 16 + 98 files changed, 92650 insertions(+) create mode 100644 mxm_wifiex/wlan_src/Makefile create mode 100644 mxm_wifiex/wlan_src/README create mode 100644 mxm_wifiex/wlan_src/README_MLAN create mode 100644 mxm_wifiex/wlan_src/gpl-2.0.txt create mode 100644 mxm_wifiex/wlan_src/mapp/mlan2040coex/Makefile create mode 100644 mxm_wifiex/wlan_src/mapp/mlan2040coex/mlan2040coex.c create mode 100644 mxm_wifiex/wlan_src/mapp/mlan2040coex/mlan2040coex.h create mode 100644 mxm_wifiex/wlan_src/mapp/mlan2040coex/mlan2040misc.c create mode 100644 mxm_wifiex/wlan_src/mapp/mlan2040coex/mlan2040misc.h create mode 100644 mxm_wifiex/wlan_src/mapp/mlanconfig/Makefile create mode 100644 mxm_wifiex/wlan_src/mapp/mlanconfig/config/11axcfg.conf create mode 100644 mxm_wifiex/wlan_src/mapp/mlanconfig/config/11n_2040coex.conf create mode 100644 mxm_wifiex/wlan_src/mapp/mlanconfig/config/auto_tx.conf create mode 100644 mxm_wifiex/wlan_src/mapp/mlanconfig/config/band_steer_cfg.conf create mode 100644 mxm_wifiex/wlan_src/mapp/mlanconfig/config/bg_scan.conf create mode 100644 mxm_wifiex/wlan_src/mapp/mlanconfig/config/bg_scan_wifidirect.conf create mode 100644 mxm_wifiex/wlan_src/mapp/mlanconfig/config/crypto_test.conf create mode 100644 mxm_wifiex/wlan_src/mapp/mlanconfig/config/cwmode.conf create mode 100644 mxm_wifiex/wlan_src/mapp/mlanconfig/config/debug.conf create mode 100644 mxm_wifiex/wlan_src/mapp/mlanconfig/config/ed_mac_ctrl_V2_8887.conf create mode 100644 mxm_wifiex/wlan_src/mapp/mlanconfig/config/ed_mac_ctrl_V2_8897.conf create mode 100644 mxm_wifiex/wlan_src/mapp/mlanconfig/config/ed_mac_ctrl_V3_8977.conf create mode 100644 mxm_wifiex/wlan_src/mapp/mlanconfig/config/ed_mac_ctrl_V3_8978.conf create mode 100644 mxm_wifiex/wlan_src/mapp/mlanconfig/config/ed_mac_ctrl_V3_8987.conf create mode 100644 mxm_wifiex/wlan_src/mapp/mlanconfig/config/ed_mac_ctrl_V3_8997.conf create mode 100644 mxm_wifiex/wlan_src/mapp/mlanconfig/config/ed_mac_ctrl_V3_909x.conf create mode 100644 mxm_wifiex/wlan_src/mapp/mlanconfig/config/init_cfg.conf create mode 100644 mxm_wifiex/wlan_src/mapp/mlanconfig/config/mef.conf create mode 100644 mxm_wifiex/wlan_src/mapp/mlanconfig/config/mef_mdns.conf create mode 100644 mxm_wifiex/wlan_src/mapp/mlanconfig/config/mef_ws_discovery.conf create mode 100644 mxm_wifiex/wlan_src/mapp/mlanconfig/config/mem.conf create mode 100644 mxm_wifiex/wlan_src/mapp/mlanconfig/config/mgmt_frame.conf create mode 100644 mxm_wifiex/wlan_src/mapp/mlanconfig/config/mgmtfilter.conf create mode 100644 mxm_wifiex/wlan_src/mapp/mlanconfig/config/or_data.conf create mode 100644 mxm_wifiex/wlan_src/mapp/mlanconfig/config/pad_cfg.conf create mode 100644 mxm_wifiex/wlan_src/mapp/mlanconfig/config/requesttpc.conf create mode 100644 mxm_wifiex/wlan_src/mapp/mlanconfig/config/robust_btc.conf create mode 100644 mxm_wifiex/wlan_src/mapp/mlanconfig/config/rutxpower_limit.conf create mode 100644 mxm_wifiex/wlan_src/mapp/mlanconfig/config/sdio_pulldown.conf create mode 100644 mxm_wifiex/wlan_src/mapp/mlanconfig/config/small_debug.conf create mode 100644 mxm_wifiex/wlan_src/mapp/mlanconfig/config/smc.conf create mode 100644 mxm_wifiex/wlan_src/mapp/mlanconfig/config/ssu.conf create mode 100644 mxm_wifiex/wlan_src/mapp/mlanconfig/config/subevent.conf create mode 100644 mxm_wifiex/wlan_src/mapp/mlanconfig/config/tspecs.conf create mode 100644 mxm_wifiex/wlan_src/mapp/mlanconfig/config/turbo_mode.conf create mode 100644 mxm_wifiex/wlan_src/mapp/mlanconfig/config/tx_ctrl.conf create mode 100644 mxm_wifiex/wlan_src/mapp/mlanconfig/config/txpwrlimit_cfg.conf create mode 100644 mxm_wifiex/wlan_src/mapp/mlanconfig/config/txrate_cfg.conf create mode 100644 mxm_wifiex/wlan_src/mapp/mlanconfig/config/wifi_mod_para.conf create mode 100644 mxm_wifiex/wlan_src/mapp/mlanconfig/mlanconfig.c create mode 100644 mxm_wifiex/wlan_src/mapp/mlanconfig/mlanconfig.h create mode 100644 mxm_wifiex/wlan_src/mapp/mlanconfig/mlanhostcmd.c create mode 100644 mxm_wifiex/wlan_src/mapp/mlanconfig/mlanhostcmd.h create mode 100644 mxm_wifiex/wlan_src/mapp/mlanconfig/mlanmisc.c create mode 100644 mxm_wifiex/wlan_src/mapp/mlanconfig/mlanmisc.h create mode 100644 mxm_wifiex/wlan_src/mapp/mlanevent/Makefile create mode 100644 mxm_wifiex/wlan_src/mapp/mlanevent/mlanevent.c create mode 100644 mxm_wifiex/wlan_src/mapp/mlanevent/mlanevent.h create mode 100644 mxm_wifiex/wlan_src/mapp/mlanutl/Makefile create mode 100644 mxm_wifiex/wlan_src/mapp/mlanutl/mlanhostcmd.c create mode 100644 mxm_wifiex/wlan_src/mapp/mlanutl/mlanhostcmd.h create mode 100644 mxm_wifiex/wlan_src/mapp/mlanutl/mlanoffload.c create mode 100644 mxm_wifiex/wlan_src/mapp/mlanutl/mlanoffload.h create mode 100644 mxm_wifiex/wlan_src/mapp/mlanutl/mlanregclass.c create mode 100644 mxm_wifiex/wlan_src/mapp/mlanutl/mlanregclass.h create mode 100644 mxm_wifiex/wlan_src/mapp/mlanutl/mlanroamagent.c create mode 100644 mxm_wifiex/wlan_src/mapp/mlanutl/mlanroamagent.h create mode 100644 mxm_wifiex/wlan_src/mapp/mlanutl/mlanscanagent.c create mode 100644 mxm_wifiex/wlan_src/mapp/mlanutl/mlanscanagent.h create mode 100644 mxm_wifiex/wlan_src/mapp/mlanutl/mlanutl.c create mode 100644 mxm_wifiex/wlan_src/mapp/mlanutl/mlanutl.h create mode 100644 mxm_wifiex/wlan_src/mapp/mlanutl/timestamp.c create mode 100644 mxm_wifiex/wlan_src/mapp/mlanutl/timestamp.h create mode 100644 mxm_wifiex/wlan_src/mapp/uaputl/Makefile create mode 100644 mxm_wifiex/wlan_src/mapp/uaputl/config/80211d_domain.conf create mode 100644 mxm_wifiex/wlan_src/mapp/uaputl/config/embedded_dhcp.conf create mode 100644 mxm_wifiex/wlan_src/mapp/uaputl/config/sample_cal_data_bg_8688.conf create mode 100644 mxm_wifiex/wlan_src/mapp/uaputl/config/uapcoex.conf create mode 100644 mxm_wifiex/wlan_src/mapp/uaputl/config/uaputl.conf create mode 100644 mxm_wifiex/wlan_src/mapp/uaputl/config/uaputl_wifidirect.conf create mode 100644 mxm_wifiex/wlan_src/mapp/uaputl/uapcmd.c create mode 100644 mxm_wifiex/wlan_src/mapp/uaputl/uapcmd.h create mode 100644 mxm_wifiex/wlan_src/mapp/uaputl/uaphostcmd.c create mode 100644 mxm_wifiex/wlan_src/mapp/uaputl/uaputl.c create mode 100644 mxm_wifiex/wlan_src/mapp/uaputl/uaputl.h create mode 100644 mxm_wifiex/wlan_src/mapp/wifidirectutl/Makefile create mode 100644 mxm_wifiex/wlan_src/mapp/wifidirectutl/config/wifidirect.conf create mode 100644 mxm_wifiex/wlan_src/mapp/wifidirectutl/wifidirectutl.c create mode 100644 mxm_wifiex/wlan_src/mapp/wifidirectutl/wifidirectutl.h create mode 100644 mxm_wifiex/wlan_src/script/load create mode 100644 mxm_wifiex/wlan_src/script/unload create mode 100644 mxm_wifiex/wlan_src/script/usbconfig create mode 100644 mxm_wifiex/wlan_src/script/wifidirect/start_auto_go.sh create mode 100644 mxm_wifiex/wlan_src/script/wifidirect/start_find_phase.sh create mode 100644 mxm_wifiex/wlan_src/script/wifidirect/start_listen_state.sh create mode 100644 mxm_wifiex/wlan_src/script/wifidirect/stop_auto_go.sh create mode 100644 mxm_wifiex/wlan_src/script/wifidirect/stop_wifidirect_client.sh create mode 100644 mxm_wifiex/wlan_src/script/wifidirect/update_mac.sh diff --git a/mxm_wifiex/wlan_src/Makefile b/mxm_wifiex/wlan_src/Makefile new file mode 100644 index 0000000..c8980bf --- /dev/null +++ b/mxm_wifiex/wlan_src/Makefile @@ -0,0 +1,558 @@ +# File: Makefile +# +# Copyright 2014-2020 NXP +# +# This software file (the File) is distributed by NXP +# under the terms of the GNU General Public License Version 2, June 1991 +# (the License). You may use, redistribute and/or modify the 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. +# + +COMPATDIR=/lib/modules/$(KERNELVERSION_X86)/build/compat-wireless-3.2-rc1-1/include +ifeq ($(CC),) +CC= $(CROSS_COMPILE)gcc -I$(COMPATDIR) +endif +ifeq ($(LD),) +LD= $(CROSS_COMPILE)ld +endif +BACKUP= /root/backup +YMD= `date +%Y%m%d%H%M` + +############################################################################# +# Configuration Options +############################################################################# +# Multi-chipsets +CONFIG_SD8887=n +CONFIG_SD8897=n +CONFIG_USB8897=n +CONFIG_PCIE8897=n +CONFIG_SD8977=n +CONFIG_SD8978=n +CONFIG_USB8978=n +CONFIG_SD8997=n +CONFIG_USB8997=n +CONFIG_PCIE8997=n +CONFIG_SD8987=y +CONFIG_SD9097=n +CONFIG_USB9097=n +CONFIG_PCIE9097=n +CONFIG_SD9098=n +CONFIG_USB9098=n +CONFIG_PCIE9098=n + + +# Debug Option +# DEBUG LEVEL n/1/2: +# n: NO DEBUG +# 1: Only PRINTM(MMSG,...), PRINTM(MFATAL,...), ... +# 2: All PRINTM() +CONFIG_DEBUG=1 + +# Enable STA mode support +CONFIG_STA_SUPPORT=y + +# Enable uAP mode support +CONFIG_UAP_SUPPORT=y + +# Enable WIFIDIRECT support +CONFIG_WIFI_DIRECT_SUPPORT=y + + +# Re-association in driver +CONFIG_REASSOCIATION=y + + +# Manufacturing firmware support +CONFIG_MFG_CMD_SUPPORT=y + +# OpenWrt support +CONFIG_OPENWRT_SUPPORT=n + +# Big-endian platform +CONFIG_BIG_ENDIAN=n + + + +ifeq ($(CONFIG_DRV_EMBEDDED_SUPPLICANT), y) +CONFIG_EMBEDDED_SUPP_AUTH=y +else +ifeq ($(CONFIG_DRV_EMBEDDED_AUTHENTICATOR), y) +CONFIG_EMBEDDED_SUPP_AUTH=y +endif +endif + +#ifdef SDIO_MMC +# SDIO suspend/resume +CONFIG_SDIO_SUSPEND_RESUME=y +#endif + +# DFS testing support +CONFIG_DFS_TESTING_SUPPORT=y + + + +CONFIG_ANDROID_KERNEL=n + + +#32bit app over 64bit kernel support +CONFIG_USERSPACE_32BIT_OVER_KERNEL_64BIT=n + + +############################################################################# +# Select Platform Tools +############################################################################# + +ccflags-y += -DLINUX + +KERNELVERSION_X86 := $(shell uname -r) +KERNELDIR ?= /lib/modules/$(KERNELVERSION_X86)/build +LD += -S + +BINDIR = ../bin_mxm_wifiex +APPDIR= $(shell if test -d "mapp"; then echo mapp; fi) + +############################################################################# +# Compiler Flags +############################################################################# + + ccflags-y += -I$(KERNELDIR)/include + + ccflags-y += -DFPNUM='"92"' + +ifeq ($(CONFIG_DEBUG),1) + ccflags-y += -DDEBUG_LEVEL1 +endif + +ifeq ($(CONFIG_DEBUG),2) + ccflags-y += -DDEBUG_LEVEL1 + ccflags-y += -DDEBUG_LEVEL2 + DBG= -dbg +endif + +ifeq ($(CONFIG_64BIT), y) + ccflags-y += -DMLAN_64BIT +endif + +ifeq ($(CONFIG_STA_SUPPORT),y) + ccflags-y += -DSTA_SUPPORT +ifeq ($(CONFIG_REASSOCIATION),y) + ccflags-y += -DREASSOCIATION +endif +else +CONFIG_WIFI_DIRECT_SUPPORT=n +CONFIG_STA_WEXT=n +CONFIG_STA_CFG80211=n +endif + +ifeq ($(CONFIG_UAP_SUPPORT),y) + ccflags-y += -DUAP_SUPPORT +else +CONFIG_WIFI_DIRECT_SUPPORT=n +CONFIG_UAP_WEXT=n +CONFIG_UAP_CFG80211=n +endif + +ifeq ($(CONFIG_WIFI_DIRECT_SUPPORT),y) + ccflags-y += -DWIFI_DIRECT_SUPPORT +endif + +ifeq ($(CONFIG_MFG_CMD_SUPPORT),y) + ccflags-y += -DMFG_CMD_SUPPORT +endif + +ifeq ($(CONFIG_BIG_ENDIAN),y) + ccflags-y += -DBIG_ENDIAN_SUPPORT +endif + +ifeq ($(CONFIG_USERSPACE_32BIT_OVER_KERNEL_64BIT),y) + ccflags-y += -DUSERSPACE_32BIT_OVER_KERNEL_64BIT +endif + +#ifdef SDIO_MMC +ifeq ($(CONFIG_SDIO_SUSPEND_RESUME),y) + ccflags-y += -DSDIO_SUSPEND_RESUME +endif +#endif + + +ifeq ($(CONFIG_DFS_TESTING_SUPPORT),y) + ccflags-y += -DDFS_TESTING_SUPPORT +endif + + +ifeq ($(CONFIG_ANDROID_KERNEL), y) + ccflags-y += -DANDROID_KERNEL +endif + +ifeq ($(CONFIG_OPENWRT_SUPPORT), y) + ccflags-y += -DOPENWRT +endif + +ifeq ($(CONFIG_T50), y) + ccflags-y += -DT50 + ccflags-y += -DT40 + ccflags-y += -DT3T +endif + +ifeq ($(CONFIG_SD8887),y) + CONFIG_SDIO=y + ccflags-y += -DSD8887 +endif +ifeq ($(CONFIG_SD8897),y) + CONFIG_SDIO=y + ccflags-y += -DSD8897 +endif +ifeq ($(CONFIG_SD8977),y) + CONFIG_SDIO=y + ccflags-y += -DSD8977 +endif +ifeq ($(CONFIG_SD8978),y) + CONFIG_SDIO=y + ccflags-y += -DSD8978 +endif +ifeq ($(CONFIG_SD8997),y) + CONFIG_SDIO=y + ccflags-y += -DSD8997 +endif +ifeq ($(CONFIG_SD8987),y) + CONFIG_SDIO=y + ccflags-y += -DSD8987 +endif +ifeq ($(CONFIG_SD9097),y) + CONFIG_SDIO=y + ccflags-y += -DSD9097 +endif +ifeq ($(CONFIG_SD9098),y) + CONFIG_SDIO=y + ccflags-y += -DSD9098 +endif +ifeq ($(CONFIG_USB8897),y) + CONFIG_MUSB=y + ccflags-y += -DUSB8897 +endif +ifeq ($(CONFIG_USB8997),y) + CONFIG_MUSB=y + ccflags-y += -DUSB8997 +endif +ifeq ($(CONFIG_USB8978),y) + CONFIG_MUSB=y + ccflags-y += -DUSB8978 +endif +ifeq ($(CONFIG_USB9097),y) + CONFIG_MUSB=y + ccflags-y += -DUSB9097 +endif +ifeq ($(CONFIG_USB9098),y) + CONFIG_MUSB=y + ccflags-y += -DUSB9098 +endif +ifeq ($(CONFIG_PCIE8897),y) + CONFIG_PCIE=y + ccflags-y += -DPCIE8897 +endif +ifeq ($(CONFIG_PCIE8997),y) + CONFIG_PCIE=y + ccflags-y += -DPCIE8997 +endif +ifeq ($(CONFIG_PCIE9097),y) + CONFIG_PCIE=y + ccflags-y += -DPCIE9097 +endif +ifeq ($(CONFIG_PCIE9098),y) + CONFIG_PCIE=y + ccflags-y += -DPCIE9098 +endif +ifeq ($(CONFIG_SDIO),y) + ccflags-y += -DSDIO + ccflags-y += -DSDIO_MMC +endif +ifeq ($(CONFIG_MUSB),y) + ccflags-y += -DUSB +endif +ifeq ($(CONFIG_PCIE),y) + ccflags-y += -DPCIE +endif + + +# add -Wno-packed-bitfield-compat when GCC version greater than 4.4 +GCC_VERSION := $(shell echo `gcc -dumpversion | cut -f1-2 -d.` \>= 4.4 | sed -e 's/\./*100+/g' | bc ) +ifeq ($(GCC_VERSION),1) + ccflags-y += -Wno-packed-bitfield-compat +endif + ccflags-y += -Wno-stringop-overflow + ccflags-y += -Wno-tautological-compare + +############################################################################# +# Make Targets +############################################################################# + +ifneq ($(KERNELRELEASE),) + +ifeq ($(CONFIG_WIRELESS_EXT),y) +ifeq ($(CONFIG_WEXT_PRIV),y) + # Enable WEXT for STA + CONFIG_STA_WEXT=y + # Enable WEXT for uAP + CONFIG_UAP_WEXT=y +else +# Disable WEXT for STA + CONFIG_STA_WEXT=n +# Disable WEXT for uAP + CONFIG_UAP_WEXT=n +endif +endif + +# 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 + +# OpenWrt +ifeq ($(CONFIG_OPENWRT_SUPPORT), y) +ifeq ($(CPTCFG_CFG80211),y) + CONFIG_STA_CFG80211=y +else +ifeq ($(CPTCFG_CFG80211),m) + CONFIG_STA_CFG80211=y +else + CONFIG_STA_CFG80211=n +endif +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 + +# OpenWrt +ifeq ($(CONFIG_OPENWRT_SUPPORT), y) +ifeq ($(CPTCFG_CFG80211),y) + CONFIG_STA_CFG80211=y +else +ifeq ($(CPTCFG_CFG80211),m) + CONFIG_STA_CFG80211=y +else + CONFIG_STA_CFG80211=n +endif +endif +endif + +ifneq ($(CONFIG_STA_SUPPORT),y) + CONFIG_WIFI_DIRECT_SUPPORT=n + CONFIG_STA_WEXT=n + CONFIG_STA_CFG80211=n +endif + +ifneq ($(CONFIG_UAP_SUPPORT),y) + CONFIG_WIFI_DIRECT_SUPPORT=n + CONFIG_UAP_WEXT=n + CONFIG_UAP_CFG80211=n +endif + +ifeq ($(CONFIG_STA_SUPPORT),y) +ifeq ($(CONFIG_STA_WEXT),y) + ccflags-y += -DSTA_WEXT +endif +ifeq ($(CONFIG_STA_CFG80211),y) + ccflags-y += -DSTA_CFG80211 +endif +endif +ifeq ($(CONFIG_UAP_SUPPORT),y) +ifeq ($(CONFIG_UAP_WEXT),y) + ccflags-y += -DUAP_WEXT +endif +ifeq ($(CONFIG_UAP_CFG80211),y) + ccflags-y += -DUAP_CFG80211 +endif +endif + +print: +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 + +# Otherwise we were called directly from the command line; invoke the kernel build system. +else + +default: + $(MAKE) -C $(KERNELDIR) M=$(PWD) modules + +endif + +############################################################### + +export CC LD ccflags-y 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 NXP 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 -rpf script/load $(BINDIR)/ + cp -rpf script/unload $(BINDIR)/ +ifeq ($(CONFIG_MUSB),y) + cp -rpf script/usbconfig $(BINDIR)/ +endif + +ifeq ($(CONFIG_STA_SUPPORT),y) + cp -f README $(BINDIR) + cp -f README_MLAN $(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) +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 "*.mod" -exec rm {} \; + -find . -name "Module.symvers" -exec rm {} \; + -find . -name "Module.markers" -exec rm {} \; + -find . -name "modules.order" -exec rm {} \; + -find . -name ".*.dwo" -exec rm {} \; + -find . -name "*dwo" -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 +#ifdef SDIO +#endif // SDIO + +install: default + + echo $(INSTALLDIR) + echo "MX 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 {} \; + -find . -name ".*.dwo" -exec rm {} \; + -find . -name "*dwo" -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/mxm_wifiex/wlan_src/README b/mxm_wifiex/wlan_src/README new file mode 100644 index 0000000..34ec998 --- /dev/null +++ b/mxm_wifiex/wlan_src/README @@ -0,0 +1,1125 @@ +=============================================================================== + U S E R M A N U A L + + Copyright 2014-2020 NXP + + +1) FOR DRIVER BUILD + + Goto source code directory wlan_src/. + make [clean] build + The driver and utility binaries can be found in ../bin_xxxx directory. + The driver code supports Linux kernel from 2.6.32 to 5.5.2. + +2) FOR DRIVER INSTALL + + a) Copy firmware image to /lib/firmware/nxp/, copy wifi_mod_para.conf to /lib/firmware/nxp/. + b) Install WLAN driver + There are drv_mode, max_sta_bss, max_uap_bss etc. module parameters. + The bit settings of drv_mode are, + Bit 0 : STA + Bit 1 : uAP + Bit 2 : WIFIDIRECT + + max_sta_bss: Maximum number of STA BSS (default 1, max 1) + sta_name: Name of the STA interface (default: "mlan") + max_uap_bss: Maximum number of uAP BSS (default 1, max 1) + uap_name: Name of the uAP interface (default: "uap") + uap_max_sta: Maximum number of STA for UAP/GO (default 0, max 64) + max_wfd_bss: Maximum number of WIFIDIRECT BSS (default 1, max 1) + wfd_name: Name of the WIFIDIRECT interface (default: "wfd") + max_vir_bss: Number of Virtual interfaces (default 0) + uap_oper_ctrl: uAP operation control when in-STA disconnect with ext-AP + 0: default do nothing, 2: uAP stops and restarts automatically + For example, to install multi-chip driver, + insmod mlan.ko + insmod moal.ko mod_para=nxp/wifi_mod_para.conf [drvdbg=0x7] + wifi_mod_para.conf is used to support multi-chips which has different load module parameters. It contains + the module parameters for different chips. + c) Uninstall WLAN driver, + ifconfig mlanX down + ifconfig uapX down + rmmod moal + rmmod mlan + + To load driver with MFG firmware file, use mfg_mode=1 when insmod WLAN driver and + specify MFG firmware name if needed. + + There are some other parameters for debugging purpose etc. Use modinfo to check details. + drvdbg= + dev_cap_mask= + mac_addr=xx:xx:xx:xx:xx:xx + auto_ds=0|1|2 + ps_mode=0|1|2 + max_tx_buf=2048|4096|8192 + pm_keep_power=1|0 + shutdown_hs=1|0 + cfg_11d=0|1|2 + dts_enable=0|1 + fw_name = + e.g. copy pcieuart9098_combo_v1.bin to firmware directory, fw_name=nxp/pcieuart9098_combo_v1.bin + fw_region + hw_test=0|1 + fw_serial=0|1 + req_fw_nowait=0|1 + antcfg=0|1|2|0xffff + slew_rate: Slew Rate Control value = 0|1|2|3 (0 is the slowest slew rate and 03 has the highest slew rate (default)) + init_cfg= + e.g. copy init_cfg.conf to firmware directory, init_cfg=nxp/init_cfg.conf + cal_data_cfg= + e.g. copy cal_data.conf to firmware directory, cal_data_cfg=nxp/cal_data.conf + dpd_data_cfg= + e.g. copy dpd_data.conf to firmware directory, dpd_data_cfg=nxp/dpd_data.conf + txpwrlimit_cfg= + e.g. copy txpwrlimit_cfg_set.conf to firmware directory, txpwrlimit_cfg=nxp/txpwrlimit_cfg_set.conf + cntry_txpwr= + init_hostcmd_cfg= + e.g. copy init_hostcmd_cfg.conf to firmware directory, init_hostcmd_cfg=nxp/init_hostcmd_cfg.conf + sdio_rx_aggr=1|0 + cfg80211_wext= + Bit 0: STA WEXT + Bit 1: uAP WEXT + Bit 2: STA CFG80211 + Bit 3: uAP CFG80211 + reg_alpha2= + skip_fwdnld=0|1 + wq_sched_prio: Priority for work queue + wq_sched_policy: Scheduling policy for work queue + (0: SCHED_NORMAL, 1: SCHED_FIFO, 2: SCHED_RR, 3: SCHED_BATCH, 5: SCHED_IDLE) + Please note that, both wq_sched_prio and wq_sched_policy should be provided + as module parameters. If wq_sched_policy is (0, 3 or 5), then wq_sched_prio + must be 0. wq_sched_prio should be 1 to 99 otherwise. + rx_work=0|1|2 + pcie_int_mode=0|1|2 + pcie_int_mode=0|1 + wakelock_timeout= + defined(SD9098)||defined(USB9098) || defined(PCIE9098) || defined(SD9097) || defined(USB9097)|| defined(PCIE9097)||defined(SD8978) + pmic=0|1 + indication_gpio=0xXY + hs_wake_interval= + disconnect_on_suspend=0|1 + hs_mimo_switch=0|1 + usb_aggr=0|1|2 + low_power_mode_enable=0|1 + When low power mode is enabled, the output power will be clipped at ~+10dBm and the + expected PA current is expected to be in the 80-90 mA range for b/g/n modes + indrstcfg=<2-byte IR configuration> + gpio pin (high byte): GPIO pin no to be used as trigger for out band reset + (0xFF: default pin configuration) + ir_mode (low byte) : independent reset mode + (0: disable, 1: enable out band, 2: enable in band) + For example, to enable out band reset via gpio_pin 14 + indrstcfg=0x0e01 + To enable out band reset via default gpio_pin + indrstcfg=0xff01 + To enable in band reset and disable out band reset + indrstcfg=0x02 + fixed_beacon_buffer=0|1 + GoAgeoutTime=0|x + multi_dtim=0|x + inact_tmo=0|x + host_mlme=0|1 + country_ie_ignore=0|1 + beacon_hints=0|1 + + Note: On some platforms (e.g. PXA910/920) double quotation marks ("") need to used + for module parameters. + insmod sdxxx.ko " ..." + +3) FOR DRIVER PROC & DEBUG + + The following info are provided in /proc/net/mwlan/adapterX/mlanY/info, + on kernel 2.6.24 or later, the entry is /proc/mwlan/adapterX/mlanY/info. + + driver_name = "wlan" + driver_version = + interface_name = "mlanX" + bss_mode = "Ad-hoc" | "Managed" | "Auto" | "Unknown" + media_state = "Disconnected" | "Connected" + mac_address = <6-byte adapter MAC address> + multicase_count = + essid = + bssid = + channel = + region_code = + multicast_address[n] = + num_tx_bytes = + num_rx_bytes = + num_tx_pkts = + num_rx_pkts = + num_tx_pkts_dropped = + num_rx_pkts_dropped = + num_tx_pkts_err = + num_rx_pkts_err = + carrier "on" | "off" + tx queue "stopped" | "started" + + The following debug info are provided in /proc/net/mwlan/adapterX/mlanY/debug, + on kernel 2.6.24 or later, the entry is /proc/mwlan/adapterX/mlanY/debug. + + drvdbg = + wmm_ac_vo = + wmm_ac_vi = + wmm_ac_be = + wmm_ac_bk = + max_tx_buf_size = + tx_buf_size = + curr_tx_buf_size = + ps_mode = <0/1, CAM mode/PS mode> + ps_state = <0/1/2/3, awake state/pre-sleep state/sleep-confirm state/sleep state> + is_deep_sleep = <0/1, not deep sleep state/deep sleep state> + wakeup_dev_req = <0/1, wakeup device not required/required> + wakeup_tries = + hs_configured = <0/1, host sleep not configured/configured> + hs_activated = <0/1, extended host sleep not activated/activated> + tx_pkts_queued = + pps_uapsd_mode = <0/1, PPS/UAPSD mode disabled/enabled> + sleep_pd = + qos_cfg = + tx_lock_flag = <0/1, Tx lock flag> + port_open = <0/1, port open flag> + scan_processing = <0/1, scan processing flag> + num_tx_timeout = + num_cmd_timeout = + timeout_cmd_id = + timeout_cmd_act = + last_cmd_id = + last_cmd_act = + last_cmd_index = <0 based last command index> + last_cmd_resp_id = + last_cmd_resp_index = <0 based last command response index> + last_event = + last_event_index = <0 based last event index> + num_cmd_h2c_fail = + num_cmd_sleep_cfm_fail = + num_tx_h2c_fail = + num_cmdevt_c2h_fail = + num_rx_c2h_fail = + num_int_read_fail = + last_int_status = + num_evt_deauth = + num_evt_disassoc = + num_evt_link_lost = + num_cmd_deauth = + num_cmd_assoc_ok = + num_cmd_assoc_fail = + cmd_sent = <0/1, send command resources available/sending command to device> + data_sent = <0/1, send data resources available/sending data to device> + mp_rd_bitmap = + curr_rd_port = + mp_wr_bitmap = + curr_wr_port = + txbd_rdptr = + txbd_wrptr = + rxbd_rdptr = + rxbd_wrptr = + eventbd_rdptr = + eventbd_wrptr = + cmd_resp_received = <0/1, no cmd response to process/response received and yet to process> + event_received = <0/1, no event to process/event received and yet to process> + tx_cmd_urb_pending = + tx_data_urb_pending = + rx_cmd_urb_pending = + rx_data_urb_pending = + ioctl_pending = + tx_pending = + rx_pending = + lock_count = + malloc_count = + mbufalloc_count = + malloc_cons_count = + main_state = + sdiocmd53w = + sdiocmd53r = + hs_skip_count = + hs_force_count = + + Issue SDIO cmd52 read/write through proc. + Usage: + echo "sdcmd52rw= [data]" > /proc/mwlan/adapterX/config + where the parameters: + func: The function number to use (0-7) + reg: The address of the register + data: The value to write, read if the value is absent + For SDIO MMC driver, only function 0 and WLAN function access is allowed. + And there is a limitation for function 0 write, only vendor specific CCCR + registers (0xf0 -0xff) are permiited. + Examples: + echo "sdcmd52rw= 0 4" > /proc/mwlan/adapterX/config # read func 0 address 4 + cat /proc/mwlan/adapterX/config # display the register value + echo "sdcmd52rw= 1 3 0xf" > /proc/mwlan/adapterX/config # write 0xf to func 1 address 3 + + Use dmesg or cat /var/log/debug to check driver debug messages. + To log driver debug messages to file, + a) Edit /etc/syslog.conf, add one line "*.debug /var/log/debug" + on kernel 2.6.24 or later, edit /etc/rsyslog.conf instead + b) touch /var/log/debug (if the file doesn't exist) + c) service syslog restart + on kernel 2.6.24 or later, service rsyslog restart + + Update /proc/sys/kernel/printk to change message log levels. + For example, + echo 6 > /proc/sys/kernel/printk (messages with a higher priority than 6 + will be printed to the console) + echo 15 > /proc/sys/kernel/printk (all messages will be printed to console) + +4) FOR IWPRIV COMMAND + +NAME + This manual describes the usage of private commands used in NXP MLAN + Linux Driver. + + To use parameters as hex format, a '0x' must precede it for the parameters to + be parsed properly. + +SYNOPSIS + iwpriv [sub-command] ... + + iwpriv mlanX version + iwpriv mlanX verext + iwpriv mlanX getsignal [m] [n] + iwpriv mlanX antcfg [m] [n] + iwpriv mlanX regioncode [n] + iwpriv mlanX cfpcode [m] [n] + iwpriv mlanX wwscfg [m] + iwpriv mlanX esuppmode + iwpriv mlanX passphrase + iwpriv mlanX httxcfg [] [] + iwpriv mlanX htcapinfo [] [] + iwpriv mlanX addbapara

+ iwpriv mlanX aggrpriotbl + iwpriv mlanX addbareject + iwpriv mlanX txbufcfg + iwpriv mlanX amsduaggrctrl + iwpriv mlanX httxbfcap [cap] + iwpriv mlanX httxbfcfg "[;GlobalData/tsData/interval/txPeerData/snrData]" + iwpriv mlanX mpactrl [tx_ena] [rx_ena] [tx_size] [rx_size] [tx_ports] [rx_ports] + iwpriv mlanX deepsleep [n] [m] + iwpriv mlanX usbsuspend + iwpriv mlanX usbresume + iwpriv mlanX hscfg [condition [[GPIO# [gap]]]] + iwpriv mlanX hssetpara condition [GPIO# [gap]] + iwpriv mlanX deauth [n] + iwpriv mlanX radioctrl + iwpriv mlanX reassoctrl [n] + iwpriv mlanX bandcfg [l] [m] [n] + iwpriv mlanX getlog + iwpriv mlanX 11dcfg + iwpriv mlanX 11dclrtbl + iwpriv mlanX wmmcfg [n] + iwpriv mlanX hotspotcfg [n] + iwpriv mlanX txpowercfg [ [ [ ]]] + iwpriv mlanX qoscfg + iwpriv mlanX getdatarate + iwpriv mlanX txratecfg [n] + iwpriv mlanX bcninterval [n] + iwpriv mlanX sysclock [clk1] [clk2] [clk3] [clk4] + iwpriv mlanX drvdbg [n] + iwpriv mlanX mgmtframectrl + iwpriv mlanX warmreset + iwpriv mlanX regrdwr [value] + iwpriv mlanX rdeeprom + iwpriv mlanX memrdwr

[value] + iwpriv mlanX inactivityto [k] + iwpriv mlanX sdioclock + iwpriv mlanX sdcmd52rw
[data] + iwpriv mlanX scancfg [t] [m] [p] [s] [a] [b] [ext] + iwpriv mlanX sleeppd [n] + iwpriv mlanX pscfg [k] [d] [l] ... + iwpriv mlanX getkey + iwpriv mlanX associate " " + iwpriv mlanX sleepparams [ ] + iwpriv mlanX authtype [n] + iwpriv mlanX powercons [n] + iwpriv mlanX htstreamcfg [n] + iwpriv mlanX ipaddr [";"] + iwpriv mlanX macctrl [n] + iwpriv mlanX dfstesting [ ] + iwpriv mlanX thermal + iwpriv mlanX indrstcfg [gpio_pin] + +DESCRIPTION + Those commands are used to send additional commands to the NXP MLAN + card via the Linux device driver. + + The mlanX parameter specifies the network device that is to be used to + perform this command on. It could be mlan0, mlan1 etc. + +version + This is used to get the current version of the driver and the firmware. + +verext + Retrieve and display an extended version string from the firmware + + Usage: + iwpriv mlanX verext [#] + + where [#] is an optional argument to retrieve a specific version string, + omission of the argument retrieves the 0 indexed string. + +getsignal + This command gets the last and average value of RSSI, SNR and NF of + Beacon and Data. + Note: This command is available only when STA is connected. + + where value of m is: + 1 -- RSSI (Receive Signal Strength Indication) + 2 -- SNR (Signal to Noise Ratio) + 3 -- NF (Noise Floor) + where value of n is: + 1 -- Beacon last + 2 -- Beacon average + 3 -- Data last + 4 -- Data average + + Examples: + iwpriv mlan0 getsignal 1 : Get the RSSI info (beacon last, beacon + average, data last and data average) + iwpriv mlan0 getsignal 3 4 : Get the NF of data average + iwpriv mlan0 getsignal 2 1 : Get the SNR of beacon last + iwpriv mlan0 getsignal : Get all of the signal info + mlan0 getsignal:-32 -33 -35 -36 67 59 63 56 -99 -92 -98 -92 + RSSI info: beacon last -32, beacon average -33, data last -35, data average -36 + SNR info: beacon last 67, beacon average 59, data last 63, data average 56 + NF info: beacon last -99, beacon average -92, data last -98, data average -92 + +antcfg + This command is used to set/get the mode of Tx/Rx path. + + where value of m is: + Bit 0 -- Tx Path A + Bit 1 -- Tx Path B + Bit 0-1 -- Tx Path A+B + For 9097/9098, LOW BYTE for 2G setting + Bit 8 -- Tx Path A + Bit 9 -- Tx Path B + Bit 8-9 -- Tx Path A+B + For 9097/9098, HIGH BYTE for 5G setting + + where value of n is: + Bit 0 -- Rx Path A + Bit 1 -- Rx Path B + Bit 0-1 -- Rx Path A+B + For 9097/9098, LOW BYTE for 2G setting + Bit 8 -- Rx Path A + Bit 9 -- Rx Path B + Bit 8-9 -- Rx Path A+B + For 9097/9098, HIGH BYTE for 5G setting + The Tx path setting (m) is used if Rx path (n) is not provided. + + Examples: + iwpriv mlan0 antcfg : Get Tx and Rx path + iwpriv mlan0 antcfg 3 : Set Tx and Rx path to A+B + iwpriv mlan0 antcfg 1 3 : Set Tx path to A and Rx path to A+B + mlanutl mlan0 antcfg 0x103 : Set Tx and Rx path to A+B on 2G and Tx and Rx path to A on 5G + mlanutl mlan0 antcfg 0x103 0x103 : Set Tx path to A+B and Rx path to A+B on 2G, and Tx and Rx path to A on 5G + +regioncode + This command is used to set/get the region code in the station. + Note: This command should be issued at beginning before band/channel selection + and association. + + where value is 'region code' for various regions like + USA FCC, Canada IC, Europe ETSI, Japan ... + The special code (0xff) is used for Japan to support channel 1-14 in B/G/N mode. + + Examples: + iwpriv mlan0 regioncode : Get region code + iwpriv mlan0 regioncode 0x10 : Set region code to USA (0x10) + + Note : in some case regioncode will be 0 after updated countycode or 80211d + i.e. mlanutl mlanX countrycode (CA, JP, CN, DE, ES AT, BR, RU) + or uaputl.exe sys_cfg_80211d state 1 country (CA, JP, CN, DE, ES AT, BR, RU) + Please use cfp instead of it. + +cfpcode + This command is used to set/get the Channel-Frequency-Power table codes. + The region table can be selected through region code. + The current configuration is returned if no parameter provided. + + where the parameters are, + [m]: code of the CFP table for 2.4GHz (0: unchanged) + [n]: code of the CFP table for 5GHz (0 or not provided: unchanged) + + Examples: + iwpriv mlan0 cfpcode : Get current configuration + iwpriv mlan0 cfpcode 0x30 : Set 2.4GHz CFP table code 0x30 (EU), + keep 5GHz table unchanged + iwpriv mlan0 cfpcode 0x10 5 : Set 2.4GHz CFP table code 0x10 (USA) + and 5GHz table code 5 + +wwscfg + This command is used to set/get the WWS (World Wide Safe) mode. + + where value of m is: + 0 -- Disable WWS mode (default) + 1 -- Enable WWS mode + + Examples: + iwpriv mlan0 wwscfg : Get WWS mode + iwpriv mlan0 wwscfg 1 : Enable WWS mode + iwpriv mlan0 wwscfg 0 : Disable WWS mode + +esuppmode + This command is used to get the current RSN mode and active pairwise/group + cipher for WPA/WPA2 mode. + Note: This command is available only when STA is connected. + + These are bits settings used to indicate each RSN mode. + Bit 0 : No RSN + Bit 1-2 : RFU + Bit 3 : WPA + Bit 4 : WPA-NONE + Bit 5 : WPA2 + Bit 6 : AES + Bit 7-15 : RFU + + These are bits settings used to indicate each pairwise and group cipher. + Bit 0 : RFU + Bit 1 : RFU + Bit 2 : TKIP + Bit 3 : AES + Bit 2-7 : RFU + + Example: + iwpriv mlan0 esuppmode : Get RSN mode and pairwise/group cipher + 8 4 4 + (The current RSN mode is WPA, active pairwise cipher is TKIP and + active group cipher is TKIP.) + +passphrase + This command is used to set/get passphrase for WPA-PSK/WPA2-PSK mode. + + Where + ASCII string for ssid/passphrase/psk. + + This passphrase is used as password if WPA3 SAE protocol is configured, so please + use extremely difficult to guess password to protect from attacks. + + Also setting psk for WPA3 SAE protocol is not possible, as new psk gets generated + everytime in protocol flow. + + 1) "0;" - This will get the passphrase, AKMP + for specified ssid, if none specified then it will get all. + + Example: + iwpriv mlan0 passphrase "0;ssid=nxp" + + 2) "1;; + " - Passphrase and psk cannot be provided for the same SSID. + This command takes only one SSID at a time, If ssid= is present 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 ';' or '/' has to be used in an SSID then a '/' should be preceded + to ';' or '/' as a escape. + + Examples: + iwpriv mlan0 passphrase "1;ssid=nxpAP;passphrase=abcdefgd" + iwpriv mlan0 passphrase "1;ssid=nxp AP;psk=<64 bytes hexpsk>" + + If user wants to input the ssid as "nxp; AP" then command has to be + iwpriv mlan0 passphrase "1;ssid=nxp/; AP;passphrase=abcdefgh" + + If user wants to input the ssid as "//;" then command has to be + iwpriv mlan0 passphrase "1;ssid=/////;;passphrase=abcdefgh" + + 3) "2;" - This will clear the passphrase + for specified ssid, if none specified then it will clear all. + + Examples: + iwpriv mlan0 passphrase "2;ssid=nxp" + iwpriv mlan0 passphrase "2" : Clear all profiles and disable embedded supplicant + +httxcfg + This command is used to configure various 11n specific configuration + for transmit (such as Short GI, Channel BW and Green field support) + + where is + This is a bitmap and should be used as following + Bit 15-8: Reserved set to 0 + Bit 7: STBC enable/disable + Bit 6: Short GI in 40 Mhz enable/disable + Bit 5: Short GI in 20 Mhz enable/disable + Bit 4: Green field enable/disable + Bit 3-2: Reserved set to 1 + Bit 1: 20/40 Mhz enable disable. + Bit 0: LDPC enable/disable + + When Bit 1 is set then firmware could transmit in 20Mhz or 40Mhz based + on rate adaptation. When this bit is reset then firmware will only + transmit in 20Mhz. + + where is + - This is the band info for settings. + 0: Settings for both 2.4G and 5G bands + 1: Settings for 2.4G band + 2: Settings for 5G band + + Examples: + iwpriv mlanX httxcfg + This will display HT Tx configuration. + If the configurations for 2.4G and 5G are different, + the first value is for 2.4G and the second value is for 5G. + Otherwise, it will display a single value for both bands. + + iwpriv mlanX httxcfg 0x62 + This will enable 20/40 and Short GI but will disable Green field for 2.4G and 5G band. + + iwpriv mlanX httxcfg 0x30 1 + This will enable Short GI 20 Mhz and Green field for 2.4G band. + + The default value is 0x20 for 2.4G and 0x62 for 5G. + + Note:- If 20/40 MHz support is disabled in htcapinfo, device will not transmit + in 40 MHz even 20/40 MHz is enabled in httxcfg. + +htcapinfo + This command is used to configure some of parameters in HTCapInfo IE + (such as Short GI, Channel BW, and Green field support) + + where is + - This is a bitmap and should be used as following + Bit 29: Green field enable/disable + Bit 26: Rx STBC Support enable/disable. (As we support + single spatial stream only 1 bit is used for Rx STBC) + Bit 24: Short GI in 40 Mhz enable/disable + Bit 23: Short GI in 20 Mhz enable/disable + Bit 17: 20/40 Mhz enable disable. + Bit 8: Enable/disable 40Mhz Intolarent bit in ht capinfo. + 0 will reset this bit and 1 will set this bit in + htcapinfo attached in assoc request. + All others are reserved and should be set to 0. + + Setting of any other bits will return error. + + where is + - This is the band info for settings. + 0: Settings for both 2.4G and 5G bands + 1: Settings for 2.4G band + 2: Settings for 5G band + + Examples: + iwpriv mlanX htcapinfo + This will display HT capabilties information. + If the information for 2.4G and 5G is different, + the first value is for 2.4G and the second value is for 5G. + Otherwise, it will display a single value for both bands. + + iwpriv mlanX htcapinfo 0x1820000 + This will enable Short GI, Channel BW to 20/40 and disable Green field support for 2.4G and 5G band. + + iwpriv mlanX htcapinfo 0x800000 2 + This will enable Short GI, Channel BW to 20 only, No Rx STBC support and disable Green field support for 5G band. + + The default value is 0x4800000 for 2.4G and 0x5820000 for 5G. + + Note:- This command can be issued any time but it will only come to effect from + next association. (as HTCapInfo is sent only during Association). + +addbapara + This command can be used to update the default ADDBA parameters. + + where is + - This is the block ack timeout for ADDBA request. + 0 : Disable (recommended for throughput test) + 1 - 65535 : Block Ack Timeout in TU + + where is + - Window size for ADDBA request. (16 is recommended and default value) + + where is + - Window size for ADDBA response. (48 is recommended and 32 is default value) + (16 is recommended for IWNCOMM AP in WAPI throughput test) + + Current window size limit for Tx as well as Rx is 1023. + + where

is + - amsdu support for ADDBA request. (1 is default value) + 0: disable amsdu in ADDBA request + 1: enable amsdu in ADDBA request + + where is + - amsdu support for ADDBA response. (1 is default value) + 0: disable amsdu in ADDBA response + 1: enable amsdu in ADDBA response + + eg: + iwpriv mlanX addbapara - This command will get the current addba params + iwpriv mlanX addbapara 1000 64 8 0 0 - This will change the ADDBA timeout to (1000 * 1024) us, + txwinsize to 64 and rxwinsize to 8 and disable amdsu in ADDBA request/response. + + The default setting is 65535 16 32 1 1. + + In case the ADDBA timeout value is updated then a ADDBA is sent for all streams + to update the timeout value. + + In case txwinsize and/or rxwinsize is updated, the effect could only be seen on + next ADDBA request/response. The current streams will not be affected with this + change. + + In case of txamsdu/rxamsdu is updated, the effect could only be seen on + next ADDBA request/response. The current streams will not be affected with this + change. AMSDU in AMPDU stream will be enabled when AP support this feature + and AMSDU is enabled in aggrpriotbl. + +aggrpriotbl + This command is used set/get the priority table for AMPDU/AMSDU traffic per tid. + This command can also be used to disable AMPDU/AMSDU for a given tid. + In case of AMPDU this priority table will be used to setup block ack (to make + sure the highest priority tid always uses AMPDU as we have limited AMPDU streams) + + where ... + + - This is priority for Tid0 for AMPDU packet. A priority could be any + values between 0 - 7, 0xff to disable aggregation. + - This is priority for Tid0 for AMSDU packet. A priority could be any + values between 0 - 7, 0xff to disable aggregation. + + eg: + iwpriv mlanX aggrpriotbl - This command will get the current Priority table for AMPDU and AMSDU. + <2 2 0 0 1 1 3 3 4 4 5 5 255 255 255 255>. This is read as + <"Prio for AMPDU for Tid0" "Prio for AMSDU for Tid0" + "Prio for AMPDU for Tid1" "Prio for AMSDU for Tid1" and so on + iwpriv mlanX aggrpriotbl 2 2 0 0 1 1 3 3 4 4 5 5 255 255 255 255 - + This will set the priority table for AMPDU and AMSDU + Priority for Tid0/AMPDU = 2, Tid0/AMSDU = 2, Tid1/AMPDU = 0, Tid1/AMSDU = 0 + and so on. Aggregation for Tid6 and Tid7 are disabled. + Here higher the priority number, higher the priority (i.e. 7 + has higher priority than 6). Similarly for AMSDU. + iwpriv mlanX aggrpriotbl 0xff 2 0xff 0 0xff 1 0xff 3 0xff 4 0xff 5 0xff 0xff 0xff 0xff - This will disable + AMPDU for all the TIDs but will still keep AMSDU enabled to Tid0 to Tid5 + + The default setting is 2 255 0 255 1 255 3 255 4 255 5 255 255 255 255 255. + + A delBA should be seen in case a disable happens on a TID for which AMPDU stream + is currently setup. + + Note:- This command should only be issue in disconnected state. + +addbareject + This command is used set/get the addbareject table for all the TIDs. + This command can also be used to enable rejection of ADDBA requests for a given tid. + + where ... + + - This can be 0/1 for TidX. 1 enables rejection of ADDBA request for TidX and + 0 would accept any ADDBAs for TidX. + + eg: + iwpriv mlanX addbareject - This command will get the current table. + [0 0 0 0 0 0 0 0]. ADDBA would be accepted for all TIDs. This is the default state. + + iwpriv mlanX addbareject 0 0 1 1 0 0 0 0 - This command will accept ADDBA requests for + Tid [0,1,4,5,6,7] and reject ADDBA requests for Tid [2,3] + + iwpriv mlanX addbareject 1 1 1 1 1 1 1 1 - This will enable rejection of ADDBA requests for + all Tids. + + Note:- This command should only be issue in disconnected state. + +txbufcfg + This command can be used to get current buffer size. + + eg: + iwpriv mlanX txbufcfg - This will display the current buffer size. + + Note:- The actual tx buf size will depends on AP's capability and max transmit buffer size. + +amsduaggrctrl + This command could be used to enable/disable a feature where firmware gives feedback to driver + regarding the optimal AMSDU buffer size to use with the current rate. Firmware will use the + current rate to decide the buffer size we could transmit. The max buffer size will still be + limited by buffer size provided in txbufcfg. (i.e. if the txbufcfg is 4K, then we could only transmit + 4K/2K AMSDU packets, if the txbufcfg is 8K then we could transmit 8k/4k/2k based on current rate) + + If enabled AMSDU buffer size at various rates will be as follows + + 1. Legacy B/G rate. + No AMSDU aggregation. + + 2. BW20 HT Rate: + When TX rate goes down, + MCS 7, 6, 5, 4: + a 8K aggregation size (if TX buffer size is 8K) + b 4K aggregation size (if TX buffer size is 4K) + c 2K aggregation size (if TX buffer size is 2K) + + MCS 3, 2: + a 4K aggregation size (if TX buffer size is 8K/4K) + b 2K aggregation size (if TX buffer size is 2K) + + MCS 1, 0: + a No aggregation + + When TX rate goes up, + MCS 7, 6, 5: + a 8K aggregation size (if TX buffer size is 8K) + b 4K aggregation size (if TX buffer size is 4K) + c 2K aggregation size (if TX buffer size is 2K) + + MCS 4, 3: + a 4K aggregation size (if TX buffer size is 8K/4K) + b 2K aggregation size (if TX buffer size is 2K) + + MCS 2, 1, 0: + a No aggregation + + 3. BW40 HT Rate: + When TX rate goes down, + MCS 7, 6, 5, 4, 3, 2, 1: + a 8K aggregation size (if TX buffer size is 8K) + b 4K aggregation size (if TX buffer size is 4K) + c 2K aggregation size (if TX buffer size is 2K) + + MCS 0: + a No aggregation + + When TX rate goes up, + MCS 7, 6, 5, 4, 3: + a 8K aggregation size (if TX buffer size is 8K) + b 4K aggregation size (if TX buffer size is 4K) + c 2K aggregation size (if TX buffer size is 2K) + + MCS 2, 1, 0: + a No aggregation + + where is 0/1 (for disable/enable) + + eg: + iwpriv mlanx amsduaggrctrl 1 - Enable this feature + iwpriv mlanx amsduaggrctrl 0 - Disable this feature + iwpriv mlanx amsduaggrctrl - This will get the enable/disable flag + and the current AMSDU buffer size). The AMSDU buffer size returned is only + valid after association as before association there is no rate info. + + Note:- This command to enable/disable could be given anytime (before/after + association). This feature is enabled by default by the driver during + initialization. + +httxbfcap + This command is used to set/get the TX beamforming capabilities. + + Usage: + iwpriv mlanX httxbfcap [cap] + + where the parameters are, + cap: TX beamforming capabilities + Bit 0 : Implicit TX BF receiving capable + Bit 1 : RX staggered sounding capable + Bit 2 : TX staggered sounding capable + Bit 3 : RX NDP capable + Bit 4 : TX NDP capable + Bit 5 : Implicit TX BF capable + Bit 6-7 : Calibration + 0: - not supported + 1: - STA can respond to a calibration request using + the CSI Report, but cannot initiate calibration + 2: - reserved + 3: - STA can both initiate and respond to a calibration request + Bit 8 : Explicit CSI TX BF capable + Bit 9 : Explicit non-compressed steering capable + Bit 10 : Explicit compressed steering capable + Bit 11-12: Explicit TX BF CSI feedback + 0: - not supported + 1: - delayed feedback + 2: - immediate feedback + 3: - delayed and immediate feedback + Bit 13-14: Explicit non-compressed BF feedback capable + 0: - not supported + 1: - delayed feedback + 2: - immediate feedback + 3: - delayed and immediate feedback + Bit 15-16: Explicit compressed BF feedback capable + 0: - not supported + 1: - delayed feedback + 2: - immediate feedback + 3: - delayed and immediate feedback + Bit 17-18: Minimal grouping + 0: - no grouping (STA supports groups of 1) + 1: - groups of 1, 2 + 2: - groups of 1, 4 + 3: - groups of 1, 2, 4 + Bit 19-20: CSI number of beamformer antennas supported + 0: - single TX antenna sounding + 1: - 2 TX antenna sounding + 2: - 3 TX antenna sounding + 3: - 4 TX antenna sounding + Bit 21-22: Non-compressed steering number of beamformer antennas supported + 0: - single TX antenna sounding + 1: - 2 TX antenna sounding + 2: - 3 TX antenna sounding + 3: - 4 TX antenna sounding + Bit 23-24: Compressed steering number of beamformer antennas supported + 0: - single TX antenna sounding + 1: - 2 TX antenna sounding + 2: - 3 TX antenna sounding + 3: - 4 TX antenna sounding + Bit 25-26: CSI max number of rows beamformer supported + 0: - single row of CSI + 1: - 2 rows of CSI + 2: - 3 rows of CSI + 3: - 4 rows of CSI + Bit 27-28: Channel estimation capability + 0: - 1 space time stream + 1: - 2 space time streams + 2: - 3 space time streams + 3: - 4 space time streams + Bit 29-31: Reserved + + Examples: + iwpriv mlan0 httxbfcap : Get the current TX BF capabilities + iwpriv mlan0 httxbfcap 0x0000001F : Set the TX BF capabilities of the + Implicit TX BF receiving capable, + RX staggered sounding capable, + TX staggered sounding capable, + RX NDP capable and TX NDP capable + +httxbfcfg + This command is used to configure the TX beamforming options. + Note: Any new subcommand should be inserted in the second + argument and each argument of the sub command should be + separated by semicolon. For global configuration, the + arguments should be separated by space. + + Usage: + iwpriv mlanX httxbfcfg "[;GlobalData/tsData/interval/txPeerData/snrData]" + + where the parameters are, + action: TX beamforming action + 0: Control global parameters for beamforming + 1: Performs NDP Sounding for PEER + 2: TX BF interval in milliseconds + 3: Enable/Disable beamforming/sounding for a particular peer + 4: TX BF SNR Threshold for peer + .. + GlobalData: Global parameter arguments. + It contains beamforming enable, sounding enable, FB type, snr_threshold + sounding interval, Beamformig mode values seperated by space. + Syntax: + iwpriv mlanX httxbfcfg ; + + tsData: Trigger sounding for PEER specific arguments, + it contains PEER MAC and status + interval: TX BF interval in milliseconds + txPeerData: Enable/Disable beamforming/sounding for the indicated peer, + it contains PEER MAC, sounding, beamfoming options and FB type; + snrData: TX BF SNR Threshold for peer, it contains PEER MAC and SNR + + Examples: + iwpriv mlan0 httxbfcfg "0" : Get current global configuration parameter + iwpriv mlan0 httxbfcfg "2;00:50:43:20:BF:64" : Get the TX BF periodicity for a given peer + iwpriv mlan0 httxbfcfg "3" : Get the list of MAC addresses that have + beamforming and/or sounding enabled + iwpriv mlan0 httxbfcfg "4" : Get the list of PEER MAC, SNR tuples + programmed into the firmware. + iwpriv mlan0 httxbfcfg "0;0 0 3 10 500 5" : Disable beamforming, sounding, set FB type + to 3, snr threshold to 10, sounding interval + to 500 ms and beamforming mode to 5 + iwpriv mlan0 httxbfcfg "1;00:50:43:20:BF:64" : Perform NDP Trigger sounding to peer + 00:50:43:20:BF:64 + iwpriv mlan0 httxbfcfg "2;00:50:43:20:BF:64;500" : Set TX BF periodicity for peer 00:50:43:20:BF:64 + to 500 milliseconds + iwpriv mlan0 httxbfcfg "3;00:50:43:20:BF:43;1;0;3" : Enable beamforming, disable sounding and set + FB type to 3 for peer 00:50:43:20:BF:43 + iwpriv mlan0 httxbfcfg "4;00:50:43:20:BF:24;43" : Set TX BF SNR threshold to peer + 00:50:43:20:BF:24 with SNR 43 + +mgmtframectrl + This command is used to get/set mask for the management frames which needs to be forwarded to application layer. + + Usage: + iwpriv mlanX mgmtframectrl [m] + + where the parameter [m] is the bit mask of management frame reception. + Following are the bit definitions. + Bit 0 : Association Request + Bit 1 : Association Response + Bit 2 : Re-Association Request + Bit 3 : Re-Association Response + Bit 4 : Probe Request + Bit 5 : Probe Response + Bit 8 : Beacon Frames + + Examples: + iwpriv mlan0 mgmtframectrl : Get the current Mgmt Frame forwarding mask + iwpriv mlan0 mgmtframectrl 0x0020 : Bit 5 is set, Forward probe response + frames to application layer + +mpactrl + This command is used to set/get the Tx, Rx SDIO aggregation parameters. + Note: The parameters can be set only in disconnected state. + + Usage: + iwpriv mlanX mpactrl [tx_ena] [rx_ena] [tx_size] [rx_size] [tx_ports] [rx_ports] + + where the parameter are: + [tx_ena]: Enable/disable (1/0) Tx MP-A + [rx_ena]: Enable/disable (1/0) Rx MP-A + [tx_size]: Size of Tx MP-A buffer + [rx_size]: Size of Rx MP-A buffer + [tx_ports]: Max ports (1-16) for Tx MP-A + [rx_ports]: Max ports (1-16) for Rx MP-A + default values are 1 1 16384 32768 16 16 + The MP-A may be disabled by default at build time if the MMC driver byte mode patch + is not available in kernel. + + Examples: + iwpriv mlan0 mpactrl : Get MP aggregation parameters + iwpriv mlan0 mpactrl 0 0 + : Disable MP aggregation for Tx, Rx respectively + iwpriv mlan0 mpactrl 1 1 8192 8192 8 8 + : Enable MP aggregation for Tx, Rx + : Set Tx, Rx buffer size to 8192 bytes + : Set maximum Tx, Rx ports to 8 + +deepsleep + This command is used to set/get auto deep sleep mode. + + Usage: + iwpriv mlanX deepsleep [n] [m] + + where the parameters are: + [n]: Enable/disable auto deep sleep mode (1/0) + [m]: Idle time in milliseconds after which firmware will put the device + in deep sleep mode. Default value is 100 ms. + + Examples: + iwpriv mlan0 deepsleep : Display auto deep sleep mode + iwpriv mlan0 deepsleep 1 : Enable auto deep sleep mode, idle time unchanged + iwpriv mlan0 deepsleep 0 : Disable auto deep sleep mode + iwpriv mlan0 deepsleep 1 500 : Enable auto deep sleep mode with idle time 500 ms + Note: + Deepsleep must be disabled before changing idle time. + +usbsuspend + This command is used to put device to suspend mode. + Note: It's only valid on kernel 2.6.24 or later. + +usbresume + This command is used to resume the device from suspend mode. + Note: It's only valid on kernel 2.6.24 or later. + +hscfg + This command is used to configure the host sleep parameters. + + Usage: + iwpriv mlanX hscfg [condition [[GPIO# [gap]]]] + + This command takes one (condition), two (condition and GPIO#) or three + (condition, GPIO# and gap) parameters for set. If no parameter provided, + get is performed. + + where Condition is: + bit 0 = 1 -- broadcast data + bit 1 = 1 -- unicast data + bit 2 = 1 -- mac event + bit 3 = 1 -- multicast data + bit 6 = 1 -- Wakeup when mgmt frame received. + bit 7 = 1 -- Reserved + bit 8 = 1 -- Disable non maskable data wakeup. + + The host sleep mode will be canceled if condition is set to -1. The default is 0x7. + + where GPIO is the pin number of GPIO used to wakeup the host. It could be any valid + GPIO pin# (e.g. 0-7) or 0xff (interface, e.g. SDIO will be used instead). + The default is 0xff. + + where Gap is the gap in milliseconds between wakeup signal and wakeup event or 0xff + for special setting (host acknowledge required) when GPIO is used to wakeup host. + The default is 200. + + The host sleep set except for cancellation will be blocked if host sleep is + already activated. + + Please note hssetpara and usbsuspend/usbresume commands should be used for USB + host sleep related tests. + + Examples: + iwpriv mlan0 hscfg : Get current host sleep mode + iwpriv mlan0 hscfg -1 : Cancel host sleep mode + iwpriv mlan0 hscfg 3 : Broadcast and unicast data + Use GPIO and gap set previously + iwpriv mlan0 hscfg 2 3 : Unicast data + Use GPIO 3 and gap set previously + iwpriv mlan0 hscfg 2 1 0xa0 : Unicast data + Use GPIO 1 and gap 160 ms + iwpriv mlan0 hscfg 2 0xff : Unicast data + Use interface (e.g. SDIO) + Use gap set previously + iwpriv mlan0 hscfg 4 3 0xff : MAC event + Use GPIO 3 + Special host sleep mode + iwpriv mlan0 hscfg 1 0xff 0xff : Broadcast data + Use interface (e.g. SDIO) + Use gap 255ms + +hssetpara + This command is used to set host sleep parameters. + + Usage: + iwpriv mlanX hssetpara Condition [GPIO# [gap]] + + Note: + 1) The usages of parameters are the same as "hscfg" command. + 2) The parameters will be saved in the driver and be used when host suspends. + +deauth + This command is used to send a de-authentication to an arbitrary AP. + If [n] is omitted, the driver will deauth the associated AP. + If in ad-hoc mode this command is used to stop beacon transmission + from the station and go into idle state. + + When is supplied as a MAC address, the driver will deauth the + specified AP. If the AP address matches the driver's associated AP, + the driver will disconnect. Otherwise, the driver remains connected. + +radioctrl + This command is used to turn on/off the radio. + Note: The radio can be disabled only in disconnected state. + + where value of n is: + 0 -- Disable + 1 -- Enable + + Examples: + iwpriv mlan0 radioctrl 1 : Turn the radio on + iwpriv mlan0 radioctrl : Get radio status + +reassoctrl + This command is used to turn on/off re-association in driver. + + Usage: + iwpriv mlanX reassoctrl [n] + + Where value of n is: + 0 -- Disable + 1 -- Enable + + Examples: + iwpriv mlan0 reassoctrl : Get re-association status + iwpriv mlan0 reassoctrl 1 : Turn re-association on + +bandcfg + This command is used to set/get infra/ad-hoc band. + Note: This command is only available in disconnected state. + + Usage: + iwpriv mlanX bandcfg [l] [m] [n] + + where the parameters: + [l]: Infrastructure band + bit 0: B + bit 1: G + bit 2: A + bit 3: GN + bit 4: AN + + bit 5: AC 2.4G + bit 6: AC 5G + [m]: Ad-hoc start band + bit 0: B + bit 1: G + bit 2: A diff --git a/mxm_wifiex/wlan_src/README_MLAN b/mxm_wifiex/wlan_src/README_MLAN new file mode 100644 index 0000000..1fe737c --- /dev/null +++ b/mxm_wifiex/wlan_src/README_MLAN @@ -0,0 +1,3972 @@ +=============================================================================== + U S E R M A N U A L + + Copyright 2014-2020 NXP + + +1) FOR DRIVER BUILD + + Goto source code directory wlan_src/. + make [clean] build + The driver and utility binaries can be found in ../bin_xxxx directory. + The driver code supports Linux kernel from 2.6.32 to 5.5.2. + +2) FOR DRIVER INSTALL + + a) Copy firmware image to /lib/firmware/nxp/, copy wifi_mod_para.conf to /lib/firmware/nxp/. + b) Install WLAN driver + There are drv_mode, max_sta_bss, max_uap_bss etc. module parameters. + The bit settings of drv_mode are, + Bit 0 : STA + Bit 1 : uAP + Bit 2 : WIFIDIRECT + + max_sta_bss: Maximum number of STA BSS (default 1, max 1) + sta_name: Name of the STA interface (default: "mlan") + max_uap_bss: Maximum number of uAP BSS (default 1, max 1) + uap_name: Name of the uAP interface (default: "uap") + max_wfd_bss: Maximum number of WIFIDIRECT BSS (default 1, max 1) + wfd_name: Name of the WIFIDIRECT interface (default: "wfd") + max_vir_bss: Number of Virtual interfaces (default 0) + uap_oper_ctrl: uAP operation control when in-STA disconnect with ext-AP + 0: default do nothing, 2: uAP stops and restarts automatically + For example, to install multi-chip driver, + insmod mlan.ko + insmod moal.ko mod_para=nxp/wifi_mod_para.conf [drvdbg=0x7] + wifi_mod_para.conf is used to support multi-chips which has different load module parameters. It contains + the module parameters for different chips. + c) Uninstall WLAN driver, + ifconfig mlanX down + ifconfig uapX down + rmmod moal + rmmod mlan + + To load driver with MFG firmware file, use mfg_mode=1 when insmod WLAN driver and + specify MFG firmware name if needed. + + There are some other parameters for debugging purpose etc. Use modinfo to check details. + drvdbg= + dev_cap_mask= + mac_addr=xx:xx:xx:xx:xx:xx + auto_ds=0|1|2 + ps_mode=0|1|2 + max_tx_buf=2048|4096|8192 + pm_keep_power=1|0 + shutdown_hs=1|0 + cfg_11d=0|1|2 + dts_enable=0|1 + fw_name = + e.g. copy pcieuart9098_combo_v1.bin to firmware directory, fw_name=nxp/pcieuart9098_combo_v1.bin + fw_region + hw_test=0|1 + fw_serial=0|1 + req_fw_nowait=0|1 + SD8887: antcfg=0|1|2|0xffff + SD8897/SD8997: antcfg=0x11|0x13|0x33 + slew_rate: Slew Rate Control value = 0|1|2|3 (0 is the slowest slew rate and 03 has the highest slew rate (default)) + init_cfg= + e.g. copy init_cfg.conf to firmware directory, init_cfg=nxp/init_cfg.conf + cal_data_cfg= + e.g. copy cal_data.conf to firmware directory, cal_data_cfg=nxp/cal_data.conf + Note: Loading driver with 8887 must include correct cal_data_cfg parameter. + dpd_data_cfg= + e.g. copy dpd_data.conf to firmware directory, dpd_data_cfg=nxp/dpd_data.conf + txpwrlimit_cfg= + e.g. copy txpwrlimit_cfg_set.conf to firmware directory, txpwrlimit_cfg=nxp/txpwrlimit_cfg_set.conf + cntry_txpwr= + init_hostcmd_cfg= + e.g. copy init_hostcmd_cfg.conf to firmware directory, init_hostcmd_cfg=nxp/init_hostcmd_cfg.conf + band_steer_cfg= + e.g. generate bscfg.conf by band_steer_cfg.conf, then copy bscfg.conf to firmware directory, band_steer_cfg=nxp/bscfg.conf + sdio_rx_aggr=1|0 + cfg80211_wext= + Bit 0: STA WEXT + Bit 1: uAP WEXT + Bit 2: STA CFG80211 + Bit 3: uAP CFG80211 + reg_alpha2= + skip_fwdnld=0|1 + wq_sched_prio: Priority for work queue + wq_sched_policy: Scheduling policy for work queue + (0: SCHED_NORMAL, 1: SCHED_FIFO, 2: SCHED_RR, 3: SCHED_BATCH, 5: SCHED_IDLE) + Please note that, both wq_sched_prio and wq_sched_policy should be provided + as module parameters. If wq_sched_policy is (0, 3 or 5), then wq_sched_prio + must be 0. wq_sched_prio should be 1 to 99 otherwise. + rx_work=0|1|2 + pcie_int_mode=0|1|2 + pcie_int_mode=0|1 + aggrctrl=1|0 + usb_aggr=0|1|2 + low_power_mode_enable=0|1 + When low power mode is enabled, the output power will be clipped at ~+10dBm and the + expected PA current is expected to be in the 80-90 mA range for b/g/n modes + wakelock_timeout= + defined(SD9098)||defined(USB9098) || defined(PCIE9098) || defined(SD9097) || defined(USB9097)|| defined(PCIE9097)||defined(SD8978) + pmic=0|1 + indication_gpio=0xXY + hs_wake_interval= + disconnect_on_suspend=0|1 + hs_mimo_switch=0|1 + gtk_rekey_offload=0|1|2 + napi=0|1 + fixed_beacon_buffer=0|1 + GoAgeoutTime=0|x + multi_dtim=0|x + inact_tmo=0|x + uap_max_sta: Maximum number of STA for UAP/GO (default 0, max 64) + host_mlme=0|1 + country_ie_ignore=0|1 + beacon_hints=0|1 + + Note: On some platforms (e.g. PXA910/920) double quotation marks ("") need to used + for module parameters. + insmod sdxxx.ko " ..." + +3) FOR DRIVER PROC & DEBUG + + The following info are provided in /proc/net/mwlan/adapterX/mlanY|uapY|wfdY/info, + on kernel 2.6.24 or later, the entry is /proc/mwlan/adapterX/mlanY|uapY|wfdY/info. + + driver_name = "wlan" or "uap" + driver_version = + interface_name = "mlanX", "uapX" or "wfdX" + bss_mode = "Ad-hoc" | "Managed" | "Auto" | "Unknown" + media_state = "Disconnected" | "Connected" + mac_address = <6-byte adapter MAC address> + multicase_count = // Only for STA + essid = // Only for STA + bssid = // Only for STA + channel = // Only for STA + region_code = // Only for STA + multicast_address[n] = // Only for STA + num_tx_bytes = + num_rx_bytes = + num_tx_pkts = + num_rx_pkts = + num_tx_pkts_dropped = + num_rx_pkts_dropped = + num_tx_pkts_err = + num_rx_pkts_err = + carrier "on" | "off" + tx queue "stopped" | "started" + tkip_mic_failures = 0 // Only for uAP + ccmp_decrypt_errors = 0 // Only for uAP + wep_undecryptable_count = 0 // Only for uAP + wep_icv_error_count = 0 // Only for uAP + decrypt_failure_count = 0 // Only for uAP + mcast_tx_count = 0 // Only for uAP + failed_count = 0 // Only for uAP + retry_count = 0 // Only for uAP + multiple_retry_count = 0 // Only for uAP + frame_duplicate_count = 0 // Only for uAP + rts_success_count = 0 // Only for uAP + rts_failure_count = 0 // Only for uAP + ack_failure_count = 0 // Only for uAP + rx_fragment_count = 0 // Only for uAP + mcast_rx_frame_count = 0 // Only for uAP + fcs_error_count = 0 // Only for uAP + tx_frame_count = 0 // Only for uAP + rsna_tkip_cm_invoked = 0 // Only for uAP + rsna_4way_hshk_failures = 0 // Only for uAP + + The following debug info are provided in /proc/net/mwlan/adapterX/mlanY|uapY|wfdY/debug, + on kernel 2.6.24 or later, the entry is /proc/mwlan/adapterX/mlanY|uapY|wfdY/debug. + + drvdbg = + wmm_ac_vo = + wmm_ac_vi = + wmm_ac_be = + wmm_ac_bk = + max_tx_buf_size = + tx_buf_size = + curr_tx_buf_size = + ps_mode = <0/1, CAM mode/PS mode> + ps_state = <0/1/2/3, awake state/pre-sleep state/sleep-confirm state/sleep state> + is_deep_sleep = <0/1, not deep sleep state/deep sleep state> // Only for STA + wakeup_dev_req = <0/1, wakeup device not required/required> + wakeup_tries = + hs_configured = <0/1, host sleep not configured/configured> + hs_activated = <0/1, extended host sleep not activated/activated> + tx_pkts_queued = + pps_uapsd_mode = <0/1, PPS/UAPSD mode disabled/enabled> // Only for STA + sleep_pd = // Only for STA + qos_cfg = // Only for STA + tx_lock_flag = <0/1, Tx lock flag> // Only for STA + port_open = <0/1, port open flag> // Only for STA + scan_processing = <0/1, scan processing flag> // Only for STA + num_bridge_pkts = // Only for uAP + num_drop_pkts = // Only for uAP + num_tx_timeout = + num_cmd_timeout = + timeout_cmd_id = + timeout_cmd_act = + last_cmd_id = + last_cmd_act = + last_cmd_index = <0 based last command index> + last_cmd_resp_id = + last_cmd_resp_index = <0 based last command response index> + last_event = + last_event_index = <0 based last event index> + num_cmd_h2c_fail = + num_cmd_sleep_cfm_fail = + num_tx_h2c_fail = + num_cmdevt_c2h_fail = + num_rx_c2h_fail = + num_int_read_fail = + last_int_status = + num_evt_deauth = // Only for STA + num_evt_disassoc = // Only for STA + num_evt_link_lost = // Only for STA + num_cmd_deauth = // Only for STA + num_cmd_assoc_ok = // Only for STA + num_cmd_assoc_fail = // Only for STA + cmd_sent = <0/1, send command resources available/sending command to device> + data_sent = <0/1, send data resources available/sending data to device> + mp_rd_bitmap = + curr_rd_port = + mp_wr_bitmap = + curr_wr_port = + txbd_rdptr = + txbd_wrptr = + rxbd_rdptr = + rxbd_wrptr = + eventbd_rdptr = + eventbd_wrptr = + cmd_resp_received = <0/1, no cmd response to process/response received and yet to process> + event_received = <0/1, no event to process/event received and yet to process> + tx_cmd_urb_pending = + tx_data_urb_pending = + rx_cmd_urb_pending = + rx_data_urb_pending = + ioctl_pending = + tx_pending = + rx_pending = + lock_count = + malloc_count = + mbufalloc_count = + malloc_cons_count = + main_state = + sdiocmd53w = + sdiocmd53r = + hs_skip_count = + hs_force_count = + + Issue SDIO cmd52 read/write through proc. + Usage: + echo "sdcmd52rw= [data]" > /proc/mwlan/adapterX/config + where the parameters: + func: The function number to use (0-7) + reg: The address of the register + data: The value to write, read if the value is absent + For SDIO MMC driver, only function 0 and WLAN function access is allowed. + And there is a limitation for function 0 write, only vendor specific CCCR + registers (0xf0 -0xff) are permiited. + Examples: + echo "sdcmd52rw= 0 4" > /proc/mwlan/adapterX/config # read func 0 address 4 + cat /proc/mwlan/adapterX/config # display the register value + echo "sdcmd52rw= 1 3 0xf" > /proc/mwlan/adapterX/config # write 0xf to func 1 address 3 + + Issue debug_dump command through proc. + Usage: + echo "debug_dump" > /proc/mwlan/adapterX/config + + Examples: + echo "debug_dump" > /proc/mwlan/adapterX/config # dump driver internal debug status. + + Use dmesg or cat /var/log/debug to check driver debug messages. + To log driver debug messages to file, + a) Edit /etc/syslog.conf, add one line "*.debug /var/log/debug" + on kernel 2.6.24 or later, edit /etc/rsyslog.conf instead + b) touch /var/log/debug (if the file doesn't exist) + c) service syslog restart + on kernel 2.6.24 or later, service rsyslog restart + + Update /proc/sys/kernel/printk to change message log levels. + For example, + echo 6 > /proc/sys/kernel/printk (messages with a higher priority than 6 + will be printed to the console) + echo 15 > /proc/sys/kernel/printk (all messages will be printed to console) + +4) FOR FW RELOAD + a) Enable parallel firmware download in driver parameter + insmod sdxxx.ko fw_serial=0 + + b) default fw name for parallel firmware download + sd8887_wlan_a2.bin + + c) Trigger FW reload + echo "fw_reload=1" > /proc/mwlan/adapterX/config trigger inband firmware reset and reload firmware + echo "fw_reload=2" > /proc/mwlan/adapterX/config trigger firmware reload + echo "fw_reload=3" > /proc/mwlan/adapterX/config set firmware reload flag in driver. + echo "fw_reload=4" > /proc/mwlan/config trigger pcie FLR and reload firmware. + + (Note: This feature will be supported on Robin3 and KF2. + For CAC-A2, it only work with the board which supports parallel fw download) + + + +=============================================================================== + U S E R M A N U A L F O R MLANUTL + +NAME + mlanutl - configure the additional parameters available for NXP mdriver. + +SYNOPSIS + mlanutl -v + mlanutl [parameters] ... + + mlanutl mlanX 11dcfg + mlanutl mlanX 11dclrtbl + mlanutl mlanX addbapara [

] + mlanutl uapX addbapara [

] + mlanutl mlanX addbareject [ ... ] + mlanutl uapX addbareject [ ... ] + mlanutl mlanX addts + mlanutl mlanX aggrpriotbl [ ... ] + mlanutl uapX aggrpriotbl [ ... ] + mlanutl mlanX amsduaggrctrl + + mlanutl mlanX min_ba_threshold + mlanutl mlanX antcfg [m] [n] + mlanutl mlanX/uapX mimoswitch [tx_antmode] [rx_antmode] + mlanutl mlanX assocessid <"[essid]"> + mlanutl mlanX assocessid_bssid <"[bssid] [essid]"> + mlanutl mlanX associate " " + mlanutl mlanX get_chnrgpwr [save_region_channel_power_data_file] + mlanutl mlanX comparergpwr [target_file] + mlanutl mlanX get_txpwrlimit [raw_data_file] + mlanutl mlanX comparetrpc [display] + mlanutl mlanX getcfgchanlist + mlanutl mlanX authtype [n] + mlanutl uapX dfs_offload [n] + mlanutl mlanX cloud_keep_alive + mlanutl mlanX bandcfg [l] [m] [n] + mlanutl mlanX bcninterval [n] + mlanutl wfdX bssrole [l] + mlanutl mlanX cfgdata [] + mlanutl mlanX cfpcode [m] [n] + mlanutl mlanX changraph [ ] + mlanutl mlanX coex_rx_winsize [m] + mlanutl mlanX countrycode [l] + + mlanutl mlanX cfpinfo + mlanutl uapX cfpinfo + + mlanutl mlanX customie [[[] ] ] + mlanutl mlanX deauth [l] + mlanutl uapX deauth [l] + mlanutl mlanX deepsleep [l] [m] + mlanutl mlanX delba [ ] + mlanutl uapX delba [ ] + mlanutl mlanX delts + mlanutl mlanX dfstesting [ ] + mlanutl mlanX dfs_repeater [n] + mlanutl mlanX drvdbg [n] + mlanutl mlanX esuppmode [l] [m] [n] + mlanutl mlanX extcapcfg [] + mlanutl mlanX fwmacaddr [mac_addr] + mlanutl mlanX getdatarate + mlanutl uapX getdatarate + mlanutl mlanX getkey + mlanutl mlanX getlog + mlanutl mlanX getscantable [ARGS] + mlanutl mlanX getsignal [m] [n] + mlanutl mlanX signalextcfg [m] + mlanutl mlanX getsignalextv2 [m] + mlanutl mlanX getsignalext [m] + mlanutl mlanX dyn_bw [n] + mlanutl uapX getstalist + mlanutl uapX channel_switch + mlanutl mlanX hostcmd <11n_2040coex.conf> 2040coex + mlanutl mlanX hostcmd auto_tx_get + mlanutl mlanX hostcmd auto_tx_unreg + mlanutl mlanX hostcmd bgscfg + + mlanutl mlanX hostcmd coalesce_cfg + mlanutl mlanX hostcmd ed_mac_ctrl + mlanutl mlanX hostcmd crypto_test + mlanutl mlanX hostcmd nat_keep_alive + mlanutl mlanX hostcmd pad_cfg_get + mlanutl mlanX hostcmd pad_cfg_set + mlanutl mlanX hostcmd requesttpc + mlanutl mlanX hostcmd mode_get + mlanutl mlanX hostcmd mode_timeshare + mlanutl mlanX hostcmd mode_spatial + mlanutl mlanX hostcmd mode_none + mlanutl mlanX hostcmd gpio_cfg + mlanutl mlanX hostcmd generictime + mlanutl mlanX hostcmd a2dptime + mlanutl mlanX hostcmd inquirytim + mlanutl mlanX hostcmd ap_generictime + mlanutl mlanX hostcmd ap_a2dptime + mlanutl mlanX hostcmd ap_inquirytime + mlanutl mlanX hostcmd sdio_pulldown_disable + mlanutl mlanX hostcmd sdio_pulldown_get + mlanutl mlanX hostcmd sdio_pulldown_set + mlanutl mlanX hostcmd subevent_get + mlanutl mlanX hostcmd subevent_set + mlanutl mlanX hostcmd txpwrlimit_2g_cfg_set + mlanutl mlanX hostcmd txpwrlimit_5g_cfg_set + mlanutl mlanX hostcmd txpwrlimit_cfg_get + mlanutl mlanX hostcmd txrate_cfg_get + mlanutl mlanX hostcmd txrate_cfg_set_bg + mlanutl mlanX hostcmd txrate_cfg_set_bgn + mlanutl mlanX hostcmd generate_raw + mlanutl mlanX hostcmd fwdump + + mlanutl mlanX hostcmd stop_su + mlanutl mlanX hostcmd start_su + + mlanutl mlanX hotspotcfg [] + mlanutl mlanX hscfg [condition [[GPIO# [gap]]]] [ind_GPIO# [level]] + mlanutl mlanX hssetpara condition [GPIO# [gap]] [ind_GPIO# [level]] + mlanutl mlanX mgmtfilter + mlanutl mlanX auto_arp [n] + mlanutl mlanX htcapinfo [] [] + mlanutl mlanX htstreamcfg [n] + mlanutl mlanX httxbfcap [cap] + mlanutl mlanX httxbfcfg "[;GlobalData/tsData/interval/txPeerData/snrData]" + mlanutl mlanX httxcfg [] [] + mlanutl mlanX inactivityto [k] + mlanutl mlanX ipaddr [";"] + mlanutl mlanX linkstats + mlanutl mlanX listeninterval [l] + mlanutl mlanX macctrl [n] + mlanutl uapX macctrl [n] + mlanutl mlanX mefcfg + mlanutl mlanX memrdwr

[value] + mlanutl mlanX miracastcfg [l] [m] [n] + mlanutl mlanX mgmtframectrl [] + mlanutl uapX mgmtframectrl [] + mlanutl mlanX mgmtframetx + mlanutl mlanX mpactrl [tx_ena] [rx_ena] [tx_size] [rx_size] [tx_ports] [rx_ports] + mlanutl mlanX offchannel [ ] + mlanutl mlanX otpuserdata + mlanutl mlanX passphrase [l] + mlanutl mlanX pb_bypass [data_1, data_2, ... data_n] + mlanutl mlanX pcieregrw [value] + mlanutl mlanX pciebar0regrw [value] + mlanutl mlanX pmfcfg + mlanutl mlanX port_ctrl [n] + mlanutl mlanX powercons [n] + mlanutl mlanX pscfg [k] [d] [l] ... + mlanutl mlanX bcntimeoutcfg [l] [m] [o] [p] + mlanutl mlanX psmode [l] + + mlanutl robustcoex [Enable/Disable] [gpionum] [gpiopolarity] + mlanutl mlanX qconfig def [Queue Id: 0-3] + mlanutl mlanX qconfig get [Queue Id: 0-3] + mlanutl mlanX qconfig set msdu [Queue Id: 0-3] + mlanutl mlanX qoscfg + mlanutl mlanX qstatus + mlanutl mlanX radioctrl [n] + mlanutl mlanX rdeeprom + mlanutl mlanX reassoctrl [n] + mlanutl mlanX regioncode [n] + mlanutl mlanX regrdwr [value] + mlanutl mlanX rejectaddbareq [conditions] + mlanutl uapX rejectaddbareq [conditions] + mlanutl mlanX scancfg [t] [m] [p] [s] [a] [b] [c] [ext] [gap] + mlanutl mlanX sdcmd52rw
[data] + mlanutl mlanX sdcmd53rw
[data1] ... [dataN] + mlanutl mlanX sdioclock + mlanutl mlanX setuserscan [ARGS] + mlanutl mlanX cancelscan + mlanutl mlanX sleepparams [ ] + mlanutl mlanX sleeppd [n] + mlanutl mlanX sysclock [clk1] [clk2] [clk3] [clk4] + mlanutl mlanX tcpackenh [l] + mlanutl mlanX thermal + mlanutl mlanX ts_status + mlanutl mlanX tsf + mlanutl mlanX txbufcfg + mlanutl mlanX txratecfg [l] [m] [n] [o] + mlanutl uapX txratecfg [l] [m] [n] [o] + mlanutl mlanX aggrctrl [l] + mlanutl mlanX usbaggrctrl [l] [m] [n] [o] [p] [q] [r] [s] + mlanutl mlanX usbresume + mlanutl mlanX usbsuspend + mlanutl mlanX verext + mlanutl mlanX version + mlanutl mlanX vhtcfg [l] [m] [n] [o] + mlanutl uapX vhtcfg [l] [m] [n] [o] + mlanutl per_pkt_cfg [tx_rx_control] [type_num] [ether_type1 ether_type2 ...] [tx_rx_control] [type_num] [ether_type1 ether_type2 ...] + mlanutl dot11_txrx + mlanutl mlanX txrxhistogram [action] [tx_rx_statics] + mlanutl uapX txrxhistogram [action] [tx_rx_statics] + mlanutl mlanX wakeupreason + mlanutl uapX wakeupreason + mlanutl mlanX warmreset + mlanutl mlanX wpssession [n] + mlanutl mlanX wmmcfg [n] + mlanutl mlanX wmmparamcfg [AC_BE AIFSN ECW_MAX ECW_MIN TX_OP] + [AC_BK AIFSN ECW_MAX ECW_MIN TX_OP] + [AC_VI AIFSN ECW_MAX ECW_MIN TX_OP] + [AC_VO AIFSN ECW_MAX ECW_MIN TX_OP] + mlanutl mlanX wwscfg [m] + mlanutl p2pX cfg_noa [h] [i] [j] [k] [l] + mlanutl p2pX cfg_opp_ps [m] [n] + mlanutl mlanX get_sensor_temp + mlanutl indrstcfg [gpio_pin] + + + mlanutl uapX ctrldeauth + + mlanutl mlanX/uapX bootsleep <1/0> + + mlanutl mlanX ssu [mode] [ssu file] + + mlanutl mlanX dmcs [value] + + mlanutl mlanX 11axcfg [config/11axcfg.conf] + mlanutl mlanX 11axcmd + mlanutl rx_abort_cfg [enable] [rssi_threshold] + mlanutl rx_abort_cfg_ext [enable] [margin ceil_thresh] + mlanutl tx_ampdu_prot_mode [mode] + mlanutl rate_adapt_cfg [low_thresh high_thresh timer_interval] + mlanutl cck_desense_cfg [mode] [margin ceil_thresh] [num_on_intervals num_off_intervals] + mlanutl mlanX/uapX lpm [mode] + +DESCRIPTION + Those commands are used to send additional commands to the NXP MLAN + card via the Linux device driver. + + The mlanX parameter specifies the network device that is to be used to + perform this command on. It could be mlan0, mlan1 etc. + +11dcfg + This command is used to control 11D. No argument is used to get. + + where value of n is: + 0 -- Disable + 1 -- Enable + + Examples: + mlanutl mlan0 11dcfg 1 : Enable 11D + mlanutl mlan0 11dcfg : Get 11D status + +11dclrtbl + This command is used to clear the 11D channel table. + + Usage: + mlanutl mlanX 11dclrtbl + +addbapara + This command can be used to update the default ADDBA parameters. + + where is + - This is the block ack timeout for ADDBA request. + 0 : Disable (recommended for throughput test) + 1 - 65535 : Block Ack Timeout in TU + + where is + - Window size for ADDBA request. (16 is recommended and default value) + + where is + - Window size for ADDBA response. (48 is recommended and 32 is default value) + (16 is recommended for IWNCOMM AP in WAPI throughput test) + + Current window size limit for Tx as well as Rx is 1023. + + where

is + - amsdu support for ADDBA request. (1 is default value) + 0: disable amsdu in ADDBA request + 1: enable amsdu in ADDBA request + + where is + - amsdu support for ADDBA response. (1 is default value) + 0: disable amsdu in ADDBA response + 1: enable amsdu in ADDBA response + + eg: + mlanutl mlanX addbapara - This command will get the current addba params + mlanutl mlanX addbapara 1000 64 8 0 0 - This will change the ADDBA timeout to (1000 * 1024) us, + txwinsize to 64 and rxwinsize to 8 and disable amdsu in ADDBA request/response. + + The default setting is 65535 16 32 1 1. + + In case the ADDBA timeout value is updated then a ADDBA is sent for all streams + to update the timeout value. + + In case txwinsize and/or rxwinsize is updated, the effect could only be seen on + next ADDBA request/response. The current streams will not be affected with this + change. + + In case of txamsdu/rxamsdu is updated, the effect could only be seen on + next ADDBA request/response. The current streams will not be affected with this + change. AMSDU in AMPDU stream will be enabled when AP support this feature + and AMSDU is enabled in aggrpriotbl. + +addbareject + This command is used set/get the addbareject table for all the TIDs. + This command can also be used to enable rejection of ADDBA requests for a given tid. + + where ... + + - This can be 0/1 for TidX. 1 enables rejection of ADDBA request for TidX and + 0 would accept any ADDBAs for TidX. + + eg: + mlanutl mlanX addbareject - This command will get the current table. + [0 0 0 0 0 0 0 0]. ADDBA would be accepted for all TIDs. This is the default state. + + mlanutl mlanX addbareject 0 0 1 1 0 0 0 0 - This command will accept ADDBA requests for + Tid [0,1,4,5,6,7] and reject ADDBA requests for Tid [2,3] + + mlanutl mlanX addbareject 1 1 1 1 1 1 1 1 - This will enable rejection of ADDBA requests for + all Tids. + + Note:- This command should only be issue in disconnected state. + +addts + Send an ADDTS command to the associated AP. + + Process a given conf file for a specific TSPEC data block. Send the + TSPEC along with any other IEs to the driver/firmware for transmission + in an ADDTS request to the associated AP. + + Return the execution status of the command as well as the ADDTS response + from the AP if any. + + Usage: + mlanutl mlanX addts + +aggrpriotbl + This command is used set/get the priority table for AMPDU/AMSDU traffic per tid. + This command can also be used to disable AMPDU/AMSDU for a given tid. + In case of AMPDU this priority table will be used to setup block ack (to make + sure the highest priority tid always uses AMPDU as we have limited AMPDU streams) + + where ... + + - This is priority for Tid0 for AMPDU packet. A priority could be any + values between 0 - 7, 0xff to disable aggregation. + - This is priority for Tid0 for AMSDU packet. A priority could be any + values between 0 - 7, 0xff to disable aggregation. + + eg: + mlanutl mlanX aggrpriotbl - This command will get the current Priority table for AMPDU and AMSDU. + <2 2 0 0 1 1 3 3 4 4 5 5 255 255 255 255>. This is read as + <"Prio for AMPDU for Tid0" "Prio for AMSDU for Tid0" + "Prio for AMPDU for Tid1" "Prio for AMSDU for Tid1" and so on + mlanutl mlanX aggrpriotbl 2 2 0 0 1 1 3 3 4 4 5 5 255 255 255 255 - + This will set the priority table for AMPDU and AMSDU + Priority for Tid0/AMPDU = 2, Tid0/AMSDU = 2, Tid1/AMPDU = 0, Tid1/AMSDU = 0 + and so on. Aggregation for Tid6 and Tid7 are disabled. + Here higher the priority number, higher the priority (i.e. 7 + has higher priority than 6). Similarly for AMSDU. + mlanutl mlanX aggrpriotbl 0xff 2 0xff 0 0xff 1 0xff 3 0xff 4 0xff 5 0xff 0xff 0xff 0xff - This will disable + AMPDU for all the TIDs but will still keep AMSDU enabled to Tid0 to Tid5 + + The default setting is 2 255 0 255 1 255 3 255 4 255 5 255 255 255 255 255. + + A delBA should be seen in case a disable happens on a TID for which AMPDU stream + is currently setup. + + Note:- This command should only be issue in disconnected state. + +amsduaggrctrl + This command could be used to enable/disable a feature where firmware gives feedback to driver + regarding the optimal AMSDU buffer size to use with the current rate. Firmware will use the + current rate to decide the buffer size we could transmit. The max buffer size will still be + limited by buffer size provided in txbufcfg. (i.e. if the txbufcfg is 4K, then we could only transmit + 4K/2K AMSDU packets, if the txbufcfg is 8K then we could transmit 8k/4k/2k based on current rate) + + If enabled AMSDU buffer size at various rates will be as follows + + 1. Legacy B/G rate. + No AMSDU aggregation. + + 2. BW20 HT Rate: + When TX rate goes down, + MCS 7, 6, 5, 4: + a 8K aggregation size (if TX buffer size is 8K) + b 4K aggregation size (if TX buffer size is 4K) + c 2K aggregation size (if TX buffer size is 2K) + + MCS 3, 2: + a 4K aggregation size (if TX buffer size is 8K/4K) + b 2K aggregation size (if TX buffer size is 2K) + + MCS 1, 0: + a No aggregation + + When TX rate goes up, + MCS 7, 6, 5: + a 8K aggregation size (if TX buffer size is 8K) + b 4K aggregation size (if TX buffer size is 4K) + c 2K aggregation size (if TX buffer size is 2K) + + MCS 4, 3: + a 4K aggregation size (if TX buffer size is 8K/4K) + b 2K aggregation size (if TX buffer size is 2K) + + MCS 2, 1, 0: + a No aggregation + + 3. BW40 HT Rate: + When TX rate goes down, + MCS 7, 6, 5, 4, 3, 2, 1: + a 8K aggregation size (if TX buffer size is 8K) + b 4K aggregation size (if TX buffer size is 4K) + c 2K aggregation size (if TX buffer size is 2K) + + MCS 0: + a No aggregation + + When TX rate goes up, + MCS 7, 6, 5, 4, 3: + a 8K aggregation size (if TX buffer size is 8K) + b 4K aggregation size (if TX buffer size is 4K) + c 2K aggregation size (if TX buffer size is 2K) + + MCS 2, 1, 0: + a No aggregation + + where is 0/1 (for disable/enable) + + eg: + mlanutl mlan0 amsduaggrctrl 1 - Enable this feature + mlanutl mlan0 amsduaggrctrl 0 - Disable this feature + mlanutl mlan0 amsduaggrctrl - This will get the enable/disable flag + and the current AMSDU buffer size). The AMSDU buffer size returned is only + valid after association as before association there is no rate info. + + Note:- This command to enable/disable could be given anytime (before/after + association). This feature is enabled by default by the driver during + initialization. + +min_ba_threshold + This command is to set minimum Tx BA setup threshold + + Usage: + mlanutl mlanX min_ba_threshold + + where the parameters are: + : minimum BA Threshold :0-16 (default is 16) + Example: + mlanutl mlan0 min_ba_threshold : get min_ba_threshold value + mlanutl mlan0 min_ba_threshold 10 : set minimum BA threshold to 10 + +antcfg + This command is used to set/get the mode of Tx/Rx path. + + For chip which support STREAM_2X2 + where value of m is: + Bit 0 -- Tx Path A or Tx/Rx Path A if [n] is not provided + Bit 1 -- Tx Path B or Tx/Rx Path B if [n] is not provided + Bit 0-1 -- Tx Path A+B or Tx/Rx Path A+B if [n] is not provided + For 9097/9098, LOW BYTE for 2G setting + Bit 8 -- Tx Path A or Tx/Rx Path A if [n] is not provided + Bit 9 -- Tx Path B or Tx/Rx Path B if [n] is not provided + Bit 8-9 -- Tx Path A+B or Tx/Rx Path A+B if [n] is not provided + For 9097/9098, HIGH BYTE for 5G setting + where value of n is: + Bit 0 -- Rx Path A + Bit 1 -- Rx Path B + Bit 0-1 -- Rx Path A+B + For 9097/9098, LOW BYTE for 2G setting + Bit 8 -- Rx Path A + Bit 8 -- Rx Path B + Bit 8-9 -- Rx Path A+B + For 9097/9098, HIGH BYTE for 5G setting + The Tx path setting (m) is used for both Tx and Rx if Rx path (n) is not provided. + + Examples: + mlanutl mlan0 antcfg : Get Tx and Rx path + mlanutl mlan0 antcfg 3 : Set Tx and Rx path to A+B + mlanutl mlan0 antcfg 1 3 : Set Tx path to A and Rx path to A+B + mlanutl mlan0 antcfg 0x103 : Set Tx and Rx path to A+B on 2G and Tx and Rx path to A on 5G + mlanutl mlan0 antcfg 0x103 0x103 : Set Tx path to A+B and Rx path to A+B on 2G, and Tx and Rx path to A on 5G + + For chip which support SAD + where value of m is: + Bit 0 -- Tx/Rx antenna 1 + Bit 1 -- Tx/Rx antenna 2 + ... + 0xFFFF -- Tx/Rx antenna diversity + + where value of n is: + SAD evaluate time interval, only be provided when m = 0xFFFF, default value is 6s(0x1770) + + Examples: + mlanutl mlan0 antcfg : Get Tx/Rx antenna mode + mlanutl mlan0 antcfg 1 : Set Tx/Rx antenna 1 + mlanutl mlan0 antcfg 0xFFFF : Set Tx/Rx antenna diversity + mlanutl mlan0 antcfg 0xFFFF 0x1770 : Set antenna evaluate time interval to 6s +mimoswitch + This command is used to do MIMO switch for 11n and 11ac mode and is available for all interfaces. + mlanutl mlanX/uapX mimoswitch [tx_antmode] [rx_antmode] + + This command takes 2 conditions. + The supported options are: + tx_antmode: 1 - ANTENNA A + 2 - ANTENNA B + 3 - ANTENNA AB + rx_antmode: 1 - ANTENNA A + 2 - ANTENNA B + 3 - ANTENNA AB + Examples: + mlanutl mlan0/uap0 mimoswitch 1 1 : set Tx and Rx path to ANTENNA A + mlanutl mlna0/uap0 mimoswitch 2 2 : set Tx and Rx path to ANTENNA B + mlanutl mlan0/uap0 mimoswitch 3 3 : set Tx and Rx path to ANTENNA A+B + mlnautl mlan0/uap0 mimoswitch 1 3 : set Tx path to ANTENNA A and Rx path to ANTENNA A+B + +assocessid + This command is used to assoc essid with asynced mode, + and driver will auto retry if driver auto assoc enabled. + + Usage: + mlanutl mlanX assocessid <"[essid]"> + + Where + <"[essid]"> is the essid which need to be associated with asynced mode. + + Examples: + mlanutl mlan0 assocessid "NXP Micro AP" : Associate to the ESSID "NXP Micro AP" + +assocessid_bssid + This command is used to assoc AP by ssid/bssid pair with asynced mode, + and driver will auto retry if driver auto assoc enabled. + + Usage: + mlanutl mlanX assocessid_bssid <"[bssid] [essid]"> + + Where + <"[bssid]"> is the bssid which need to be associated with asynced mode. + <"[essid]"> is the essid which need to be associated with asynced mode. + + Examples: + mlanutl mlan0 assocessid_bssid "xx:xx:xx:xx:xx:xx NXP Micro AP" : Associate to the AP which ssid = "NXP Micro AP", bssid = "xx:xx:xx:xx:xx:xx" + +associate + Request an association to a given SSID/BSSID pair. This the only accurate + way to pick a specific AP and ESS for an association. The entry must + already exist in the scan table for the association to be attempted. + + mlanutl mlanX associate "xx:xx:xx:xx:xx:xx SSID" + +get_chnrgpwr + This command is used to get the txpwrlimit table in FW +Usage: + mlanutl mlanX get_chnrgpwr [save_region_channel_power_data_file] + driver will save fw raw data to this file. + + Examples: + mlanutl mlan0 get_chnrgpwr fw_region_pwr.bin : Get region channel power table and save to file fw_region_pwr.bin + +comparergpwr + This command is used to compare two regionpower tables and output differences. + + Usage : + mlanutl mlanX comparergpwr [target_file] + where: + : raw data file save from get_chnrgpwr command. + : uncompressed raw data file generated by powerutil from the excel input region power file + + Example : + mlanutl mlan0 comparergpwr uncompressed.bin fw_region_pwr.bin : Show power table comparison in text format + mlanutl mlan0 comparergpwr uncompressed.bin : Show power table of uncompressed file in text format +get_txpwrlimit + This command is used to get the txpwrlimit table in FW +Usage: + mlanutl mlanX get_txpwrlimit [raw_data_file] + where + 0: Get 2.4G txpwrlimit table + 0x10: Get 5G sub0 txpwrlimit table + 0x11: Get 5G sub1 txpwrlimit table + 0x12 Get 5G sub2 txpwrlimit table + 0x1f Get all 5G txpwrlimit table + 0xff Get both 2G and 5G txpwrlimit table + driver will save fw raw data to this file. + + Examples: + mlanutl mlan0 get_txpwrlimit 0 : Get 2G txpwrlimit table. + mlanutl mlan0 get_txpwrlimit 0x10 : Get 5G sub band0 txpwrlimit table + mlanutl mlan0 get_txpwrlimit 0xff txpwrlimit.bin : Get both 2G/5G txpwrlimit table and save to txpwrlimit.bin +comparetrpc + This command is used to compare two txpower tables and output differences. + + Usage : + mlanutl mlanX comparetrpc [display] + where: + : raw data file save from get_txpwrlimit command. + : raw data file used by driver load parameter "txpwrlimit_cfg" which will be download to FW during driver init. + : display comparison output + : 1 - text format + : 2 - table format + + Example : + mlanutl mlan0 comparetrpc txpwrlimit.bin txpwrlimit_init.bin 1 : Show power table comparison in text format + mlanutl mlan0 comparetrpc txpwrlimit.bin txpwrlimit_init.bin 2 : Show power table comparison in table format +getcfgchanlist + This command is used to get the channel list used by cfg80211 stack + + Example: + mlanutl mlan0 getcfgchanlist + + +authtype + This command is used to set/get authentication type. + + Usage: + mlanutl mlanX authtype [n] + + where + 0: 802.11 open system authentication + 1: 802.11 shared key authentication + 3: 802.11 WPA3 SAE authentication + 255: allow open system or shared key authentication (default) + + Examples: + mlanutl mlan0 authtype 0 : use open system authentication + mlanutl mlan0 authtype 1 : use shared key authentication + mlanutl mlan0 authtype 255 : allow open system or shared key authentication + mlanutl mlan0 authtype : get current setting + +dyn_bw + This command is used to set/get dynamic bandwidth. + + Usage: + mlanutl mlanX dyn_bw [n] + + where + [BIT0] + 0 = TxInfo Indicated BW Disable + 1 = TxInfo Indicated BW Enable + [BIT1] + 0 = TxInfo Dynamatic BW Disable + 1 = TxInfo Dynamatic BW Enable + [BIT2] + 0 = TxInfo Force send RTS Disable + 1 = TxInfo Force send RTS Enable + [BIT3] + 0 = Mac Dynamic BW Operation Mode Disable (Static BW Operation Mode) + 1 = Mac Dynamic BW Operation Mode Enable + other bits reserved. + + If no parameter provided, get is performed. + + Examples: + mlanutl mlan0 dyn_bw 0x1 : Enable TxInfo Indicated BW + mlanutl mlan0 dyn_bw : get current setting + +dfs_offload + This command is used to enable/disable DFS offload. The valid value is 0/1. + Note: The parameters can be set only in disconnected state. + + Usage: + mlanutl uapX dfs_offload [n] + + where + Enable/disable + + Examples: + mlanutl uap0 dfs_offload 1 : enable DFS offload + mlanutl uap0 dfs_offload 0 : disable DFS offload + +cloud_keep_alive + This command is used to start/stop send keep alive packet which set from host.And reset TCP connection. + + Usage: + mlanutl mlanX cloud_keep_alive + + where + start means set cloud keep alive packet and paramters to firmware. stop means stop firmware from sending keep alive packet.reset will stop and reset TCP connection when host resume. + + Examples: + mlanutl mlan0 cloud_keep_alive keep_alive.conf start + mlanutl mlan0 cloud_keep_alive keep_alive.conf stop + mlanutl mlan0 cloud_keep_alive keep_alive.conf reset + +bandcfg + This command is used to set/get infra/ad-hoc band. + Note: This command is only available in disconnected state. + + Usage: + mlanutl mlanX bandcfg [l] [m] [n] + + where the parameters: + [l]: Infrastructure band + bit 0: B + bit 1: G + bit 2: A + bit 3: GN + bit 4: AN + + bit 5: AC 2.4G + bit 6: AC 5G + bit 8: AX 2.4G + bit 9: AX 5G + [m]: Ad-hoc start band + bit 0: B + bit 1: G + bit 2: A + [n]: Ad-hoc start channel + Examples: + mlanutl mlan0 bandcfg : Get infra/ad-hoc band and ad-hoc + start channel configurations + mlanutl mlan0 bandcfg 1 : Set infra band to B only + mlanutl mlan0 bandcfg 3 2 6 : Set infra band to B/G, ad-hoc start band + to G and ad-hoc start channel to 6 + +bcninterval + This command is used to set/get the beacon interval in ad-hoc mode. + The valid beacon interval is between 20 - 1000, default beacon + interval is 100. + + Where + Beacon interval in TU (Time Unit: 1024 us). + + Examples: + mlanutl mlan0 bcninterval 200 : Set ad-hoc beacon interval to 200 + mlanutl mlan0 bcninterval : Get ad-hoc beacon interval + +bssrole + This command is used to set/get the BSS role. + + Where + [l] is + - This parameter specifies the BSS role to set. + 0 : STA + 1 : uAP + + Examples: + mlanutl wfd0 bssrole : Get the current BSS role + mlanutl wfd0 bssrole 1 : Set the current BSS role to uAP + +cfgdata + This command is used to set/get the configuration data to/from firmware. + + Usage: + mlanutl mlanX cfgdata [<.conf file name>] + + Where the parameters are: + type : + 2 -- CAL data download and <.conf file name> is cal_data.conf + .conf file name : The configuration file used to set/get the configuration data. + + Examples: + mlanutl mlan0 cfgdata 2 + : This command is used to get and display the CAL data from firmware. + +cfpcode + This command is used to set/get the Channel-Frequency-Power table codes. + The region table can be selected through region code. + The current configuration is returned if no parameter provided. + + where the parameters are, + [m]: code of the CFP table for 2.4GHz (0: unchanged) + [n]: code of the CFP table for 5GHz (0 or not provided: unchanged) + + Examples: + mlanutl mlan0 cfpcode : Get current configuration + mlanutl mlan0 cfpcode 0x30 : Set 2.4GHz CFP table code 0x30 (EU), + keep 5GHz table unchanged + mlanutl mlan0 cfpcode 0x10 5 : Set 2.4GHz CFP table code 0x10 (USA) + and 5GHz table code 5 + +changraph + Displays 2-dimensional graph, plotting channel number along x-axis and + anpi or channel-load along y-axis, depending on whether it is an anpi graph + or a channel load graph. + + Usage: + mlanutl mlanX changraph [ ] + where: + load: Only channel vs channel-load graph is displayed + anpi: Only channel vs Average Noise Power Indicator(ANPI) + graph is displayed + anpiload: Both the graphs for anpi and for the load are displayed + loops: This is used to calculate the number of times + the graph [load or anpi or both] will be printed + +coex_rx_winsize + This command is used to set/get control to coex RX window size + + where value of m is: + 0 -- Disable COEX RX winsize (default) + 1 -- Enable COEX RX winsize + + Examples: + mlanutl mlan0 coex_rx_winsize : Get COEX RX winsize + mlanutl mlan0 coex_rx_winsize 1 : Enable COEX RX winsize + +countrycode + This command is used to set and get the country code. + + Where + [l] is Country code + + Examples: + mlanutl mlan0 countrycode : Get current countrycode + mlanutl mlan0 countrycode CN : Set countrycode as China (CN) + +cfpinfo + This command is used to get region, country, environment codes, + channel and power table information from the FW. + + Examples: + mlanutl mlan0 cfpinfo : Display cfp tables + mlanutl uap0 cfpinfo + +customie + This command is used to set or get custom IEs for management frames. + + Usage: + mlanutl mlanX customie [[[] ] ] + + Where the parameter is: + empty - Get all IE settings + : 0 - Get/Set IE index 0 setting + 1 - Get/Set IE index 1 setting + 2 - Get/Set IE index 2 setting + MAX IE Index depends on device memory. + -1 - Append/Delete IE automatically + Delete will delete the IE from the matching IE buffer + Append will append the IE to the buffer with the same mask + : Management subtype mask value as per bit definitions + : Bit 0 - Association request + : Bit 1 - Association response + : Bit 2 - Reassociation request + : Bit 3 - Reassociation response + : Bit 4 - Probe request + : Bit 5 - Probe response + : Bit 8 - Beacon + : mask = 0 to clear the mask and the IE buffer + : IE Buffer in hex (max 256 bytes) + The Buffer should not be space separated. + + Examples: + mlanutl mlan0 customie + : Get IE buffer, subtype mask settings for all indices. + + mlanutl mlan0 customie 1 + : Get IE buffer and subtype mask for the Index = 1. + + mlanutl mlan0 customie 2 0 + : Clear IE buffer and mask value for Index = 2. + + mlanutl mlan0 customie 3 0x101 0xdd051234567890 + : Set IE buffer and mask value for Index = 3. + + mlanutl mlan0 customie -1 0x101 0xdd051234567890 + : Append the specified IEBuffer at index with mask value of 0x101. + + mlanutl mlan0 customie -1 0 0xdd051234567890 + : Delete the specified IEBuffer from all the IEs. + + mlanutl mlan0 customie 2 0 0xdd051234567890 + : Delete the specified IEBuffer from the IEs at index 2. + +deauth + This command is used to send a de-authentication to an arbitrary AP. + If [l] is omitted, the driver will deauth the associated AP. + If in ad-hoc mode this command is used to stop beacon transmission + from the station and go into idle state. + + When is supplied as a MAC address, the driver will deauth the + specified AP. If the AP address matches the driver's associated AP, + the driver will disconnect. Otherwise, the driver remains connected. + + When this command is executed on AP interface, it is used to send + a de-authentication to associated station. + +deepsleep + This command is used to set/get auto deep sleep mode. + + Usage: + mlanutl mlanX deepsleep [l] [m] + + where the parameters are: + [l]: Enable/disable auto deep sleep mode (1/0) + [m]: Idle time in milliseconds after which firmware will put the device + in deep sleep mode. Default value is 100 ms. + + Examples: + mlanutl mlan0 deepsleep : Display auto deep sleep mode + mlanutl mlan0 deepsleep 1 : Enable auto deep sleep mode, idle time unchanged + mlanutl mlan0 deepsleep 0 : Disable auto deep sleep mode + mlanutl mlan0 deepsleep 1 500 : Enable auto deep sleep mode with idle time 500 ms + Note: + Deepsleep must be disabled before changing idle time. + +delba + This command is used to delete either all Tx BA or all Rx BA or a specific BA stream + based on direction, TID and peer address. + + where [ ] + - This is the direction of BA stream, Tx (bit 0), Rx (bit 1). + - This is the TID (0-7, 0xff for all) of BA stream. + - This is the peer MAC addres of BA stream. + + eg: + mlanutl mlanX delba 2 - This command will delete all the Rx BA streams. + mlanutl mlanX delba 3 - This command will delete all the Tx and Rx BA streams. + mlanutl mlanX delba 1 0 - This command will delete all the Tx streams with TID 0. + mlanutl mlanX delba 2 0xff "00:11:22:33:44:55" - This command will delete all the Rx BA streams + with specified peer MAC address + mlanutl mlanX delba 1 3 "00:11:22:33:44:55" - This command will delete the Tx BA stream with + TID 3 and specified peer MAC address. + +delts + Send a DELTS command to the associated AP. + + Process a given conf file for a specific TSPEC data block. Send the + TSPEC along with any other IEs to the driver/firmware for transmission + in a DELTS request to the associated AP. + + Return the execution status of the command. There is no response to a + DELTS from the AP. + + Usage: + mlanutl mlanX delts + +dfstesting + This command is used to set/get settings for DFS testing. + + Usage: + mlanutl mlanX dfstesting [ ] + + where is user-configured Channel Availability Check in msec + 0 = disable, use default period (60000) + 1-65535 = enable with that period + where is user-configured Non-Occupancy Period in sec + 0 = disable, use default period (1800) + 1-65535 = enable with that period + where is enable/disable no channel change on radar + 0 = disable, 1 = enable (overrides below) + where is user-configured channel to change to on radar + 0 = disable, 1-255 = enable with that channel + (channel validity for region, etc. is not checked) + (only takes effect if no_chan_change = 0) + + Examples: + mlanutl mlan0 dfstesting : Get current dfstesting settings + mlanutl mlan0 dfstesting 2000 0 0 0 : user_cac=2sec, others disabled/default + mlanutl mlan0 dfstesting 0 0 1 0 : only no_chan_change enabled + mlanutl mlan0 dfstesting 0 120 0 64 : user_nop=2min, force chan 64 on radar + +dfs_repeater + This command is used to get/set DFS Repeater mode. + + Usage: + mlanutl mlan0 dfs_repeater + + where the parameter is : + null: to get current setting + 1: to enable dfs_repeater mode + 0: to disable dfs_repeater mode + + eg., + mlanutl mlan0 dfs_repeater :get current setting + mlanutl mlan0 dfs_repeater 1 :enable dfs repeater mode + mlanutl mlan0 dfs_repeater 0 :disable dfs repeater mode + +drvdbg + This command is used to set/get the bit masks of driver debug message control. + + Usage: + mlanutl mlanX drvdbg [n] + + Where the parameter is the generic debug message control bit mask. + The following types of driver debug messages can be dynamically enabled or + disabled by setting or clearing the corresponding bits, + bit 0: MMSG PRINTM(MMSG,...) + bit 1: MFATAL PRINTM(MFATAL,...) + bit 2: MERROR PRINTM(MERROR,...) + bit 3: MDATA PRINTM(MDATA,...) + bit 4: MCMND PRINTM(MCMND,...) + bit 5: MEVENT PRINTM(MEVENT,...) + bit 6: MINTR PRINTM(MINTR,...) + bit 7: MIOCTL PRINTM(MIOCTL,...) + ... + bit 16: MDAT_D PRINTM(MDAT_D,...), DBG_HEXDUMP(MDAT_D,...) + bit 17: MCMD_D PRINTM(MCMD_D,...), DBG_HEXDUMP(MCMD_D,...) + bit 18: MEVT_D PRINTM(MEVT_D,...), DBG_HEXDUMP(MEVT_D,...) + bit 19: MFW_D PRINTM(MFW_D,...), DBG_HEXDUMP(MFW_D,...) + bit 20: MIF_D PRINTM(MIF_D,...), DBG_HEXDUMP(MIF_D,...) + ... + bit 28: MENTRY PRINTM(MENTRY,...), ENTER(), LEAVE() + bit 29: MWARN PRINTM(MWARN,...) + bit 30: MINFO PRINTM(MINFO,...) + + If CONFIG_DEBUG=2, all kinds of debug messages can be configured. + + If CONFIG_DEBUG=1, all kinds of debug messages can be configured except + for MENTRY, MWARN and MINFO. By default MMSG, MFATAL and MERROR are enabled. + + Some special debug messages, + '*' // MLAN driver ISR is called (bit 6 MINTR enabled) + '|' // PS awake event is received (bit 5 MEVENT enabled) + '_' // PS sleep event is received (bit 5 MEVENT enabled) + '+' // PS sleep confirm is sent (bit 5 MEVENT enabled) + + Examples: + mlanutl mlan0 drvdbg : Get the current driver debug masks + mlanutl mlan0 drvdbg 0 : Disable all the debug messages + mlanutl mlan0 drvdbg 7 : Enable MMSG, MFATAL and MERROR messages + mlanutl mlan0 drvdbg 0x20037 : Enable MMSG, MFATAL, MEEROR, + MCMND, MEVENT and MCMD_D messages + mlanutl mlan0 drvdbg -1 : Enable all the debug messages + +esuppmode + This command is used to set/get the e-supplicant mode configurations/status. + + Note: The configurations can be set only before association. + For get, the configurations will be returned before association + and the current status will be returned after association. + + Where + [l] is + - This parameter specifies the RSN mode configuration + Bit 0 : No RSN + Bit 1-2 : RFU + Bit 3 : WPA + Bit 4 : WPA-NONE + Bit 5 : WPA2 + Bit 6-15 : RFU + [m] is + - This parameter specifies the pairwise cipher + Bit 0 : RFU + Bit 1 : RFU + Bit 2 : TKIP + Bit 3 : AES + Bit 4-7 : RFU + [n] is + - This parameter specifies the group cipher + Bit 0 : RFU + Bit 1 : RFU + Bit 2 : TKIP + Bit 3 : AES + Bit 4-7 : RFU + Note that: the RFU bits cannot be SET. + + Examples: + mlanutl mlan0 esuppmode : Get RSN mode and pairwise/group cipher + mlanutl mlan0 esuppmode 8 4 4 : Set RSN mode yo WPA, active pairwise and + group ciphers to TKIP + +extcapcfg + This command is used to set/get extended capabilities. + + Usage: + mlanutl mlanX extcapcfg [] + + where : Extended capabilities in hex (max 9 bytes) + The Buffer should not be space separated. + + Examples: + mlanutl mlan0 extcapcfg 0x0000008020 : Set TDLS support and Interworking bits. + +fwmacaddr + This command is used to set/get FW side MAC address but host side address will remain as earlier. + + Usage: + mlanutl mlanX fwmacaddr [mac_addr] + + where is desired MAC address + + Examples: + mlanutl mlan0 fwmacaddr : Get current FW MAC address + mlanutl mlan0 fwmacaddr 00:50:43:20:bc:44 : Set FW side MAC address + +getdatarate + This command is used to get the data rate being used in last Tx + packet and last Rx packet. + +getkey + This command is used to get PTK/GTK + mlanutl mlanX getkey + +getlog + This command is used to get the statistics available in the station. + Following stats are displayed:- + dot11MulticastTransmittedFrameCount Increments when the multicast bit is set in the destination + MAC address of a successfully transmitted MSDU + + dot11FailedCount Increments when an MSDU is not transmitted successfully + + dot11RetryCount Increments when an MSDU is successfully transmitted after one + or more retransmissions + + dot11MultipleRetryCount Increments when an MSDU is successfully transmitted after more + than one retransmission + + dot11FrameDuplicateCount Increments when a frame is received that the Sequence Control + field is indicating a duplicate count + + dot11RTSSuccessCount Increments when a CTS is received in response to an RTS + + dot11RTSFailureCount Increments when a CTS is not received in response to an RTS + + dot11ACKFaliureCount Increments when an ACK is not received when expected + + dot11ReceivedFragmentCount Increments for each successfully received MPDU of type Data or Management + + dot11MulticastReceivedFrameCount Increments when a MSDU is received with the multicast bit set in the destination MAC address + + dot11FCSErrorCount Increments when an FCS error is detected in a received MPDU + + dot11TransmittedFrameCount Increments for each successfully transmitted MSDU + + dot11WeplcvErrCnt Increment when WEP decryption error for key index 0.3 + + beaconReceivedCnt Increments when received beacon + + beaconMissedCnt Increments when beacon missed + + dot11TransmittedFrameCount Increments for each successfully transmitted MSDU + + dot11QosTransmittedFragmentCount Increments when a corresponding UP's MPDU transmitted successfully + + dot11QosFailedCount Increments when a corresponding UP's MSDU not transmitted successfully + + dot11QosRetryCount Increment when a corresponding UP's MSDU transmitted successfully after one or more retransmission + + dot11QosMultipleRetryCount Increments when a corresponding UP's MSDU is successfully transmitted after more than one retransmission + + dot11QosFrameDuplicateCount Increments when a corresponding UP's frame is received that the Sequence + Control field is indicating a duplicate frame + + dot11QosRTSSuccessCount Increments when a CTS is received in response to an RTS, which is sent for a corresponding UP's Qos frame + + dot11QosRTSFailureCount Increments when a CTS is not received in response to an RTS, which is sent for a corresponding UP's + Qos frame + + dot11QosACKFailureCount Increments when an ACK is not received when expected for a corresponding UP's Qos frame + + dot11QosReceivedFragmentCount Increments when a corresponding UP's MPDU received + + dot11QosTransmittedFrameCount Increments when a corresponding UP's MSDU transmitted + + dot11QosDiscardedFrameCount Increments when a corresponding UP's MSDU not transmitted successfully + + dot11QosMPDUsReceivedCount Increments when a corresponding UP's MDPU received + + + dot11QosRetriesReceivedCount Increments when a corresponding UP's MDPU received which retry bit is set + + dot11RSNAStatsCMACICVErrors Increment when a MPDU discard by CMAC integrity check + + dot11RSNAStatsCMACReplays Increments when a MPDU discarded by the CMAC replay error + + dot11RSNAStatsRobustMgmtCCMPReplays Increments when a robust management frame discarded by CCMP replay error + + dot11RSNAStatsTKIPICVErrors Increments when a MPDU discarded by TKIP ICV error + + dot11RSNAStatsTKIPReplays Increments when a MPDU discarded by TKIP replay error + + dot11RSNAStatsCCMPDecryptErrors Increments when a MPDU discarded by CCMP decryption error + + dot11RSNAStatsCCMPReplays Increments when a MPDU discarded by CCMP replay error + + dot11TransmittedAMSDUCount Increments when a A-MSDU transmitted successfully + + dot11FailedAMSDUCount Increments when a A-MSDU not transmitted successfully + + dot11RetryAMSDUCount Increments when a A-MSDU is successfully transmitted after one or more retransmissions + + dot11MultipleRetryAMSDUCount Increments when a A-MSDU is successfully transmitted after more than one retransmissions + + dot11TransmittedOctetsInAMSDUCount Increments by the number of octets in the frame body + of an A-MSDU frame when an A-MSDU frame is successfully transmitted + + dot11AMSDUAckFailureCount Increments when an acknowledgment to an A-MSDU is not received when expected. + + dot11ReceivedAMSDUCount Increments when a A-MSDU frame received + + dot11ReceivedOctetsInAMSDUCount Increments by the number of octets in the frame body + of an A-MSDU frame when an A-MSDU frame is received + + dot11TransmittedAMPDUCount Increments when an A-MPDU is transmitted + + dot11TransmittedMPDUsInAMPDUCount Increments by the number of MPDUs in the A-MPDU when an A-MPDU is transmitted + + dot11TransmittedOctetsInAMPDUCount Increments by the number of octets in the A-MPDU frame when an A-MPDU frame is transmitted + + dot11AMPDUReceivedCount Increments when the MAC receives an A-MPDU from the PHY + + dot11MPDUInReceivedAMPDUCount Increments by the number of MPDUs received in the + A-MPDU when an A-MPDU is received + + dot11ReceivedOctetsInAMPDUCount Increments by the number of octets in the A-MPDU + frame when an A-MPDU frame is received + + dot11AMPDUDelimiterCRCErrorCount Increments when an MPDU delimiter has a CRC error when this is the first + CRC error in the received A-MPDU or when the previous delimiter has been decoded correctly + +per_pkt_cfg +-------------- + mlanutl per_pkt_cfg [tx_rx_control] [type_num] [ether_type1 ether_type2...] [tx_rx_control] [type_num] [ether_type1 ether_type2 ...] + This command is used to set tx/rx per packet Txctl and Rxinfo configuration. + + The supported options are: + tx_rx_control : + 0 - disable Tx and Rx per packet control + 1 - enable Tx per packet control + 2 - enable Rx Per packet control + 3 - enable Tx and Rx Per packet control + + type_num : Number of ether_types which support per packet control, the Max is 8. + ether_type : Array of ether_types for which need to do per-packet Tx control or get per-packet Rx info. + + Examples: + mlanutl mlan0/uap0 per_pkt_cfg : get the configuration of per-packet control + mlanutl mlan0/uap0 per_pkt_cfg 0 : disable per-packet control + mlanutl mlan0/uap0 per_pkt_cfg 3 1 0x88dc : set the Tx and Rx per-packet control configuration + +dot11_txrx + This command is used to send or receive packets. + + Usage: + mlanutl dot11_txrx + interface : mlanX or uapX + options send : + conf_file : config file name + options recv : [ verbose_mode ] + protocol : packet protocol type + verbose_mode : v -- enter verbose mode + + Example: + mlanutl mlan0 dot11_txrx send config/tx_ctrl.conf : To send packets + mlanutl mlan0 dot11_txrx recv 0x88dc : To receive packets of type 0x88dc + mlanutl mlan0 dot11_txrx recv 0x88dc v : To receive packets of type 0x88dc and + enter verbose mode + +txrxhistogram +-------------- + mlanutl mlanX/uapX txrxhistogram [action] [tx_rx_statics] + This command is used to get tx/rx statics from firmware. + + This command takes 2 conditions. + The supported options are: + action : 0 - disable Tx/Rx statics + 1 - enable Tx/Rx statics + 2 - get Tx/Rx statics + tx_rx_statics: 1 - enable/disable/get Tx statics + 2 - enable/disable/get Rx statics + 3 - enable/disable/get Tx and Rx statics + Examples: + mlanutl mlan0/uap0 txrxhistogram 1 3 : enable Tx and Rx statics + mlanutl mlna0/uap0 txrxhistogram 0 3 : disable Tx and Rx statics + mlanutl mlan0/uap0 txrxhistogram 2 2 : Get only Rx statics + mlnautl mlan0/uap0 txrxhistogram 2 1 : Get only Tx statics + mlnautl mlan0/uap0 txrxhistogram 2 3 : Get both Tx/Rx statics + +getscantable + Display the current contents of the driver scan table + + Usage: + mlanutl mlanX getscantable + mlanutl mlanX getscantable [#] + mlanutl mlanX getscantable tsf + mlanutl mlanX getscantable ch + mlanutl mlanX getscantable help + + 1) Without argument, the entire scantable is displayed in terms of channel (ch), signal strength (ss), BSS id (bssid), capability (cap), and SSID, + where each column in the capability is described as follows: + column 1 indicates the IBSS capability: A (Adhoc), I (Infra) + column 2 indicates the encryption capability: P (WEP), W (WPA), 2 (WPA2) + column 3 indicates the 11D capability: D (11D) + column 4 indicates the WMM capability: W (WMM), C (CAC) + column 5 indicates the 11K capability: K (11K) + column 6 indicates the 11R capability: R (11R) + column 7 indicates the WPS capability: S (WPS) + column 8 indicates the 11N/11AC capability: N (11N), A (11AC) + + 2) Specifying a # will display detailed information about a specific scan + table entry. '0' displays driver cached information regarding the + current association (if any). + 3) The tsf argument will display the entire scan table with the recorded + TSF timestamp for the entry. + 4) The ch argument will display the entire scan table sorted by channel + number in the ascending order. If this argument is not specified, + scan table is sorted by signal strength in the descending order. + 6) The help argument will display the legend for the capability field. + +getsignal + This command gets the last and average value of RSSI, SNR and NF of + Beacon and Data. + Note: This command is available only when STA is connected. + + where value of m is: + 1 -- RSSI (Receive Signal Strength Indication) + 2 -- SNR (Signal to Noise Ratio) + 3 -- NF (Noise Floor) + where value of n is: + 1 -- Beacon last + 2 -- Beacon average + 3 -- Data last + 4 -- Data average + + Examples: + mlanutl mlan0 getsignal 1 : Get the RSSI info (beacon last, beacon + average, data last and data average) + mlanutl mlan0 getsignal 3 4 : Get the NF of data average + mlanutl mlan0 getsignal 2 1 : Get the SNR of beacon last + mlanutl mlan0 getsignal : Get all of the signal info + mlan0 getsignal:-32 -33 -35 -36 67 59 63 56 -99 -92 -98 -92 + RSSI info: beacon last -32, beacon average -33, data last -35, data average -36 + SNR info: beacon last 67, beacon average 59, data last 63, data average 56 + NF info: beacon last -99, beacon average -92, data last -98, data average -92 + +getsignalext + This command gets the last and average value of RSSI, SNR and NF of + Beacon and Data of spectific antenna path. + Note: This command is available only when STA is connected. + Driver will enable signalext and collect signal information for one second + + where value of m is: + 1 -- PATH A + 2 -- PATH B + 3 -- PATH A+B + + Examples: + mlanutl mlan0 getsignalext :Get All path's signal. + mlanutl maln0 getsignalext 3 :Get path A+B signal + mlanutl maln0 getsignalext 1 :Get path A signal + mlanutl mlan0 getsignalext 2 :Get path B signal + + PATH A: -46 -46 -49 -49 65 45 39 42 -111 -91 -88 -91 + + PATH A: RSSI info: beacon last -46, beacon average -46, data last -49, data average -49 + SNR info: beacon last 65, beacon average 45, data last 39, data average 42 + NF info: beacon last -111, beacon average -91, data last -88, data average -91 + +signalextcfg + This command is used to enable/disable signalext + Usage: + mlanutl mlanX signalextcfg [m] + where the value of [m] is: + 1 -- enable signalext in firmware + 0 -- disable signalext in firmware + Examples: + mlanutl mlan0 signalextcfg 1 : Enable signalext in firmware + mlanutl mlan0 signalextcfg 0 : Disable signalext in firmware + +getsignalextv2 + This command gets the last and average value of RSSI, SNR and NF of + Beacon and Data of spectific antenna path. + Note: This command is available only when STA is connected. + "mlanutl mlanX signalextcfg 1" command needs to be issued before issuing this command + + where value of m is: + 1 -- PATH A + 2 -- PATH B + 3 -- PATH A+B + + Examples: + mlanutl mlan0 getsignalextv2 :Get All path's signal. + mlanutl maln0 getsignalextv2 3 :Get path A+B signal + mlanutl maln0 getsignalextv2 1 :Get path A signal + mlanutl mlan0 getsignalextv2 2 :Get path B signal + + PATH A: -46 -46 -49 -49 65 45 39 42 -111 -91 -88 -91 + + PATH A: RSSI info: beacon last -46, beacon average -46, data last -49, data average -49 + SNR info: beacon last 65, beacon average 45, data last 39, data average 42 + NF info: beacon last -111, beacon average -91, data last -88, data average -91 + +getstalist + This command is used to get list of associated stations to the AP. + + Example: + mlanutl uap0 getstalist + +channel_switch + This command is used to do channel switch according to spec. + + Where the paramters are: + switch mode : 0 -- no need to block traffic, 1 -- need block traffic + oper class : operating class according to IEEE std802.11 spec, when 0 is used, only CSA IE will be used + new channel : the channel will switch to + switch count: channel switch time to send ECSA ie + bandwidth : channel width switch to(optional),only for 5G channels. + Support value 1 -- 40M above, 3 -- 40M below, 4 -- 80M, 5 -- 160M + + Example: + mlanutl uap0 channel_switch 1 115 36 10 :switch to channel 36, oper class 115 + mlanutl uap0 channel_switch 1 81 6 10 :switch to channel 6, oper class 81 + mlanutl uap0 channel_switch 1 0 6 10 :switch to channel 6 + mlanutl uap0 channel_switch 1 0 36 10 1 :switch to channel 36, bandwidth 40MHz above + +hostcmd 2040coex + This command is used to send the 11n 20/40 Coex command to firmware. + Firmware will send 11n 20/40 Coex management action frame to AP. + + Usage: + mlanutl mlanX hostcmd config/11n_2040coex.conf 2040coex + +hostcmd auto_tx_get +hostcmd auto_tx_unreg + This command is used to configures the Frame Auto Transmission parameters. + auto_tx_get: get auto_tx parameters + auto_tx_unreg: unregister to firmware auto_tx + + Usage: + mlanutl mlanX hostcmd config/auto_tx.conf auto_tx_get + mlanutl mlanX hostcmd config/auto_tx.conf auto_tx_unreg + +hostcmd bgscfg + This command is used to configure the various parameters for PPS/UAPSD + or normal background scan. + + Usage: + mlanutl mlanX hostcmd config/bg_scan.conf bgscfg + +hostcmd coalesce_cfg + This command is used to set/clear rules to filter and buffer + broadcast/multicast packet which reduce unwanted patcket or interrupt to + host. + + Usage: + mlanutl mlanX hostcmd coalesce_cfg + +hostcmd ed_mac_ctrl + This command is used to control ED MAC. + + Usage: + mlanutl mlanX hostcmd ed_mac_ctrl + +hostcmd crypto_test + This command is used to test the encryption/decryption API of the firmware. + + Usage: + mlanutl mlanX hostcmd config/crypto_test.conf crypto_test + +hostcmd nat_keep_alive + This command is used to configures the Frame Auto Transmission parameters. + nat_keep_alive: register to firmware for sending NAT Keep Alive packet + + Usage: + mlanutl mlanX hostcmd config/auto_tx.conf nat_keep_alive + +hostcmd pad_cfg_get +hostcmd pad_cfg_set + This command is used to set/get the configuration data for PAD OR. + + Usage: + mlanutl mlanX hostcmd config/pad_cfg.conf pad_cfg_get + mlanutl mlanX hostcmd config/pad_cfg.conf pad_cfg_set + +hostcmd requesttpc + This command is used to request 802.11H TPC info. + + Usage: + mlanutl mlanX hostcmd config/requesttpc.conf requesttpc + +hostcmd mode_get +hostcmd mode_timeshare +hostcmd mode_spatial +hostcmd mode_none + This command is used to get/set Robust BT Coex. + mode_get: get the current mode + mode_timeshare: set Robust BT Coex to timeshare mode (default on 1x1 chips) + mode_spatial: set Robust BT Coex to spatial mode (only for, and default on 2x2 chips) + mode_none: set Robust BT Coex to mode none (only for, and default on 2x2_3Antenna chips) + + Usage: + mlanutl mlanX hostcmd config/robust_btc.conf mode_get + mlanutl mlanX hostcmd config/robust_btc.conf mode_timeshare + mlanutl mlanX hostcmd config/robust_btc.conf mode_spatial + mlanutl mlanX hostcmd config/robust_btc.conf mode_none + +hostcmd gpio_cfg + This command is used to enable/disable GPIO cfg. + gpio_cfg: enable/disable GPIO cfg for external bt request (default is enable with High Polarity) + + Usage: + mlanutl mlanX hostcmd config/robust_btc.conf gpio_cfg +hostcmd generictime +hostcmd a2dptime +hostcmd inquirytime +hostcmd ap_generictime +hostcmd ap_a2dptime +hostcmd ap_inquirytime + This command is used to configure the time slice of COEX (only works in timeshare mode) + generictime: configure the Bttime and Wlantime in Station Generic case + a2dptime: configure the Bttime and Wlantime in Station A2DP case + inquirytime: configure the Bttime and Wlantime in Station Inquiry case + ap_generictime: configure the Bttime and Wlantime in Ap Generic case + ap_a2dptime: configure the Bttime and Wlantime in Ap A2DP case + ap_inquirytime: configure the Bttime and Wlantime in Ap Inquiry case + + Usage: + mlanutl mlanX hostcmd config/robust_btc.conf generictime + mlanutl mlanX hostcmd config/robust_btc.conf a2dptime + mlanutl mlanX hostcmd config/robust_btc.conf inquirytim + mlanutl mlanX hostcmd config/robust_btc.conf ap_generictime + mlanutl mlanX hostcmd config/robust_btc.conf ap_a2dptime + mlanutl mlanX hostcmd config/robust_btc.conf ap_inquirytime + +hostcmd sdio_pulldown_get +hostcmd sdio_pulldown_set +hostcmd sdio_pulldown_disable + This command is used to set/get the settings of pulling up and + pulling down of SDIO lines. + + Usage: + mlanutl mlanX hostcmd config/sdio_pulldown.conf sdio_pulldown_get + mlanutl mlanX hostcmd config/sdio_pulldown.conf sdio_pulldown_set + mlanutl mlanX hostcmd config/sdio_pulldown.conf sdio_pulldown_disable + +hostcmd subevent_get +hostcmd subevent_set + This command is used to get/set the configurations for event descriptor + interface command. + subsvent_get: get subscribed event parameters + subsvent_set: set subscribed event parameters + + Usage: + mlanutl mlanX hostcmd config/subevent.conf subevent_get + mlanutl mlanX hostcmd config/subevent.conf subevent_set + +hostcmd txpwrlimit_2g_cfg_set +hostcmd txpwrlimit_5g_cfg_set +hostcmd txpwrlimit_cfg_get + This command is used to set/get the configuration data of Tx power limitation. + Note: The configuration set should be issued when STA is disconnected. + + Usage: + mlanutl mlanX hostcmd config/txpwrlimit_cfg.conf txpwrlimit_cfg_get + mlanutl mlanX hostcmd config/txpwrlimit_cfg.conf txpwrlimit_2g_cfg_set + mlanutl mlanX hostcmd config/txpwrlimit_cfg.conf txpwrlimit_5g_cfg_set + +hostcmd txrate_cfg_get +hostcmd txrate_cfg_set_bg +hostcmd txrate_cfg_set_bgn + This command is used to set/get the transmit data rate. + + Usage: + mlanutl mlanX hostcmd config/txrate_cfg.conf txrate_cfg_get + mlanutl mlanX hostcmd config/txrate_cfg.conf txrate_cfg_set_bg + mlanutl mlanX hostcmd config/txrate_cfg.conf txrate_cfg_set_bgn + +hostcmd generate_raw + This command is used to generate the raw data(hostcommand block) for + hostcommand in and write that to file + + Usage: + mlanutl mlanX hostcmd generate_raw + +hostcmd fwdump + This command is used to trigger firmware dump + + Usage: + mlanutl mlanX hostcmd fwdump + +hostcmd stop_su +hostcmd start_su + This command is used to set/get 11ax related setting + stop_su: stop su + start_su: resume su + stop_forceRTS: stop force Tx RTS + start_forceRTS: start force Tx RTS + Usage: + mlanutl mlanX hostcmd config/debug.conf stop_su + mlanutl mlanX hostcmd config/debug.conf start_su + mlanutl mlanX hostcmd config/debug.conf stop_forceRTS + mlanutl mlanX hostcmd config/debug.conf start_forceRTS + +hotspotcfg + This command is used to get/set the HotSpot configuration. + + Usage: + mlanutl mlanX hotspotcfg [] + + Where the parameter is: + : configuration bitset + : Bit 31-10 - Reserved set to 0 + : Bit 9 - TDLS support indication enable/disable + : Bit 8 - Interworking indication enable/disable + : Bit 7-1 - Reserved set to 0 + : Bit 0 - HotSpot feature enable/disable + + Examples: + mlanutl mlan0 hotspotcfg : Get present remote address mode + mlanutl mlan0 hotspotcfg 0x301 : Turn on HotSpot2.0 and enable TDLS support and interworking indication + mlanutl mlan0 hotspotcfg 0 : Turn off HotSpot2.0 and disable TDLS support and interworking indication + +hscfg + This command is used to configure the host sleep parameters. + Please note hssetpara and usbsuspend/usbresume commands should be used for USB + host sleep related tests. + + Usage: + mlanutl mlanX hscfg [condition [[GPIO# [gap]]]] (optional)[type ind_GPIO# [level]] (optional)[type event_force_ignore event_use_ext_gap ext_gap [gpio_wave]] + + This command takes one (condition), two (condition and GPIO#) or three + (condition, GPIO# and gap). If more than three parameters, it can set different or multiple features indicating by type(this is optional): + + If type=1, it will set indication gpio and its level. And the parameter format will be (condition, GPIO#,gap and type,ind_GPIO#) or + (condition, GPIO#, gap, type, ind_GPIO# and level). + + If type=2, it will set extend hscfg wakup method. And the parameter format will be (condition, GPIO#, gap, type, force_ignore, + use_ext_gap, ext_gap [gpio_wave]). gpio_wave parameter is optional and default value is 0(falling edge). Each bit of + event_force_ignore and event_use_ext_gap will be defined to one same event, and set one same event(same bit) in those two + parameters is not allowed. Set bit(s) in event_force_ignore means the event(s) will be forced ignore in firmware silently. + Set bit(s) in event_use_ext_gap mean the event(s) will use extend gap to inform host. Not set means not handle. + + If type=3, it will set hs_wakeup_interval. + + If no parameter provided, get is performed. + + The usages of parameters for "hscfg" are the same as that for "hssetpara" command. + +hssetpara + This command is used to set host sleep parameters. + + Usage: + mlanutl mlanX hssetpara condition [GPIO# [gap]] (optional)[type ind_GPIO# [level]] (optional)[type event_force_ignore event_use_ext_gap ext_gap [gpio_wave]] (optional)[type hs_wakeup_interval] + + This command takes one (condition), two (condition and GPIO#) or three + (condition, GPIO# and gap).If more than three parameters, it can set different or multiple features indicating by type and + the detailed usage is the same as hscfg above. + + where Condition is: + bit 0 = 1 -- broadcast data + bit 1 = 1 -- unicast data + bit 2 = 1 -- mac event + bit 3 = 1 -- multicast data + bit 6 = 1 -- Wakeup when mgmt frame received. + Bit 31 = 1 -- Don't wakeup when IPV6 packet received. + + The host sleep mode will be canceled if condition is set to -1. The default is 0x7. + + where GPIO is the pin number of GPIO used to wakeup the host. It could be any valid + GPIO pin# (e.g. 0-7) or 0xff (interface, e.g. SDIO will be used instead). + The default is 0xff. + + where Gap is the gap in milliseconds between wakeup signal and wakeup event or 0xff + for special setting (host acknowledge required) when GPIO is used to wakeup host. + The default is 200. + + The host sleep set except for cancellation will be blocked if host sleep is + already activated. + + where ind_GPIO# is the pin number of GPIO used to indicate wakeup source. The level on + this GPIO will indicate normal wakeup source or abnormal wakeup source. + + where level is used to set level(0/1) on ind_GPIO# pin for indication normal wakeup source. + The opposite level will indicate abnormal wakeup source. The default value is 0. + + where event_force_ignore is a bitmap,each bit represent one wakeup reason event. Set the bit means this + wakeup reason should be force ignored in firmware. Reset the bit means do not handle this reason. + + where event_use_ext_gap is a bitmap, each bit represent one wakeup reason event. Set the bit means this + wakeup reason should use ext_gap to indicate host. Reset the bit means do not handle this reason. + + where event_force_ignore and event_use_ext_gap have the same wakeup reason event definition of each bit: + bit 0 = 1 --Disconnect + bit 1 = 1 --GTK/iGTK rekey failure + bit 2 = 1 --Eapol + other bits --Reserved + They should not set both for one same wakeup reason. + + where ext_gap is the extend gap based on third parameter Gap. Only valid when use_ext_gap is used. + The total gap is (Gap + (x+1)*ext_gap). x means the bit number(start from 0) of this reason in use_ext_gap. + + where gpio_wave is used to set GPIO wave level for hscfg extend. 0 means falling edge, 1 means rising edge. + This parameter is optional and default value is 0. + + where hs_wakeup_interval is used to set host sleep wakeup interval and the type must set to 3 to indicate + this feature. And the value will round to the nearest multiple dtim*beacon_interval in fw. The unit is milliseconds. + + Examples: + mlanutl mlan0 hssetpara -1 : Cancel host sleep mode + mlanutl mlan0 hssetpara 3 : Broadcast and unicast data + Use GPIO and gap set previously + mlanutl mlan0 hssetpara 2 3 : Unicast data + Use GPIO 3 and gap set previously + mlanutl mlan0 hssetpara 2 1 0xa0 : Unicast data + Use GPIO 1 and gap 160 ms + mlanutl mlan0 hssetpara 2 0xff : Unicast data + Use interface (e.g. SDIO) + Use gap set previously + mlanutl mlan0 hssetpara 4 3 0xff : MAC event + Use GPIO 3 + Special host sleep mode + mlanutl mlan0 hssetpara 1 0xff 0xff : Broadcast data + + mlanutl mlan0 hssetpara 2 1 0xa0 1 5 1 : Unicast data + Use GPIO 1 + Gap 160 ms + type=1 to set indication GPIO feature + Use GPIO 5 to indicate wakeup source + High level on GPIO 5 means this is a normal wakeup + mlanutl mlan0 hssetpara 2 1 0xa0 1 5 : Unicast data + Use GPIO 1 + Gap 160 ms + type=1 to set indication GPIO feature + Use GPIO 5 to indicate wakeup source + Use level set previously. + + mlanutl mlan0 hssetpara 2 1 0xa0 2 0 0x1 10 1: Unicast data + Use GPIO 1 + Gap 160 ms + type=2 to set extend hscfg feature + Force_ignore not used + Disconnect will use extend gap to indicate host + Use gap 170. + Rising edge + mlanutl mlan0 hssetpara 2 1 0xa0 2 0x1 0 0 0: Unicast data + Use GPIO 1 + Gap 160 ms + type=2 to set extend hscfg feature + Falling edge + Force ignore Disconnect + Extend gap not used + Not used. + Falling edge + mlanutl mlan0 hssetpara 2 1 0xa0 3 400: Unicast data + Use GPIO 1 + Gap 160 ms + type=3 to set hs_wakeup_interval feature + hs_wakeup_interval set to 400ms + + Note: The parameters will be saved in the driver and be used when host suspends. + The ind_GPIO# and level parameters only work with specific board and firmware. + +mgmtfilter + This command is used to set management frame to wake up host when host suspend. + + Usage: + mlanutl mlanX mgmtfilter + + where + This conf file will set management frame catagory, action and frame mask. + + Examples: + mlanutl mlan0 mgmtfilter mgmtfilter.conf + +auto_arp + This command is used to enable/disable auto arp response in host sleep mode. + No argument is used to get. + + where value of n is: + 0 -- Disable + 1 -- Enable + + Examples: + mlanutl mlan0 auto_arp 0 : Disable auto arp response from FW + mlanutl mlan0 auto_arp : Get auto arp configuration status + +htcapinfo + This command is used to configure some of parameters in HTCapInfo IE + (such as Short GI, Channel BW, and Green field support) + + where is + - This is a bitmap and should be used as following + Bit 29: Green field enable/disable + Bit 26: Rx STBC Support enable/disable. (As we support + single spatial stream only 1 bit is used for Rx STBC) + Bit 25: Tx STBC support enable/disable. + Bit 24: Short GI in 40 Mhz enable/disable + Bit 23: Short GI in 20 Mhz enable/disable + Bit 22: Rx LDPC enable/disable + Bit 17: 20/40 Mhz enable disable. + Bit 8: Enable/disable 40Mhz Intolarent bit in ht capinfo. + 0 will reset this bit and 1 will set this bit in + htcapinfo attached in assoc request. + All others are reserved and should be set to 0. + + Setting of any other bits will return error. + + where is + - This is the band info for settings. + 0: Settings for both 2.4G and 5G bands + 1: Settings for 2.4G band + 2: Settings for 5G band + + Example: + mlanutl mlanX htcapinfo + This will display HT capabilties information. + If the information for 2.4G and 5G is different, + the first value is for 2.4G and the second value is for 5G. + Otherwise, it will display a single value for both bands. + + mlanutl mlanX htcapinfo 0x1820000 + This will enable Short GI, Channel BW to 20/40 and disable Green field support for 2.4G and 5G band. + + mlanutl mlanX htcapinfo 0x800000 2 + This will enable Short GI, Channel BW to 20 only, No Rx STBC support and disable Green field support for 5G band. + + The default value is 0x4800000 for 2.4G and 0x5820000 for 5G. + + Note:- This command can be issued any time but it will only come to effect from + next association. (as HTCapInfo is sent only during Association). + +htstreamcfg + This command is used to set/get HT stream configuration. + The setting only takes effect in next association. + + Usage: + mlanutl mlanX htstreamcfg [n] + + where + 0x11: HT stream 1x1 mode + 0x22: HT stream 2x2 mode + + Examples: + mlanutl mlan0 htstreamcfg : Get current setting + mlanutl mlan0 htstreamcfg 0x11 : Set HT stream 1x1 mode + mlanutl mlan0 htstreamcfg 0x22 : Set HT stream 2x2 mode + +httxbfcap + This command is used to set/get the TX beamforming capabilities. + + Usage: + mlanutl mlanX httxbfcap [cap] + + where the parameters are, + cap: TX beamforming capabilities + Bit 0 : Implicit TX BF receiving capable + Bit 1 : RX staggered sounding capable + Bit 2 : TX staggered sounding capable + Bit 3 : RX NDP capable + Bit 4 : TX NDP capable + Bit 5 : Implicit TX BF capable + Bit 6-7 : Calibration + 0: - not supported + 1: - STA can respond to a calibration request using + the CSI Report, but cannot initiate calibration + 2: - reserved + 3: - STA can both initiate and respond to a calibration request + Bit 8 : Explicit CSI TX BF capable + Bit 9 : Explicit non-compressed steering capable + Bit 10 : Explicit compressed steering capable + Bit 11-12: Explicit TX BF CSI feedback + 0: - not supported + 1: - delayed feedback + 2: - immediate feedback + 3: - delayed and immediate feedback + Bit 13-14: Explicit non-compressed BF feedback capable + 0: - not supported + 1: - delayed feedback + 2: - immediate feedback + 3: - delayed and immediate feedback + Bit 15-16: Explicit compressed BF feedback capable + 0: - not supported + 1: - delayed feedback + 2: - immediate feedback + 3: - delayed and immediate feedback + Bit 17-18: Minimal grouping + 0: - no grouping (STA supports groups of 1) + 1: - groups of 1, 2 + 2: - groups of 1, 4 + 3: - groups of 1, 2, 4 + Bit 19-20: CSI number of beamformer antennas supported + 0: - single TX antenna sounding + 1: - 2 TX antenna sounding + 2: - 3 TX antenna sounding + 3: - 4 TX antenna sounding + Bit 21-22: Non-compressed steering number of beamformer antennas supported + 0: - single TX antenna sounding + 1: - 2 TX antenna sounding + 2: - 3 TX antenna sounding + 3: - 4 TX antenna sounding + Bit 23-24: Compressed steering number of beamformer antennas supported + 0: - single TX antenna sounding + 1: - 2 TX antenna sounding + 2: - 3 TX antenna sounding + 3: - 4 TX antenna sounding + Bit 25-26: CSI max number of rows beamformer supported + 0: - single row of CSI + 1: - 2 rows of CSI + 2: - 3 rows of CSI + 3: - 4 rows of CSI + Bit 27-28: Channel estimation capability + 0: - 1 space time stream + 1: - 2 space time streams + 2: - 3 space time streams + 3: - 4 space time streams + Bit 29-31: Reserved + + Examples: + mlanutl mlan0 httxbfcap : Get the current TX BF capabilities + mlanutl mlan0 httxbfcap 0x0000001F : Set the TX BF capabilities of the + Implicit TX BF receiving capable, + RX staggered sounding capable, + TX staggered sounding capable, + RX NDP capable and TX NDP capable + +httxbfcfg + This command is used to configure the TX beamforming options. + Note: Any new subcommand should be inserted in the second + argument and each argument of the sub command should be + separated by semicolon. For global configuration, the + arguments should be separated by space. + + Usage: + mlanutl mlanX httxbfcfg "[;GlobalData/tsData/interval/txPeerData/snrData/txSounding]" + + where the parameters are, + action: TX beamforming action + 0: Control global parameters for beamforming + 1: Performs NDP Sounding for PEER + 2: TX BF interval in milliseconds + 3: Enable/Disable beamforming/sounding for a particular peer + 4: TX BF SNR Threshold for peer + .. + GlobalData: Global parameter arguments. + It contains beamforming enable, sounding enable, FB type, snr_threshold + sounding interval, Beamformig mode values seperated by space. + Syntax: + mlanutl mlanX httxbfcfg ; + + tsData: Trigger sounding for PEER specific arguments, + it contains PEER MAC and status + interval: TX BF interval in milliseconds + txPeerData: Enable/Disable beamforming/sounding for the indicated peer, + it contains PEER MAC, sounding, beamfoming options and FB type; + snrData: TX BF SNR Threshold for peer, it contains PEER MAC and SNR + + Examples: + mlanutl mlan0 httxbfcfg "0" : Get current global configuration parameter + mlanutl mlan0 httxbfcfg "2;00:50:43:20:BF:64" : Get the TX BF periodicity for a given peer + mlanutl mlan0 httxbfcfg "3" : Get the list of MAC addresses that have + beamforming and/or sounding enabled + mlanutl mlan0 httxbfcfg "4" : Get the list of PEER MAC, SNR tuples + programmed into the firmware. + mlanutl mlan0 httxbfcfg "0;0 0 3 10 500 5" : Disable beamforming, sounding, set FB type + to 3, snr threshold to 10, sounding interval + to 500 ms and beamforming mode to 5 + mlanutl mlan0 httxbfcfg "1;00:50:43:20:BF:64" : Perform NDP Trigger sounding to peer + 00:50:43:20:BF:64 + mlanutl mlan0 httxbfcfg "2;00:50:43:20:BF:64;500" : Set TX BF periodicity for peer 00:50:43:20:BF:64 + to 500 milliseconds + mlanutl mlan0 httxbfcfg "3;00:50:43:20:BF:43;1;0;3" : Enable beamforming, disable sounding and set + FB type to 3 for peer 00:50:43:20:BF:43 + mlanutl mlan0 httxbfcfg "4;00:50:43:20:BF:24;43" : Set TX BF SNR threshold to peer + 00:50:43:20:BF:24 with SNR 43 + +httxcfg + This command is used to configure various 11n specific configuration + for transmit (such as Short GI, Channel BW and Green field support) + + where is + This is a bitmap and should be used as following + Bit 15-8: Reserved set to 0 + Bit 7: STBC enable/disable + Bit 6: Short GI in 40 Mhz enable/disable + Bit 5: Short GI in 20 Mhz enable/disable + Bit 4: Green field enable/disable + Bit 3-2: Reserved set to 1 + Bit 1: 20/40 Mhz enable disable. + Bit 0: LDPC enable/disable + + When Bit 1 is set then firmware could transmit in 20Mhz or 40Mhz based + on rate adaptation. When this bit is reset then firmware will only + transmit in 20Mhz. + + where is + - This is the band info for settings. + 0: Settings for both 2.4G and 5G bands + 1: Settings for 2.4G band + 2: Settings for 5G band + + Example: + mlanutl mlanX httxcfg + This will display HT Tx configuration for 2.4G and 5G band. + + mlanutl mlanX httxcfg 0x62 + This will enable 20/40 and Short GI but will disable Green field for 2.4G and 5G band. + + mlanutl mlanX httxcfg 0x30 1 + This will enable Short GI 20 Mhz and Green field for 2.4G band. + + The default value is 0x20 for 2.4G and 0x62 for 5G. + + Note:- If 20/40 MHz support is disabled in htcapinfo, device will not transmit + in 40 MHz even 20/40 MHz is enabled in httxcfg. + +inactivityto + This command is used to set/get the inactivity timeout value, which specifies + when WLAN device is put to sleep. + + Usage: + mlanutl mlanX inactivityto [k] + + where the parameter are: + : timeout unit in microseconds. + : Inactivity timeout for unicast data. + : Inactivity timeout for multicast data. + [k]: Inactivity timeout for new Rx traffic after PS notification to AP. + + Examples: + mlanutl mlan0 inactivityto : Get the timeout value + mlanutl mlan0 inactivityto 1000 2 3 : Set timeout unit to 1000 us (1 ms), + inactivity timeout for unicast data is 2 ms, + inactivity timeout for multicast data is 3 ms + +ipaddr + This command is used to set/get IP address. + + Usage: + mlanutl mlanX ipaddr [";"] + + where + 0: Remove the IP address + bit 1: Set IP address for auto broadcast ARP response + + Examples: + mlanutl mlan0 ipaddr : Get current settings + mlanutl mlan0 ipaddr "0" : Remove IP address + +linkstats + This command is used to get the link statistics from the firmware. + + Usage: + mlanutl mlanX linkstats + +listeninterval + This command is used to set/get listen interval in assoc request. + + Usage: + mlanutl mlanX listeninterval [l] + + where the parameter: + [l]: Value of listen interval [Default 10] + + Examples: + mlanutl mlan0 listeninterval : Display Listen interval + mlanutl mlan0 listeninterval 1 : Set Listen interval to 1. + +macctrl + This command is used to set/get MAC control. + It's recommended to read the current setting first to avoid override issue. + + Usage: + mlanutl mlanX macctrl [n] + + where + bit 0: Rx enabled + bit 1: Directed Filter enabled + bit 2: LoopBack enabled + bit 3: WEP enabled + bit 4: EthernetII enabled + bit 5: MultiCast enabled + bit 6: BroadCast enabled + bit 7: Promiscuous enabled + bit 8: All MultiCast enabled + bit 9: RTS/CTS enabled (0: CTS to self) + bit 10: Enforce Protection enabled + bit 11: Force 11N Protection enabled + bit 12: Rx 802.11 Packets enabled + bit 13: Ad-hoc g Protection enabled + bit 14: Reserved + bit 15: WEP Type + bit 16: BandWidth Indication in RTS enabled + bit 17: Dynamic BandWidth Indication Mode in RTS enabled + bit 18-31: Reserved + + Examples: + mlanutl mlan0 macctrl : Get current MAC control + mlanutl mlan0 macctrl 0x13 : Set Rx enabled and Directed Filter enabled and EthernetII enabled + mlanutl mlan0 macctrl 0x813 : Set Rx enabled and Directed Filter enabled and EthernetII enabled + Force 11N Protection enabled + +mefcfg + This command is used to set MEF settings. + + Usage: + mlanutl mlanX mefcfg + + Where the parameter is: + mef.conf : The configuration file specifying the MEF settings. + + Example: + mlanutl mlan0 mefcfg config/mef.conf + +memrdwr + This command is used to read/write the adapter memory. + + Usage: + mlanutl mlanX memrdwr

[value] + + where the parameters are, +
: memory address + [value]: value to be written + + Examples: + mlanutl mlan0 memrdwr 0x4cf70 : Read memory address 0x4cf70 + mlanutl mlan0 memrdwr 0x80000000 0xffffffff + : Write 0xffffffff to memory address 0x80000000 + +miracastcfg + This command is used to set/get the miracast configuration. + + Usage: + mlanutl mlanX miracastcfg [l] [m] [n] + + where the parameters are, + [l]: miracast mode + 0: Disable + 1: Source + 2: Sink + [m]: scan time per channel, in ms + [n]: gap during two scans, in ms + + Examples: + mlanutl mlan0 miracastcfg : Get miracast configuration + mlanutl mlan0 miracastcfg 0 : Disable miracast configuration + mlanutl mlan0 miracastcfg 1 20 40 : Set miracast mode as source, with scan time + 20ms per channel and gap during two scans 40ms + +mgmtframectrl + This command is used to set/get registered frame type to passthrough. + + Usage: + mlanutl mlanX mgmtframectrl [] + mlanutl uapX mgmtframectrl [] + + Where the parameter is: + : the bit mask of management frame reception. + : Bit 0 - Association Request + : Bit 1 - Association Response + : Bit 2 - Re-Association Request + : Bit 3 - Re-Association Response + : Bit 4 - Probe Request + : Bit 5 - Probe Response + : Bit 8 - Beacon Frames + : Bit 13 - Action Frames + + Examples: + mlanutl mlan0 mgmtframectrl : Get present mask + mlanutl mlan0 mgmtframectrl 0x0020 : Bit 5 is set, Forward probe response frames to application layer + +mgmtframetx + This command is used to send management frame. + + Usage: + mlanutl mlanX mgmtframetx + + Where the parameter is: + mgmt_frame.conf : The configuration file contains the management frame. + + Examples: + mlanutl mlan0 mgmtframetx config/mgmt_frame.conf + +mpactrl + This command is used to set/get the Tx, Rx SDIO aggregation parameters. + Note: The parameters can be set only in disconnected state. + + Usage: + mlanutl mlanX mpactrl [tx_ena] [rx_ena] [tx_size] [rx_size] [tx_ports] [rx_ports] + + where the parameter are: + [tx_ena]: Enable/disable (1/0) Tx MP-A + [rx_ena]: Enable/disable (1/0) Rx MP-A + [tx_size]: Size of Tx MP-A buffer + [rx_size]: Size of Rx MP-A buffer + [tx_ports]: Max ports (1-16) for Tx MP-A + [rx_ports]: Max ports (1-16) for Rx MP-A + default values are 1 1 16384 32768 16 16 + The MP-A may be disabled by default at build time if the MMC driver byte mode patch + is not available in kernel. + + Examples: + mlanutl mlan0 mpactrl : Get MP aggregation parameters + mlanutl mlan0 mpactrl 0 0 + : Disable MP aggregation for Tx, Rx respectively + mlanutl mlan0 mpactrl 1 1 8192 8192 8 8 + : Enable MP aggregation for Tx, Rx + : Set Tx, Rx buffer size to 8192 bytes + : Set maximum Tx, Rx ports to 8 + +offchannel + This command is used to set/cancel the offchannel configuration. + Note: This command only can be used when cfg80211 is enabled during load time. + + Usage: + mlanutl mlanX offchannel [ ] + + where + + 0 : Cancel the offchannel configuration + 1 : Set the offchannel configuration + + The channel to configure + + The duration for which to configure + : channel bandwidth + 0 - Bandwidth 20Mhz + 1 - HT Bandwidth 40Mhz sec channel above + 3 - HT Bandwidth 40Mhz sec channel below + 4 - VHT Bandwidth 80Mhz + + Examples: + mlanutl mlan0 offchannel : Get current offchannel status. + mlanutl mlan0 offchannel 0 : Cancel the offchannel configuration. + mlanutl mlan0 offchannel 1 3 5 : Configure channel 3 for 5 milliseconds. + mlanutl mlan0 offchannel 1 36 5000 : Configure channel 36 for 5000 milliseconds. + mlanutl mlan0 offchannel 1 64 500 4 : Configure channel 64 in 80MHz for 500 milliseconds. + +otpuserdata + This command is used to get the OTP user data. + + Where + is + - This parameter specifies the length of OTP user data to be read + + Examples: + mlanutl mlan0 otpuserdata 10 : Get the 10-byte OTP user data + +passphrase + This command is used to set/get passphrase for WPA-PSK/WPA2-PSK/WPA3-SAE mode. + + Where + ASCII string for ssid/passphrase/psk/sae_password. + + Setting psk for WPA3 SAE protocol is not possible, as new psk gets generated + everytime in protocol flow. + + 1) "0;" - This will get the passphrase, AKMP + for specified ssid, if none specified then it will get all. + + Example: + mlanutl mlan0 passphrase "0;ssid=nxp" + + 2) "1;; + " - Passphrase and psk cannot be provided for the same SSID. + This command takes only one SSID at a time, If ssid= is present 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 ';' or '/' has to be used in an SSID then a '/' should be preceded + to ';' or '/' as a escape. + + Examples: + mlanutl mlan0 passphrase "1;ssid=nxpAP;passphrase=abcdefgd" + mlanutl mlan0 passphrase "1;ssid=nxp AP;psk=<64 bytes hexpsk>" + + If user wants to input the ssid as "nxp; AP" then command has to be + mlanutl mlan0 passphrase "1;ssid=nxp/; AP;passphrase=abcdefgh" + + If user wants to input the ssid as "//;" then command has to be + mlanutl mlan0 passphrase "1;ssid=/////;;passphrase=abcdefgh" + + 3) "2;" - This will clear the passphrase + for specified ssid, if none specified then it will clear all. + + Examples: + mlanutl mlan0 passphrase "2;ssid=nxp" + mlanutl mlan0 passphrase "2" : Clear all profiles and disable embedded supplicant + + 4)"1;ssid=;sae_password=" This will set WPA3 SAE ssid & password. sae_password should be within the range of 8 to 255 char. + Examples: + mlanutl mlan0 passphrase "1;ssid=nxp;sae_password=1234567890" + +pb_bypass + This command is used to get the By-passed TX packet from upper layer. + + Usage: + + mlanutl mlanX pb_bypass [data_1, data_2, ... data_n] + + where value of data_1, data_2, ... data_n isBypass TX Data + +pcieregrw + This command is used to read/write PCIE register. + + Usage: + mlanutl mlanX pcieregrw [value] + + where the parameters are, + : The offset of PCIE register + [value]: The value to write + + Examples: + mlanutl mlan0 pcieregrw 0x48 : Read PCIE register 0x48 + mlanutl mlan0 pcieregrw 0x44 8 : Write 8 to PCIE register 0x44 + +pciebar0regrw + This command is used to read/write PCIE register/memory from BAR0. + + Usage: + mlanutl mlanX pciebar0regrw [value] + + where the parameters are, + : The offset of PCIE register + [value]: The value to write + + Examples: + mlanutl mlan0 pciebar0regrw 0x48 : Read PCIE register 0x48 + mlanutl mlan0 pciebar0regrw 0x44 8 : Write 8 to PCIE register 0x44 + +pmfcfg + This command is used to set/get management frame protection parameters. + + Usage: + mlanutl mlanX pmfcfg + + where + : Management Frame Protection Capable (MFPC) + 1: Management Frame Protection Capable + 0: Management Frame Protection not Capable + : Management Frame Protection Required (MFPR) + 1: Management Frame Protection Required + 0: Management Frame Protection Optional + Default setting is PMF not capable. + m = 0, n = 1 is an invalid combination + + Examples: + mlanutl mlan0 pmfcfg : Get PMF parameters + mlanutl mlan0 pmfcfg 1 0 : Set MFPC and make MFPR optional + +port_ctrl + This command is used to Set/Get Port Control mode. No argument is used to get. + + where value of n is: + 0 -- Disable + 1 -- Enable + + Examples: + mlanutl mlan0 port_ctrl 1 : Enable Port Control mode + mlanutl mlan0 port_ctrl : Get Port Control mode status + +powercons + This command is used to set the local transmit power constraint. + Value is in dbm unit. This command is only used for ad-hoc start. + + Usage: + mlanutl mlanX powercons [n] + + Examples: + mlanutl mlanX powercons : get the current setting + mlanutl mlanX powercons 12 : set local power constraint to 12 dbm + +pscfg + This command is used to set/get PS configuration parameters. + + Usage: + mlanutl mlanX pscfg [k] [d] [l] ... + + Where the parameters: + [k]: Keep alive null packet interval (0: Unchanged, -1: Disable, n: Interval in seconds) + [d]: DTIM interval ( 0: Unchanged, + 1-5: Value, + 65534: DTIM will be ignored, listen interval will be used, + 65533: Closest DTIM to the listen interval period will be used ) + [l]: Local listen interval ( 0: Unchanged, + -1: Disable, + 1-49: Value in beacon intervals, + >= 50: Value in TUs ) + [b]: Beacon miss timeout (0: Unchanged, 1-50: Value in milliseconds, 65535: Disable) + [p]: Delay to PS (0-65535: Value in milliseconds, default 1000ms) + [m]: PS mode (0: Unchanged, 1: Auto mode, 2: PS-Poll mode, 3: PS Null mode) + No change if parameters are not provided. + + Examples: + mlanutl mlan0 pscfg : Get all the current PS configuration settings + mlanutl mlan0 pscfg 3 4 : Set PS keep alive null packet interval to 3 seconds + and DTIM interval to 4, all the other configurations + are unchanged + mlanutl mlan0 pscfg 0 0 0 0 50 2 : Set delay to PS to 50 ms and PS mode to PS-Poll mode, + keep the others unchanged + +bcntimeoutcfg + This command is used to set Beacon timeout parameters. + + Usage: + mlanutl mlanX bcntimeoutcfg [l] [m] [o] [p] + + Where the parameters: + [l]: Beacon miss timeout period Rx window (in ms) + [m]: Beacon miss timeout period (unit in beacon interval) + [o]: Beacon reacquire timeout period Rx window (unit in beacon interval) + [p]: Beacon reacquire timeout period (unit in beacon interval) + Please note that it would be better [m]+[p] not exceed 64. + Examples: + mlanutl mlan0 bcntimeoutcfg 10 30 2 30 : Set beacon timeout configure to + Beacon miss timeout period Rx window : 10 (ms) + Beacon miss timeout period : 30 (Beacon Interval) + Beacon reacquire timeout period Rx window : 2 (Beacon Interval) + Beacon reacquire timeout period : 30 (Beacon Interval) + +psmode + This command is used to set/get the IEEE PS mode configuration. + + Usage: + mlanutl mlanX psmode [l] + + where the parameter: + [l] + 0 : Disable IEEE PS mode + 1 : Enable IEEE PS mode + : Get IEEE PS mode + + Examples: + mlanutl mlan0 psmode : Get IEEE PS mode. + mlanutl mlan0 psmode 1 : Enable IEEE PS mode. + +qconfig + Send a WMM AC Queue configuration command to get/set/default params + + Configure or get the parameters of a WMM AC queue. The command takes + an optional Queue Id as a last parameter. Without the queue id, all + queues will be acted upon. + + Usage: + mlanutl mlanX qconfig def [Queue Id: 0-3] + mlanutl mlanX qconfig get [Queue Id: 0-3] + mlanutl mlanX qconfig set msdu [Queue Id: 0-3] + +qoscfg + This command sets WMM IE QOS info when an argument is given, and gets current WMM + IE QOS info when no argument is given. + + Examples: + mlanutl mlanX qoscfg 0x0f : Set WMM IE QOS info to 0x0f + mlanutl mlanX qoscfg : Get WMM IE QOS info + +qstatus + This command retrieves the current status of the WMM queues. If WMM + is enabled then it displays the information for each AC in a table. + + Usage: + mlanutl mlanX qstatus + +radioctrl + This command is used to turn on/off the radio. + Note: The radio can be disabled only in disconnected state. + + where value of n is: + 0 -- Disable + 1 -- Enable + + Examples: + mlanutl mlan0 radioctrl 1 : Turn the radio on + mlanutl mlan0 radioctrl : Get radio status + +rdeeprom + This command is used to read the EEPROM contents of the card. + + Usage: + mlanutl mlanX rdeeprom + + where the parameters are, + : multiples of 4 + : 4-20, multiples of 4 + + Example: + mlanutl mlan0 rdeeprom 0 20 : Read 20 bytes of EEPROM data from offset 0 + +reassoctrl + This command is used to turn on/off re-association in driver. + + Usage: + mlanutl mlanX reassoctrl [n] + + Where value of n is: + 0 -- Disable + 1 -- Enable + + Examples: + mlanutl mlan0 reassoctrl : Get re-association status + mlanutl mlan0 reassoctrl 1 : Turn re-association on + +regioncode + This command is used to set/get the region code in the station. + Note: This command should be issued at beginning before band/channel selection + and association. + + where value is 'region code' for various regions like + USA FCC, Canada IC, Europe ETSI, Japan ... + The special code (0xff) is used for Japan to support channel 1-14 in B/G/N mode. + + Examples: + mlanutl mlan0 regioncode : Get region code + mlanutl mlan0 regioncode 0x10 : Set region code to USA (0x10) + Note : in some case regioncode will be 0 after updated countycode or 80211d + i.e. mlanutl mlanX countrycode (CA, JP, CN, DE, ES AT, BR, RU) + or uaputl.exe sys_cfg_80211d state 1 country (CA, JP, CN, DE, ES AT, BR, RU) + Please use cfp instead of it. + +regrdwr + This command is used to read/write the adapter register. + + Usage: + mlanutl mlanX regrdwr [value] + + where the parameters are, + : 1:MAC/SOC, 2:BBP, 3:RF, 5:CAU, 6:PSU, 0x81:MAC2, 0x82:BBP2, 0x83: RF2 + : 1:MAC/SOC, 2:BBP, 3:RF, 5:CAU, 6:PSU + : offset of register + [value]: value to be written + Note: + BBP reg (type 2) 0xXZZZ: + X: 0=BBUD, 8=BBUA. + ZZZ: offset (0-0xFFF). + RF reg (type 3) 0xXYZZ: + + For 8887/8897/8777 + 1. If Y == 0, access RFU BASE Register. + X = Path ID (0=Path_A, 1=Path_B), ZZ = offset (0-0xFF). + 2. If Y != 0, access RFU XCVR Register on Path Y (1=Path_A, 2=Path_B). + X = Page # (0=Page_1, 1=Page_2, 2=Page_3 if chip support), ZZ: offset (0-0xFF). + For 8977/8997/8987 + X = Path ID (0-1) + Y = Page Number (0-6) in selected Path + ZZ = Register offset in selected path/page + + Examples: + mlanutl mlan0 regrdwr 1 0xa060 : Read the MAC register + mlanutl mlan0 regrdwr 1 0xa794 0x80000000 : Write 0x80000000 to MAC register + mlanutl mlan0 regrdwr 0x81 0xa060 :Read MAC2 register + +rejectaddbareq + This command is used to set/get the conditions of rejecting addba request. + + Usage: + mlanutl mlanX rejectaddbareq [conditions] + mlanutl uapX rejectaddbareq [conditions] + + Where conditions are: + bit 0 = 1 -- reject the addba request when host sleep activated + others -- reserved + + Examples: + mlanutl mlan0 rejectaddbareq : Get the reject addba request conditions + mlanutl mlan0 rejectaddbareq 0x1 : Reject the addba request + when host sleep activated + mlanutl uap0 rejectaddbareq 0x1 : Reject the addba request + when host sleep activated + +scancfg + This command is used to set/get scan configuration parameters. + + Usage: + mlanutl mlanX scancfg [t] [m] [p] [s] [a] [b] [c] [ext] [gap] + + where the parameters: + [t]: Scan Type (0: Unchanged, 1: Active, 2: Passive, default Active) + [m]: Scan Mode (0: Unchanged, 1: BSS, 2: IBSS, 3: Any, default Any) + [p]: Scan Probes (0: Unchanged, 1-5: Number of probes per channel, default 4) + [s]: Specific Scan Time (0: Unchanged, n: Value in ms, default 110 ms, max 500 ms) + [a]: Active Scan Time (0: Unchanged, n: Value in ms, default 200 ms, max 500 ms) + [b]: Passive Scan Time (0: Unchanged, n: Value in ms, default 200 ms, max 2000 ms) + [c]: Passive to Active Scan (0: Unchanged, 1: Enable, 2: Disable, default Enable) + [ext]: Extended scan (0: Unchanged, 1: Legacy scan, 2: Extended scan, 3: Extended scan enhance) + [gap]: Time gap between two scans in milliseconds (max value 500ms) + No change if the parameter is 0 or the parameter is not provided. + + Examples: + mlanutl mlan0 scancfg : Get all the current scan configuration settings + mlanutl mlan0 scancfg 1 3 : Set scan type to active and scan mode to any, + all the other scan configurations are unchanged + mlanutl mlan0 scancfg 0 1 2 200 : Set scan mode to BSS, number of probes to 2 and + specific scan time to 200 ms, all the other scan + configurations are unchanged + mlanutl mlan0 scancfg 0 0 0 0 0 0 1 : Set Passive to Active Scan to enable, all the + other scan configurations are unchanged + mlanutl mlan0 scancfg 2 0 0 0 0 0 2 : Set scan type to passive, Passive to Active + Scan to disable, all the other scan configurations + are unchanged + +sdcmd52rw + This command is used to read/write a controller register in + Secure Digital I/O Interfaces. + + Usage: + mlanutl mlanX sdcmd52rw [value] + + For SDIO MMC driver, only function 0 and 1 access is allowed. And there + is a limitation for function 0 write, only vendor specific CCCR registers + (0xf0 -0xff) are permiited. + + Examples: + mlanutl mlan0 sdcmd52rw 1 3 : Read SDIO function 1 register 3 + mlanutl mlan0 sdcmd52rw 1 1 0x3f : Write 0x3f to SDIO function 1 register 1 + +sdcmd53rw + This command is used to issue a CMD53 read/write data in + Secure Digital I/O Interfaces. + + Usage: + mlanutl mlanX sdcmd53rw
[data1] ... [dataN] + + where the parameters are, + : function number (0/1/2/..) +
: data address + : byte mode/block mode (0/1) + : block size (32/64/../512, NA for byte mode) + : block number or byte number + ... : data for write + + Note: The total data length is block size * block number for block mode + or byte number for byte mode. The max data length is 2000-byte. + For write the data pattern will be duplicated to data buffer. + + Examples: + mlanutl mlan0 sdcmd53rw 0 0x8000 1 0x40 2 + mlanutl mlan0 sdcmd53rw 1 0x10000 0 1 5 0x0a 0x0b 0x0c 0x0d 0x0e + +sdioclock + Turn On(1) or Off(0) the SDIO clock. + + Usage: + mlanutl mlanX sdioclock 1 (on) + mlanutl mlanX sdioclock 0 (off) + mlanutl mlanX sdioclock (get the current clock state) + + +setuserscan + Initiate a customized scan and retrieve the results + + Usage: + mlanutl mlanX setuserscan [ARGS] + + Where [ARGS]: + ssid="[SSID]" specify a SSID filter for the scan + group= specify the channel group(s) to scan + chan=[chan#][band][mode] where band is [a,b,g,n] and mode is + blank for unchange, or 'c' for active or 'p' for passive + bssid=xx:xx:xx:xx:xx:xx specify a BSSID filter for the scan + wc="[WILDCARD SSID]" specify a UNIX pattern matching filter (using * + and ?) for SSIDs found in a broadcast probe + keep=[0 or 1] keep the previous scan results (1), discard (0) + dur=[scan time] time to scan for each channel in milliseconds + gap=[gap time] Time gap between two scans in milliseconds + probes=[#] number of probe requests to send on each chan + for each broadcast probe required and each SSID + specific probe required (1-5) + bss_type=[1,2,3] BSS type: 1 (Infra), 2(Adhoc), 3(Any) + sort_by_ch Sort by channel number in ascending order. + Default mode: Sort by Signal Strength in descending order. + scan_type=[0,1] ext scan type (0-1) 0: legacy, 1: enhance scan + + Any combination of the above arguments can be supplied on the command line. + If the chan token is absent, a full channel scan will be completed by driver. + If the dur or probes tokens are absent, the driver default setting will be + used. The bssid and ssid fields, if blank, will produce an unfiltered scan. + It's allowed to input multiple ssid/wc entries, the max entry number is 10. + The type field will default to 3 (Any) and the keep field will default to 0 + (Discard). + + Examples: + 1) Perform an active scan on channels 1, 6, and 11 in the 'g' band: + setuserscan chan=1g,6g,11g + + 2) Perform a passive scan on channel 11 for 20 ms: + setuserscan chan=11gp dur=20 + + 3) Perform an active scan on channels 1, 6, and 11; and a passive scan on + channel 36 in the 'a' band: + setuserscan chan=1g,6g,11g,36ap + + 4) Perform an active scan on channel 6 and 36 for specific SSID: + setuserscan chan=6g,36a ssid=TestAP1 ssid=TestAP2 + + 5) Scan all available channels (B/G/N, A bands) for a specific BSSID, keep + the current scan table intact, update existing or append new scan data: + setuserscan bssid=00:50:43:20:12:82 keep=1 + + 6) Scan channel 6, for all infrastructure networks, sending two probe + requests. Keep the previous scan table intact. Update any duplicate + BSSID/SSID matches with the new scan data: + setuserscan chan=6g bss_type=1 probes=2 keep=1 + + 7) Scan channel 1 and 6, for all networks matching the NXP*AP + or AP*NXP? patterns and for NXPTst SSID. Generate 3 broadcast + probes for the patterns and 3 SSID specific probes for NXPTst on + both channel 1 and channel 6. + setuserscan chan=1g,6g probes=3 wc="NXP*AP" wc="AP*NXP?" ssid="NXPTst" + + 8) Scan all the channels for specified band. + setuserscan chan=0g + 9) Perform active scan for a list of specific BSSIDs + setuserscan bssid=00:50:43:20:12:82 bssid=48:e2:44:3f:ec:76 + + 9) Scan channel 1 and 6, send 3 probe requests, scan each channel for 40 ms + with time gap of 50ms between 2 scans + setuserscan chan=1g,6g probes=3 dur=40 gap=50 + + 10) Perform an enhance scan + setuserscan scan_type=1 + + All entries in the scan table (not just the new scan data when keep=1) + will be displayed upon completion by use of the getscantable ioctl. +cancelscan + This command is used to cancel scan + Usage: + mlanutl mlanX cancelscan +sleepparams + This command is used to set the sleepclock configurations + + Usage: + mlanutl mlanX sleepparams [ ] + + where: + p1 is Sleep clock error in ppm (0-65535) + p2 is Wakeup offset in usec (0-65535) + p3 is Clock stabilization time in usec (0-65535) + p4 is Control periodic calibration (0-2) + p5 is Control the use of external sleep clock (0-2) + p6 is reserved for debug (0-65535) + + Examples: + mlanutl mlan0 sleepparams : Get current sleepclock configuration + mlanutl mlan0 sleepparams 10 1000 2000 1 0 128 : Set sleepclock configuration + +sleeppd + This command is used to configure the sleep period of the WLAN device. + + Usage: + mlanutl mlanX sleeppd [] + + Where the parameter is: + period: sleep period in milliseconds. Range 10~60. 0 for disable. + + Examples: + mlanutl mlan0 sleeppd : Get sleep period configuration + mlanutl mlan0 sleeppd 10 : Set sleep period to 10 ms + +sysclock + This command is used to set/get system clocks in MHz. + The current system clock, configurable system clocks and all of the + supported system clocks will be returned if no parameter provided. + + Examples: + mlanutl mlan0 sysclock : Get system clocks + 80 80 128 128 128 5 11 16 20 22 32 40 44 64 80 106 128 160 ... + (The current system clock is 80 MHz. + The configurable system clocks of non-security, security, non-security + A-MPDU and security A-MPDU are 80 MHz, 128 MHz, 128 MHz and 128 MHz. + The supported system clocks are 5 MHz, 11 MHz, ..., 160 MHz, 182 MHz, + 213 MHz, 256 MHz, 320 Mhz, 366 MHz , ... . the Max system clocks is different + for different chips, you could use this command to get the supported system clock) + + mlanutl mlanX sysclock 80 : Set system clock in non-security mode + to 80 MHz, no change for others + mlanutl mlanX sysclock 0 0 128 : Set system clock in non-security A-MPDU + mode to 128 MHz, no changes for others + +thermal + This command is used to get the current thermal reading. + + Examples: + mlanutl mlan0 thermal : Get thermal reading + +ts_status + This command queries the FW for the status of TSIDs 0 through 7 + configured via call admission control and displays the results in a + table. + + Usage: + mlanutl mlanX ts_status + +tsf + Get the TSF timer value for the station. Station maintains a TSF timer with + modulus 2^64 counting in increments of microseconds. + + Usage: + mlanutl mlanX tsf + +txbufcfg + This command can be used to get current buffer size. + + eg: + mlanutl mlanX txbufcfg - This will display the current buffer size. + + Note:- The actual tx buf size will depends on AP's capability and max transmit buffer size. + +txratecfg + This command is used to set/get the transmit data rate. + + Note: + 1) The data rate can be set only after association. + + 2) If the reassoc is OFF driver reset the data rate to auto if the connection state is disconnected. + Please note that user has to re-issue the set data rate command if the driver is disconnected. + + 3) If the reassoc is ON driver remembers the data rate set by the user, if the driver is + disconnected user does not have to re-issue the set data rate again. + 4) Parameter [o] is optional. If [o] is not given, it will be set as 0xffff. + + Where + [l] is + - This parameter specifies the data rate format used in this command + 0: LG + 1: HT + 2: VHT + 3: HE + 0xff: Auto + + [m] is + - This parameter specifies the rate or MCS index + If is 0 (LG), + 0 1 Mbps + 1 2 Mbps + 2 5.5 Mbps + 3 11 Mbps + 4 6 Mbps + 5 9 Mbps + 6 12 Mbps + 7 18 Mbps + 8 24 Mbps + 9 36 Mbps + 10 48 Mbps + 11 54 Mbps + If is 1 (HT), + 0 MCS0 + 1 MCS1 + 2 MCS2 + 3 MCS3 + 4 MCS4 + 5 MCS5 + 6 MCS6 + 7 MCS7 + 8 MCS8 + 9 MCS9 + 10 MCS10 + 11 MCS11 + 12 MCS12 + 13 MCS13 + 14 MCS14 + 15 MCS15 + If is 2 (VHT), + 0 MCS0 + 1 MCS1 + 2 MCS2 + 3 MCS3 + 4 MCS4 + 5 MCS5 + 6 MCS6 + 7 MCS7 + 8 MCS8 + 9 MCS9 + If is 3 (HE), + 0 MCS0 + 1 MCS1 + 2 MCS2 + 3 MCS3 + 4 MCS4 + 5 MCS5 + 6 MCS6 + 7 MCS7 + 8 MCS8 + 9 MCS9 + 10 MCS10 + 11 MCS11 + [n] is + - This parameter specifies the NSS. It is valid for VHT + If is 2 (VHT), + 1 NSS1 + 2 NSS2 + [n] is + - This parameter specifies the NSS. It is valid for HE + If is 3 (HE), + 1 NSS1 + 2 NSS2 + [o] is + Bit0 - 1: indicate preambleType + For legacy 11b: preemble type + 00 = long + 01 = short + 10/11 = reserved + For legacy 11g: reserved + For 11n: Green field PPDU indicator + 00 = HT-mix + 01 = HT-GF + 10/11 = reserved. + For 11ac: reserved. + For 11ax: + 00 = HE-SU + 01 = HE-EXT-SU + others are reserved + + Bit 2 - 4 : indicate BW: + For HE ER: + 0 = 242-tone RU + 1 = upper frequency 106-tone RU within the primary 20 MHz + Otherwise: + 0 = 20 MHz + 1 = 40 MHz + 2 = 80 MHz + 3 = 160 MHz + + Bit 5 -6: indicate LTF + GI size + For HT: + 0 = normal + 1 = Short GI + For VHT: + 01 = Short GI + 11 = Short GI and Nsym mod 10=9 + 00 = otherwise + For HE: + 0 = 1xHELTF + GI0.8us + 1 = 2xHELTF + GI0.8us + 2 = 2xHELTF + GI1.6us + 3 = 4xHELTF + GI0.8us if DCM = 1 and STBC = 1 + 4xHELTF + GI3.2us, otherwise. + + Bit 7: Indicate STBC: + 0 = no STBC + 1 = STBC + + Bit 8: indicate DCM: + 0 = no DCM + 1 = DCM + + Bit 9: indicate coding: + 0 = BCC + 1 = LDPC + + Bit 10 - 11: reserved. + + Bit 12 - 13: Indicate maxPE + Max packet extension + 0 - 0 usec + 1 - 8 usec + 2 - 16 usec. + + Bit 14 - 15: reserved. + + 0xffff: Auto + + Examples: + mlanutl mlan0 txratecfg : Read the current data rate setting + mlanutl mlan0 txratecfg 0 3 : Set fixed Tx rate to 11 Mbps + mlanutl mlan0 txratecfg 0 11 : Set fixed Tx rate to 54 Mbps + mlanutl mlan0 txratecfg 1 3 : Set fixed Tx rate to MCS3 + mlanutl mlan0 txratecfg 2 3 2 : Set fixed Tx rate to MCS3 for NSS2 + mlanutl mlan0 txratecfg 3 3 2 : Set 11AX fixed Tx rate to MCS3 for NSS2 + mlanutl mlan0 txratecfg 3 5 2 0x2282 : Set 11AX fixed Tx rate to MCS5 for NSS2, and Preamble type is 2, BW is 0, LTF + GI size 0 + STBC is 1, DMC is 0, Coding is 1, maxPE is 2. + mlanutl mlan0 txratecfg 0xff : Disable fixed rate and uses auto rate + +aggrctrl + This command is used to set/get aggregation parameters. + + Usage: + mlanutl mlanX aggrctrl [l] + + where the parameter: + [l]: Enable (1) or disable (0) Tx aggregation + + Examples: + mlanutl mlan0 aggrctrl : Display aggregation configurations + mlanutl mlan0 aggrctrl 0 : Disable Tx aggregation + mlanutl mlan0 aggrctrl 1 : Enable Tx aggregation + +usbaggrctrl + This command is used to set/get USB aggregation parameters. + + Usage: + mlanutl mlanX usbaggrctrl [l] [m] [n] [o] [p] [q] [r] [s] + + where the parameter: + [l]: Enable (1) or disable (0) Tx aggregation + [m]: Enable (1) or disable (0) Rx aggregation + [n]: Tx aggregation max size/number + For number based aggregation, the values supported are + - 2, 4, 8, 16 + For size based aggregation, the number supported are + - 4096, 8192, 16384, 32768 + [o]: Rx aggregation max size/number + For number based deaggregation, the values supported are + - 2, 4, 8, 16 + For size based deaggregation, the number supported are + - 4096, 8192, 16384, 32768 + [p]: Tx aggregation alignment + The value must be 2048, 4096, 8192 etc. + [q]: Rx aggregation alignment + The value must be 512, 1024, 2048, 4096, 8192 etc. + [r]: Tx aggregation timeout + Timeout value in us, 0 for disabled, 0xFFFF for dynamic timeout + and 1-10000 are valid timeout value + [s]: Rx aggregation timeout + Timeout value in us, 0 for disabled + + Examples: + mlanutl mlan0 usbaggrctrl : Display USB aggregation configurations + mlanutl mlan0 usbaggrctrl 0 0 : Disable both Tx and Rx aggregation + mlanutl mlan0 usbaggrctrl 1 1 4 8 2048 512 1000 200 : Enable both Tx and Rx aggregation + +usbresume + This command is used to resume the device from suspend mode. + Note: It's only valid on kernel 2.6.24 or later. + +usbsuspend + This command is used to put device to suspend mode. + Note: It's only valid on kernel 2.6.24 or later. + +verext + Retrieve and display an extended version string from the firmware + + Usage: + mlanutl mlanX verext [#] + + where [#] is an optional argument to retrieve a specific version string, + omission of the argument retrieves the 0 indexed string. + +version + This is used to get the current version of the driver and the firmware. + +vhtcfg + This command is used to set and get various 11ac specific configuration + for transmission and reception. For the SET operation, all paramaters + may be applied. For the GET operation, only the first two parameters are applied. + The 6th argument "rx_mcs_set" can be used to disbale/enable 802.11ac. + + where is + - This is the band setting for the vhtcfg + 0: Settings for both 2.4G and 5G bands (for SET operation, 11N BW only) + 1: Settings for 2.4G band (for 11N BW only) + 2: Settings for 5G band + + where is + - This parameter specifies the configuration of VHT operation for TX or/and VHT capabilities + 0: Unspecified + 1: configuration of VHT capabilities for Tx operations (STA only) + 2: configuration of VHT capabilities for association (STA only) + 3: configuration of VHT capabilities (uAP only) + Note: For the STA, the VHT capabilities configuration is applied in association, + whereas the VHT operations configuration is actually used in Tx. + + where [l] is + - This parameter specifies the bandwidth (BW) configuration + applied to the vhtcfg. + If is 1/3 (Tx operations), + 0: Tx BW follows the BW (20/40 MHz) from 11N CFG + 1: Tx BW follows the BW (80/160/80+80 MHz) from VHT Capabilities + defined in below for 5G band. + If is 2 (association), + 0: Rx BW follows the BW (20/40 MHz) from 11N CFG + 1: Rx BW follows the BW (80/160/80+80 MHz) from VHT Capabilities + defined in below for 5G band. + + where [m] is + - This parameter specifies the VHT capabilities info if is 2 (association) + or the VHT Tx operations if is 1 (Tx operations). + The VHT Tx operation should be a subset of VHT capabilities for association. + It is a bitmap and should be used as follows: + + Bit 31-30: Reserved and set to 0 + Bit 29: TX antenna pattern consistency + 1: antenna pattern does not change + 0: antenna pattern might change + Bit 28: RX antenna pattern consistency + 1: antenna pattern does not change + 0: antenna pattern might change + Bit 27-26: VHT link adaptation capable + 0: no feedback of VHT MFB from the STA + 1: unsolicted feedback of VHT MFB from the STA + 2: both response and unsolicted feedback of VHT MFB + from the STA + 3: reserved and set to 0 + Bit 25-23: Maximum A-MPDU length exponent + Bit 22: +HTC-VHT capable (1: enable. 0 disable) + Bit 21: VHT TXOP PS + Bit 20: MU beamformee capable (1: enable. 0 disable) + Bit 19: MU beamformer capable (1: enable. 0 disable) + Bit 18-16: Number of sounding dimensions (set to maximum-1 + if Bit 11 is 1. Otherwise, reserved and set to 0) + Bit 15-13: Compressed steering number of beamformer + antennas supported (set to maximum-1 if Bit 12 is 1. + Otherwise, reserved and set to 0) + Bit 12: SU beamformee capable (1: enable. 0 disable) + Bit 11: SU beamformer capable (1: enable. 0 disable) + Bit 10-8: Rx STBC + 0: no support + 1: support of 1 spatial stream + 2: support of 1-2 streams + 3: support of 1-3 spatial streams + 4: support of 1-4 spatial streams + 5-7: reserved and set to 0 + Bit 7: TX STBC (1: enable. 0 disable) + Bit 6: Short GI for 160 and 80+80 MHz (1: enable. 0 disable) + Bit 5: Short GI for 80 MHz (1: enable. 0 disable) + Bit 4: Rx LDPC (1: enable. 0 disable) + Bit 3-2: Supported channel width set. + 0: no support of either 160 or 80+80 MHz. + 1: support of 160 MHz + 2: support of both 160 and 80+80 MHz. + 3: reserved and set to 0. + Bit 1-0: Maximum MPDU length + 0: 3895 octets. + 1: 7991 octets. + 2: 11454 octets. + 3: reserved and set to 0. + + Note: for the STA, if is 1 (Tx operations), the bitmap for may be simplied as follows: + Bit 31-8: Reserved and set to 0 + Bit 7: Tx STBC (1: enable. 0 disable) + Bit 6: Reserved and set to 0 + Bit 5: Short GI for 80 Mhz (1: enable. 0 disable) + Bit 4: LDPC (1: enable. 0 disable) + Bit 3-0: Reserved and set to 0 + + where [n] is , + - This parameter specifies the TX MCS map. It may not be used for the STA if is 1 (Tx operations). + It is a bitmap and should be used as following + Bit 15-0: MCS map, which is defined as folows: + Bit 15-14: Max MCS for 8 SS + Bit 13-12: Max MCS for 7 SS + Bit 11-10: Max MCS for 6 SS + Bit 9-8: Max MCS for 5 SS + Bit 7-6: Max MCS for 4 SS + Bit 5-4: Max MCS for 3 SS + Bit 3-2: Max MCS for 2 SS + Bit 1-0: Max MCS for 1 SS + + where [o] is . + - This parameter specifies the RX MCS map. It may not be used for the STA if is 1 (Tx operations). + It is a bitmap with the same sructure as for + rx_mcs_map = 0xffff : FW will disable 802.11ac + rx_mcs_map = others : FW will enable 802.11ac + + Note: The user setting of vhtcap may be overwritten by the driver + if the setting of those fields is beyond the hardware capabilities. + + Examples: + mlanutl mlan0 vhtcfg 2 1 : Get current VHT configuration in 5GHz for the STA. + mlanutl mlan0 vhtcfg 2 2 : Get maximum VHT configuration in 5GHz for the STA. + mlanutl mlan0 vhtcfg 2 1 1 0x000001f0 + : Set the Tx operations configuration in 5GHz for the STA, + Tx BW follows the VHT Capabilities. + mlanutl mlan0 vhtcfg 2 2 0 0x000001f0 0xfff5 0xfffa + : Set the VHT capabilities configuration in 5GHz for the STA, + the Tx supports MCS 0-8 for both 1 and 2 spatial streams, + while the Rx supports MCS 0-9 for both 1 and 2 spatial streams. + mlanutl uap0 vhtcfg 2 3 0 0x000001f0 0xfffa 0xfffa + : Set the current/maximum VHT configuration in 5GHz for the uAP. + Both Tx and Rx supports MCS 0-9 for both 1 and 2 spatial streams. + mlanutl uap0 vhtcfg 2 3 0 0x000001b0 + : Set the VHT capability information in 5GHz for the uAP, and keep the Tx/Rx MCS Map same as before. + +opermodecfg + This command is used to set and get 11ac Operating Mode Notification configuration. + + where is + - This is the channel width setting for the opermodecfg + 1: 20MHz + 2: 40MHz + 3: 80MHz + 4: 160MHz or 80+80MHz + + where is + - This parameter specifies the nss that the STA can receive. + 1: NSS1 + 2: NSS2 + 3: NSS3 + 4: NSS4 + 5: NSS5 + 6: NSS6 + 7: NSS7 + 8: NSS8 + +wakeupreason + This command is used to get the host sleep wakeup reason. + + Usage: + mlanutl mlanX wakeupreason + mlanutl uapX wakeupreason + Examples: + mlanutl mlan0 wakeupreason : Get the host sleep wakeup reason + mlanutl uap0 wakeupreason : Get the host sleep wakeup reason + 0: unknown + 1: Broadcast data matched + 2: Multicast data matched + 3: Unicast data matched + 4: Maskable event matched + 5. Non-maskable event matched + 6: Non-maskable condition matched (EAPoL rekey) + 7: Magic pattern matched + 8: Control frame matched + 9: Management frame matched + Others: reserved. (0) + +warmreset + This command is used for warm reset of the interface. + + Usage: + mlanutl mlanX warmreset + +wpssession + This command is used to control wps session. No argument is used to get. + + where value of n is: + 0 -- Disable + 1 -- Enable + + Examples: + mlanutl mlan0 wpssession 1 : Enable wpssession + mlanutl mlan0 wpssession : Get wpssession status + +wmmcfg + This command is used to control WMM. No argument is used to get. + + where value of n is: + 0 -- Disable + 1 -- Enable + + Examples: + mlanutl mlan0 wmmcfg 1 : Enable WMM + mlanutl mlan0 wmmcfg : Get WMM status + +wmmparamcfg + This command is used to configure WMM paramameters. + + Usage: + mlanutl mlanX wmmparamcfg [AC_BE AIFSN ECW_MAX ECW_MIN TX_OP] + [AC_BK AIFSN ECW_MAX ECW_MIN TX_OP] + [AC_VI AIFSN ECW_MAX ECW_MIN TX_OP] + [AC_VO AIFSN ECW_MAX ECW_MIN TX_OP] + + The supported option are: + AC_BE: 0 + AC_BK: 1 + AC_VI: 2 + AC_V0: 3 + AIFSN: AIFSN value + ECW_MAX: ECW max + ECW_MIN: ECW min + TX_OP: TXOP Limit + empty - Get current WMM parameters + + Example: + mlanutl mlanX wmmparamcfg 0 3 10 4 0 + Set AC_BE with AIFSN 3, ECW_MAX 10, ECW_MIN 4 and TXOP 0 + + mlanutl mlanX wmmparamcfg 1 7 10 4 0 + Set AC_BK with AIFSN 7, ECW_MAX 10, ECW_MIN 4 and TXOP 0 + + mlanutl mlanX wmmparamcfg 2 2 4 3 94 + Set AC_VI with AIFSN 2, ECW_MAX 4, ECW_MIN 3 and TXOP 94 + + mlanutl mlanX wmmparamcfg 3 2 3 2 47 + Set AC_VO with AIFSN 2, ECW_MAX 3, ECW_MIN 2 and TXOP 47 + + mlanutl mlanX wmmparamcfg + Get current WMM parameters + + mlanutl mlanX wmmparamcfg 0 3 10 4 0 1 7 10 4 0 2 2 4 3 94 3 2 3 2 47 + Set AC_BE with AIFSN 3, ECW_MAX 10, ECW_MIN 4 and TXOP 0 + Set AC_BK with AIFSN 7, ECW_MAX 10, ECW_MIN 4 and TXOP 0 + Set AC_VI with AIFSN 2, ECW_MAX 4, ECW_MIN 3 and TXOP 94 + Set AC_VO with AIFSN 2, ECW_MAX 3, ECW_MIN 2 and TXOP 47 + +wwscfg + This command is used to set/get the WWS (World Wide Safe) mode. + + where value of m is: + 0 -- Disable WWS mode (default) + 1 -- Enable WWS mode + + Examples: + mlanutl mlan0 wwscfg : Get WWS mode + mlanutl mlan0 wwscfg 1 : Enable WWS mode + mlanutl mlan0 wwscfg 0 : Disable WWS mode + +cfg_noa + This is used to get/set P2P NoA (Notice of Absence) parameters only for P2P GO. + + Usage: + mlanutl p2pX cfg_noa [h] [i] [j] [k] [l] + + where: + [h] : noa_enable : 1/0 Set to 1 to enable NoA, 0 to disable NoA. + [i] : index : 0 - 255 Identifies an instance of NoA timing. + [j] : count : 1 - 255 Indicates the number of absence intervals. + 255 means a continuous schedule. + [k] : duration : Indicates the maximum duration in units of microseconds + that P2P GO can remain absent following the start of + a NoA interval. + [l] : interval : Indicates the length of the NoA interval in units of + microseconds. + + Examples: + mlanutl p2pX cfg_noa : Get noa configuration. + mlanutl p2pX cfg_noa 1 1 255 50 100 : Set noa configuration. + +cfg_opp_ps + This is used to get/set P2P OPP-PS parameters only for P2P GO. + + Usage: + mlanutl p2pX cfg_opp_ps [m] [n] + + where: + [m] : ps_enable : 1/0 Set to 1 to indicate P2P GO is using opportunistic + power save. Set to 0 if opportunistic power save is disabled. + [n] : ct_window : A period of time in TU after a TBTT during which P2P GO + is present. 0 indicates that there shall be no + CTWindow (Client Traffic Window). + + Examples: + mlanutl p2pX cfg_opp_ps : Get noa configuration. + mlanutl p2pX cfg_opp_ps 1 7 : Set noa configuration. + +rxpktcoal_cfg + This is used to get/set RX packet coalescing paramters + Usage: + mlanutl mlanX rxpktcoal_cfg [m] [n] + + where: + [m]: pkt_threshold: count after which packets would be sent to host. Valid values 1-7 + [n]: delay: timeout in ms after which packets would be sent to host. Valid values 1-4 + Coalescing is disabled if both or either of packet_thershold and delay is zero + + RX packet coalescing parameters can be changed only when device is in + idle state i.e. all interfaces are disconnected. + +get_sensor_temp + This command is used to get SOC temperature + Usage: + mlanutl mlanX get_sensor_temp + +indrstcfg + This command is used to set/ get independent reset mode configuration + + Usage : + mlanutl indrstcfg [gpio_pin] + + interface : mlanX, uapX + ir_mode : 0 -- Disable + 1 -- Enable out band reset, disable in band + 2 -- Enable in band, disable out band + gpio_pin : 255 -- Default pin for reset + any other number for changing the gpio for reset. + + Example : + mlanutl mlan0 indrstcfg 1 255 : Set default pin on interface mlan0 as reset pin + mlanutl mlan0 indrstcfg 0 : Disable the gpio 17 as reset pin on interface mlan0 + mlanutl mlan0 indrstcfg : Get the status and the pin used for reset pin + mlanutl mlan0 indrstcfg 2 : Enable in band reset mode + +ctrldeauth + This command is used to set/get firmware ctrldeauth setting + Usage : + mlanutl uapX ctrldeauth + + Where value of n is : + 0 -- Firmware will use default behavior + 1 -- Firmware will not send deauth packet when uap move to another channel. + + Example : + mlanutl uap0 ctrldeauth : Get current setting + mlanutl uap0 ctrldeauth : Firmware will not send deauth packet when uap move to different channel. + +robustcoex + This command is used to set robust coex. + + Usage : + mlanutl robustcoex [Enable/Disable] [gpionum] [gpiopolarity] + Enable/Disable : 0 -- Disable ; 1 -- Enable + gpionum : Number of gpio + gpiopolarity : polarity of gpio + + Example : + mlanutl mlan0 robustcoex gpiocfg 1 4 1 : Enable robustcoex gpio, set gpionum to 4 and gpiopolarity to 1 + mlanutl mlan0 robustcoex gpiocfg 0 : Disable robustcoex gpio + +cwmode + This command is used to set Cont. Tx/Wave mode. + + Usage: + mlanutl cwmode config/cwmode.conf + interface: mlanX + cwmode.conf: This config file specifies whether to enable/disable Cont Tx/Wave mode. + User can specify parameters like Channel, datarate, BW, Channel Offset, Band. + Detailed information about parameters is mentioned in the conf file. + Example: + mlanutl mlan0 cwmode config/cwmode.conf : Enable/Disable Cont Tx/Wave mode. + mlanutl mlan0 cwmode : Get current Tx mode + +bootsleep + This command is used to set and get boot sleep configure. + + Usage : + mlanutl mlanX/uapX bootsleep + : enable boot sleep + : 0 - disable boot sleep + : 1 - enable boot sleep + + Example : + mlanutl mlan0/uap0 bootsleep 1 : Enable boot sleep + mlanutl mlan0/uap0 bootsleep : Get boot sleep configure + +ssu + Collect spectral analysis data and save them into /data/ssudump.txt + + Usage : + mlanutl mlanX ssu [mode] [ssu file] + + mode : 2 -- Enable ssu and use FW default ssu parameter + ssu file : file to config ssu parameter + + Example : + mlanutl mlan0 ssu :Enable SSU and use driver default ssu parameter + mlanutl mlan0 ssu config/ssu.conf :Enable SSU and use ssu parameter from ssu.conf + mlanutl mlan0 ssu 2 :Enable SSU and use FW default ssu parameter + +dmcs + This command is used to config DMCS or get DMCS status. + + Usage: + mlanutl mlanX dmcs [value] + + : config mapping policy + disable dynamic mapping when [value = 0] + enable dynamic mapping when [value = 1] + : get DMCS status + + Example : + mlanutl mlan0 dmcs 0 1 : Enable dynamic mapping + mlanutl mlan0 dmcs 0 0 : Disable dynamic mapping + mlanutl mlan0 dmcs 1 : Get DMCS status + +11axcfg + This command is used to config 11ax HE capability using conf file. + + Usage: + mlanutl mlanX 11axcfg [conf file] + + Example: + mlanutl mlan0 11axcfg config/11axcfg.conf + mlanutl uap0 11axcfg config/11axcfg.conf + +11axcmd + This command is used to config 11ax HE capability using command. + + Usage: + mlanutl mlanX 11axcmd [value_1] [value_2] + + : spatial reuse configuration + set obss_pd offset, [value_1] = NON_SRG_OffSET, [value_2] = SRG_OFFSET + + : spatial reuse configuration + control SR, [value_1]= 1 is enable SR, [value_1] = 0 is disable SR + + : enable/disable beam change + enable beam_change when [value_1 = 0] + disable beam_change when [value_1 = 1] + + : enable/disable HTC transmission + enable transmission of HTC when [value_1 = 1] + disable transmission of HTC when [value_1 = 0] + Example : + mlanutl mlan0 11axcmd obss_pd_offset 2 3 : set obss_pd offset of spatial reuse, NON_SRG_OffSET = 2, SRG_OFFSET = 3 + mlanutl mlan0 11axcmd obss_pd_offset : get obss_pd offset of spatial reuse + mlanutl mlan0 11axcmd enable_sr 1 : enable spatial reuse + mlanutl mlan0 11axcmd beam_change 0 : enable beam change + mlanutl mlan0 11axcmd enable_htc 1 : enable transmission of HTC + +rx_abort_cfg + This command is used to set/get static rx abort config for pkt having + weaker RSSI than threshold. This threshold will be overwritten on starting + dynamic rx abort cfg ext. + + Usage: + mlanutl rx_abort_cfg [enable] [rssi_threshold] + + Where the parameters are: + : mlanX, + uapX + [enable] : 0 - Disable Rx abort + 1 - Enable Rx abort of pkt having weak RSSI + [rssi_threshold] : weak RSSI pkt threshold in dBm (absolute value) + (default = 70) + + Examples: + mlanutl mlan0 rx_abort_cfg + - Display current rx abort configuration + mlanutl uap0 rx_abort_cfg 1 60 + - Enable rx abort and set weak RSSI Threshold to -60 dBm + mlanutl mlan0 rx_abort_cfg 1 40 + - Enable rx abort and set weak RSSI Threshold to -40 dBm + mlanutl mlan0 rx_abort_cfg 0 + - Disable rx abort + +rx_abort_cfg_ext + This command is used to set/get dynamic rx abort config. This will set + threshold based on minimum of ceiling rssi threshold and the weakest + RSSI among all connected peers. Margin can be specified as an offset to + this threshold. Default margin is set to -10 dBm. Ceiling rssi threshold + can be changed by specifying. Default ceil is set to -70 dBm. + This will be disabled on enabling fixed rx abort (rx_abort_cfg) + + Note: This dynamic rx abort mode is enabled by default. + + Usage: + mlanutl rx_abort_cfg_ext [enable] [margin ceil_thresh] + + Where the parameters are: + : mlanX, + uapX + [enable] : 0 - Disable Rx abort + 1 - Enable Rx abort of pkt having weak RSSI + [margin] : rssi margin in dBm (absolute val) + (default = 10) + [ceil_thresh] : ceiling weak RSSI pkt threshold in dBm + (absolute value) (default = 70) + + Examples: + mlanutl mlan0 rx_abort_cfg_ext + - Display current rx abort configuration + mlanutl uap0 rx_abort_cfg_ext 1 10 60 + - Enable dynamic rx abort, set margin to -10 dBm and set ceil + RSSI Threshold to -60 dBm + mlanutl mlan0 rx_abort_cfg_ext 1 5 50 + - Enable dynamic rx abort, set margin to -5 dBm and set ceil + RSSI Threshold to -50 dBm + mlanutl mlan0 rx_abort_cfg_ext 0 + - Disable dynamic rx abort + +tx_ampdu_prot_mode + This command is used to set either RTS/CTS or CTS2SELF protection mechanism + in MAC, for aggregated Tx QoS data frames. RTS/CTS is enabled by default. + + Usage: + mlanutl tx_ampdu_prot_mode [mode] + + Where the parameters are: + : mlanX, + uapX + [mode] : 0 - Set RTS/CTS mode + 1 - Set CTS2SELF mode + 2 - Disable Protection mode + 3 - Set Dynamic RTS/CTS mode + + Examples: + mlanutl mlan0 tx_ampdu_prot_mode + - Get currently set protection mode for Tx AMPDU + mlanutl mlan0 tx_ampdu_prot_mode 1 + - Set protection mode for Tx AMPDU to CTS2SELF + +rate_adapt_cfg + This command is used to switch between SR rateadapt and Legacy rateadapt. + FW default Algorithm is Legacy rateadapt + when SR rateadapt is enabled then it is used to set static threshold based + or dynamic noise based rate adaptation and set the timer interval to evaluate + sw rate adaptation.For static mode, low and high thresholds for Tx aggregated + pkt success rate should be configured. The Tx rate will decrease if success rate + goes lower than LOW_THRESH, will increase if it goes beyond HIGH_THRESH, and will + remain the same when success rate is between these thresholds.To set dynamic mode, + specify 0xff for both low and high thresh. + + Note: config can be set only before associating with an external AP + when in STA mode, or before starting bss when in uAP mode + + Usage: + mlanutl rate_adapt_cfg + [sr_rateadapt low_thresh high_thresh timer_interval] + + Where the parameters are: + : mlanX, + uapX + [sr_rateadapt] : SR Rateadapt or Legacy Rateadapt + [low_thresh] : lower tx success rate threshold + [high_thresh] : higher tx success rate threshold + [timer_interval] : interval to evaluate tx rate in sw in multiples + of 10 (ms) + + Examples: + mlanutl mlan0 rate_adapt_cfg + - Display SR rateadapt or Legacy rateadapt enabled + - Display current rate adapt configuration if SR rateadapt is enabled. + mlanutl uap0 rate_adapt_cfg 1 60 80 10 + - set lower Tx success rate threshold to 60%, higher to 80% + and evaluate tx rate every 100 ms (i.e 10 * 10 = 100 ms) + when SR Rateadapt is enabled. + mlanutl mlan0 rateadapt_cfg 0 + - switch to Legacy rateadapt. + mlanutl mlan0 rateadapt_cfg 1 + - switch to SR rateadapt. + Fw default is dynamic Success threshold enabled + with 100 ms linkadapt timer. + mlanutl mlan0 rate_adapt_cfg 1 50 70 50 + - set lower Tx success rate threshold to 50%, higher to 70% + and evaluate tx rate every 500 ms (i.e 50 * 10 = 500 ms) + when SR Rateadapt is enabled. + mlanutl mlan0 rate_adapt_cfg 1 0xff 0xff 10 + - set dynamic environment noise based mode and evaluate tx rate + every 100 ms (i.e 10 * 10 = 100 ms) + when SR Rateadapt is enabled. + +cck_desense_cfg + This command is used to configure CCK (802.11b) Desensitization RSSI + threshold. All CCK traffic beyond this threshold will be ignored, resulting + in higher Tx throughput. Threshold value is in absolute value of rssi in + dBm. In dynamic and enhanced modes, cck desense will be turned on only in + presence of an active connection and the effective CCK desense RSSI + threshold will be updated every rateadapt interval, based on: + min{ceil_thresh, [min RSSI among all connected peers] - margin} + + Further, for dynamic enhanced mode, CCK desense will be turned on/off based + on environment noise condition and ongoing Tx traffic rate. In this mode, + CCK desense will also be turned off periodically in order to allow 802.11b + Rx frames from Ext-AP, if rx rssi becomes weaker than the current threshold + or when in uAP mode, frames from clients which attempt to connect with the + uAP, but have weaker RSSI than the set threshold. + Turn on and off intervals are specified in terms of rateadapt intervals. + Please note that in this mode, if dynamic Rx Abort is enabled, then it + will turn on/off in sync with cck desense. + + Usage: + mlanutl cck_desense_cfg [mode] [margin ceil_thresh] + [num_on_intervals num_off_intervals] + + Where the parameters are: + : mlanX, + uapX + [mode] : 0 - Disable cck desense + 1 - Enable dynamic cck desense mode + 2 - Enable dynamic enhanced cck desense mode + [margin] : rssi margin in dBm (absolute val) + (default = 10) + [ceil_thresh] : ceiling weak RSSI pkt threshold in dBm + (absolute value) (default = 70) + [num_on_intervals] : number of rateadapt intervals to keep cck + desense "on" [for mode 2 only] (default = 20) + [num_off_intervals]: number of rateadapt intervals to keep cck + desense "off" [for mode 2 only] (default = 3) + + Examples: + mlanutl mlan0 cck_desense_cfg + - Display current cck desense configuration + mlanutl uap0 cck_desense_cfg 1 10 70 + - Set dynamic mode, margin to -10 dBm and ceil RSSI Threshold to + -70 dBm + mlanutl uap0 cck_desense_cfg 2 10 60 30 5 + - Set dynamic enhanced mode, margin to -10 dBm, ceil RSSI Threshold + to -60 dBm, num on intervals to 30 and num off intervals to 5. + mlanutl mlan0 cck_desense_cfg 1 10 50 + - Set dynamic mode, margin to -10 dBm and ceil RSSI Threshold to + -50 dBm + mlanutl mlan0 cck_desense_cfg 2 5 60 + - Set dynamic enhanced mode, set margin to -5 dBm, set ceil RSSI + Threshold to -60 dBm, and retain previous num on/off intervals + setting. + mlanutl mlan0 cck_desense_cfg 0 + - Disable cck desense + +lpm + This command is used to configure low power mode. + + Usage: + mlanutl mlanX/uapX lpm [mode] + + Where the paramter is: + [mode] : low power mode 0, 1, 2, 3 + + Examples: + mlanutl mlan0 lpm Get low power mode + mlanutl mlan0 lpm 1 Set low power mode to 1 + +=============================================================================== +=============================================================================== + U S E R M A N U A L F O R Enable Scan GAP + +Following commands can be used to enable gap between scans. + +mlanutl mlanX scancfg [t] [m] [p] [s] [a] [b] [c] [ext] [gap] +mlanutl mlanX setuserscan [ARGS] + +For detail information, please refer the command description. +=============================================================================== + diff --git a/mxm_wifiex/wlan_src/gpl-2.0.txt b/mxm_wifiex/wlan_src/gpl-2.0.txt new file mode 100644 index 0000000..2c62266 --- /dev/null +++ b/mxm_wifiex/wlan_src/gpl-2.0.txt @@ -0,0 +1,339 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your + freedom to share and change it. By contrast, the GNU General Public + License is intended to guarantee your freedom to share and change free + software--to make sure the software is free for all its users. This + General Public License applies to most of the Free Software + Foundation's software and to any other program whose authors commit to + using it. (Some other Free Software Foundation software is covered by + the GNU Lesser General Public License instead.) You can apply it to + your programs, too. + + When we speak of free software, we are referring to freedom, not + price. Our General Public Licenses are designed to make sure that you + have the freedom to distribute copies of free software (and charge for + this service if you wish), that you receive source code or can get it + if you want it, that you can change the software or use pieces of it + in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid + anyone to deny you these rights or to ask you to surrender the rights. + These restrictions translate to certain responsibilities for you if you + distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether + gratis or for a fee, you must give the recipients all the rights that + you have. You must make sure that they, too, receive or can get the + source code. And you must show them these terms so they know their + rights. + + We protect your rights with two steps: (1) copyright the software, and + (2) offer you this license which gives you legal permission to copy, + distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain + that everyone understands that there is no warranty for this free + software. If the software is modified by someone else and passed on, we + want its recipients to know that what they have is not the original, so + that any problems introduced by others will not reflect on the original + authors' reputations. + + Finally, any free program is threatened constantly by software + patents. We wish to avoid the danger that redistributors of a free + program will individually obtain patent licenses, in effect making the + program proprietary. To prevent this, we have made it clear that any + patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and + modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains + a notice placed by the copyright holder saying it may be distributed + under the terms of this General Public License. The "Program", below, + refers to any such program or work, and a "work based on the Program" + means either the Program or any derivative work under copyright law: + that is to say, a work containing the Program or a portion of it, + either verbatim or with modifications and/or translated into another + language. (Hereinafter, translation is included without limitation in + the term "modification".) Each licensee is addressed as "you". + + Activities other than copying, distribution and modification are not + covered by this License; they are outside its scope. The act of + running the Program is not restricted, and the output from the Program + is covered only if its contents constitute a work based on the + Program (independent of having been made by running the Program). + Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's + source code as you receive it, in any medium, provided that you + conspicuously and appropriately publish on each copy an appropriate + copyright notice and disclaimer of warranty; keep intact all the + notices that refer to this License and to the absence of any warranty; + and give any other recipients of the Program a copy of this License + along with the Program. + + You may charge a fee for the physical act of transferring a copy, and + you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion + of it, thus forming a work based on the Program, and copy and + distribute such modifications or work under the terms of Section 1 + above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + + These requirements apply to the modified work as a whole. If + identifiable sections of that work are not derived from the Program, + and can be reasonably considered independent and separate works in + themselves, then this License, and its terms, do not apply to those + sections when you distribute them as separate works. But when you + distribute the same sections as part of a whole which is a work based + on the Program, the distribution of the whole must be on the terms of + this License, whose permissions for other licensees extend to the + entire whole, and thus to each and every part regardless of who wrote it. + + Thus, it is not the intent of this section to claim rights or contest + your rights to work written entirely by you; rather, the intent is to + exercise the right to control the distribution of derivative or + collective works based on the Program. + + In addition, mere aggregation of another work not based on the Program + with the Program (or with a work based on the Program) on a volume of + a storage or distribution medium does not bring the other work under + the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, + under Section 2) in object code or executable form under the terms of + Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + + The source code for a work means the preferred form of the work for + making modifications to it. For an executable work, complete source + code means all the source code for all modules it contains, plus any + associated interface definition files, plus the scripts used to + control compilation and installation of the executable. However, as a + special exception, the source code distributed need not include + anything that is normally distributed (in either source or binary + form) with the major components (compiler, kernel, and so on) of the + operating system on which the executable runs, unless that component + itself accompanies the executable. + + If distribution of executable or object code is made by offering + access to copy from a designated place, then offering equivalent + access to copy the source code from the same place counts as + distribution of the source code, even though third parties are not + compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program + except as expressly provided under this License. Any attempt + otherwise to copy, modify, sublicense or distribute the Program is + void, and will automatically terminate your rights under this License. + However, parties who have received copies, or rights, from you under + this License will not have their licenses terminated so long as such + parties remain in full compliance. + + 5. You are not required to accept this License, since you have not + signed it. However, nothing else grants you permission to modify or + distribute the Program or its derivative works. These actions are + prohibited by law if you do not accept this License. Therefore, by + modifying or distributing the Program (or any work based on the + Program), you indicate your acceptance of this License to do so, and + all its terms and conditions for copying, distributing or modifying + the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the + Program), the recipient automatically receives a license from the + original licensor to copy, distribute or modify the Program subject to + these terms and conditions. You may not impose any further + restrictions on the recipients' exercise of the rights granted herein. + You are not responsible for enforcing compliance by third parties to + this License. + + 7. If, as a consequence of a court judgment or allegation of patent + infringement or for any other reason (not limited to patent issues), + conditions are imposed on you (whether by court order, agreement or + otherwise) that contradict the conditions of this License, they do not + excuse you from the conditions of this License. If you cannot + distribute so as to satisfy simultaneously your obligations under this + License and any other pertinent obligations, then as a consequence you + may not distribute the Program at all. For example, if a patent + license would not permit royalty-free redistribution of the Program by + all those who receive copies directly or indirectly through you, then + the only way you could satisfy both it and this License would be to + refrain entirely from distribution of the Program. + + If any portion of this section is held invalid or unenforceable under + any particular circumstance, the balance of the section is intended to + apply and the section as a whole is intended to apply in other + circumstances. + + It is not the purpose of this section to induce you to infringe any + patents or other property right claims or to contest validity of any + such claims; this section has the sole purpose of protecting the + integrity of the free software distribution system, which is + implemented by public license practices. Many people have made + generous contributions to the wide range of software distributed + through that system in reliance on consistent application of that + system; it is up to the author/donor to decide if he or she is willing + to distribute software through any other system and a licensee cannot + impose that choice. + + This section is intended to make thoroughly clear what is believed to + be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in + certain countries either by patents or by copyrighted interfaces, the + original copyright holder who places the Program under this License + may add an explicit geographical distribution limitation excluding + those countries, so that distribution is permitted only in or among + countries not thus excluded. In such case, this License incorporates + the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions + of the General Public License from time to time. Such new versions will + be similar in spirit to the present version, but may differ in detail to + address new problems or concerns. + + Each version is given a distinguishing version number. If the Program + specifies a version number of this License which applies to it and "any + later version", you have the option of following the terms and conditions + either of that version or of any later version published by the Free + Software Foundation. If the Program does not specify a version number of + this License, you may choose any version ever published by the Free Software + Foundation. + + 10. If you wish to incorporate parts of the Program into other free + programs whose distribution conditions are different, write to the author + to ask for permission. For software which is copyrighted by the Free + Software Foundation, write to the Free Software Foundation; we sometimes + make exceptions for this. Our decision will be guided by the two goals + of preserving the free status of all derivatives of our free software and + of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY + FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN + OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES + PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED + OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS + TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE + PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, + REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING + WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR + REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, + INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING + OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED + TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY + YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER + PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE + POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest + possible use to the public, the best way to achieve this is to make it + free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest + to attach them to the start of each source file to most effectively + convey the exclusion of warranty; and each file should have at least + the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + Also add information on how to contact you by electronic and paper mail. + + If the program is interactive, make it output a short notice like this + when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + + The hypothetical commands `show w' and `show c' should show the appropriate + parts of the General Public License. Of course, the commands you use may + be called something other than `show w' and `show c'; they could even be + mouse-clicks or menu items--whatever suits your program. + + You should also get your employer (if you work as a programmer) or your + school, if any, to sign a "copyright disclaimer" for the program, if + necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + + This General Public License does not permit incorporating your program into + proprietary programs. If your program is a subroutine library, you may + consider it more useful to permit linking proprietary applications with the + library. If this is what you want to do, use the GNU Lesser General + Public License instead of this License. diff --git a/mxm_wifiex/wlan_src/mapp/mlan2040coex/Makefile b/mxm_wifiex/wlan_src/mapp/mlan2040coex/Makefile new file mode 100644 index 0000000..9725f90 --- /dev/null +++ b/mxm_wifiex/wlan_src/mapp/mlan2040coex/Makefile @@ -0,0 +1,48 @@ +# +# File : mlan2040coex/Makefile +# +# Copyright 2014-2020 NXP + +# Path to the top directory of the mlandriver distribution +PATH_TO_TOP = ../.. + +# Determine how we should copy things to the install directory +ABSPATH := $(filter /%, $(INSTALLDIR)) +RELPATH := $(filter-out /%, $(INSTALLDIR)) +INSTALLPATH := $(ABSPATH) +ifeq ($(strip $(INSTALLPATH)),) +INSTALLPATH := $(PATH_TO_TOP)/$(RELPATH) +endif + +# Override CFLAGS for application sources, remove __ kernel namespace defines +CFLAGS := $(filter-out -D__%, $(ccflags-y)) +# remove KERNEL include dir +CFLAGS := $(filter-out -I$(KERNELDIR)%, $(CFLAGS)) + +# +# List of application executables to create +# +libobjs:= mlan2040coex.o mlan2040misc.o +exectarget=mlan2040coex +TARGETS := $(exectarget) + +# +# Make target rules +# + +# All rule compiles list of TARGETS using builtin program target from src rule +all : +$(exectarget): $(libobjs) + $(CC) $(CFLAGS) $(libobjs) -o $(exectarget) + +# Update any needed TARGETS and then copy to the install path +build install: $(TARGETS) + @cp -f $(exectarget) $(INSTALLPATH) + +clean: + @rm -f $(exectarget) + @rm -f *.o + +distclean: clean + @rm -f *~ core + @rm -f tags diff --git a/mxm_wifiex/wlan_src/mapp/mlan2040coex/mlan2040coex.c b/mxm_wifiex/wlan_src/mapp/mlan2040coex/mlan2040coex.c new file mode 100644 index 0000000..8d2b398 --- /dev/null +++ b/mxm_wifiex/wlan_src/mapp/mlan2040coex/mlan2040coex.c @@ -0,0 +1,1387 @@ +/** @file mlan2040coex.c + * + * @brief 11n 20/40 MHz Coex application + * + * Usage: + * + * + * Copyright 2014-2020 NXP + * + * NXP CONFIDENTIAL + * The source code contained or described herein and all documents related to + * the source code (Materials) are owned by NXP, its + * suppliers and/or its licensors. Title to the Materials remains with NXP, + * its suppliers and/or its licensors. The Materials contain + * trade secrets and proprietary and confidential information of NXP, its + * suppliers and/or its licensors. The Materials are protected by worldwide copyright + * and trade secret laws and treaty provisions. No part of the Materials may be + * used, copied, reproduced, modified, published, uploaded, posted, + * transmitted, distributed, or disclosed in any way without NXP's prior + * express written permission. + * + * No license under any patent, copyright, trade secret or other intellectual + * property right is granted to or conferred upon you by disclosure or delivery + * of the Materials, either expressly, by implication, inducement, estoppel or + * otherwise. Any license under such intellectual property rights must be + * express and approved by NXP in writing. + * + */ +/************************************************************************ +Change log: + 06/24/2009: initial version +************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "mlan2040coex.h" +#include "mlan2040misc.h" + +/** coex application's version number */ +#define COEX_VER "M2.0" + +/** Initial number of total private ioctl calls */ +#define IW_INIT_PRIV_NUM 128 +/** Maximum number of total private ioctl calls supported */ +#define IW_MAX_PRIV_NUM 1024 + +/******************************************************** + Local Variables +********************************************************/ + +static char *usage[] = { + "Usage: ", + " mlan2040coex [-i ] [-hvB] ", + " -h = help", + " -v = version", + " -B = run the process in background.", + " (if intfname not present then mlan0 assumed)" +}; + +t_s32 sockfd = 0; /**< socket descriptor */ +char dev_name[IFNAMSIZ + 1]; /**< device name */ + +/** Flag: is 2040coex command required */ +int coex_cmd_req_flag = FALSE; +/** Flag: is associated */ +int assoc_flag = FALSE; +/** Flag: is HT AP */ +int is_ht_ap = FALSE; +/** terminate flag */ +int terminate_flag = FALSE; + +/******************************************************** + Global Variables +********************************************************/ +/** OBSS scan parameter of associated AP */ +OBSSScanParam_t cur_obss_scan_param; + +/******************************************************** + Local Functions +********************************************************/ + +/** + * @brief Prepare command buffer + * @param buffer Command buffer to be filled + * @param cmd Command id + * @param num Number of arguments + * @param args Arguments list + * @return MLAN_STATUS_SUCCESS + */ +static int +prepare_buffer(t_u8 *buffer, char *cmd, t_u32 num, char *args[]) +{ + t_u8 *pos = NULL; + unsigned int i = 0; + + memset(buffer, 0, MRVDRV_SIZE_OF_CMD_BUFFER); + + /* Flag it for our use */ + pos = buffer; + strncpy((char *)pos, CMD_NXP, strlen(CMD_NXP)); + pos += (strlen(CMD_NXP)); + + /* Insert command */ + strncpy((char *)pos, (char *)cmd, strlen(cmd)); + pos += (strlen(cmd)); + + /* Insert arguments */ + for (i = 0; i < num; i++) { + strncpy((char *)pos, args[i], strlen(args[i])); + pos += strlen(args[i]); + if (i < (num - 1)) { + strncpy((char *)pos, " ", strlen(" ")); + pos += 1; + } + } + + return MLAN_STATUS_SUCCESS; +} + +/** + * @brief Process OBSS scan table + * @return MLAN_STATUS_SUCCESS--success, otherwise--fail + */ +int +process_scantable(void) +{ + char ssid[MRVDRV_MAX_SSID_LENGTH + 1] = { 0 }; + unsigned int scan_start; + int idx, i = 0, j, already_listed, ssid_len = 0, ssid_idx; + + t_u8 *pcurrent; + t_u8 *pnext; + IEEEtypes_ElementId_e *pelement_id; + t_u8 *pelement_len, ht_cap_present, intol_bit_is_set; + int ret = MLAN_STATUS_SUCCESS; + t_s32 bss_info_len = 0; + t_u32 fixed_field_length = 0; + + IEEEtypes_CapInfo_t cap_info; + t_u8 tsf[8]; + t_u16 beacon_interval; + IEEEtypes_HTCap_t *pht_cap; + + wlan_ioctl_get_scan_table_info *prsp_info; + wlan_get_scan_table_fixed fixed_fields; + + t_u8 *buffer = NULL; + struct eth_priv_cmd *cmd = NULL; + struct ifreq ifr; + + /* Start preparing the buffer */ + /* Initialize buffer */ + buffer = (t_u8 *)malloc(MRVDRV_SIZE_OF_CMD_BUFFER); + if (!buffer) { + printf("ERR:Cannot allocate buffer for command!\n"); + ret = MLAN_STATUS_FAILURE; + goto done; + } + + cmd = (struct eth_priv_cmd *)malloc(sizeof(struct eth_priv_cmd)); + if (!cmd) { + printf("ERR:Cannot allocate buffer for command!\n"); + ret = MLAN_STATUS_FAILURE; + goto done; + } + + /* Fill up buffer */ +#ifdef USERSPACE_32BIT_OVER_KERNEL_64BIT + memset(cmd, 0, sizeof(struct eth_priv_cmd)); + memcpy(&cmd->buf, &buffer, sizeof(buffer)); +#else + cmd->buf = buffer; +#endif + cmd->used_len = 0; + cmd->total_len = MRVDRV_SIZE_OF_CMD_BUFFER; + + memset(&cap_info, 0x00, sizeof(cap_info)); + memset(leg_ap_chan_list, 0, sizeof(leg_ap_chan_list)); + num_leg_ap_chan = 0; + + scan_start = 1; + + do { + /* buffer = CMD_NXP + */ + prepare_buffer(buffer, "getscantable", 0, NULL); + prsp_info = + (wlan_ioctl_get_scan_table_info *)(buffer + + strlen(CMD_NXP) + + strlen + ("getscantable")); + + prsp_info->scan_number = scan_start; + + /* Perform IOCTL */ + memset(&ifr, 0, sizeof(struct ifreq)); + strncpy(ifr.ifr_ifrn.ifrn_name, dev_name, strlen(dev_name)); + ifr.ifr_ifru.ifru_data = (void *)cmd; + + if (ioctl(sockfd, MLAN_ETH_PRIV, &ifr)) { + if (errno == EAGAIN) { + ret = -EAGAIN; + } else { + perror("mlan2040coex"); + fprintf(stderr, + "mlan2040coex: getscantable fail\n"); + ret = MLAN_STATUS_FAILURE; + } + goto done; + } + + prsp_info = (wlan_ioctl_get_scan_table_info *)buffer; + pcurrent = 0; + pnext = prsp_info->scan_table_entry_buf; + + if (scan_start == 1) { + printf("----------------------------------------------\n"); + } + + for (idx = 0; (unsigned int)idx < prsp_info->scan_number; idx++) { + + /* + * Set pcurrent to pnext in case pad bytes are at the end + * of the last IE we processed. + */ + pcurrent = pnext; + + memcpy((t_u8 *)&fixed_field_length, + (t_u8 *)pcurrent, sizeof(fixed_field_length)); + pcurrent += sizeof(fixed_field_length); + + memcpy((t_u8 *)&bss_info_len, + (t_u8 *)pcurrent, sizeof(bss_info_len)); + pcurrent += sizeof(bss_info_len); + + memcpy((t_u8 *)&fixed_fields, + (t_u8 *)pcurrent, sizeof(fixed_fields)); + pcurrent += fixed_field_length; + + pnext = pcurrent + bss_info_len; + + if (bss_info_len >= (sizeof(tsf) + + sizeof(beacon_interval) + + sizeof(cap_info))) { + pcurrent += + (sizeof(tsf) + sizeof(beacon_interval) + + sizeof(cap_info)); + bss_info_len -= + (sizeof(tsf) + sizeof(beacon_interval) + + sizeof(cap_info)); + } + ht_cap_present = FALSE; + intol_bit_is_set = FALSE; + memset(ssid, 0, MRVDRV_MAX_SSID_LENGTH + 1); + ssid_len = 0; + while (bss_info_len >= 2) { + pelement_id = (IEEEtypes_ElementId_e *)pcurrent; + pelement_len = pcurrent + 1; + pcurrent += 2; + + switch (*pelement_id) { + case SSID: + if (*pelement_len && + *pelement_len <= + MRVDRV_MAX_SSID_LENGTH) { + memcpy(ssid, pcurrent, + *pelement_len); + ssid_len = *pelement_len; + } + break; + + case HT_CAPABILITY: + pht_cap = + (IEEEtypes_HTCap_t *) + pelement_id; + ht_cap_present = TRUE; + if (IS_INTOL_BIT_SET + (le16_to_cpu + (pht_cap->ht_cap.ht_cap_info))) { + intol_bit_is_set = TRUE; + } + break; + default: + break; + } + pcurrent += *pelement_len; + bss_info_len -= (2 + *pelement_len); + } + if (!ht_cap_present || intol_bit_is_set) { + printf("%s AP found on channel number: %-3d ", + intol_bit_is_set ? "40 MHZ intolerant" : + "Legacy", fixed_fields.channel); + if (ssid_len) { + printf("SSID: "); + /* Print out the ssid or the hex values if non-printable */ + for (ssid_idx = 0; ssid_idx < ssid_len; + ssid_idx++) { + if (isprint(ssid[ssid_idx])) { + printf("%c", + ssid[ssid_idx]); + } else { + printf("\\%02x", + ssid[ssid_idx]); + } + } + } + printf("\n"); + + /* Verify that the channel is already listed or not */ + already_listed = FALSE; + for (j = 0; j < i; j++) { + if (leg_ap_chan_list[j].chan_num == + fixed_fields.channel) { + already_listed = TRUE; + if (intol_bit_is_set) + leg_ap_chan_list[j]. + is_intol_set = + intol_bit_is_set; + break; + } + } + if (!already_listed) { + /* add the channel in list */ + leg_ap_chan_list[i].chan_num = + fixed_fields.channel; + leg_ap_chan_list[i].is_intol_set = + intol_bit_is_set; + i++; + coex_cmd_req_flag = TRUE; + num_leg_ap_chan++; + } + } + } + scan_start += prsp_info->scan_number; + + } while (prsp_info->scan_number); + +done: + if (cmd) + free(cmd); + if (buffer) + free(buffer); + return ret; +} + +/** BSS Mode any (both infra and adhoc) */ +#define BSS_MODE_ANY 3 + +/** current scan config parameters */ +#define SCAN_CFG_PARAMS 7 + +/** Active : 1 , Passive : 2 */ +#define SCAN_TYPE_ACTIVE 1 + +/** + * @brief Issue get scan type command + * @return MLAN_STATUS_SUCCESS--success, otherwise--fail + */ +static int +get_scan_cfg(int *scan_param) +{ + t_u8 *buffer = NULL; + struct eth_priv_cmd *cmd = NULL; + struct ifreq ifr; + int ret = MLAN_STATUS_SUCCESS; + + /* Start preparing the buffer */ + /* Initialize buffer */ + buffer = (t_u8 *)malloc(MRVDRV_SIZE_OF_CMD_BUFFER); + if (!buffer) { + printf("ERR:Cannot allocate buffer for command!\n"); + return MLAN_STATUS_FAILURE; + } + + /* buffer = CMD_NXP + */ + prepare_buffer(buffer, "scancfg", 0, NULL); + + cmd = (struct eth_priv_cmd *)malloc(sizeof(struct eth_priv_cmd)); + if (!cmd) { + printf("ERR:Cannot allocate buffer for command!\n"); + ret = MLAN_STATUS_FAILURE; + goto done; + } + + /* Fill up buffer */ +#ifdef USERSPACE_32BIT_OVER_KERNEL_64BIT + memset(cmd, 0, sizeof(struct eth_priv_cmd)); + memcpy(&cmd->buf, &buffer, sizeof(buffer)); +#else + cmd->buf = buffer; +#endif + cmd->used_len = 0; + cmd->total_len = MRVDRV_SIZE_OF_CMD_BUFFER; + + /* Perform IOCTL */ + memset(&ifr, 0, sizeof(struct ifreq)); + strncpy(ifr.ifr_ifrn.ifrn_name, dev_name, strlen(dev_name)); + ifr.ifr_ifru.ifru_data = (void *)cmd; + + if (ioctl(sockfd, MLAN_ETH_PRIV, &ifr)) { + perror("mlan2040coex"); + fprintf(stderr, "mlan2040coex: get_scan_cfg fail\n"); + ret = MLAN_STATUS_FAILURE; + goto done; + } + scan_param = (int *)(buffer); +done: + if (cmd) + free(cmd); + if (buffer) + free(buffer); + + return ret; +} + +/** + * @brief Issue OBSS scan command + * @return MLAN_STATUS_SUCCESS--success, otherwise--fail + */ +int +process_setuserscan(void) +{ + wlan_ioctl_user_scan_cfg scan_req; + int scan_cfg[SCAN_CFG_PARAMS]; + t_u8 *buffer = NULL, *pos = NULL; + struct eth_priv_cmd *cmd = NULL; + struct ifreq ifr; + int status = 0; + + memset(&scan_req, 0x00, sizeof(scan_req)); + memset(scan_cfg, 0x00, SCAN_CFG_PARAMS); + coex_cmd_req_flag = FALSE; + + if (get_scan_cfg(scan_cfg) != MLAN_STATUS_SUCCESS) { + printf("mlan2040coex: scancfg ioctl failure"); + return -EFAULT; + } + + if (scan_cfg[0] == SCAN_TYPE_ACTIVE) + scan_req.chan_list[0].scan_time = + (t_u32)le16_to_cpu(cur_obss_scan_param. + obss_scan_active_dwell); + else + scan_req.chan_list[0].scan_time = + (t_u32)le16_to_cpu(cur_obss_scan_param. + obss_scan_passive_total); + scan_req.bss_mode = (scan_cfg[1]) ? scan_cfg[1] : BSS_MODE_ANY; + + /* Start preparing the buffer */ + /* Initialize buffer */ + buffer = (t_u8 *)malloc(MRVDRV_SIZE_OF_CMD_BUFFER); + if (!buffer) { + printf("ERR:Cannot allocate buffer for command!\n"); + return MLAN_STATUS_FAILURE; + } + + /* buffer = CMD_NXP + */ + prepare_buffer(buffer, "setuserscan", 0, NULL); + pos = buffer + strlen(CMD_NXP) + strlen("setuserscan"); + + /* buffer = buffer + 'scan_req' */ + memcpy(pos, &scan_req, sizeof(wlan_ioctl_user_scan_cfg)); + + cmd = (struct eth_priv_cmd *)malloc(sizeof(struct eth_priv_cmd)); + if (!cmd) { + printf("ERR:Cannot allocate buffer for command!\n"); + free(buffer); + return MLAN_STATUS_FAILURE; + } + + /* Fill up buffer */ +#ifdef USERSPACE_32BIT_OVER_KERNEL_64BIT + memset(cmd, 0, sizeof(struct eth_priv_cmd)); + memcpy(&cmd->buf, &buffer, sizeof(buffer)); +#else + cmd->buf = buffer; +#endif + cmd->used_len = 0; + cmd->total_len = MRVDRV_SIZE_OF_CMD_BUFFER; + + /* Perform IOCTL */ + memset(&ifr, 0, sizeof(struct ifreq)); + strncpy(ifr.ifr_ifrn.ifrn_name, dev_name, strlen(dev_name)); + ifr.ifr_ifru.ifru_data = (void *)cmd; + + if (ioctl(sockfd, MLAN_ETH_PRIV, &ifr)) { + perror("mlan2040coex"); + fprintf(stderr, "mlan2040coex: setuserscan fail\n"); + if (cmd) + free(cmd); + if (buffer) + free(buffer); + return MLAN_STATUS_FAILURE; + } + + /** process scan results */ + do { + status = process_scantable(); + } while (status == -EAGAIN); + + if (cmd) + free(cmd); + if (buffer) + free(buffer); + + return MLAN_STATUS_SUCCESS; +} + +/** + * @brief Display usage + * + * @return NA + */ +static t_void +display_usage(t_void) +{ + t_u32 i; + for (i = 0; i < NELEMENTS(usage); i++) + fprintf(stderr, "%s\n", usage[i]); +} + +/** + * @brief get connection status + * + * @param data Pointer to the output buffer holding connection status + * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE + */ +int +get_connstatus(int *data) +{ + struct ether_addr apaddr; + struct ether_addr etherzero = { {0x00, 0x00, 0x00, 0x00, 0x00, 0x00} }; + t_u8 *buffer = NULL; + struct eth_priv_cmd *cmd = NULL; + struct ifreq ifr; + + /* Initialize buffer */ + buffer = (t_u8 *)malloc(MRVDRV_SIZE_OF_CMD_BUFFER); + if (!buffer) { + printf("ERR:Cannot allocate buffer for command!\n"); + return MLAN_STATUS_FAILURE; + } + + /* buffer = CMD_NXP + */ + prepare_buffer(buffer, "getwap", 0, NULL); + + cmd = (struct eth_priv_cmd *)malloc(sizeof(struct eth_priv_cmd)); + if (!cmd) { + printf("ERR:Cannot allocate buffer for command!\n"); + free(buffer); + return MLAN_STATUS_FAILURE; + } + + /* Fill up buffer */ +#ifdef USERSPACE_32BIT_OVER_KERNEL_64BIT + memset(cmd, 0, sizeof(struct eth_priv_cmd)); + memcpy(&cmd->buf, &buffer, sizeof(buffer)); +#else + cmd->buf = buffer; +#endif + cmd->used_len = 0; + cmd->total_len = MRVDRV_SIZE_OF_CMD_BUFFER; + + /* Perform IOCTL */ + memset(&ifr, 0, sizeof(struct ifreq)); + strncpy(ifr.ifr_ifrn.ifrn_name, dev_name, strlen(dev_name)); + ifr.ifr_ifru.ifru_data = (void *)cmd; + + if (ioctl(sockfd, MLAN_ETH_PRIV, &ifr)) { + perror("mlan2040coex"); + fprintf(stderr, "mlan2040coex: getwap fail\n"); + if (cmd) + free(cmd); + if (buffer) + free(buffer); + return MLAN_STATUS_FAILURE; + } + + memset(&apaddr, 0, sizeof(struct ether_addr)); + memcpy(&apaddr, (struct ether_addr *)(buffer), + sizeof(struct ether_addr)); + + if (!memcmp(&apaddr, ðerzero, sizeof(struct ether_addr))) { + /* not associated */ + *data = FALSE; + } else { + /* associated */ + *data = TRUE; + } + + if (buffer) + free(buffer); + if (cmd) + free(cmd); + + return MLAN_STATUS_SUCCESS; +} + +/** + * @brief Print connect and disconnect event related information + * + * @param buffer Pointer to received event buffer + * @param size Length of the received event + * + * @return N/A + */ +void +print_event_drv_connected(t_u8 *buffer, t_u16 size) +{ + struct ether_addr *wap; + struct ether_addr etherzero = { {0x00, 0x00, 0x00, 0x00, 0x00, 0x00} }; + char buf[32]; + + wap = (struct ether_addr *)(buffer + strlen(CUS_EVT_AP_CONNECTED)); + + if (!memcmp(wap, ðerzero, sizeof(struct ether_addr))) { + printf("---< Disconnected from AP >---\n"); + memset(&cur_obss_scan_param, 0, sizeof(cur_obss_scan_param)); + assoc_flag = FALSE; + is_ht_ap = FALSE; + } else { + memset(buf, 0, sizeof(buf)); + snprintf(buf, sizeof(buf), "%02X:%02X:%02X:%02X:%02X:%02X", + wap->ether_addr_octet[0], + wap->ether_addr_octet[1], + wap->ether_addr_octet[2], + wap->ether_addr_octet[3], + wap->ether_addr_octet[4], wap->ether_addr_octet[5]); + printf("---< Connected to AP: %s >---\n", buf); + /** set TRUE, if connected */ + assoc_flag = TRUE; + } +} + +/** + * @brief Parse and print received event information + * + * @param event Pointer to received event + * @param size Length of the received event + * @param evt_conn A pointer to a output buffer. It sets TRUE when it gets + * the event CUS_EVT_OBSS_SCAN_PARAM, otherwise FALSE + * @param if_name The interface name + * + * @return N/A + */ +void +print_event(event_header *event, t_u16 size, int *evt_conn, char *if_name) +{ + if (!strncmp + (CUS_EVT_AP_CONNECTED, (char *)event, + strlen(CUS_EVT_AP_CONNECTED))) { + if (strlen(if_name)) + printf("EVENT for interface %s\n", if_name); + print_event_drv_connected((t_u8 *)event, size); + return; + } + if (!strncmp + (CUS_EVT_OBSS_SCAN_PARAM, (char *)event, + strlen(CUS_EVT_OBSS_SCAN_PARAM))) { + if (strlen(if_name)) + printf("EVENT for interface %s\n", if_name); + printf("---< %s >---\n", CUS_EVT_OBSS_SCAN_PARAM); + memset(&cur_obss_scan_param, 0, sizeof(cur_obss_scan_param)); + memcpy(&cur_obss_scan_param, + ((t_u8 *)event + strlen(CUS_EVT_OBSS_SCAN_PARAM) + 1), + sizeof(cur_obss_scan_param)); + /** set TRUE, since it is an HT AP */ + is_ht_ap = TRUE; + *evt_conn = TRUE; + return; + } + if (!strncmp + (CUS_EVT_BW_CHANGED, (char *)event, strlen(CUS_EVT_BW_CHANGED))) { + if (strlen(if_name)) + printf("EVENT for interface %s\n", if_name); + printf("---< %s >---\n", CUS_EVT_BW_CHANGED); + return; + } +} + +/** + * @brief This function parses for NETLINK events + * + * @param nlh Pointer to Netlink message header + * @param bytes_read Number of bytes to be read + * @param evt_conn A pointer to a output buffer. It sets TRUE when it gets + * the event CUS_EVT_OBSS_SCAN_PARAM, otherwise FALSE + * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE + */ +static int +drv_nlevt_handler(struct nlmsghdr *nlh, int bytes_read, int *evt_conn) +{ + int len, plen; + t_u8 *buffer = NULL; + t_u32 event_id = 0; + event_header *event = NULL; + char if_name[IFNAMSIZ + 1]; + + /* Initialize receive buffer */ + buffer = (t_u8 *)malloc(NL_MAX_PAYLOAD); + if (!buffer) { + printf("ERR: Could not alloc buffer\n"); + return MLAN_STATUS_FAILURE; + } + memset(buffer, 0, NL_MAX_PAYLOAD); + + *evt_conn = FALSE; + while ((unsigned int)bytes_read >= NLMSG_HDRLEN) { + len = nlh->nlmsg_len; /* Length of message including header */ + plen = len - NLMSG_HDRLEN; + if (len > bytes_read || plen < 0) { + free(buffer); + /* malformed netlink message */ + return MLAN_STATUS_FAILURE; + } + if ((unsigned int)len > NLMSG_SPACE(NL_MAX_PAYLOAD)) { + printf("ERR:Buffer overflow!\n"); + free(buffer); + return MLAN_STATUS_FAILURE; + } + memset(buffer, 0, NL_MAX_PAYLOAD); + memcpy(buffer, NLMSG_DATA(nlh), plen); + + if (NLMSG_OK(nlh, len)) { + memcpy(&event_id, buffer, sizeof(event_id)); + + if (((event_id & 0xFF000000) == 0x80000000) || + ((event_id & 0xFF000000) == 0)) { + event = (event_header *)buffer; + } else { + memset(if_name, 0, IFNAMSIZ + 1); + memcpy(if_name, buffer, IFNAMSIZ); + event = (event_header *)(buffer + IFNAMSIZ); + } + } + + print_event(event, bytes_read, evt_conn, if_name); + len = NLMSG_ALIGN(len); + bytes_read -= len; + nlh = (struct nlmsghdr *)((char *)nlh + len); + } + free(buffer); + return MLAN_STATUS_SUCCESS; +} + +/** Maximum event message length */ +#define MAX_MSG_LENGTH 1024 + +/** + * @brief Configure and read event data from netlink socket + * + * @param nl_sk Netlink socket handler + * @param msg Pointer to message header + * @param ptv Pointer to struct timeval + * + * @return Number of bytes read or MLAN_STATUS_FAILURE + */ +int +read_event(int nl_sk, struct msghdr *msg, struct timeval *ptv) +{ + int count = -1; + int ret = MLAN_STATUS_FAILURE; + fd_set rfds; + + /* Setup read fds and initialize event buffers */ + FD_ZERO(&rfds); + FD_SET(nl_sk, &rfds); + + /* Wait for reply */ + ret = select(nl_sk + 1, &rfds, NULL, NULL, ptv); + + if (ret == MLAN_STATUS_FAILURE) { + /* Error */ + terminate_flag++; + ptv->tv_sec = DEFAULT_SCAN_INTERVAL; + ptv->tv_usec = 0; + goto done; + } else if (!ret) { + if (assoc_flag && is_ht_ap) { + /** Issue OBSS scan */ + process_setuserscan(); + /** Invoke 2040coex command, if any legacy AP found or + * any AP has 40MHz intolarent bit set */ + if (coex_cmd_req_flag) + invoke_coex_command(); + } + if (assoc_flag && is_ht_ap) { + /* Timeout. Try again after BSS channel width triger scan + interval when the STA is connected with a HT AP */ + ptv->tv_sec = + (t_u32)le16_to_cpu(cur_obss_scan_param. + bss_chan_width_trigger_scan_int); + } else { + /* Timeout. Try again after default duration when the STA is + not connected with a HT AP */ + ptv->tv_sec = DEFAULT_SCAN_INTERVAL; + } + ptv->tv_usec = 0; + goto done; + } + + if (!FD_ISSET(nl_sk, &rfds)) { + /* Unexpected error. Try again */ + ptv->tv_sec = DEFAULT_SCAN_INTERVAL; + ptv->tv_usec = 0; + goto done; + } + /* Success */ + count = recvmsg(nl_sk, msg, 0); + +done: + return count; +} + +/** Maximum event message length */ +#define MAX_MSG_LENGTH 1024 +/** + * @brief Run the application + * + * @param nl_sk Netlink socket + * + * @return N/A + */ +void +run_app(int nl_sk) +{ + struct timeval tv; + int bytes_read, evt_conn; + struct msghdr msg; + struct sockaddr_nl dest_addr; + struct nlmsghdr *nlh; + struct iovec iov; + + /** Get connection status */ + if (get_connstatus(&assoc_flag) == MLAN_STATUS_FAILURE) + return; + + /* Initialize timeout value */ + tv.tv_sec = DEFAULT_SCAN_INTERVAL; + tv.tv_usec = 0; + + /* Initialize netlink header */ + nlh = (struct nlmsghdr *)malloc(NLMSG_SPACE(NL_MAX_PAYLOAD)); + if (!nlh) { + printf("ERR: Could not allocate space for netlink header\n"); + goto done; + } + memset(nlh, 0, NLMSG_SPACE(NL_MAX_PAYLOAD)); + /* Fill the netlink message header */ + nlh->nlmsg_len = NLMSG_SPACE(NL_MAX_PAYLOAD); + nlh->nlmsg_pid = getpid(); /* self pid */ + nlh->nlmsg_flags = 0; + + /* Initialize I/O vector */ + memset(&iov, 0, sizeof(struct iovec)); + iov.iov_base = (void *)nlh; + iov.iov_len = nlh->nlmsg_len; + + /* Set destination address */ + memset(&dest_addr, 0, sizeof(struct sockaddr_nl)); + dest_addr.nl_family = AF_NETLINK; + dest_addr.nl_pid = 0; /* Kernel */ + dest_addr.nl_groups = NL_MULTICAST_GROUP; + + /* Initialize message header */ + memset(&msg, 0, sizeof(struct msghdr)); + msg.msg_name = (void *)&dest_addr; + msg.msg_namelen = sizeof(dest_addr); + msg.msg_iov = &iov; + msg.msg_iovlen = 1; + + while (!terminate_flag) { + /* event buffer is received for all the interfaces */ + bytes_read = read_event(nl_sk, &msg, &tv); + /* handle only NETLINK events here */ + drv_nlevt_handler((struct nlmsghdr *)nlh, bytes_read, + &evt_conn); + if (assoc_flag && is_ht_ap) { + /** If the event is connected with an HT AP then issue OBSS scan immediately */ + if (evt_conn) { + /** Issue OBSS scan */ + process_setuserscan(); + /** Invoke 2040coex command, if any legacy AP found or + * any AP has 40MHz intolarent bit set */ + if (coex_cmd_req_flag) + invoke_coex_command(); + } + tv.tv_sec = + (t_u32)le16_to_cpu(cur_obss_scan_param. + bss_chan_width_trigger_scan_int); + } else { + tv.tv_sec = DEFAULT_SCAN_INTERVAL; + } + tv.tv_usec = 0; + } + +done: + if (nl_sk > 0) + close(nl_sk); + if (nlh) + free(nlh); + return; +} + +/** + * @brief Determine the netlink number + * + * @return Netlink number to use + */ +static int +get_netlink_num(char *dev_name, int dev_index) +{ + FILE *fp = NULL; + int netlink_num = -1; + char str[64]; + char *srch = "netlink_num"; + char filename[64]; + t_u8 *buffer = NULL; + struct eth_priv_cmd *cmd = NULL; + struct ifreq ifr; + + /* if dev_index is specified by user */ + if (dev_index >= 0) { + /* Try to open old driver proc: /proc/mwlan/configX first */ + if (dev_index == 0) + strcpy(filename, "/proc/mwlan/config"); + else if (dev_index > 0) + sprintf(filename, "/proc/mwlan/config%d", dev_index); + fp = fopen(filename, "r"); + if (!fp) { + /* Try to open multi-adapter driver proc: /proc/mwlan/adapterX/config if old proc access fail */ + snprintf(filename, sizeof(filename), + "/proc/mwlan/adapter%d/config", dev_index); + fp = fopen(filename, "r"); + } + + if (fp) { + while (fgets(str, sizeof(str), fp)) { + if (strncmp(str, srch, strlen(srch)) == 0) { + netlink_num = + atoi(str + strlen(srch) + 1); + break; + } + } + fclose(fp); + } else { + return -1; + } + } else { + /* Start preparing the buffer */ + /* Initialize buffer */ + buffer = (t_u8 *)malloc(MRVDRV_SIZE_OF_CMD_BUFFER); + if (!buffer) { + printf("ERR:Cannot allocate buffer for command!\n"); + return -1; + } + /* buffer = CMD_NXP + */ + prepare_buffer(buffer, "getnlnum", 0, NULL); + + cmd = (struct eth_priv_cmd *) + malloc(sizeof(struct eth_priv_cmd)); + if (!cmd) { + printf("ERR:Cannot allocate buffer for command!\n"); + goto done; + } + + /* Fill up buffer */ +#ifdef USERSPACE_32BIT_OVER_KERNEL_64BIT + memset(cmd, 0, sizeof(struct eth_priv_cmd)); + memcpy(&cmd->buf, &buffer, sizeof(buffer)); +#else + cmd->buf = buffer; +#endif + cmd->used_len = 0; + cmd->total_len = MRVDRV_SIZE_OF_CMD_BUFFER; + + /* Perform IOCTL */ + memset(&ifr, 0, sizeof(struct ifreq)); + strncpy(ifr.ifr_ifrn.ifrn_name, dev_name, strlen(dev_name)); + ifr.ifr_ifru.ifru_data = (void *)cmd; + + if (ioctl(sockfd, MLAN_ETH_PRIV, &ifr)) { + perror("mlan2040coex"); + fprintf(stderr, "mlan2040coex: getnlnum fail\n"); + goto done; + } + netlink_num = *(int *)(buffer); + } + +done: + if (cmd) + free(cmd); + if (buffer) + free(buffer); + printf("Netlink number = %d\n", netlink_num); + return netlink_num; +} + +/** + * @brief opens netlink socket to receive NETLINK events + * @return socket id --success, otherwise--MLAN_STATUS_FAILURE + */ +int +open_netlink(char *dev_name, int dev_index) +{ + int sk = -1; + struct sockaddr_nl src_addr; + int netlink_num = 0; + + netlink_num = get_netlink_num(dev_name, dev_index); + if (netlink_num < 0) { + printf("ERR:Could not get netlink socket. Invalid device number.\n"); + return sk; + } + + /* Open netlink socket */ + sk = socket(PF_NETLINK, SOCK_RAW, netlink_num); + if (sk < 0) { + printf("ERR:Could not open netlink socket.\n"); + return sk; + } + + /* Set source address */ + memset(&src_addr, 0, sizeof(src_addr)); + src_addr.nl_family = AF_NETLINK; + src_addr.nl_pid = getpid(); + src_addr.nl_groups = NL_MULTICAST_GROUP; + + /* Bind socket with source address */ + if (bind(sk, (struct sockaddr *)&src_addr, sizeof(src_addr)) < 0) { + printf("ERR:Could not bind socket!\n"); + close(sk); + return -1; + } + return sk; +} + +/** + * @brief Terminate signal handler + * @param signal Signal to handle + * @return NA + */ +static t_void +terminate_handler(int signal) +{ + printf("Stopping application.\n"); +#if DEBUG + printf("Process ID of process killed = %d\n", getpid()); +#endif + terminate_flag = TRUE; +} + +/******************************************************** + Global Functions +********************************************************/ +/** + * @brief Process host command + * @param hostcmd_idx Host command index + * @param chan_list A pointer to a channel list + * @param chan_num Number of channels in the channel list + * @param reg_class Regulatory class of the channels + * @param is_intol_ap_present Flag:is there any 40 MHz intolerant AP is present or not + * + * @return MLAN_STATUS_SUCCESS--success, otherwise--fail + */ +int +process_host_cmd(int hostcmd_idx, t_u8 *chan_list, t_u8 chan_num, + t_u8 reg_class, t_u8 is_intol_ap_present) +{ + int ret = MLAN_STATUS_SUCCESS; + t_u8 *buffer = NULL; + struct eth_priv_cmd *cmd = NULL; + struct ifreq ifr; + + buffer = (t_u8 *)malloc(MRVDRV_SIZE_OF_CMD_BUFFER); + if (!buffer) { + printf("ERR:Cannot allocate buffer for command!\n"); + ret = MLAN_STATUS_FAILURE; + goto done; + } + + prepare_buffer(buffer, "hostcmd", 0, NULL); + switch (hostcmd_idx) { + case CMD_2040COEX: + prepare_coex_cmd_buff(buffer + strlen(CMD_NXP) + + strlen("hostcmd"), chan_list, chan_num, + reg_class, is_intol_ap_present); + break; + default: + break; + } + + cmd = (struct eth_priv_cmd *)malloc(sizeof(struct eth_priv_cmd)); + if (!cmd) { + printf("ERR:Cannot allocate buffer for command!\n"); + ret = MLAN_STATUS_FAILURE; + goto done; + } + + /* Fill up buffer */ +#ifdef USERSPACE_32BIT_OVER_KERNEL_64BIT + memset(cmd, 0, sizeof(struct eth_priv_cmd)); + memcpy(&cmd->buf, &buffer, sizeof(buffer)); +#else + cmd->buf = buffer; +#endif + cmd->used_len = 0; + cmd->total_len = MRVDRV_SIZE_OF_CMD_BUFFER; + + /* Perform IOCTL */ + memset(&ifr, 0, sizeof(struct ifreq)); + strncpy(ifr.ifr_ifrn.ifrn_name, dev_name, strlen(dev_name)); + ifr.ifr_ifru.ifru_data = (void *)cmd; + + if (ioctl(sockfd, MLAN_ETH_PRIV, &ifr)) { + perror("mlan2040coex"); + fprintf(stderr, "mlan2040coex: hostcmd fail\n"); + ret = MLAN_STATUS_FAILURE; + goto done; + } + + ret = process_host_cmd_resp("hostcmd", buffer); + +done: + if (cmd) + free(cmd); + if (buffer) + free(buffer); + return ret; +} + +/** + * @brief Check the STA is 40 MHz intolerant or not + * @param intol Flag: TRUE when the STA is 40 MHz intolerant, otherwise FALSE + * @return MLAN_STATUS_SUCCESS--success, otherwise--fail + */ +int +is_intolerant_sta(int *intol) +{ + t_u8 *buffer = NULL; + struct eth_priv_cmd *cmd = NULL; + struct ifreq ifr; + int htcap_info, ret = MLAN_STATUS_SUCCESS; + + *intol = FALSE; + + /* Initialize buffer */ + buffer = (t_u8 *)malloc(MRVDRV_SIZE_OF_CMD_BUFFER); + if (!buffer) { + printf("ERR:Cannot allocate buffer for command!\n"); + ret = MLAN_STATUS_FAILURE; + goto done; + } + + /* buffer = CMD_NXP + */ + prepare_buffer(buffer, "htcapinfo", 0, NULL); + + cmd = (struct eth_priv_cmd *)malloc(sizeof(struct eth_priv_cmd)); + if (!cmd) { + printf("ERR:Cannot allocate buffer for command!\n"); + ret = MLAN_STATUS_FAILURE; + goto done; + } + + /* Fill up buffer */ +#ifdef USERSPACE_32BIT_OVER_KERNEL_64BIT + memset(cmd, 0, sizeof(struct eth_priv_cmd)); + memcpy(&cmd->buf, &buffer, sizeof(buffer)); +#else + cmd->buf = buffer; +#endif + cmd->used_len = 0; + cmd->total_len = MRVDRV_SIZE_OF_CMD_BUFFER; + + /* Perform IOCTL */ + memset(&ifr, 0, sizeof(struct ifreq)); + strncpy(ifr.ifr_ifrn.ifrn_name, dev_name, strlen(dev_name)); + ifr.ifr_ifru.ifru_data = (void *)cmd; + + if (ioctl(sockfd, MLAN_ETH_PRIV, &ifr)) { + perror("mlan2040coex"); + fprintf(stderr, "mlan2040coex: htcapinfo fail\n"); + ret = MLAN_STATUS_FAILURE; + goto done; + } + + htcap_info = *((int *)(buffer)); + + if (htcap_info & MBIT(8)) + *intol = TRUE; + +done: + if (cmd) + free(cmd); + if (buffer) + free(buffer); + return ret; +} + +/** + * @brief get region code + * @param reg_code Pointer to region code + * @return MLAN_STATUS_SUCCESS--success, otherwise--fail + */ +int +get_region_code(int *reg_code) +{ + t_u8 *buffer = NULL; + struct eth_priv_cmd *cmd = NULL; + struct ifreq ifr; + int ret = MLAN_STATUS_SUCCESS; + + /* Initialize buffer */ + buffer = (t_u8 *)malloc(MRVDRV_SIZE_OF_CMD_BUFFER); + if (!buffer) { + printf("ERR:Cannot allocate buffer for command!\n"); + ret = MLAN_STATUS_FAILURE; + goto done; + } + + /* buffer = CMD_NXP + */ + prepare_buffer(buffer, "regioncode", 0, NULL); + + cmd = (struct eth_priv_cmd *)malloc(sizeof(struct eth_priv_cmd)); + if (!cmd) { + printf("ERR:Cannot allocate buffer for command!\n"); + ret = MLAN_STATUS_FAILURE; + goto done; + } + + /* Fill up buffer */ +#ifdef USERSPACE_32BIT_OVER_KERNEL_64BIT + memset(cmd, 0, sizeof(struct eth_priv_cmd)); + memcpy(&cmd->buf, &buffer, sizeof(buffer)); +#else + cmd->buf = buffer; +#endif + cmd->used_len = 0; + cmd->total_len = MRVDRV_SIZE_OF_CMD_BUFFER; + + /* Perform IOCTL */ + memset(&ifr, 0, sizeof(struct ifreq)); + strncpy(ifr.ifr_ifrn.ifrn_name, dev_name, strlen(dev_name)); + ifr.ifr_ifru.ifru_data = (void *)cmd; + + if (ioctl(sockfd, MLAN_ETH_PRIV, &ifr)) { + perror("mlan2040coex"); + fprintf(stderr, "mlan2040coex: regioncode fail\n"); + ret = MLAN_STATUS_FAILURE; + goto done; + } + + memcpy(reg_code, buffer, sizeof(int)); +done: + if (cmd) + free(cmd); + if (buffer) + free(buffer); + return ret; +} + +/** No option */ +#define NO_OPTION -1 + +/** + * @brief Entry function for coex + * @param argc number of arguments + * @param argv A pointer to arguments array + * @return MLAN_STATUS_SUCCESS--success, otherwise--fail + */ +int +main(int argc, char *argv[]) +{ + char ifname[IFNAMSIZ + 1] = "mlan0"; + int c, daemonize = FALSE; + t_s32 nl_sk = 0; + /**< netlink socket descriptor to receive an event */ + int dev_index = -1; /** initialise with -1 to open multiple NETLINK Sockets */ + + char temp[2]; + int arg_count = 0; + int ifname_given = FALSE; + + memset(dev_name, 0, sizeof(dev_name)); + + for (;;) { + c = getopt(argc, argv, "Bhi:vd:"); + /* check if all command-line options have been parsed */ + if (c == NO_OPTION) + break; + + switch (c) { + case 'B': + daemonize = TRUE; + break; + case 'h': + display_usage(); + return MLAN_STATUS_SUCCESS; + case 'v': + fprintf(stdout, + "NXP 20/40coex application version %s\n", + COEX_VER); + return MLAN_STATUS_SUCCESS; + case 'i': + ifname_given = TRUE; + if (strlen(optarg) < IFNAMSIZ) + strncpy(ifname, optarg, IFNAMSIZ - 1); + else { + fprintf(stdout, "Interface name too long\n"); + display_usage(); + return MLAN_STATUS_SUCCESS; + } + arg_count += 1; + break; + case 'd': + strncpy(temp, optarg, strlen(optarg)); + if (isdigit(temp[0])) + dev_index = atoi(temp); + arg_count += 1; + break; + default: + fprintf(stdout, "Invalid argument\n"); + display_usage(); + return MLAN_STATUS_SUCCESS; + } + } + + if (!ifname_given) { + sprintf(ifname, "mlan%d", dev_index); + } + + if (optind < argc) { + fputs("Too many arguments.\n", stderr); + display_usage(); + goto done; + } + + strncpy(dev_name, ifname, IFNAMSIZ - 1); + + /* create a socket */ + if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) { + fprintf(stderr, "mlan2040coex: Cannot open socket.\n"); + goto done; + } + + /* create netlink sockets and bind them with app side addr */ + nl_sk = open_netlink(dev_name, dev_index); + + if (nl_sk < 0) { + fprintf(stderr, "mlan2040coex: Cannot open netlink socket.\n"); + goto done; + } + + signal(SIGHUP, terminate_handler); /* catch hangup signal */ + signal(SIGTERM, terminate_handler); /* catch kill signal */ + signal(SIGINT, terminate_handler); /* catch kill signal */ + signal(SIGALRM, terminate_handler); /* catch kill signal */ + + /** Make the process background-process */ + if (daemonize) { + if (daemon(0, 0)) + fprintf(stderr, "mlan2040coex: Cannot start daemon\n"); + } + + /** run the application */ + run_app(nl_sk); + +done: + if (sockfd > 0) + close(sockfd); + if (nl_sk > 0) + close(nl_sk); + + return MLAN_STATUS_SUCCESS; +} diff --git a/mxm_wifiex/wlan_src/mapp/mlan2040coex/mlan2040coex.h b/mxm_wifiex/wlan_src/mapp/mlan2040coex/mlan2040coex.h new file mode 100644 index 0000000..c065bd0 --- /dev/null +++ b/mxm_wifiex/wlan_src/mapp/mlan2040coex/mlan2040coex.h @@ -0,0 +1,239 @@ +/** @file mlan2040coex.h + * + * @brief This file contains definitions for application + * + * + * Copyright 2014-2020 NXP + * + * NXP CONFIDENTIAL + * The source code contained or described herein and all documents related to + * the source code (Materials) are owned by NXP, its + * suppliers and/or its licensors. Title to the Materials remains with NXP, + * its suppliers and/or its licensors. The Materials contain + * trade secrets and proprietary and confidential information of NXP, its + * suppliers and/or its licensors. The Materials are protected by worldwide copyright + * and trade secret laws and treaty provisions. No part of the Materials may be + * used, copied, reproduced, modified, published, uploaded, posted, + * transmitted, distributed, or disclosed in any way without NXP's prior + * express written permission. + * + * No license under any patent, copyright, trade secret or other intellectual + * property right is granted to or conferred upon you by disclosure or delivery + * of the Materials, either expressly, by implication, inducement, estoppel or + * otherwise. Any license under such intellectual property rights must be + * express and approved by NXP in writing. + * + */ +/************************************************************************ +Change log: + 06/24/2009: initial version +************************************************************************/ +#ifndef _COEX_H_ +#define _COEX_H_ + +/** NXP private command identifier */ +#define CMD_NXP "MRVL_CMD" + +/** IOCTL number */ +#define MLAN_ETH_PRIV (SIOCDEVPRIVATE + 14) + +#if (BYTE_ORDER == LITTLE_ENDIAN) +#undef BIG_ENDIAN_SUPPORT +#endif + +/** 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) )) + +/** Convert to correct endian format */ +#ifdef BIG_ENDIAN_SUPPORT +/** CPU to little-endian convert for 16-bit */ +#define cpu_to_le16(x) swap_byte_16(x) +/** CPU to little-endian convert for 32-bit */ +#define cpu_to_le32(x) swap_byte_32(x) +/** CPU to little-endian convert for 64-bit */ +#define cpu_to_le64(x) swap_byte_64(x) +/** Little-endian to CPU convert for 16-bit */ +#define le16_to_cpu(x) swap_byte_16(x) +/** Little-endian to CPU convert for 32-bit */ +#define le32_to_cpu(x) swap_byte_32(x) +/** Little-endian to CPU convert for 64-bit */ +#define le64_to_cpu(x) swap_byte_64(x) +#else +/** Do nothing */ +#define cpu_to_le16(x) (x) +/** Do nothing */ +#define cpu_to_le32(x) (x) +/** Do nothing */ +#define cpu_to_le64(x) (x) +/** Do nothing */ +#define le16_to_cpu(x) (x) +/** Do nothing */ +#define le32_to_cpu(x) (x) +/** Do nothing */ +#define le64_to_cpu(x) (x) +#endif + +#ifdef __GNUC__ +/** Structure packing begins */ +#define PACK_START +/** Structure packeing end */ +#define PACK_END __attribute__ ((packed)) +#else +/** Structure packing begins */ +#define PACK_START __packed +/** Structure packeing end */ +#define PACK_END +#endif + +/** Character, 1 byte */ +typedef signed char t_s8; +/** Unsigned character, 1 byte */ +typedef unsigned char t_u8; + +/** Short integer */ +typedef signed short t_s16; +/** Unsigned short integer */ +typedef unsigned short t_u16; + +/** Integer */ +typedef signed int t_s32; +/** Unsigned integer */ +typedef unsigned int t_u32; + +/** Long long integer */ +typedef signed long long t_s64; +/** Unsigned long long integer */ +typedef unsigned long long t_u64; + +/** Void pointer (4-bytes) */ +typedef void t_void; + +#ifdef FALSE +#undef FALSE +#endif + +#ifdef TRUE +#undef TRUE +#endif + +#ifndef MIN +/** Find minimum value */ +#define MIN(a, b) ((a) < (b) ? (a) : (b)) +#endif /* MIN */ + +/** Type definition: boolean */ +typedef enum { FALSE, TRUE } boolean; + +/** Find number of elements */ +#define NELEMENTS(x) (sizeof(x)/sizeof(x[0])) +/** Success */ +#define MLAN_STATUS_SUCCESS (0) +/** Failure */ +#define MLAN_STATUS_FAILURE (-1) + +/** Enumeration for host-command index */ +enum COMMANDS { + CMD_2040COEX = 1, +}; +/** Maximum number of channels that can be sent in a setuserscan ioctl */ +#define WLAN_IOCTL_USER_SCAN_CHAN_MAX 50 + +#ifndef ETH_ALEN +/** MAC address length */ +#define ETH_ALEN 6 +#endif + +/** Netlink protocol number */ +#define NETLINK_NXP (MAX_LINKS - 1) +/** Netlink maximum payload size */ +#define NL_MAX_PAYLOAD 1024 +/** Netlink multicast group number */ +#define NL_MULTICAST_GROUP RTMGRP_LINK +/** Default wait time in seconds for events */ +#define UAP_RECV_WAIT_DEFAULT 10 +#ifndef NLMSG_HDRLEN +/** NL message header length */ +#define NLMSG_HDRLEN ((int) NLMSG_ALIGN(sizeof(struct nlmsghdr))) +#endif + +/** Event header */ +typedef PACK_START struct _event_header { + /** Event ID */ + t_u32 event_id; + /** Event data */ + t_u8 event_data[]; +} PACK_END event_header; + +/** Event ID length */ +#define EVENT_ID_LEN 4 + +/** Custom events definitions */ +/** AP connected event */ +#define CUS_EVT_AP_CONNECTED "EVENT=AP_CONNECTED" + +/** 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 events definitions end */ + +/** Structure defination of chan_intol_t*/ +typedef struct _chan_intol_t { + /** Channel numer */ + t_u8 chan_num; + /** Flag: Is any 40MHz intolerant AP found in this channel */ + t_u8 is_intol_set; +} chan_intol_t; + +/** Private command structure */ +#ifdef USERSPACE_32BIT_OVER_KERNEL_64BIT +struct eth_priv_cmd { + /** Command buffer pointer */ + t_u64 buf; + /** buffer updated by driver */ + int used_len; + /** buffer sent by application */ + int total_len; +} __ATTRIB_PACK__; +#else +struct eth_priv_cmd { + /** Command buffer */ + t_u8 *buf; + /** Used length */ + int used_len; + /** Total length */ + int total_len; +}; +#endif + +/** Legacy APs channel list */ +chan_intol_t leg_ap_chan_list[WLAN_IOCTL_USER_SCAN_CHAN_MAX]; +/** Total number of channel present in Legacy APs channel list */ +t_u8 num_leg_ap_chan; +int get_region_code(int *reg_code); +int process_host_cmd(int cmd, t_u8 *chan_list, t_u8 chan_num, t_u8 reg_class, + t_u8 is_intol_ap_present); +int is_intolerant_sta(int *intol); + +#endif /* _COEX_H_ */ diff --git a/mxm_wifiex/wlan_src/mapp/mlan2040coex/mlan2040misc.c b/mxm_wifiex/wlan_src/mapp/mlan2040coex/mlan2040misc.c new file mode 100644 index 0000000..8ff2a2e --- /dev/null +++ b/mxm_wifiex/wlan_src/mapp/mlan2040coex/mlan2040misc.c @@ -0,0 +1,286 @@ +/** @file mlan2040misc.c + * + * @brief This file contains helper functions for coex application + * + * + * Copyright 2014-2020 NXP + * + * NXP CONFIDENTIAL + * The source code contained or described herein and all documents related to + * the source code (Materials) are owned by NXP, its + * suppliers and/or its licensors. Title to the Materials remains with NXP, + * its suppliers and/or its licensors. The Materials contain + * trade secrets and proprietary and confidential information of NXP, its + * suppliers and/or its licensors. The Materials are protected by worldwide copyright + * and trade secret laws and treaty provisions. No part of the Materials may be + * used, copied, reproduced, modified, published, uploaded, posted, + * transmitted, distributed, or disclosed in any way without NXP's prior + * express written permission. + * + * No license under any patent, copyright, trade secret or other intellectual + * property right is granted to or conferred upon you by disclosure or delivery + * of the Materials, either expressly, by implication, inducement, estoppel or + * otherwise. Any license under such intellectual property rights must be + * express and approved by NXP in writing. + * + */ +/************************************************************************ +Change log: + 06/24/2009: initial version +************************************************************************/ +#include +#include +#include +#include +#include "mlan2040coex.h" +#include "mlan2040misc.h" + +/******************************************************** + Local Variables +********************************************************/ +/** Regulatory class and Channel mapping for various regions */ +static class_chan_t us_class_chan_t[] = { + {32, {1, 2, 3, 4, 5, 6, 7}, 7}, + {33, {5, 6, 7, 8, 9, 10, 11}, 7} +}; + +static class_chan_t europe_class_chan_t[] = { + {11, {1, 2, 3, 4, 5, 6, 7, 8, 9}, 9}, + {12, {5, 6, 7, 8, 9, 10, 11, 12, 13}, 9} +}; + +static class_chan_t japan_class_chan_t[] = { + {56, {1, 2, 3, 4, 5, 6, 7, 8, 9}, 9}, + {57, {5, 6, 7, 8, 9, 10, 11, 12, 13}, 9}, + {58, {14}, 1} +}; + +/** Region-code(Regulatory domain) and Class-channel table mapping */ +static region_class_chan_t region_class_chan_table[] = { + {0x10, us_class_chan_t, sizeof(us_class_chan_t) / sizeof(class_chan_t)} /* US */ + , + {0x20, us_class_chan_t, sizeof(us_class_chan_t) / sizeof(class_chan_t)} /* CANADA */ + , + {0x30, europe_class_chan_t, sizeof(europe_class_chan_t) / sizeof(class_chan_t)} /* EUROPE */ + , + {0x32, europe_class_chan_t, sizeof(europe_class_chan_t) / sizeof(class_chan_t)} /* FRANCE */ + , + {0x40, japan_class_chan_t, sizeof(japan_class_chan_t) / sizeof(class_chan_t)} /* JAPAN */ + , + {0x41, japan_class_chan_t, sizeof(japan_class_chan_t) / sizeof(class_chan_t)} /* JAPAN */ + , + {0x50, europe_class_chan_t, sizeof(europe_class_chan_t) / sizeof(class_chan_t)} /* CHINA */ +}; + +/******************************************************** + Global Variables +********************************************************/ + +/******************************************************** + Local Functions +********************************************************/ +/** + * @brief This function prepares the channel list for a particular + * regulatory class from channel number for legacy AP + * @param cur_class_chan_table A pointer to the class_chan_t + * @param num_entry Number of entry in cur_class_chan_table table + * @param chan_list A pointer to the output channel list + * @param chan_num total number of channel in output channel list + * @param reg_domain regulatory domain + * @param reg_class regulatory class + * @param is_intol_ap_present It sets TRUE when 40MHz intolerant AP is found + * otherwise FALSE + * @return None + */ +static void +get_channels_for_specified_reg_class(class_chan_t *cur_class_chan_table, + int num_entry, t_u8 *chan_list, + t_u8 *chan_num, t_u8 reg_domain, + t_u8 reg_class, t_u8 *is_intol_ap_present) +{ + int i, j, k, idx = 0; + + *is_intol_ap_present = FALSE; + + /* For each regulatory class */ + for (i = 0; i < num_entry; i++) { + if (cur_class_chan_table[i].reg_class == reg_class) { + /* For each channel of the regulatory class */ + for (j = 0; j < cur_class_chan_table[i].total_chan; j++) { + for (k = 0; k < num_leg_ap_chan; k++) { + + if (cur_class_chan_table[i]. + channels[j] == + leg_ap_chan_list[k].chan_num) { + *(chan_list + idx) = + leg_ap_chan_list[k]. + chan_num; + idx++; + if (leg_ap_chan_list[k]. + is_intol_set) + *is_intol_ap_present = + TRUE; + } + } + } + break; + } + } + /* update the total number of channel */ + *chan_num = idx--; + return; +} + +/******************************************************** + Global Functions +********************************************************/ +/** + * @brief Prepare 2040 coex command buffer + * @param buf A pointer to the command buffer + * @param chan_list Channel list + * @param num_of_chan Number of channel present in channel list + * @param reg_class Regulatory class + * @param is_intol_ap_present Flag: is any 40 MHz intolerant AP + * is present in these chaanel set + * @return MLAN_STATUS_SUCCESS--success, otherwise--fail + */ +void +prepare_coex_cmd_buff(t_u8 *buf, t_u8 *chan_list, t_u8 num_of_chan, + t_u8 reg_class, t_u8 is_intol_ap_present) +{ + HostCmd_DS_GEN *hostcmd; + MrvlIETypes_2040COEX_t *coex_ie = NULL; + MrvlIETypes_2040BssIntolerantChannelReport_t *bss_intol_ie = NULL; + t_u8 *pos = NULL; + int intol; + + hostcmd = (HostCmd_DS_GEN *)(buf + sizeof(t_u32)); + hostcmd->command = cpu_to_le16(HostCmd_CMD_11N_2040COEX); + hostcmd->size = S_DS_GEN; + pos = buf + sizeof(t_u32) + S_DS_GEN; + { + coex_ie = (MrvlIETypes_2040COEX_t *)pos; + coex_ie->header.element_id = TLV_ID_2040COEX; + coex_ie->header.len = sizeof(coex_ie->coex_elem); + /* Check STA is 40 MHz intolerant or not */ + is_intolerant_sta(&intol); + if (intol) + coex_ie->coex_elem |= MBIT(1); + + if (is_intol_ap_present) + coex_ie->coex_elem |= MBIT(2); + pos += sizeof(MrvlIETypes_2040COEX_t); + hostcmd->size += sizeof(MrvlIETypes_2040COEX_t); + } + { + bss_intol_ie = + (MrvlIETypes_2040BssIntolerantChannelReport_t *)pos; + bss_intol_ie->header.element_id = + TLV_ID_2040BSS_INTOL_CHAN_REPORT; + hostcmd->size += + sizeof(MrvlIETypes_2040BssIntolerantChannelReport_t) - + sizeof(bss_intol_ie->chan_num); + bss_intol_ie->reg_class = reg_class; + memcpy(bss_intol_ie->chan_num, chan_list, num_of_chan); + bss_intol_ie->header.len = + sizeof(bss_intol_ie->reg_class) + num_of_chan; + hostcmd->size += num_of_chan; + } + hostcmd->size = cpu_to_le16(hostcmd->size); + return; +} + +/** + * @brief Invoke multiple 2040Coex commands for multiple regulatory classes + * + * @return MLAN_STATUS_SUCCESS--success, otherwise--fail + */ +int +invoke_coex_command(void) +{ + int cur_reg_domain; + t_u8 chan_list[MAX_CHAN], is_intol_ap_present; + t_u8 num_of_chan; + int i, num_entry, ret = MLAN_STATUS_SUCCESS; + class_chan_t *cur_class_chan_table = NULL; + + /** get region code */ + ret = get_region_code(&cur_reg_domain); + if (ret != MLAN_STATUS_SUCCESS) + return ret; + /** Find region_class_chan_table for this region */ + for (i = 0; + (unsigned int)i < + (sizeof(region_class_chan_table) / sizeof(region_class_chan_t)); + i++) { + if (region_class_chan_table[i].reg_domain == cur_reg_domain) { + cur_class_chan_table = + region_class_chan_table[i].class_chan_list; + num_entry = + region_class_chan_table[i].num_class_chan_entry; + break; + } + } + if (cur_class_chan_table == NULL) { + printf("No region_class_chan table found for this region\n"); + return MLAN_STATUS_FAILURE; + } + + for (i = 0; i < num_entry; i++) { + /** Get channels for the specified regulatory class */ + get_channels_for_specified_reg_class(cur_class_chan_table, + num_entry, chan_list, + &num_of_chan, + cur_reg_domain, + cur_class_chan_table[i]. + reg_class, + &is_intol_ap_present); + + /** If any channel found for this regulatory class, then invoke the 2040coex command */ + if (num_of_chan > 0) { + ret = process_host_cmd(CMD_2040COEX, chan_list, + num_of_chan, + cur_class_chan_table[i]. + reg_class, is_intol_ap_present); + if (ret) + break; + } + } + return ret; +} + +/** + * @brief Process host_cmd response + * + * @param cmd_name The command string + * @param buf A pointer to the response buffer + * + * @return MLAN_STATUS_SUCCESS--success, otherwise--fail + */ +int +process_host_cmd_resp(char *cmd_name, t_u8 *buf) +{ + t_u32 hostcmd_size = 0; + HostCmd_DS_GEN *hostcmd = NULL; + int ret = MLAN_STATUS_SUCCESS; + + buf += strlen(CMD_NXP) + strlen(cmd_name); + memcpy((t_u8 *)&hostcmd_size, buf, sizeof(t_u32)); + buf += sizeof(t_u32); + + hostcmd = (HostCmd_DS_GEN *)buf; + hostcmd->command = le16_to_cpu(hostcmd->command); + hostcmd->size = le16_to_cpu(hostcmd->size); + + hostcmd->command &= ~HostCmd_RET_BIT; + if (!le16_to_cpu(hostcmd->result)) { + switch (hostcmd->command) { + } + } else { + printf("HOSTCMD failed: ReturnCode=%#04x, Result=%#04x\n", + le16_to_cpu(hostcmd->command), + le16_to_cpu(hostcmd->result)); + ret = MLAN_STATUS_FAILURE; + } + return ret; +} diff --git a/mxm_wifiex/wlan_src/mapp/mlan2040coex/mlan2040misc.h b/mxm_wifiex/wlan_src/mapp/mlan2040coex/mlan2040misc.h new file mode 100644 index 0000000..8acd3fc --- /dev/null +++ b/mxm_wifiex/wlan_src/mapp/mlan2040coex/mlan2040misc.h @@ -0,0 +1,449 @@ +/** @file mlan2040misc.h + * + * @brief This file contains command definitions for application + * + * + * Copyright 2014-2020 NXP + * + * NXP CONFIDENTIAL + * The source code contained or described herein and all documents related to + * the source code (Materials) are owned by NXP, its + * suppliers and/or its licensors. Title to the Materials remains with NXP, + * its suppliers and/or its licensors. The Materials contain + * trade secrets and proprietary and confidential information of NXP, its + * suppliers and/or its licensors. The Materials are protected by worldwide copyright + * and trade secret laws and treaty provisions. No part of the Materials may be + * used, copied, reproduced, modified, published, uploaded, posted, + * transmitted, distributed, or disclosed in any way without NXP's prior + * express written permission. + * + * No license under any patent, copyright, trade secret or other intellectual + * property right is granted to or conferred upon you by disclosure or delivery + * of the Materials, either expressly, by implication, inducement, estoppel or + * otherwise. Any license under such intellectual property rights must be + * express and approved by NXP in writing. + * + */ +/************************************************************************ +Change log: + 06/24/2009: initial version +************************************************************************/ +#ifndef _COEX_MISC_H_ +#define _COEX_MISC_H_ + +/** MLAN MAC Address Length */ +#define MLAN_MAC_ADDR_LENGTH (6) +/** Size of command buffer */ +#define MRVDRV_SIZE_OF_CMD_BUFFER (3 * 1024) + +/** 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 +/** TLV Id for 2040Coex IE */ +#define TLV_ID_2040COEX 0x48 +/** TLV Id for 2040BSS intolarent channel report IE */ +#define TLV_ID_2040BSS_INTOL_CHAN_REPORT 0x49 +/** Host-command for 2040coex command */ +#define HostCmd_CMD_11N_2040COEX 0x00e9 +/** Maximum scan response buffer size */ +#define SCAN_RESP_BUF_SIZE 2000 + +/** Maximum length of SSID */ +#define MRVDRV_MAX_SSID_LENGTH 32 + +/** Length of ethernet address */ +#ifndef ETH_ALEN +#define ETH_ALEN 6 +#endif +/** Maximum length of SSID list */ +#define MRVDRV_MAX_SSID_LIST_LENGTH 10 +/** Default scan interval in second*/ +#define DEFAULT_SCAN_INTERVAL 300 + +/** BIT value */ +#define MBIT(x) (((t_u32)1) << (x)) + +/** Check intolerent bit set */ +#define IS_INTOL_BIT_SET(cap_info) (cap_info & MBIT(14)) + +/** Check OBSS non-HT STAs present bit set */ +#define IS_NON_HT_STA_PRESENT(ht_info) (ht_info.field3 & MBIT(4)) + +/** IEEE Type definitions */ +typedef 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, + 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, + RSN_IE = 48, +} __attribute__ ((packed)) + IEEEtypes_ElementId_e; + +/** HT Capabilities Data */ + typedef struct _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; + /** Reserved set to 0 */ + t_u16 reserved; + } __attribute__ ((packed)) + HTCap_t, *pHTCap_t; + +/** HT Information Data */ + typedef struct _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]; + /** Reserved set to 0 */ + t_u16 reserved; + } __attribute__ ((packed)) + HTInfo_t, *pHTInfo_t; + +/** 20/40 BSS Coexistence Data */ + typedef struct _BSSCo2040_t { + /** 20/40 BSS Coexistence value */ + t_u8 bss_co_2040_value; + /** Reserve field */ + t_u8 reserved[3]; + } __attribute__ ((packed)) + BSSCo2040_t, *pBSSCo2040_t; + +/** Extended Capabilities Data */ + typedef struct _ExtCap_t { + /** Extended Capabilities value */ + t_u8 ext_cap_value; + /** Reserved field */ + t_u8 reserved[3]; + } __attribute__ ((packed)) + ExtCap_t, *pExtCap_t; + +/** Overlapping BSS Scan Parameters Data */ + typedef struct _OverlapBSSScanParam_t { + /** OBSS Scan Passive Dwell */ + t_u16 obss_scan_passive_dwell; + /** OBSS Scan Active Dwell */ + t_u16 obss_scan_active_dwell; + /** BSS Channel Width Trigger Scan Interval */ + 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; + } __attribute__ ((packed)) + OBSSScanParam_t, *pOBSSScanParam_t; + +/** IEEEtypes_CapInfo_t structure*/ + typedef 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; + } __attribute__ ((packed)) + IEEEtypes_CapInfo_t, *pIEEEtypes_CapInfo_t; + + typedef struct { + t_u8 chan_number; + /**< Channel Number to scan */ + t_u8 radio_type; + /**< Radio type: 'B/G' Band = 0, 'A' Band = 1 */ + t_u8 scan_type; + /**< Scan type: Active = 1, Passive = 2 */ + t_u8 reserved; + /**< Reserved */ + t_u32 scan_time; + /**< Scan duration in milliseconds; if 0 default used */ + } __attribute__ ((packed)) + wlan_ioctl_user_scan_chan; + + typedef struct { + char ssid[MRVDRV_MAX_SSID_LENGTH + 1]; + /**< SSID */ + t_u8 max_len; /**< Maximum length of SSID */ + } __attribute__ ((packed)) + wlan_ioctl_user_scan_ssid; + + typedef struct { + + /** Flag set to keep the previous scan table intact */ + t_u8 keep_previous_scan; /* Do not erase the existing scan results */ + + /** BSS mode to be sent in the firmware command */ + t_u8 bss_mode; + + /** Configure the number of probe requests for active chan scans */ + t_u8 num_probes; + + /** Reserved */ + t_u8 reserved; + + /** BSSID filter sent in the firmware command to limit the results */ + t_u8 specific_bssid[ETH_ALEN]; + /** SSID filter list used in the to limit the scan results */ + wlan_ioctl_user_scan_ssid ssid_list[MRVDRV_MAX_SSID_LIST_LENGTH]; + + /** Variable number (fixed maximum) of channels to scan up */ + wlan_ioctl_user_scan_chan chan_list[WLAN_IOCTL_USER_SCAN_CHAN_MAX]; + + } __attribute__ ((packed)) + wlan_ioctl_user_scan_cfg; + +/** IEEE IE header */ + typedef struct _IEEEtypes_Header_t { + /** Element ID */ + t_u8 element_id; + /** Length */ + t_u8 len; + } __attribute__ ((packed)) + IEEEtypes_Header_t, *pIEEEtypes_Header_t; + +/** HT Capabilities IE */ + typedef struct _IEEEtypes_HTCap_t { + /** Generic IE header */ + IEEEtypes_Header_t ieee_hdr; + /** HTCap struct */ + HTCap_t ht_cap; + } __attribute__ ((packed)) + IEEEtypes_HTCap_t, *pIEEEtypes_HTCap_t; + +/** HT Information IE */ + typedef struct _IEEEtypes_HTInfo_t { + /** Generic IE header */ + IEEEtypes_Header_t ieee_hdr; + /** HTInfo struct */ + HTInfo_t ht_info; + } __attribute__ ((packed)) + IEEEtypes_HTInfo_t, *pIEEEtypes_HTInfo_t; + +/** 20/40 BSS Coexistence IE */ + typedef struct _IEEEtypes_2040BSSCo_t { + /** Generic IE header */ + IEEEtypes_Header_t ieee_hdr; + /** BSSCo2040_t struct */ + BSSCo2040_t bss_co_2040; + } __attribute__ ((packed)) + IEEEtypes_2040BSSCo_t, *pIEEEtypes_2040BSSCo_t; + +/** Extended Capabilities IE */ + typedef struct _IEEEtypes_ExtCap_t { + /** Generic IE header */ + IEEEtypes_Header_t ieee_hdr; + /** ExtCap_t struct */ + ExtCap_t ext_cap; + } __attribute__ ((packed)) + IEEEtypes_ExtCap_t, *pIEEEtypes_ExtCap_t; + +/** Overlapping BSS Scan Parameters IE */ + typedef struct _IEEEtypes_OverlapBSSScanParam_t { + /** Generic IE header */ + IEEEtypes_Header_t ieee_hdr; + /** OBSSScanParam_t struct */ + OBSSScanParam_t obss_scan_param; + } __attribute__ ((packed)) + IEEEtypes_OverlapBSSScanParam_t, *pIEEEtypes_OverlapBSSScanParam_t; + + 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 from the firmware at packet reception */ + t_u64 network_tsf; + } wlan_get_scan_table_fixed; + +/** + * 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 starting at bssInfoBuffer + */ + 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[1]; */ + } wlan_ioctl_get_scan_table_entry; + +/** + * 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; + +/* Define general hostcmd data structure */ +/** HostCmd_DS_GEN */ + typedef struct _HostCmd_DS_GEN { + /** Command */ + t_u16 command; + /** Size */ + t_u16 size; + /** Sequence number */ + t_u16 seq_num; + /** Result */ + t_u16 result; + } __attribute__ ((packed)) + HostCmd_DS_GEN; + +/** Size of HostCmd_DS_GEN */ +#define S_DS_GEN sizeof(HostCmd_DS_GEN) + +/** TLV related data structures*/ +/** MrvlIEtypesHeader_t */ + typedef struct _MrvlIEtypesHeader { + /** Header type */ + t_u16 type; + /** Header length */ + t_u16 len; + } __attribute__ ((packed)) + MrvlIEtypesHeader_t; + +/** _MrvlIETypes_2040BssIntolerantChannelReport_t */ + typedef struct _MrvlIETypes_2040BssIntolerantChannelReport_t { + /** Header */ + IEEEtypes_Header_t header; + /** regulatory class */ + t_u8 reg_class; + /** channel numbers for legacy AP */ + t_u8 chan_num[1]; + } __attribute__ ((packed)) + MrvlIETypes_2040BssIntolerantChannelReport_t; + +/** MrvlIETypes_2040COEX_t */ + typedef struct _MrvlIETypes_2040COEX_t { + /** Header */ + IEEEtypes_Header_t header; + /** 2040 coex element */ + t_u8 coex_elem; + } __attribute__ ((packed)) + MrvlIETypes_2040COEX_t; + + typedef struct _HostCmd_DS_CMD_11N_2040COEX { + /** 2040 coex element */ + MrvlIETypes_2040COEX_t coex; + /** 2040 BSS intolerant channel report*/ + MrvlIETypes_2040BssIntolerantChannelReport_t chan_intol_report; + } __attribute__ ((packed)) + HostCmd_DS_CMD_11N_2040COEX; + +/** Maximum number of channel per regulatory class */ +#define MAX_CHAN 20 + typedef struct _class_chan_t { + /** Regulatory class */ + t_u8 reg_class; + /** Channel numbers */ + t_u8 channels[MAX_CHAN]; + /** Total number of channels */ + t_u8 total_chan; + } class_chan_t; + + typedef struct _region_class_chan_t { + /** Regulatory domain */ + int reg_domain; + /** Channel numbers */ + class_chan_t *class_chan_list; + /** Number of class channel table entry */ + int num_class_chan_entry; + } region_class_chan_t; + + int process_host_cmd_resp(char *cmd_name, t_u8 *buf); + void prepare_coex_cmd_buff(t_u8 *buf, t_u8 *chan_list, t_u8 num_of_chan, + t_u8 reg_class, t_u8 is_intol_ap_present); + int invoke_coex_command(void); + +#endif /* _COEX_MISC_H_ */ diff --git a/mxm_wifiex/wlan_src/mapp/mlanconfig/Makefile b/mxm_wifiex/wlan_src/mapp/mlanconfig/Makefile new file mode 100644 index 0000000..fde2059 --- /dev/null +++ b/mxm_wifiex/wlan_src/mapp/mlanconfig/Makefile @@ -0,0 +1,48 @@ +# +# File : mlanconfig/Makefile +# +# Copyright 2014-2020 NXP + +# Path to the top directory of the mlandriver distribution +PATH_TO_TOP = ../.. + +# Determine how we should copy things to the install directory +ABSPATH := $(filter /%, $(INSTALLDIR)) +RELPATH := $(filter-out /%, $(INSTALLDIR)) +INSTALLPATH := $(ABSPATH) +ifeq ($(strip $(INSTALLPATH)),) +INSTALLPATH := $(PATH_TO_TOP)/$(RELPATH) +endif + +# Override CFLAGS for application sources, remove __ kernel namespace defines +CFLAGS := $(filter-out -D__%, $(ccflags-y)) +# remove KERNEL include dir +CFLAGS := $(filter-out -I$(KERNELDIR)%, $(CFLAGS)) + +# +# List of application executables to create +# +libobjs:= mlanconfig.o mlanhostcmd.o mlanmisc.o +exectarget=mlanconfig +TARGETS := $(exectarget) + +# +# Make target rules +# + +# All rule compiles list of TARGETS using builtin program target from src rule +all : +$(exectarget): $(libobjs) + $(CC) $(CFLAGS) $(libobjs) -o $(exectarget) + +# Update any needed TARGETS and then copy to the install path +build install: $(TARGETS) + @cp -rf config $(INSTALLPATH) + +clean: + @rm -f $(exectarget) + @rm -f *.o + +distclean: clean + @rm -f *~ core + @rm -f tags diff --git a/mxm_wifiex/wlan_src/mapp/mlanconfig/config/11axcfg.conf b/mxm_wifiex/wlan_src/mapp/mlanconfig/config/11axcfg.conf new file mode 100644 index 0000000..59ef45f --- /dev/null +++ b/mxm_wifiex/wlan_src/mapp/mlanconfig/config/11axcfg.conf @@ -0,0 +1,49 @@ +#Band config +[Band] +# band config, 1: 2.4G, 2: 5G +02 +[/Band] +# HE Capability +[HECap] +# ID +ff 00 +# Length +1a 00 +# he capability id +23 +# HE MAC capability info +01 00 00 82 00 08 +# HE PHY capability info +04 70 7e c9 fd 01 a0 0e 03 3d 00 +# Tx Rx HE-MCS NSS support +fa ff fa ff +# PPE Thresholds (optional) +# PE: 16 us +e1 ff c7 71 +[/HECap] +####### UAP HE cap ############ +#Band config +#[Band] +# band config, 1: 2.4G, 2: 5G +#02 +#[/Band] +# HE Capability +#[HECap] +# ID +#ff 00 +# Length +#1a 00 +# he capability id +#23 +# HE MAC capability info +#00 00 00 00 00 00 +# Enable PPE Threshold +#04 20 0e c9 fe 0b a0 0e 01 20 00 +# Tx Rx HE-MCS NSS support +#fa ff fa ff +# PPE Thresholds (optional) +# PE: 16 us +#e1 ff c7 71 +#[/HECap] + + diff --git a/mxm_wifiex/wlan_src/mapp/mlanconfig/config/11n_2040coex.conf b/mxm_wifiex/wlan_src/mapp/mlanconfig/config/11n_2040coex.conf new file mode 100644 index 0000000..1e8cda7 --- /dev/null +++ b/mxm_wifiex/wlan_src/mapp/mlanconfig/config/11n_2040coex.conf @@ -0,0 +1,21 @@ +# File : 11n_2040coex.conf + +######################### 20/40 Coex command ################## +2040coex={ + CmdCode=0x00e9 # do NOT change this line + + 2040CoexTlvType:1=0x48 + 2040CoexTlvLen:1={ + 2040CoexElement:1=0x04 + } + + 2040BssIntlChanTlvType:1=0x49 + 2040BssIntlChanTlvLen:1={ + RegulatoryDomain:1=32 # USA: 32 (1-7), 33 (5-11) + ChannelNum:1=1 + ChannelNum:1=2 + # ... + } +} + +################################################################## diff --git a/mxm_wifiex/wlan_src/mapp/mlanconfig/config/auto_tx.conf b/mxm_wifiex/wlan_src/mapp/mlanconfig/config/auto_tx.conf new file mode 100644 index 0000000..6c35540 --- /dev/null +++ b/mxm_wifiex/wlan_src/mapp/mlanconfig/config/auto_tx.conf @@ -0,0 +1,54 @@ +# File : auto_tx.conf + +######################### Auto-TX command ################## +auto_tx_get={ + CmdCode=0x0082 # do NOT change this line + + Action:2=0 # GET +} + +auto_tx_unreg={ + CmdCode=0x0082 # do NOT change this line + + Action:2=1 # SET +} + +nat_keep_alive={ + CmdCode=0x0082 # do NOT change this line + + Action:2=1 # SET + + AutoTxTlvType:2=0x0118 + AutoTxTlvLength:2={ # 58 = 6 + 52 (FrameLen) + Interval:2=2 # 1 - 3600 seconds + Priority:1=7 # Priority, ignored if non-WMM + Reserved:1=0 + FrameLength:2={ # 52 = 6 (DA) + 6 (SA) + 2 + 38 (Length) + DestMacAddr:6='0x00,0x40,0xf4,0xbf,0x24,0xee' + SrcMacAddr:6='0x00,0x00,0x00,0x00,0x00,0x00' + Length:2='0x00,38' # 38 = 8 (SNAP hdr) + 29 (IP) + 1 (padding) + DSAP:1=0xaa # SNAP header + SSAP:1=0xaa + Ctrl:1=0x03 + SNAP_OUI:3='0x00,0x00,0x00' + SNAP_PID:2='0x08,0x00' # IP Packet + IPv4:1=0x45 + IP_TOS:1=0x00 + IP_LEN:2='0x00,29' # IP hdr 20 + payload 9 = 29 + IP_ID:2=0xefbe + IP_Flag_FragOffset:2=0x0000 + IP_TTL:1=128 + IP_Prot:1=17 # UDP protocol + IPhdr_cksum:2=0xc5f9 # may need re-calculation if changed + IPsrcAddr:4='192,168,0,201' # 192.168.0.201 + IPdstAddr:4='192,168,0,1' # 192.168.0.1 + UDPsrcPort:2='0x11,0x94' # 4500 + UDPdstPort:2='0x11,0x94' # 4500 + UDPlength:2='0x00,9' # UDP hdr 8 + payload 1 = 9 + UDPcksum:2=0x985b # may need re-calculation if changed + UDPpayload:1=0xff + padding:1=0 # MAC Padding for 32bit alignment, set to 0 + } + } +} +######################### Auto-TX command ################## diff --git a/mxm_wifiex/wlan_src/mapp/mlanconfig/config/band_steer_cfg.conf b/mxm_wifiex/wlan_src/mapp/mlanconfig/config/band_steer_cfg.conf new file mode 100644 index 0000000..2c61e74 --- /dev/null +++ b/mxm_wifiex/wlan_src/mapp/mlanconfig/config/band_steer_cfg.conf @@ -0,0 +1,16 @@ +# File : band_steering_cfg.conf + + +######################### band steering configure command ################## +band_steering_cfg={ + CmdCode=0x026f # do NOT change this line + + Action:1=7 # Action = BIT0|BIT1|BIT2, + # BIT0: State take effect + # BIT1: or this bit if want change Block2gPrbReq + # BIT2: OR this bit if want change MaxBtmReqAllowed + State:1 = 1 # 0: disable Band steering, 1: enable bandsteering + Block2gPrbReq:1=5 # 0~15, the number of probe requests to block before allowing response for the STA + MaxBtmReqAllowed:1=3 # 0~15,max bss_transition requests to station +} + diff --git a/mxm_wifiex/wlan_src/mapp/mlanconfig/config/bg_scan.conf b/mxm_wifiex/wlan_src/mapp/mlanconfig/config/bg_scan.conf new file mode 100644 index 0000000..7bc088e --- /dev/null +++ b/mxm_wifiex/wlan_src/mapp/mlanconfig/config/bg_scan.conf @@ -0,0 +1,157 @@ +# File : bg_scan.conf + +######################### BG Scan Configuration command ################## +########### Sample configuration for Get BG Scan Configuration ##################### +#bgscfg={ +# CmdCode=0x006b # do NOT change this line +# Action:1=0 # 0- Get, 1- Set +# ConfigType:1=0 # 0- normal BG Scan config, 1-PPS or UAPSD BG Scan config +# Enable:1=1 # 0- Disable, 1-Enable +# BssType:1=0 # 1 - Infrastructure,2 - IBSS,3 - Any +# ChannelsPerScan:1=0 # Number of Channel to scan at one scan; maximum 14 +# Reserved1:3=0 +# ScanInterval:4=0 # Interval between consecutive scan (in milliseconds) +# Reserved2:4=0 +# ReportConditions:4=0 # bit0 - SSID match + # bit1 - SNR above SNR threshold + # bit2 - RSSI above RSSI threshold + # bit31 - All channels scanned at least once +# Reserved3:2=0 +#} + +########### SET BG Scan Configuration ##################### +bgscfg={ + CmdCode=0x006b # do NOT change this line + Action:1=1 # 0- Get, 1- Set + ConfigType:1=0 # 0- normal BG Scan config, 1-PPS or UAPSD BG Scan config + Enable:1=1 # 0- Disable, 1-Enable + BssType:1=3 # 1 - Infrastructure,2 - IBSS,3 - Any + ChannelsPerScan:1=14 # Number of Channel to scan at one scan; maximum 14 + Reserved1:3=0 + ScanInterval:4=1000 # Interval between consecutive scan (in milliseconds) + Reserved2:4=0 + ReportConditions:4=1 # bit0 - SSID match + # bit1 - SNR above SNR threshold + # bit2 - RSSI above RSSI threshold + # bit31 - All channels scanned at least once + Reserved3:2=0 + + # SSID parameter set: + # + # MaxSSIDLen entries: + # + # 1. MaxSSIDLen:1=0x00 - to denote match AP name exactly, + # generate SSID specific probes + # 2. MaxSSIDLen:1=maxlen - to denote AP name will be use to base match the + # SSID and SSID's max length is 'maxlen', + # do not generate SSID specific probes + # 3. MaxSSIDLen:1=wildcard match char ('*' or '?') + # - to denote wildcard AP name will be use to match the SSID + # 4. MaxSSIDLen:1=0xff - to denote unix pattern matching + # + # SSID entries: + # + # SSID="AP_NAME" - to mention the SSID to match + + # SSID Examples: + # + # + # Match SSID name "NXPAP" exactly, generate SSID specific probes + # + SSIDHeaderType:2=0x0112 + SSIDHeaderLen:2={ + MaxSSIDLen:1=0x00 + SSID:9="NXPAP" + } + + # + # NXPAP will be use to base match the SSID and SSID's max length is 12 + # +# SSIDHeaderType:2=0x0112 +# SSIDHeaderLen:2={ +# MaxSSIDLen:1=0x0c +# SSID:9="NXPAP" +# } + + # + # Match "NXPAP*" where '*' is a single char + # +# SSIDHeaderType:2=0x0112 +# SSIDHeaderLen:2={ +# MaxSSIDLen:1='*' +# SSID:10="NXPAP*" +# } + + # + # Match "Mar?ell*" with unix pattern matching + # +# SSIDHeaderType:2=0x0112 +# SSIDHeaderLen:2={ +# MaxSSIDLen:1=0xff # For unix pattern matching +# SSID:8="Mar?ell*" +# } + + # Number Probe requests to be sent for broadcast and + # for each SSID specific scan required. + # + # If any SSID in the list has a non-zero modifier (wildcard match char, + # unix pattern match, maxlen), "Numprobes" of broadcast probe requests + # will be transmitted once per channel and the results matched against + # all entries. + # + # Set to 0 to use global scan probes setting + # + ProbeHeaderType:2=0x0102 + ProbeHeaderLen:2={ + NumProbes:2=2 + } + + # ChannelList contains the channels to scan + # The ChannelList should be specified in the form of + # + # RadioType, ChanNumber, ScanType, MinScanTime, ScanTime; + # + # RadioType - 0 [B/G Band], 1 [A Band] + # ScanType - 2 [Active], 3 [Passive] + # + + ChannHeaderType:2=0x0101 + ChannHeaderLen:2={ + Chan1_RadioType:1=0 + Chan1_ChanNumber:1=10 + Chan1_ScanType:1=2 + Chan1_MinScanTime:2=10 + Chan1_ScanTime:2=100 + + Chan2_RadioType:1=0 + Chan2_ChanNumber:1=6 + Chan2_ScanType:1=3 + Chan2_MinScanTime:2=10 + Chan2_ScanTime:2=100 + } + + # SNR threshold used when ReportConditions bit1 is set + SNRHeaderType:2=0x0105 + SNRHeaderLen:2={ + SNRValue:1=40 #SNR Thereshold Value + SNRFreq:1=0 + } + + # RSSI threshold used when ReportConditions bit2 is set + # + # Threshold is absolute value and match value would + # therefore be less than or equal to trigger a report + RSSIHeaderType:2=0x0104 + RSSIHeaderLen:2={ + RSSIValue:1=50 #RSSI Thereshold Value + RSSIFreq:1=0 + } + + # StartLaterValue: 0 - BGScan start immediately + # 1 - BGScan will start later after "Scan Interval" + StartLaterHeaderType:2=0x011e + StartLaterHeaderLen:2={ + StartLaterValue:2=0 + } +} +######################### BG Scan Configuration command ################## diff --git a/mxm_wifiex/wlan_src/mapp/mlanconfig/config/bg_scan_wifidirect.conf b/mxm_wifiex/wlan_src/mapp/mlanconfig/config/bg_scan_wifidirect.conf new file mode 100644 index 0000000..f480a9c --- /dev/null +++ b/mxm_wifiex/wlan_src/mapp/mlanconfig/config/bg_scan_wifidirect.conf @@ -0,0 +1,88 @@ +# File : bg_scan_wifidirect.conf + +######################### BG Scan Configuration command ################## +########### SET BG Scan Configuration ##################### +bgscfg={ + CmdCode=0x006b # do NOT change this line + Action:1=1 # 0- Get, 1- Set + ConfigType:1=0 # 0- normal BG Scan config, 1-PPS or UAPSD BG Scan config + Enable:1=1 # 0- Disable, 1-Enable + BssType:1=3 # 1 - Infrastructure,2 - IBSS,3 - Any + ChannelsPerScan:1=3 # Number of Channel to scan at one scan; maximum 14 + Reserved1:3=0 + ScanInterval:4=1000 # Interval between consecutive scan (in milliseconds) + StoreCondition:4=1 # 1 - SSID match (bit 0) + # 2 - SSID match AND SNR above SNR threshold (bit 1) + ReportConditions:4=1 # 1 - SSID match (bit 0) + # 2 - SSID match AND SNR above SNR threshold (bit 1) + Reserved3:2=0 + + # SSID parameter set: + # + SSIDHeaderType:2=0x0112 + SSIDHeaderLen:2={ + MaxSSIDLen:1=0x00 + SSID:7="DIRECT-" + } + + # Number Probe requests to be sent for broadcast and + # for each SSID specific scan required. + # + # If any SSID in the list has a non-zero modifier (wildcard match char, + # unix pattern match, maxlen), "Numprobes" of broadcast probe requests + # will be transmitted once per channel and the results matched against + # all entries. + # + # Set to 0 to use global scan probes setting + # + ProbeHeaderType:2=0x0102 + ProbeHeaderLen:2={ + NumProbes:2=2 + } + + # ChannelList contains the channels to scan + # The ChannelList should be specified in the form of + # + # RadioType, ChanNumber, ScanType, MinScanTime, ScanTime; + # + # RadioType - 0 [B/G Band], 1 [A Band] + # ScanType - 2 [Active], 3 [Passive] + # + + ChannHeaderType:2=0x0101 + ChannHeaderLen:2={ + Chan1_RadioType:1=0 + Chan1_ChanNumber:1=1 + Chan1_ScanType:1=2 + Chan1_MinScanTime:2=10 + Chan1_ScanTime:2=100 + + Chan2_RadioType:1=0 + Chan2_ChanNumber:1=6 + Chan2_ScanType:1=2 + Chan2_MinScanTime:2=10 + Chan2_ScanTime:2=100 + + Chan3_RadioType:1=0 + Chan3_ChanNumber:1=11 + Chan3_ScanType:1=2 + Chan3_MinScanTime:2=10 + Chan3_ScanTime:2=100 + } + + # SNR threshold to match, when StoreCondition + # or ReportConditions been set to 2 + SNRHeaderType:2=0x0105 + SNRHeaderLen:2={ + SNRValue:1=40 #SNR Thereshold Value + SNRFreq:1=0 + } + + # StartLaterValue: 0 - BGScan start immediately + # 1 - BGScan will start later after "Scan Interval" + StartLaterHeaderType:2=0x011e + StartLaterHeaderLen:2={ + StartLaterValue:2=0 + } +} +######################### BG Scan Configuration command ################## diff --git a/mxm_wifiex/wlan_src/mapp/mlanconfig/config/crypto_test.conf b/mxm_wifiex/wlan_src/mapp/mlanconfig/config/crypto_test.conf new file mode 100644 index 0000000..d35812f --- /dev/null +++ b/mxm_wifiex/wlan_src/mapp/mlanconfig/config/crypto_test.conf @@ -0,0 +1,58 @@ +# File : crypto_test.conf + +######################### crypto_test command configuration ################## +# support algorithm:1-RC4, 2-AES, 3-AES_KEY_WRAP,4-AES-CCM + +crypto_test={ + CmdCode=0x0078 # do NOT change this line + #EncDec: 0-Decrypt, 1-Encrypt + EncDec:2=0 + #Algorithm: 1-RC4, 2-AES, 3-AES_KEY_WRAP + Algorithm:2=1 + #KeyIVLength: Length of KeyIV (bytes) + KeyIVLength:2=8 + #KeyIV: Key IV + KeyIV:32='0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11' + #KeyLength: Length of Key (bytes) + KeyLength:2=16 + #Key: Key + Key:32='0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22' + #DataType: DataType + DataType:2=0x0111 + #DataLength: Data Length + DataLength:2={ + #Data: Data + Data:8='0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33' + } +} + +#####Sample crypto_test command configuration for AES-CCM algorithm ######### + +#crypto_test={ +# CmdCode=0x0078 # do NOT change this line +# #EncDec: 0-Decrypt, 1-Encrypt +# EncDec:2=1 +# #Algorithm: 4-AES-CCM +# Algorithm:2=4 +# #KeyLength: Length of Key (bytes) +# KeyLength:2=16 +# #Key: Key +# Key:32='0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22' +# #NonceLength: Length of Nonce (bytes) +# NonceLength:2=10 +# #Nonce: Nonce +# Nonce:14='0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11' +# #AADLength: Length of AAD (bytes) +# AADLength:2=12 +# #AAD: AAD +# AAD:32='0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33' +# #DataType: DataType +# DataType:2=0x0111 +# #DataLength: Data Length +# DataLength:2={ +# #Data: Data +# Data:8='0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33' +# } +#} + +######################### End of crypto_test configuration command ################## diff --git a/mxm_wifiex/wlan_src/mapp/mlanconfig/config/cwmode.conf b/mxm_wifiex/wlan_src/mapp/mlanconfig/config/cwmode.conf new file mode 100644 index 0000000..1f245a2 --- /dev/null +++ b/mxm_wifiex/wlan_src/mapp/mlanconfig/config/cwmode.conf @@ -0,0 +1,51 @@ +#CW_MODE settings configuration +# +CW_MODE={ +#Mode of operation 0: Disable current Tx Mode, 1: Continuous Tx Packet, 2: Continuous Wave/Tone +Mode=1 +#Channel number +Channel=6 +#channel Info +#bit [3:0] - channel offset 0: no secondary channel, 1: secondary channel above, 2: reserved, 3: secondary channel below +#bit [4:7] - channel band 0: 2.4G, 1: 5G, 2: 4G, 3: reserved +Chaninfo=0x00 +#Tx power for Cont Tx in dbm +TxPower=12 +# Packet Length for Cont Tx +# legacy rates: upto 2312, HT/VHT rates: upto 8K +PktLength=2048 +#RateInfo for Cont Tx +RateInfo=0x0000 +#rateInfo = 0x0732 : format = VHT, Bandwidth = 80MHz, datarate/MCS index = MCS7 +#rateInfo = 0x0000 : format = legacy, Bandwidth = 20MHz, datarate/MCS index = 1Mbps +#rateInfo = 0x0521 : format = HT, Bandwidth = 40MHz, datarate/MCS index = MCS5 +#rateInfo = 0x4521 : format = HT, Bandwidth = 40MHz, datarate/MCS index = MCS5, NSS = 1 +#rateInfo = 0x8921 : format = HT, Bandwidth = 40MHz, datarate/MCS index = MCS9, NSS = 2 +#bit [1:0] - Format 0: legacy, 1: 11n (HT), 2: 11ac (VHT) +#bit 2 - STBC (Not used for Cont Tx test) +#bit 3 - Beamforming (Not used for Cont Tx test) +#bit [5:4] - Bandwidth 0: 20MHz, 2: 40MHz, 3: 80MHz +#bit [7:6] - reserved +#bit [13:8] - index : data rate or MCS +#bit [15:14]- NSS (Used for 2x2 chips). Used in FW only for 2x2 chips. +# can take following values. +#If is 0 (LG), #If is 1 (HT) #If is 2 (VHT) +# NSS = 1 NSS = 1 or 2 +# 0 1 Mbps 0 MCS0 0 MCS0 +# 1 2 Mbps 1 MCS1 1 MCS1 +# 2 5.5 Mbps 2 MCS2 2 MCS2 +# 3 11 Mbps 3 MCS3 3 MCS3 +# 5 6 Mbps 4 MCS4 4 MCS4 +# 6 9 Mbps 5 MCS5 5 MCS5 +# 7 12 Mbps 6 MCS6 6 MCS6 +# 8 18 Mbps 7 MCS7 7 MCS7 +# Used only for NSS = 2 +# 9 24 Mbps 8 MCS8 +# 10 36 Mbps 9 MCS9 +# 11 48 Mbps 10 MCS10 +# 12 54 Mbps 11 MCS11 +# 12 MCS12 +# 13 MCS13 +# 14 MCS14 +# 15 MCS15 +} diff --git a/mxm_wifiex/wlan_src/mapp/mlanconfig/config/debug.conf b/mxm_wifiex/wlan_src/mapp/mlanconfig/config/debug.conf new file mode 100644 index 0000000..09d40dc --- /dev/null +++ b/mxm_wifiex/wlan_src/mapp/mlanconfig/config/debug.conf @@ -0,0 +1,89 @@ +# +# File: debug.conf +# 11ax configuration commands +# + +enable_thermal_mgmt={ + CmdCode=0x008b # do NOT change this line + Action:2=1 # 1 - SET + SUBID:2=0x113 # THERMAL_MANAGEMENT + Value:1=1 # 1 -- ENABLE; +} + +disable_thermal_mgmt={ + CmdCode=0x008b # do NOT change this line + Action:2=1 # 1 - SET + SUBID:2=0x113 # THERMAL_MANAGEMENT + Value:1=0 # 0 -- DISABLE; +} + +get_thermal_mgmt={ + CmdCode=0x008b # do NOT change this line + Action:2=0 # 0 - GET + SUBID:2=0x113 # THERMAL_MANAGEMENT + Value:1=0 # 1 -- ENABLE; + # 0 -- DISABLE; +} + +stop_su={ + CmdCode=0x008b # do NOT change this line + Action:2=1 # 1 - SET + SUBID:2=0x101 # DOT11AX_ULOFDMA + Value:4=1 # 1 -- stop_su; + # 0 -- resume su; +} + +start_su={ + CmdCode=0x008b # do NOT change this line + Action:2=1 # 1 - SET + SUBID:2=0x101 # DOT11AX_ULOFDMA + Value:4=0 # 1 -- stop_su; + # 0 -- resume su; +} + +stop_forceRTS={ + CmdCode=0x008b # do NOT change this line + Action:2=1 # 1 - SET + SUBID:2=0x104 # DOT11AX_ULOFDMA + Value:1=0 # 1 -- stop forceRTS; + # 0 -- start forceRTS; +} + +start_forceRTS={ + CmdCode=0x008b # do NOT change this line + Action:2=1 # 1 - SET + SUBID:2=0x104 # DOT11AX_ULOFDMA + Value:1=1 # 1 -- start forceRTS; + # 0 -- stop forceRTS; +} + +set_nonampdu_txctrl_watermark={ + CmdCode=0x008b # do NOT change this line + Action:2=1 # 1 - SET + SUBID:2=0x116 # NON_AMPDU_TX_CTRL + non_ampdu_tx_water_mark.TlvType:2=0x101 + non_ampdu_tx_water_mark.TlvLength:2={ + non_ampdu_tx_high_water_mark:1=0x20 + non_ampdu_tx_low_water_mark:1=0x8 + } +} + +enable_nonampdu_txctrl={ + CmdCode=0x008b # do NOT change this line + Action:2=1 # 1 - SET + SUBID:2=0x116 # NON_AMPDU_TX_CTRL + non_ampdu_tx_ctrl.TlvType:2=0x102 + non_ampdu_tx_ctrl.TlvLength:2={ + non_ampdu_tx_ctrl:1=0x1 + } +} + +disable_nonampdu_txctrl={ + CmdCode=0x008b # do NOT change this line + Action:2=1 # 1 - SET + SUBID:2=0x116 # NON_AMPDU_TX_CTRL + non_ampdu_tx_ctrl.TlvType:2=0x102 + non_ampdu_tx_ctrl.TlvLength:2={ + non_ampdu_tx_ctrl:1=0x0 + } +} diff --git a/mxm_wifiex/wlan_src/mapp/mlanconfig/config/ed_mac_ctrl_V2_8887.conf b/mxm_wifiex/wlan_src/mapp/mlanconfig/config/ed_mac_ctrl_V2_8887.conf new file mode 100644 index 0000000..adc9279 --- /dev/null +++ b/mxm_wifiex/wlan_src/mapp/mlanconfig/config/ed_mac_ctrl_V2_8887.conf @@ -0,0 +1,29 @@ +# File : ed_mac_ctrl_V2_8887.conf +# +# ed_mac_ctrl_v2 is used for 88W8897, 88W8887, 88W8797, 88W8782, 88W8787 +# ./mlanutl mlan0 hostcmd config/ed_mac_ctrl_V2_8887.conf ed_mac_ctrl_v2 +# +## Set Energy Detect Threshold for EU Adaptivity test + +ed_mac_ctrl_v2={ + CmdCode=0x0130 #Command code, DO NOT change this line + ed_ctrl_2g.enable:2=0x1 # 0 - disable EU adaptivity for 2.4GHz band + # 1 - enable EU adaptivity for 2.4GHz band + + ed_ctrl_2g.offset:2=0x0 # 0 - Default Energy Detect threshold + #offset value range: 0x80 to 0x7F + + ed_ctrl_2g.on_period:2=0x12 #DO NOT Change this line + ed_ctrl_2g.off_period:2=0x0 #DO NOT Change this line + ed_ctrl_2g.bitmap:2=0x1 #DO NOT Change this line + + ed_ctrl_5g.enable:2=0x1 # 0 - disable EU adaptivity for 5GHz band + # 1 - enable EU adaptivity for 5GHz band + + ed_ctrl_5g.offset:2=0x6 # 0 - Default Energy Detect threshold + #offset value range: 0x80 to 0x7F + + ed_ctrl_5g.on_period:2=0x12 #DO NOT Change this line + ed_ctrl_5g.off_period:2=0x0 #DO NOT Change this line + ed_ctrl_5g.bitmap:2=0x1 #DO NOT Change this line +} diff --git a/mxm_wifiex/wlan_src/mapp/mlanconfig/config/ed_mac_ctrl_V2_8897.conf b/mxm_wifiex/wlan_src/mapp/mlanconfig/config/ed_mac_ctrl_V2_8897.conf new file mode 100644 index 0000000..f472e81 --- /dev/null +++ b/mxm_wifiex/wlan_src/mapp/mlanconfig/config/ed_mac_ctrl_V2_8897.conf @@ -0,0 +1,29 @@ +# File : ed_mac_ctrl_V2_8897.conf +# +# ed_mac_ctrl_v2 is used for 88W8897, 88W8887, 88W8797, 88W8782, 88W8787 +# ./mlanutl mlan0 hostcmd config/ed_mac_ctrl_V2_8897.conf ed_mac_ctrl_v2 +# +## Set Energy Detect Threshold for EU Adaptivity test + +ed_mac_ctrl_v2={ + CmdCode=0x0130 #Command code, DO NOT change this line + ed_ctrl_2g.enable:2=0x1 # 0 - disable EU adaptivity for 2.4GHz band + # 1 - enable EU adaptivity for 2.4GHz band + + ed_ctrl_2g.offset:2=0x0 # 0 - Default Energy Detect threshold + #offset value range: 0x80 to 0x7F + + ed_ctrl_2g.on_period:2=0x12 #DO NOT Change this line + ed_ctrl_2g.off_period:2=0x0 #DO NOT Change this line + ed_ctrl_2g.bitmap:2=0x1 #DO NOT Change this line + + ed_ctrl_5g.enable:2=0x1 # 0 - disable EU adaptivity for 5GHz band + # 1 - enable EU adaptivity for 5GHz band + + ed_ctrl_5g.offset:2=0x4 # 0 - Default Energy Detect threshold + #offset value range: 0x80 to 0x7F + + ed_ctrl_5g.on_period:2=0x12 #DO NOT Change this line + ed_ctrl_5g.off_period:2=0x0 #DO NOT Change this line + ed_ctrl_5g.bitmap:2=0x1 #DO NOT Change this line +} diff --git a/mxm_wifiex/wlan_src/mapp/mlanconfig/config/ed_mac_ctrl_V3_8977.conf b/mxm_wifiex/wlan_src/mapp/mlanconfig/config/ed_mac_ctrl_V3_8977.conf new file mode 100644 index 0000000..501f616 --- /dev/null +++ b/mxm_wifiex/wlan_src/mapp/mlanconfig/config/ed_mac_ctrl_V3_8977.conf @@ -0,0 +1,23 @@ +# File : ed_mac_ctrl_V3_8977.conf +# +# ed_mac_ctrl_v3 is used for 88W8997, 88W8987, 88W8977 +# ./mlanutl mlan0 hostcmd config/ed_mac_ctrl_V3_8977.conf ed_mac_ctrl_v3 +# +## Set Energy Detect Threshold for EU Adaptivity test + +ed_mac_ctrl_v3={ + CmdCode=0x0130 #Command code, DO NOT change this line + ed_ctrl_2g.enable:2=0x1 # 0 - disable EU adaptivity for 2.4GHz band + # 1 - enable EU adaptivity for 2.4GHz band + + ed_ctrl_2g.offset:2=0x9 # 0 - Default Energy Detect threshold + #offset value range: 0x80 to 0x7F + + ed_ctrl_5g.enable:2=0x1 # 0 - disable EU adaptivity for 5GHz band + # 1 - enable EU adaptivity for 5GHz band + + ed_ctrl_5g.offset:2=0xC # 0 - Default Energy Detect threshold + #offset value range: 0x80 to 0x7F + + ed_ctrl_txq_lock:4=0xFF #DO NOT Change this line +} diff --git a/mxm_wifiex/wlan_src/mapp/mlanconfig/config/ed_mac_ctrl_V3_8978.conf b/mxm_wifiex/wlan_src/mapp/mlanconfig/config/ed_mac_ctrl_V3_8978.conf new file mode 100644 index 0000000..03563f1 --- /dev/null +++ b/mxm_wifiex/wlan_src/mapp/mlanconfig/config/ed_mac_ctrl_V3_8978.conf @@ -0,0 +1,23 @@ +# File : ed_mac_ctrl_V3_8978.conf +# +# ed_mac_ctrl_v3 is used for 88W8997, 88W8987, 88W8977, 88W8978 +# ./mlanutl mlan0 hostcmd config/ed_mac_ctrl_V3_8978.conf ed_mac_ctrl_v3 +# +## Set Energy Detect Threshold for EU Adaptivity test + +ed_mac_ctrl_v3={ + CmdCode=0x0130 #Command code, DO NOT change this line + ed_ctrl_2g.enable:2=0x1 # 0 - disable EU adaptivity for 2.4GHz band + # 1 - enable EU adaptivity for 2.4GHz band + + ed_ctrl_2g.offset:2=0x9 # 0 - Default Energy Detect threshold + #offset value range: 0x80 to 0x7F + + ed_ctrl_5g.enable:2=0x1 # 0 - disable EU adaptivity for 5GHz band + # 1 - enable EU adaptivity for 5GHz band + + ed_ctrl_5g.offset:2=0xC # 0 - Default Energy Detect threshold + #offset value range: 0x80 to 0x7F + + ed_ctrl_txq_lock:4=0xFF #DO NOT Change this line +} diff --git a/mxm_wifiex/wlan_src/mapp/mlanconfig/config/ed_mac_ctrl_V3_8987.conf b/mxm_wifiex/wlan_src/mapp/mlanconfig/config/ed_mac_ctrl_V3_8987.conf new file mode 100644 index 0000000..af2f2da --- /dev/null +++ b/mxm_wifiex/wlan_src/mapp/mlanconfig/config/ed_mac_ctrl_V3_8987.conf @@ -0,0 +1,23 @@ +# File : ed_mac_ctrl_V3_8987.conf +# +# ed_mac_ctrl_v3 is used for 88W8997, 88W8987, 88W8977 +# ./mlanutl mlan0 hostcmd config/ed_mac_ctrl_V3_8987.conf ed_mac_ctrl_v3 +# +## Set Energy Detect Threshold for EU Adaptivity test + +ed_mac_ctrl_v3={ + CmdCode=0x0130 #Command code, DO NOT change this line + ed_ctrl_2g.enable:2=0x1 # 0 - disable EU adaptivity for 2.4GHz band + # 1 - enable EU adaptivity for 2.4GHz band + + ed_ctrl_2g.offset:2=0x6 # 0 - Default Energy Detect threshold + #offset value range: 0x80 to 0x7F + + ed_ctrl_5g.enable:2=0x1 # 0 - disable EU adaptivity for 5GHz band + # 1 - enable EU adaptivity for 5GHz band + + ed_ctrl_5g.offset:2=0x6 # 0 - Default Energy Detect threshold + #offset value range: 0x80 to 0x7F + + ed_ctrl_txq_lock:4=0xFF #DO NOT Change this line +} diff --git a/mxm_wifiex/wlan_src/mapp/mlanconfig/config/ed_mac_ctrl_V3_8997.conf b/mxm_wifiex/wlan_src/mapp/mlanconfig/config/ed_mac_ctrl_V3_8997.conf new file mode 100644 index 0000000..6c86bd7 --- /dev/null +++ b/mxm_wifiex/wlan_src/mapp/mlanconfig/config/ed_mac_ctrl_V3_8997.conf @@ -0,0 +1,23 @@ +# File : ed_mac_ctrl_V3_8997.conf +# +# ed_mac_ctrl_v3 is used for 88W8997, 88W8987, 88W8977 +# ./mlanutl mlan0 hostcmd config/ed_mac_ctrl_V3_8997.conf ed_mac_ctrl_v3 +# +## Set Energy Detect Threshold for EU Adaptivity test + +ed_mac_ctrl_v3={ + CmdCode=0x0130 #Command code, DO NOT change this line + ed_ctrl_2g.enable:2=0x1 # 0 - disable EU adaptivity for 2.4GHz band + # 1 - enable EU adaptivity for 2.4GHz band + + ed_ctrl_2g.offset:2=0x0 # 0 - Default Energy Detect threshold + #offset value range: 0x80 to 0x7F + + ed_ctrl_5g.enable:2=0x1 # 0 - disable EU adaptivity for 5GHz band + # 1 - enable EU adaptivity for 5GHz band + + ed_ctrl_5g.offset:2=0x4 # 0 - Default Energy Detect threshold + #offset value range: 0x80 to 0x7F + + ed_ctrl_txq_lock:4=0xFF #DO NOT Change this line +} diff --git a/mxm_wifiex/wlan_src/mapp/mlanconfig/config/ed_mac_ctrl_V3_909x.conf b/mxm_wifiex/wlan_src/mapp/mlanconfig/config/ed_mac_ctrl_V3_909x.conf new file mode 100644 index 0000000..d4ba59c --- /dev/null +++ b/mxm_wifiex/wlan_src/mapp/mlanconfig/config/ed_mac_ctrl_V3_909x.conf @@ -0,0 +1,23 @@ +# File : ed_mac_ctrl_V3_909x.conf +# +# ed_mac_ctrl_v3 is used for 88W9098, 88W9097 +# ./mlanutl mlan0 hostcmd config/ed_mac_ctrl_V3_909x.conf ed_mac_ctrl_v3 +# +## Set Energy Detect Threshold for EU Adaptivity test + +ed_mac_ctrl_v3={ + CmdCode=0x0130 #Command code, DO NOT change this line + ed_ctrl_2g.enable:2=0x1 # 0 - disable EU adaptivity for 2.4GHz band + # 1 - enable EU adaptivity for 2.4GHz band + + ed_ctrl_2g.offset:2=0x5 # 0 - Default Energy Detect threshold + #offset value range: 0x80 to 0x7F + + ed_ctrl_5g.enable:2=0x1 # 0 - disable EU adaptivity for 5GHz band + # 1 - enable EU adaptivity for 5GHz band + + ed_ctrl_5g.offset:2=0x5 # 0 - Default Energy Detect threshold + #offset value range: 0x80 to 0x7F + + ed_ctrl_txq_lock:4=0x1e00FF #DO NOT Change this line +} diff --git a/mxm_wifiex/wlan_src/mapp/mlanconfig/config/init_cfg.conf b/mxm_wifiex/wlan_src/mapp/mlanconfig/config/init_cfg.conf new file mode 100644 index 0000000..821c024 --- /dev/null +++ b/mxm_wifiex/wlan_src/mapp/mlanconfig/config/init_cfg.conf @@ -0,0 +1,14 @@ +# File : init_cfg.conf + +# MAC address (interface: address) +mac_addr=mlan0: 00:50:43:20:12:34 +mac_addr=mmlan0: 00:50:43:20:42:64 +mac_addr=uap0: 00:50:43:20:12:35 +mac_addr=muap0: 00:50:43:20:42:65 +mac_addr=wfd0: 00:50:43:20:12:36 +mac_addr=mwfd0: 00:40:43:20:42:66 + +# Register (type, offset, value) +# type 1:MAC/SOC, 2:BBP, 3:RF, 5:CAU +#wlan_reg=1,0xA794,0x55FF55FF + diff --git a/mxm_wifiex/wlan_src/mapp/mlanconfig/config/mef.conf b/mxm_wifiex/wlan_src/mapp/mlanconfig/config/mef.conf new file mode 100644 index 0000000..37d19a4 --- /dev/null +++ b/mxm_wifiex/wlan_src/mapp/mlanconfig/config/mef.conf @@ -0,0 +1,167 @@ +# File : mef.conf + +######################### MEF Configuration command ################## +mefcfg={ + #Criteria: bit0-broadcast, bit1-unicast, bit3-multicast + Criteria=2 # Unicast frames are received during hostsleepmode + NumEntries=1 # Number of activated MEF entries + #mef_entry_0: example filters to match TCP destination port 80 send by 192.168.0.88 pkt or magic pkt. + mef_entry_0={ + #mode: bit0--hostsleep mode, bit1--non hostsleep mode + mode=1 # HostSleep mode + #action: 0--discard and not wake host, 1--discard and wake host 3--allow and wake host + action=3 # Allow and Wake host + filter_num=3 # Number of filter + #RPN only support "&&" and "||" operator,space can not be removed between operator. + RPN=Filter_0 && Filter_1 || Filter_2 + #Byte comparison filter's type is 0x41,Decimal comparison filter's type is 0x42, + #Bit comparison filter's type is 0x43 + #Filter_0 is decimal comparison filter, it always with type=0x42 + #Decimal filter always has type, pattern, offset, numbyte 4 field + #Filter_0 will match rx pkt with TCP destination port 80 + Filter_0={ + type=0x42 # decimal comparison filter + pattern=80 # 80 is the decimal constant to be compared + offset=44 # 44 is the byte offset of the field in RX pkt to be compare + numbyte=2 # 2 is the number of bytes of the field + } + #Filter_1 is Byte comparison filter, it always with type=0x41 + #Byte filter always has type, byte, repeat, offset 4 filed + #Filter_1 will match rx pkt send by IP address 192.168.0.88 + Filter_1={ + type=0x41 # Byte comparison filter + repeat=1 # 1 copies of 'c0:a8:00:58' + byte=c0:a8:00:58 # 'c0:a8:00:58' is the byte sequence constant with each byte + # in hex format, with ':' as delimiter between two byte. + offset=34 # 34 is the byte offset of the equal length field of rx'd pkt. + } + #Filter_2 is Magic packet, it will looking for 16 contiguous copies of '00:50:43:20:01:02' from + # the rx pkt's offset 14 + Filter_2={ + type=0x41 # Byte comparison filter + repeat=16 # 16 copies of '00:50:43:20:01:02' + byte=00:50:43:20:01:02 # '00:50:43:20:01:02' is the byte sequence constant + offset=14 # 14 is the byte offset of the equal length field of rx'd pkt. + } + } +} + + +#--------------------------examples for MEF filters-------------------------------- +# example: filters to match ARP packet with protocol addr 192.168.0.104 +# mef_entry_0={ +# mode=1 # HostSleep mode +# action=3 # Allow and Wake host +# filter_num=3 # Number of filter +# RPN=Filter_0 && Filter_1 && Filter_2 +# #Filter_0 looking for rx pkt with DA is broadcast address +# Filter_0={ +# type=0x41 +# repeat=6 +# byte=ff +# offset=0 +# } +# #Filter_1 looking for rx pkt with EtherType is 0x0806(ARP) +# Filter_1={ +# type=0x41 +# repeat=1 +# byte=08:06 +# offset=20 +# } +# #Filter_2 looking for rx pkt with ARP target protocol addr 192.168.0.104 +# Filter_2={ +# type=0x41 +# repeat=1 +# byte=c0:a8:00:68 +# offset=46 +# } +# } +#------------------------------------------------------------------------------------- +# example: filter to check if the destination MAC address is unicast pkt +# mef_entry_0={ +# mode=1 # HostSleep mode +# action=3 # Allow and Wake host +# filter_num=3 # Number of filter +# RPN=Filter_0 +# #Filter_0 is Bit comparison filter, it always with type=0x43 +# #Byte filter always has type, byte, mask, offset 4 filed +# #"byte" is the byte sequence constant with each byte in hex format, with ':' as delimiter between two byte +# #"mask" is also with each byte in hex format, with ':' as delimiter between two byte +# #"byte" should has the same length as "mask" +# #Filter_0 will check if the destination MAC address is unicast pkt +# Filter_0={ +# type=0x43 #Bit comparison filter +# byte=00 #00 is the 1-byte sequence constant +# offset=0 #0 is the byte offset of the rx pkt +# mask=01 #1 is the 1-byte mask +# } +# } +#-------------------------------------------------------------------------------------------------- +# example: Disable MEF filters +# mefcfg={ +# #Criteria: bit0-broadcast, bit1-unicast, bit3-multicast +# Criteria=2 # Unicast frames are received during hostsleepmode +# NumEntries=0 # Number of activated MEF entries +# } +#-------------------------------------------------------------------------------------------------- +# example: Test MEF filters +# mefcfg={ +# Criteria=1 +# NumEntries=1 +# mef_entry_0={ +# mode=4 # Test Mode +# action=16 # Invoke Test +# filter_num=0 +# } +# } +#----------------------------------------------------------------------------------------------------- +# example: Test MEF filters +# mefcfg={ +# Criteria=1 +# NumEntries=1 +# mef_entry_0={ +# mode=4 +# action=0 +# filter_num=1 +# RPN=Filter_0 +# Filter_0={ +# type=0x44 # test filter +# repeat=2 # 2 copies of 'BE:EF' +# byte=BE:EF # 'BE:EF' is the byte sequence constant +# offset=18 # 18 is the byte offset of the equal length field of rx'd pkt. +# dest=00:50:43:20:5a:82 # '00:50:43:20:5a:82' is the byte sequence constant +# } +# } +# } +#---------------------------------------------------------------------------------------------------- +#example: Filter broadcast/ipv4 multicast/ipv6 multicast packets in non hostsleep mode +#mefcfg={ +# Criteria=9 # broadcast and multicast frames +# NumEntries=1 # Number of activated MEF entries +# mef_entry_0={ +# mode=2 # non HostSleep mode +# action=0 # discard and not wake host +# filter_num=3 # Number of filter +# RPN=Filter_0 || Filter_1 || Filter_2 +# Filter_0={ # IPV4 multicast +# type=0x41 # byte comparison filter +# byte=01:00:5e # 01:00:5e is the byte constant to be compared +# offset=0 # 0 is the byte offset of the equal length field of rx'd pkt. +# repeat=1 # +# } +# Filter_1={ # broadcast packet check +# type=0x41 # Byte comparison filter +# repeat=6 # 6 copies of 'ff', means broadcast +# byte=ff # 'ff'(0xff) is the byte sequence constant with each byte +# # in hex format, with ':' as delimiter between two byte. +# offset=0 # 0 is the byte offset of the equal length field of rx'd pkt. +# } +# Filter_2={ # IPV6 multicast +# type=0x41 # byte comparison filter +# byte=33:33 # 33:33 is the byte constant to be compared +# offset=0 # 0 is the byte offset of the equal length field of rx'd pkt. +# repeat=1 # +# } +# } +#} +#------------------------------------------------------------------------------------------------------ diff --git a/mxm_wifiex/wlan_src/mapp/mlanconfig/config/mef_mdns.conf b/mxm_wifiex/wlan_src/mapp/mlanconfig/config/mef_mdns.conf new file mode 100644 index 0000000..568ca6f --- /dev/null +++ b/mxm_wifiex/wlan_src/mapp/mlanconfig/config/mef_mdns.conf @@ -0,0 +1,204 @@ +# File : mef_mdns.conf + +######################### MEF Configuration command ################## +mefcfg={ + #Criteria: bit0-broadcast, bit1-unicast, bit3-multicast + Criteria=8 # Multicast frames are received during hostsleepmode + NumEntries=2 # Number of activated MEF entries + #mef_entry_0: example filters to match WS-Discovery pkt for IPv4. + mef_entry_0={ + #mode: bit0--hostsleep mode, bit1--non hostsleep mode + mode=1 # HostSleep mode + #action: 0--discard and not wake host, 1--discard and wake host 3--allow and wake host + action=3 # Allow and Wake host + filter_num=4 # Number of filter + #RPN only support "&&" and "||" operator,space can not be removed between operator. + RPN=Filter_0 && Filter_1 && Filter_2 && Filter_3 + #Filter_0 will match IPv4 protocol packet + Filter_0={ + type=0x41 + repeat=1 + byte=08:00 + offset=20 + } + #Filter_1 will match dest multicast IPv4 address 224.0.0.251 + Filter_1={ + type=0x41 + repeat=1 + byte=e0:00:00:fb + offset=38 + } + #Filter_2 will match UDP packet + Filter_2={ + type=0x42 + pattern=17 + offset=31 + numbyte=1 + } + #Filter_3 will match UDP port 5353 + Filter_3={ + type=0x42 + pattern=5353 + offset=44 + numbyte=2 + } + } + #mef_entry_1: example filters to match WS-Discovery pkt for IPv6. + mef_entry_1={ + #mode: bit0--hostsleep mode, bit1--non hostsleep mode + mode=1 # HostSleep mode + #action: 0--discard and not wake host, 1--discard and wake host 3--allow and wake host + action=3 # Allow and Wake host + filter_num=4 # Number of filter + #RPN only support "&&" and "||" operator,space can not be removed between operator. + RPN=Filter_0 && Filter_1 && Filter_2 && Filter_3 + #Filter_0 will match IPv4 protocol packet + Filter_0={ + type=0x41 + repeat=1 + byte=86:dd + offset=20 + } + #Filter_1 will match dest multicast IPv6 address FF02::FB + Filter_1={ + type=0x41 + repeat=1 + byte=ff:02:00:00:00:00:00:00:00:00:00:00:00:00:00:fb + offset=46 + } + #Filter_2 will match UDP packet + Filter_2={ + type=0x42 + pattern=17 + offset=28 + numbyte=1 + } + #Filter_3 will match UDP port 5353 + Filter_3={ + type=0x42 + pattern=5353 + offset=64 + numbyte=2 + } + } +} + + +#--------------------------examples for MEF filters-------------------------------- +# example: filters to match ARP packet with protocol addr 192.168.0.104 +# mef_entry_0={ +# mode=1 # HostSleep mode +# action=3 # Allow and Wake host +# filter_num=3 # Number of filter +# RPN=Filter_0 && Filter_1 && Filter_2 +# #Filter_0 looking for rx pkt with DA is broadcast address +# Filter_0={ +# type=0x41 +# repeat=6 +# byte=ff +# offset=0 +# } +# #Filter_1 looking for rx pkt with EtherType is 0x0806(ARP) +# Filter_1={ +# type=0x41 +# repeat=1 +# byte=08:06 +# offset=20 +# } +# #Filter_2 looking for rx pkt with ARP target protocol addr 192.168.0.104 +# Filter_2={ +# type=0x41 +# repeat=1 +# byte=c0:a8:00:68 +# offset=46 +# } +# } +#------------------------------------------------------------------------------------- +# example: filter to check if the destination MAC address is unicast pkt +# mef_entry_0={ +# mode=1 # HostSleep mode +# action=3 # Allow and Wake host +# filter_num=3 # Number of filter +# RPN=Filter_0 +# #Filter_0 is Bit comparison filter, it always with type=0x43 +# #Byte filter always has type, byte, mask, offset 4 filed +# #"byte" is the byte sequence constant with each byte in hex format, with ':' as delimiter between two byte +# #"mask" is also with each byte in hex format, with ':' as delimiter between two byte +# #"byte" should has the same length as "mask" +# #Filter_0 will check if the destination MAC address is unicast pkt +# Filter_0={ +# type=0x43 #Bit comparison filter +# byte=00 #00 is the 1-byte sequence constant +# offset=0 #0 is the byte offset of the rx pkt +# mask=01 #1 is the 1-byte mask +# } +# } +#-------------------------------------------------------------------------------------------------- +# example: Disable MEF filters +# mefcfg={ +# #Criteria: bit0-broadcast, bit1-unicast, bit3-multicast +# Criteria=2 # Unicast frames are received during hostsleepmode +# NumEntries=0 # Number of activated MEF entries +# } +#-------------------------------------------------------------------------------------------------- +# example: Test MEF filters +# mefcfg={ +# Criteria=1 +# NumEntries=1 +# mef_entry_0={ +# mode=4 # Test Mode +# action=16 # Invoke Test +# filter_num=0 +# } +# } +#----------------------------------------------------------------------------------------------------- +# example: Test MEF filters +# mefcfg={ +# Criteria=1 +# NumEntries=1 +# mef_entry_0={ +# mode=4 +# action=0 +# filter_num=1 +# RPN=Filter_0 +# Filter_0={ +# type=0x44 # test filter +# repeat=2 # 2 copies of 'BE:EF' +# byte=BE:EF # 'BE:EF' is the byte sequence constant +# offset=18 # 18 is the byte offset of the equal length field of rx'd pkt. +# dest=00:50:43:20:5a:82 # '00:50:43:20:5a:82' is the byte sequence constant +# } +# } +# } +#---------------------------------------------------------------------------------------------------- +#example: Filter broadcast/ipv4 multicast/ipv6 multicast packets in non hostsleep mode +#mefcfg={ +# Criteria=9 # broadcast and multicast frames +# NumEntries=1 # Number of activated MEF entries +# mef_entry_0={ +# mode=2 # non HostSleep mode +# action=0 # discard and not wake host +# filter_num=3 # Number of filter +# RPN=Filter_0 || Filter_1 || Filter_2 +# Filter_0={ # IPV4 multicast +# type=0x41 # byte comparison filter +# byte=01:00:5e # 01:00:5e is the byte constant to be compared +# offset=0 # 0 is the byte offset of the equal length field of rx'd pkt. +# repeat=1 # +# } +# Filter_1={ # broadcast packet check +# type=0x41 # Byte comparison filter +# repeat=6 # 6 copies of 'ff', means broadcast +# byte=ff # 'ff'(0xff) is the byte sequence constant with each byte +# # in hex format, with ':' as delimiter between two byte. +# offset=0 # 0 is the byte offset of the equal length field of rx'd pkt. +# } +# Filter_2={ # IPV6 multicast +# type=0x41 # byte comparison filter +# byte=33:33 # 33:33 is the byte constant to be compared +# offset=0 # 0 is the byte offset of the equal length field of rx'd pkt. +# repeat=1 # +# } +# } +#} +#------------------------------------------------------------------------------------------------------ diff --git a/mxm_wifiex/wlan_src/mapp/mlanconfig/config/mef_ws_discovery.conf b/mxm_wifiex/wlan_src/mapp/mlanconfig/config/mef_ws_discovery.conf new file mode 100644 index 0000000..518a240 --- /dev/null +++ b/mxm_wifiex/wlan_src/mapp/mlanconfig/config/mef_ws_discovery.conf @@ -0,0 +1,204 @@ +# File : mef_ws_discovery.conf + +######################### MEF Configuration command ################## +mefcfg={ + #Criteria: bit0-broadcast, bit1-unicast, bit3-multicast + Criteria=8 # Multicast frames are received during hostsleepmode + NumEntries=2 # Number of activated MEF entries + #mef_entry_0: example filters to match WS-Discovery pkt for IPv4. + mef_entry_0={ + #mode: bit0--hostsleep mode, bit1--non hostsleep mode + mode=1 # HostSleep mode + #action: 0--discard and not wake host, 1--discard and wake host 3--allow and wake host + action=3 # Allow and Wake host + filter_num=4 # Number of filter + #RPN only support "&&" and "||" operator,space can not be removed between operator. + RPN=Filter_0 && Filter_1 && Filter_2 && Filter_3 + #Filter_0 will match IPv4 protocol packet + Filter_0={ + type=0x41 + repeat=1 + byte=08:00 + offset=20 + } + #Filter_1 will match dest multicast IPv4 address 239.255.255.250 + Filter_1={ + type=0x41 + repeat=1 + byte=ef:ff:ff:fa + offset=38 + } + #Filter_2 will match UDP packet + Filter_2={ + type=0x42 + pattern=17 + offset=31 + numbyte=1 + } + #Filter_3 will match UDP port 3702 + Filter_3={ + type=0x42 + pattern=3702 + offset=44 + numbyte=2 + } + } + #mef_entry_1: example filters to match WS-Discovery pkt for IPv6. + mef_entry_1={ + #mode: bit0--hostsleep mode, bit1--non hostsleep mode + mode=1 # HostSleep mode + #action: 0--discard and not wake host, 1--discard and wake host 3--allow and wake host + action=3 # Allow and Wake host + filter_num=4 # Number of filter + #RPN only support "&&" and "||" operator,space can not be removed between operator. + RPN=Filter_0 && Filter_1 && Filter_2 && Filter_3 + #Filter_0 will match IPv4 protocol packet + Filter_0={ + type=0x41 + repeat=1 + byte=86:dd + offset=20 + } + #Filter_1 will match dest multicast IPv6 address FF02::C + Filter_1={ + type=0x41 + repeat=1 + byte=ff:02:00:00:00:00:00:00:00:00:00:00:00:00:00:0c + offset=46 + } + #Filter_2 will match UDP packet + Filter_2={ + type=0x42 + pattern=17 + offset=28 + numbyte=1 + } + #Filter_3 will match UDP port 3702 + Filter_3={ + type=0x42 + pattern=3702 + offset=64 + numbyte=2 + } + } +} + + +#--------------------------examples for MEF filters-------------------------------- +# example: filters to match ARP packet with protocol addr 192.168.0.104 +# mef_entry_0={ +# mode=1 # HostSleep mode +# action=3 # Allow and Wake host +# filter_num=3 # Number of filter +# RPN=Filter_0 && Filter_1 && Filter_2 +# #Filter_0 looking for rx pkt with DA is broadcast address +# Filter_0={ +# type=0x41 +# repeat=6 +# byte=ff +# offset=0 +# } +# #Filter_1 looking for rx pkt with EtherType is 0x0806(ARP) +# Filter_1={ +# type=0x41 +# repeat=1 +# byte=08:06 +# offset=20 +# } +# #Filter_2 looking for rx pkt with ARP target protocol addr 192.168.0.104 +# Filter_2={ +# type=0x41 +# repeat=1 +# byte=c0:a8:00:68 +# offset=46 +# } +# } +#------------------------------------------------------------------------------------- +# example: filter to check if the destination MAC address is unicast pkt +# mef_entry_0={ +# mode=1 # HostSleep mode +# action=3 # Allow and Wake host +# filter_num=3 # Number of filter +# RPN=Filter_0 +# #Filter_0 is Bit comparison filter, it always with type=0x43 +# #Byte filter always has type, byte, mask, offset 4 filed +# #"byte" is the byte sequence constant with each byte in hex format, with ':' as delimiter between two byte +# #"mask" is also with each byte in hex format, with ':' as delimiter between two byte +# #"byte" should has the same length as "mask" +# #Filter_0 will check if the destination MAC address is unicast pkt +# Filter_0={ +# type=0x43 #Bit comparison filter +# byte=00 #00 is the 1-byte sequence constant +# offset=0 #0 is the byte offset of the rx pkt +# mask=01 #1 is the 1-byte mask +# } +# } +#-------------------------------------------------------------------------------------------------- +# example: Disable MEF filters +# mefcfg={ +# #Criteria: bit0-broadcast, bit1-unicast, bit3-multicast +# Criteria=2 # Unicast frames are received during hostsleepmode +# NumEntries=0 # Number of activated MEF entries +# } +#-------------------------------------------------------------------------------------------------- +# example: Test MEF filters +# mefcfg={ +# Criteria=1 +# NumEntries=1 +# mef_entry_0={ +# mode=4 # Test Mode +# action=16 # Invoke Test +# filter_num=0 +# } +# } +#----------------------------------------------------------------------------------------------------- +# example: Test MEF filters +# mefcfg={ +# Criteria=1 +# NumEntries=1 +# mef_entry_0={ +# mode=4 +# action=0 +# filter_num=1 +# RPN=Filter_0 +# Filter_0={ +# type=0x44 # test filter +# repeat=2 # 2 copies of 'BE:EF' +# byte=BE:EF # 'BE:EF' is the byte sequence constant +# offset=18 # 18 is the byte offset of the equal length field of rx'd pkt. +# dest=00:50:43:20:5a:82 # '00:50:43:20:5a:82' is the byte sequence constant +# } +# } +# } +#---------------------------------------------------------------------------------------------------- +#example: Filter broadcast/ipv4 multicast/ipv6 multicast packets in non hostsleep mode +#mefcfg={ +# Criteria=9 # broadcast and multicast frames +# NumEntries=1 # Number of activated MEF entries +# mef_entry_0={ +# mode=2 # non HostSleep mode +# action=0 # discard and not wake host +# filter_num=3 # Number of filter +# RPN=Filter_0 || Filter_1 || Filter_2 +# Filter_0={ # IPV4 multicast +# type=0x41 # byte comparison filter +# byte=01:00:5e # 01:00:5e is the byte constant to be compared +# offset=0 # 0 is the byte offset of the equal length field of rx'd pkt. +# repeat=1 # +# } +# Filter_1={ # broadcast packet check +# type=0x41 # Byte comparison filter +# repeat=6 # 6 copies of 'ff', means broadcast +# byte=ff # 'ff'(0xff) is the byte sequence constant with each byte +# # in hex format, with ':' as delimiter between two byte. +# offset=0 # 0 is the byte offset of the equal length field of rx'd pkt. +# } +# Filter_2={ # IPV6 multicast +# type=0x41 # byte comparison filter +# byte=33:33 # 33:33 is the byte constant to be compared +# offset=0 # 0 is the byte offset of the equal length field of rx'd pkt. +# repeat=1 # +# } +# } +#} +#------------------------------------------------------------------------------------------------------ diff --git a/mxm_wifiex/wlan_src/mapp/mlanconfig/config/mem.conf b/mxm_wifiex/wlan_src/mapp/mlanconfig/config/mem.conf new file mode 100644 index 0000000..cf649c9 --- /dev/null +++ b/mxm_wifiex/wlan_src/mapp/mlanconfig/config/mem.conf @@ -0,0 +1,17 @@ +#File : memory/register update +# memory/register update file +mem_set={ + CmdCode=0x0086 #do NOT change this line + Action:2=1 # 1 - SET + Rsrvd:2=0 + Addr:4=0x8000a584 # memory/register address + Value:4=0x16161669 #Value +} + +mem_get={ + CmdCode=0x0086 #do NOT change this line + Action:2=0 # 1 - SET + Rsrvd:2=0 + Addr:4=0x8000a584 # memory/register address + Result:4=0 +} diff --git a/mxm_wifiex/wlan_src/mapp/mlanconfig/config/mgmt_frame.conf b/mxm_wifiex/wlan_src/mapp/mlanconfig/config/mgmt_frame.conf new file mode 100644 index 0000000..22b19b1 --- /dev/null +++ b/mxm_wifiex/wlan_src/mapp/mlanconfig/config/mgmt_frame.conf @@ -0,0 +1,30 @@ +# Format of the packet data to be sent. +# Update the TxControl value for TxPD, else zero is sent. +# all packet data is written under "Data" block + +PktType=0x00 # should be zero for MGMT frames +PktSubType=0x05 + # Assoc Request 0 + # Assoc Response 1 + # Re-Assoc Request 2 + # Re-Assoc Response 3 + # Probe Request 4 + # Probe Response 5 + # Beacon 8 + # Atim 9 + # Dis-assoc 10 + # Auth 11 + # Deauth 12 + # Action Frame 13 + +FromDS=0 +ToDS=0 + +Addr1=00:50:43:27:B0:41 # Destination address +Addr2=00:50:43:21:0F:84 # Source address +Addr3=00:50:43:21:0F:84 # BSSID + +Data=0x01,0x01,0x00,0x0c,0x00,0x58,0x02,0x40 + +SeqNum=0 +FragNum=0 diff --git a/mxm_wifiex/wlan_src/mapp/mlanconfig/config/mgmtfilter.conf b/mxm_wifiex/wlan_src/mapp/mlanconfig/config/mgmtfilter.conf new file mode 100644 index 0000000..8ee0298 --- /dev/null +++ b/mxm_wifiex/wlan_src/mapp/mlanconfig/config/mgmtfilter.conf @@ -0,0 +1,15 @@ +##############management frame filter to wake up host ########### +##### support two entries currently ###### +mgmtfilter={ + entry_num=1 + entry_0={ + action=1 # discard and wakeup host + type=0x1 # p2p frames + frame_mask=0x7 # Go neg req & rsp & cfm frame + } +# entry_1={ +# action=0 # discard and not wakeup host +# type=0xff # management frames +# frame_mask=0x3 # assoc req & rsp frame +# } +} diff --git a/mxm_wifiex/wlan_src/mapp/mlanconfig/config/or_data.conf b/mxm_wifiex/wlan_src/mapp/mlanconfig/config/or_data.conf new file mode 100644 index 0000000..99154f5 --- /dev/null +++ b/mxm_wifiex/wlan_src/mapp/mlanconfig/config/or_data.conf @@ -0,0 +1,7 @@ + 07 01 03 3A 80 00 3A 00 ff ff 00 17 03 00 07 03 + 09 00 0e 10 16 02 19 25 1a 04 1c ff 32 5e 33 15 + 35 29 36 17 4b 74 4c 64 4d 3b 50 27 61 d6 62 98 + 6b ae 6f 5b 77 f2 79 ff 7f 2d + 07 01 12 16 c0 00 ff ff ff ff 00 05 03 10 32 5c + 33 1a 6b a2 7f 20 + diff --git a/mxm_wifiex/wlan_src/mapp/mlanconfig/config/pad_cfg.conf b/mxm_wifiex/wlan_src/mapp/mlanconfig/config/pad_cfg.conf new file mode 100644 index 0000000..dc996ee --- /dev/null +++ b/mxm_wifiex/wlan_src/mapp/mlanconfig/config/pad_cfg.conf @@ -0,0 +1,29 @@ +# File : pad_cfg.conf + +## Get CFG data for PAD OR +pad_cfg_get={ + CmdCode=0x008f # do NOT change this line + Action:2=0 # 0 - GET + Type:2=5 # 5 - optimized pad reg + CfgLen:2={ + } +} + + +## Set CFG data for PAD OR +#pad_cfg_set={ +# CmdCode=0x008f # do NOT change this line +# Action:2=1 # 1 - SET +# Type:2=5 # 5 - optimized pad reg +# CfgLen:2={ # 9 entries for W8787 +# CFG1:4=0x00000000 # SDIO in sleep +# CFG2:4=0x55550004 # GPIO in sleep +# CFG3:4=0x00000001 +# CFG4:4=0x00000000 # RFCTRL in sleep +# CFG5:4=0x00000000 +# CFG6:4=0x0E001800 # GPIO/RFCTRL in power down +# CFG7:4=0x249A0000 +# CFG8:4=0x000000D2 +# CFG9:4=0x00000000 +# } +#} diff --git a/mxm_wifiex/wlan_src/mapp/mlanconfig/config/requesttpc.conf b/mxm_wifiex/wlan_src/mapp/mlanconfig/config/requesttpc.conf new file mode 100644 index 0000000..690c30d --- /dev/null +++ b/mxm_wifiex/wlan_src/mapp/mlanconfig/config/requesttpc.conf @@ -0,0 +1,15 @@ +# File : requesttpc.conf + +######################### requesttpc command configuration ################## + +requesttpc={ + CmdCode=0x0060 # do NOT change this line + #DestMac: Destination STA address + DestMac:6='0x02,0x04,0x0e,0x06,0x01,0x12' + #RateIndex: IEEE Rate index to send request + RateIndex:1=22 + #Timeout: Response timeout in ms + Timeout:2=10 +} + +######################### End of requesttpc command configuration ################## diff --git a/mxm_wifiex/wlan_src/mapp/mlanconfig/config/robust_btc.conf b/mxm_wifiex/wlan_src/mapp/mlanconfig/config/robust_btc.conf new file mode 100644 index 0000000..8e075f8 --- /dev/null +++ b/mxm_wifiex/wlan_src/mapp/mlanconfig/config/robust_btc.conf @@ -0,0 +1,211 @@ +# File : robust_btc.conf + +######################### Robust Coex command ############### +mode_get={ + CmdCode=0x00e0 # do NOT change this line + Action:2=0 # GET + RSVD:2=0 + + # Robust Coex Mode TLV + RobustCoexTlvType:2=0x0160 + RobustCoexTlvLength:2={ + Enable:1=0x00 # Read-back Coex mode(s) + Reserved:3=0 + } +} + +mode_timeshare={ + CmdCode=0x00e0 # do NOT change this line + Action:2=1 # SET + RSVD:2=0 + + # Robust Coex Mode TLV + RobustCoexTlvType:2=0x0160 + RobustCoexTlvLength:2={ + # All the modes below are mutually exclusive of each other; + Enable:1=0x01 # Bit0: Enable 2x2 or 1x1 Time Distribute(TMD) + # Robust Coex(RBC) mode, when uAP bss start, + # uAP TMD RBC scheme is enabled, + # STA TMD RBC scheme is disabled. + Reserved:3=0 + } +} + +mode_spatial={ + CmdCode=0x00e0 # do NOT change this line + Action:2=1 # SET + RSVD:2=0 + + # Robust Coex Mode TLV + RobustCoexTlvType:2=0x0160 + RobustCoexTlvLength:2={ + # All the modes below are mutually exclusive of each other; + Enable:1=0x82 # Bit1: Enable 1x1 SMPS Spatial RBC Mode, e.g. 0x02 + # Bit7: Enable uAP+STA SMPS RBC Mode, + # when uAP bss start, uAP SMPS RBC scheme enable, + # must combined with BIT1 or BIT2, e.g. 0x82, 0x84. + Reserved:3=0 + } +} + +mode_none={ + CmdCode=0x00e0 # do NOT change this line + Action:2=1 # SET + RSVD:2=0 + + # Robust Coex Mode TLV + RobustCoexTlvType:2=0x0160 + RobustCoexTlvLength:2={ + Enable:1=0 # Concurrent Coex mode. Used for chips which has + # separate antenna for BT + Reserved:3=0 + } +} + +mode_2={ + CmdCode=0x00e0 # do NOT change this line + Action:2=1 # SET + RSVD:2=0 + + # Robust Coex Mode TLV + RobustCoexTlvType:2=0x0160 + RobustCoexTlvLength:2={ + Enable:1=0x20 # Concurrent Coex mode with Tx power control and Rx De-sense. + # Used for chips which has separate antenna for BT + Reserved:3=0 + } +} + +gpio_cfg={ + CmdCode=0x00e0 # do NOT change this line + Action:2=1 # SET + RSVD:2=0 + + # Robust Coex Mode TLV + RobustCoexTlvType:2=0x021B + RobustCoexTlvLength:2={ + Enable:1=0x1 # enable GPIO cfg for external bt request + gpionum:1=4 # gpio 4 + gpiopolarity:1=1 # Polarity High + } +} + +external_coex_config={ + CmdCode=0x00e0 + Action:2=1 //0x0 get, 0x1 set + RSVD:2=0 + RobustCoexTlvType:2=0x0238 //TLV ID + RobustCoexTlvLength:2={ + Enabled:1=0x01 // 0x00 disable, 0x01 enalbe + + ExtHighInputPriority:1=0x02 // Input priority: 0x00 Input Low Priority, 0x01 Input Medium Priority, 0x02 Input High Priority + ExtLowInputPriority:1=0x02 + + ExtPriGPIONum:1=0x06; // Input Priority signal GPIO pin number + ExtPriGPIOPolarity:1=0x01; // Polarity: 0x00 Active Low, 0x01 Active High + + ExtReqGPIONum:1=0x07; // Input Request signal GPIO pin number + ExtReqGPIOPolarity:1=0x01; // Polarity: 0x00 Active Low, 0x01 Active High + + ExtGrntGPIONum:1=0x05; // Output Grant signal GPIO pin number + ExtGrntGPIOPolarity:1=0x01; // Polarity: 0x00 Active Low, 0x01 Active High + + } +} + +#In Station generic case +#BT time is set as BTTime +#Wlan time is set as Wlan Time +generictime={ + CmdCode=0x00e0 + Action:2=1 + RSVD:2=0 + RobustCoexTlvType:2=0x0390 + RobustCoexTlvLength:2={ + Enable:2=0x01 + BtTime:2=10000 #(10ms) BTTime must be less than 65535 + WlanTime:2=40000 #(40ms) WlanTime must be less than 65535 + } +} + +#In Station A2DP case +#BT time is set as BTTime +#Wlan time is set as Wlan Time +a2dptime={ + CmdCode=0x00e0 + Action:2=1 + RSVD:2=0 + RobustCoexTlvType:2=0x0391 + RobustCoexTlvLength:2={ + Enable:2=0x01 + BtTime:2=10000 #(10ms) BTTime must be less than 65535 + WlanTime:2=39500 #(39.5ms) WlanTime must be less than 65535 + } +} + +#In Station inquiry case +#BT time is set as BTTime +#Wlan time is set as Wlan Time +inquirytime={ + CmdCode=0x00e0 + Action:2=1 + RSVD:2=0 + RobustCoexTlvType:2=0x0392 + RobustCoexTlvLength:2={ + Enable:2=0x01 + BtTime:2=21215 #(21.215ms) BTTime must be less than 65535 + WlanTime:2=11000 #(11ms) WlanTime must be less than 65535 + } +} + +#In Ap generic case +#BT time is BTTimeBusy when BT has traffic +#BT time is BTTimeIdle when BT is idle +#Wlan time is WlanTimeBusy when Wlan has traffic +#Wlan time is WlanTimeIdle when Wlan is idle +ap_generictime={ + CmdCode=0x00e0 + Action:2=1 + RSVD:2=0 + RobustCoexTlvType:2=0x0393 + RobustCoexTlvLength:2={ + Enable:2=0x01 + BtTime_MAX:2=23000 #(23ms) BTTime(BT Busy) must be less than 28767 + BtTime_MIN:2=6500 #(6.5ms) BTTime(BT Idle) must be less than 28767 + WlanTime_MAX:2=18000 #(18ms) WlanTime(Wlan Busy) must be less than 32767 + WlanTime_MIN:2=5750 #(5.75ms) WlanTime(Wlan Idle) must be less than 32767 + } +} + +#In Ap A2DP case +#BT time is change from BTTimeMax to BTTimeMin +#Wlan time is change from WlanTimeMax to WlanTimeMin +ap_a2dptime={ + CmdCode=0x00e0 + Action:2=1 + RSVD:2=0 + RobustCoexTlvType:2=0x0394 + RobustCoexTlvLength:2={ + Enable:2=0x01 + BtTimebusy:2=23000 #(23ms) Maximum BTTime must be less than 32767 + BtTimeidle:2=6500 #(6.5ms) Minimum BTTime must be less than 32767 + WlanTimebusy:2=18000 #(18ms) Maximum WlanTime must be less than 32767 + WlanTimeidle:2=5750 #(5.75ms) Minimum WlanTime must be less than 32767 + } +} + +#In Ap inquiry case +#BT time is set as BTTime +#Wlan time is set as Wlan Time +ap_inquirytime={ + CmdCode=0x00e0 + Action:2=1 + RSVD:2=0 + RobustCoexTlvType:2=0x0395 + RobustCoexTlvLength:2={ + Enable:2=0x01 + BtTime:2=28750 #(28.75ms) BTTime must less than 32767 + WlanTime:2=20000 #(20ms) WlanTime must be less than 32767 + } +} +######################### Robust Coex command ############### diff --git a/mxm_wifiex/wlan_src/mapp/mlanconfig/config/rutxpower_limit.conf b/mxm_wifiex/wlan_src/mapp/mlanconfig/config/rutxpower_limit.conf new file mode 100644 index 0000000..d366a6e --- /dev/null +++ b/mxm_wifiex/wlan_src/mapp/mlanconfig/config/rutxpower_limit.conf @@ -0,0 +1,674 @@ +# File: rutxpower_limit.conf + +## Get CFG data for RU based Tx power limit +rutxpowerlimit_cfg_get={ + CmdCode=0x026d #do not change this line + Action:2=0 #0 - GET + SubID:2=0x117 #RU POWER +} + + +## Set CFG data for RU based Tx power limit +## +## TLVStartFreq: Starting Frequency of the band for this channel +## 2407, 2414 or 2400 for 2.4 GHz +## 5000 +## 4000 +## TLVChanWidth: Channel Width +## 20 40 80 +## TLVChanNum : Channel Number +## TLVPwr[] : Power Limit in dBm (RU=26,52,106,242,484,996) +## range from -64dBm to +63dBm in steps of 1dBm +## + +rutxpowerlimit_cfg_set={ + CmdCode=0x026d #do not change this line + Action:2=1 #1 - SET + SubID:2=0x117 #RU POWER + + PwrVal.TlvType:2=0x0244 + PwrVal.TlvLength:2={ + TLVStartFreq:2=2407 + TlvChanWidth:1=20 + TlvChanNum:1=1 + TlvPwr:6='-1,2,5,8,0,0' + } + + PwrVal.TlvType:2=0x0244 + PwrVal.TlvLength:2={ + TLVStartFreq:2=2407 + TlvChanWidth:1=20 + TlvChanNum:1=2 + TlvPwr:6='-1,2,5,8,0,0' + } + + PwrVal.TlvType:2=0x0244 + PwrVal.TlvLength:2={ + TLVStartFreq:2=2407 + TlvChanWidth:1=20 + TlvChanNum:1=3 + TlvPwr:6='-1,2,5,8,0,0' + } + + PwrVal.TlvType:2=0x0244 + PwrVal.TlvLength:2={ + TLVStartFreq:2=2407 + TlvChanWidth:1=20 + TlvChanNum:1=4 + TlvPwr:6='-1,2,5,8,0,0' + } + + PwrVal.TlvType:2=0x0244 + PwrVal.TlvLength:2={ + TLVStartFreq:2=2407 + TlvChanWidth:1=20 + TlvChanNum:1=5 + TlvPwr:6='-1,2,5,8,0,0' + } + + PwrVal.TlvType:2=0x0244 + PwrVal.TlvLength:2={ + TLVStartFreq:2=2407 + TlvChanWidth:1=20 + TlvChanNum:1=6 + TlvPwr:6='-1,2,5,8,0,0' + } + + PwrVal.TlvType:2=0x0244 + PwrVal.TlvLength:2={ + TLVStartFreq:2=2407 + TlvChanWidth:1=20 + TlvChanNum:1=7 + TlvPwr:6='-1,2,5,8,0,0' + } + + PwrVal.TlvType:2=0x0244 + PwrVal.TlvLength:2={ + TLVStartFreq:2=2407 + TlvChanWidth:1=20 + TlvChanNum:1=8 + TlvPwr:6='-1,2,5,8,0,0' + } + + PwrVal.TlvType:2=0x0244 + PwrVal.TlvLength:2={ + TLVStartFreq:2=2407 + TlvChanWidth:1=20 + TlvChanNum:1=9 + TlvPwr:6='-1,2,5,8,0,0' + } + + PwrVal.TlvType:2=0x0244 + PwrVal.TlvLength:2={ + TLVStartFreq:2=2407 + TlvChanWidth:1=20 + TlvChanNum:1=10 + TlvPwr:6='-1,2,5,8,0,0' + } + + PwrVal.TlvType:2=0x0244 + PwrVal.TlvLength:2={ + TLVStartFreq:2=2407 + TlvChanWidth:1=20 + TlvChanNum:1=11 + TlvPwr:6='-1,2,5,8,0,0' + } + + PwrVal.TlvType:2=0x0244 + PwrVal.TlvLength:2={ + TLVStartFreq:2=2407 + TlvChanWidth:1=20 + TlvChanNum:1=12 + TlvPwr:6='-1,2,5,8,0,0' + } + + PwrVal.TlvType:2=0x0244 + PwrVal.TlvLength:2={ + TLVStartFreq:2=2407 + TlvChanWidth:1=20 + TlvChanNum:1=13 + TlvPwr:6='-1,2,5,8,0,0' + } +} + +rutxpowerlimit_5g_cfg_set={ + CmdCode=0x026d #do not change this line + Action:2=1 #1 - SET + SubID:2=0x117 #RU POWER + + PwrVal.TlvType:2=0x0244 + PwrVal.TlvLength:2={ + TLVStartFreq:2=5000 + TlvChanWidth:1=20 + TlvChanNum:1=36 + TlvPwr:6='-1,2,5,8,0,0' + } + + PwrVal.TlvType:2=0x0244 + PwrVal.TlvLength:2={ + TLVStartFreq:2=5000 + TlvChanWidth:1=20 + TlvChanNum:1=40 + TlvPwr:6='-1,2,5,8,0,0' + } + + PwrVal.TlvType:2=0x0244 + PwrVal.TlvLength:2={ + TLVStartFreq:2=5000 + TlvChanWidth:1=20 + TlvChanNum:1=44 + TlvPwr:6='-1,2,5,8,0,0' + } + + PwrVal.TlvType:2=0x0244 + PwrVal.TlvLength:2={ + TLVStartFreq:2=5000 + TlvChanWidth:1=20 + TlvChanNum:1=48 + TlvPwr:6='-1,2,5,8,0,0' + } + + PwrVal.TlvType:2=0x0244 + PwrVal.TlvLength:2={ + TLVStartFreq:2=5000 + TlvChanWidth:1=20 + TlvChanNum:1=52 + TlvPwr:6='-2,1,4,7,0,0' + } + + PwrVal.TlvType:2=0x0244 + PwrVal.TlvLength:2={ + TLVStartFreq:2=5000 + TlvChanWidth:1=20 + TlvChanNum:1=56 + TlvPwr:6='-2,1,4,7,0,0' + } + + PwrVal.TlvType:2=0x0244 + PwrVal.TlvLength:2={ + TLVStartFreq:2=5000 + TlvChanWidth:1=20 + TlvChanNum:1=60 + TlvPwr:6='-2,1,4,7,0,0' + } + + PwrVal.TlvType:2=0x0244 + PwrVal.TlvLength:2={ + TLVStartFreq:2=5000 + TlvChanWidth:1=20 + TlvChanNum:1=64 + TlvPwr:6='-2,1,4,7,0,0' + } + + PwrVal.TlvType:2=0x0244 + PwrVal.TlvLength:2={ + TLVStartFreq:2=5000 + TlvChanWidth:1=20 + TlvChanNum:1=100 + TlvPwr:6='-1,2,5,8,0,0' + } + + PwrVal.TlvType:2=0x0244 + PwrVal.TlvLength:2={ + TLVStartFreq:2=5000 + TlvChanWidth:1=20 + TlvChanNum:1=104 + TlvPwr:6='-1,2,5,8,0,0' + } + + PwrVal.TlvType:2=0x0244 + PwrVal.TlvLength:2={ + TLVStartFreq:2=5000 + TlvChanWidth:1=20 + TlvChanNum:1=108 + TlvPwr:6='-1,2,5,8,0,0' + } + + PwrVal.TlvType:2=0x0244 + PwrVal.TlvLength:2={ + TLVStartFreq:2=5000 + TlvChanWidth:1=20 + TlvChanNum:1=112 + TlvPwr:6='-1,2,5,8,0,0' + } + + PwrVal.TlvType:2=0x0244 + PwrVal.TlvLength:2={ + TLVStartFreq:2=5000 + TlvChanWidth:1=20 + TlvChanNum:1=116 + TlvPwr:6='-1,2,5,8,0,0' + } + + PwrVal.TlvType:2=0x0244 + PwrVal.TlvLength:2={ + TLVStartFreq:2=5000 + TlvChanWidth:1=20 + TlvChanNum:1=120 + TlvPwr:6='-1,2,5,8,0,0' + } + + PwrVal.TlvType:2=0x0244 + PwrVal.TlvLength:2={ + TLVStartFreq:2=5000 + TlvChanWidth:1=20 + TlvChanNum:1=124 + TlvPwr:6='-1,2,5,8,0,0' + } + + PwrVal.TlvType:2=0x0244 + PwrVal.TlvLength:2={ + TLVStartFreq:2=5000 + TlvChanWidth:1=20 + TlvChanNum:1=128 + TlvPwr:6='-1,2,5,8,0,0' + } + + PwrVal.TlvType:2=0x0244 + PwrVal.TlvLength:2={ + TLVStartFreq:2=5000 + TlvChanWidth:1=20 + TlvChanNum:1=132 + TlvPwr:6='-1,2,5,8,0,0' + } + + PwrVal.TlvType:2=0x0244 + PwrVal.TlvLength:2={ + TLVStartFreq:2=5000 + TlvChanWidth:1=20 + TlvChanNum:1=136 + TlvPwr:6='-1,2,5,8,0,0' + } + + PwrVal.TlvType:2=0x0244 + PwrVal.TlvLength:2={ + TLVStartFreq:2=5000 + TlvChanWidth:1=20 + TlvChanNum:1=140 + TlvPwr:6='-1,2,5,8,0,0' + } + + PwrVal.TlvType:2=0x0244 + PwrVal.TlvLength:2={ + TLVStartFreq:2=5000 + TlvChanWidth:1=20 + TlvChanNum:1=144 + TlvPwr:6='-1,2,5,8,0,0' + } + + PwrVal.TlvType:2=0x0244 + PwrVal.TlvLength:2={ + TLVStartFreq:2=5000 + TlvChanWidth:1=20 + TlvChanNum:1=149 + TlvPwr:6='-1,2,5,8,0,0' + } + + PwrVal.TlvType:2=0x0244 + PwrVal.TlvLength:2={ + TLVStartFreq:2=5000 + TlvChanWidth:1=20 + TlvChanNum:1=153 + TlvPwr:6='-1,2,5,8,0,0' + } + + PwrVal.TlvType:2=0x0244 + PwrVal.TlvLength:2={ + TLVStartFreq:2=5000 + TlvChanWidth:1=20 + TlvChanNum:1=157 + TlvPwr:6='-1,2,5,8,0,0' + } + + PwrVal.TlvType:2=0x0244 + PwrVal.TlvLength:2={ + TLVStartFreq:2=5000 + TlvChanWidth:1=20 + TlvChanNum:1=161 + TlvPwr:6='-1,2,5,8,0,0' + } + + PwrVal.TlvType:2=0x0244 + PwrVal.TlvLength:2={ + TLVStartFreq:2=5000 + TlvChanWidth:1=20 + TlvChanNum:1=165 + TlvPwr:6='-1,2,5,8,0,0' + } + + PwrVal.TlvType:2=0x0244 + PwrVal.TlvLength:2={ + TLVStartFreq:2=5000 + TlvChanWidth:1=40 + TlvChanNum:1=36 + TlvPwr:6='-4,-1,2,5,8,0' + } + + PwrVal.TlvType:2=0x0244 + PwrVal.TlvLength:2={ + TLVStartFreq:2=5000 + TlvChanWidth:1=40 + TlvChanNum:1=40 + TlvPwr:6='-4,-1,2,5,8,0' + } + + PwrVal.TlvType:2=0x0244 + PwrVal.TlvLength:2={ + TLVStartFreq:2=5000 + TlvChanWidth:1=40 + TlvChanNum:1=44 + TlvPwr:6='-4,-1,2,5,8,0' + } + + PwrVal.TlvType:2=0x0244 + PwrVal.TlvLength:2={ + TLVStartFreq:2=5000 + TlvChanWidth:1=40 + TlvChanNum:1=48 + TlvPwr:6='-4,-1,2,5,8,0' + } + + PwrVal.TlvType:2=0x0244 + PwrVal.TlvLength:2={ + TLVStartFreq:2=5000 + TlvChanWidth:1=40 + TlvChanNum:1=52 + TlvPwr:6='-5,-2,1,4,7,0' + } + + PwrVal.TlvType:2=0x0244 + PwrVal.TlvLength:2={ + TLVStartFreq:2=5000 + TlvChanWidth:1=40 + TlvChanNum:1=56 + TlvPwr:6='-5,-2,1,4,7,0' + } + + PwrVal.TlvType:2=0x0244 + PwrVal.TlvLength:2={ + TLVStartFreq:2=5000 + TlvChanWidth:1=40 + TlvChanNum:1=60 + TlvPwr:6='-5,-2,1,4,7,0' + } + + PwrVal.TlvType:2=0x0244 + PwrVal.TlvLength:2={ + TLVStartFreq:2=5000 + TlvChanWidth:1=40 + TlvChanNum:1=64 + TlvPwr:6='-5,-2,1,4,7,0' + } + + PwrVal.TlvType:2=0x0244 + PwrVal.TlvLength:2={ + TLVStartFreq:2=5000 + TlvChanWidth:1=40 + TlvChanNum:1=100 + TlvPwr:6='-4,-1,2,5,8,0' + } + + PwrVal.TlvType:2=0x0244 + PwrVal.TlvLength:2={ + TLVStartFreq:2=5000 + TlvChanWidth:1=40 + TlvChanNum:1=104 + TlvPwr:6='-4,-1,2,5,8,0' + } + + PwrVal.TlvType:2=0x0244 + PwrVal.TlvLength:2={ + TLVStartFreq:2=5000 + TlvChanWidth:1=40 + TlvChanNum:1=108 + TlvPwr:6='-4,-1,2,5,8,0' + } + + PwrVal.TlvType:2=0x0244 + PwrVal.TlvLength:2={ + TLVStartFreq:2=5000 + TlvChanWidth:1=40 + TlvChanNum:1=112 + TlvPwr:6='-4,-1,2,5,8,0' + } + + PwrVal.TlvType:2=0x0244 + PwrVal.TlvLength:2={ + TLVStartFreq:2=5000 + TlvChanWidth:1=40 + TlvChanNum:1=116 + TlvPwr:6='-4,-1,2,5,8,0' + } + + PwrVal.TlvType:2=0x0244 + PwrVal.TlvLength:2={ + TLVStartFreq:2=5000 + TlvChanWidth:1=40 + TlvChanNum:1=120 + TlvPwr:6='-4,-1,2,5,8,0' + } + + PwrVal.TlvType:2=0x0244 + PwrVal.TlvLength:2={ + TLVStartFreq:2=5000 + TlvChanWidth:1=40 + TlvChanNum:1=124 + TlvPwr:6='-4,-1,2,5,8,0' + } + + PwrVal.TlvType:2=0x0244 + PwrVal.TlvLength:2={ + TLVStartFreq:2=5000 + TlvChanWidth:1=40 + TlvChanNum:1=128 + TlvPwr:6='-4,-1,2,5,8,0' + } + + PwrVal.TlvType:2=0x0244 + PwrVal.TlvLength:2={ + TLVStartFreq:2=5000 + TlvChanWidth:1=40 + TlvChanNum:1=132 + TlvPwr:6='-4,-1,2,5,8,0' + } + + PwrVal.TlvType:2=0x0244 + PwrVal.TlvLength:2={ + TLVStartFreq:2=5000 + TlvChanWidth:1=40 + TlvChanNum:1=136 + TlvPwr:6='-4,-1,2,5,8,0' + } + + PwrVal.TlvType:2=0x0244 + PwrVal.TlvLength:2={ + TLVStartFreq:2=5000 + TlvChanWidth:1=40 + TlvChanNum:1=149 + TlvPwr:6='-4,-1,2,5,8,0' + } + + PwrVal.TlvType:2=0x0244 + PwrVal.TlvLength:2={ + TLVStartFreq:2=5000 + TlvChanWidth:1=40 + TlvChanNum:1=153 + TlvPwr:6='-4,-1,2,5,8,0' + } + + PwrVal.TlvType:2=0x0244 + PwrVal.TlvLength:2={ + TLVStartFreq:2=5000 + TlvChanWidth:1=40 + TlvChanNum:1=157 + TlvPwr:6='-4,-1,2,5,8,0' + } + + PwrVal.TlvType:2=0x0244 + PwrVal.TlvLength:2={ + TLVStartFreq:2=5000 + TlvChanWidth:1=40 + TlvChanNum:1=161 + TlvPwr:6='-4,-1,2,5,8,0' + } + + PwrVal.TlvType:2=0x0244 + PwrVal.TlvLength:2={ + TLVStartFreq:2=5000 + TlvChanWidth:1=80 + TlvChanNum:1=36 + TlvPwr:6='-7,-4,-1,2,5,8' + } + + PwrVal.TlvType:2=0x0244 + PwrVal.TlvLength:2={ + TLVStartFreq:2=5000 + TlvChanWidth:1=80 + TlvChanNum:1=40 + TlvPwr:6='-7,-4,-1,2,5,8' + } + + PwrVal.TlvType:2=0x0244 + PwrVal.TlvLength:2={ + TLVStartFreq:2=5000 + TlvChanWidth:1=80 + TlvChanNum:1=44 + TlvPwr:6='-7,-4,-1,2,5,8' + } + + PwrVal.TlvType:2=0x0244 + PwrVal.TlvLength:2={ + TLVStartFreq:2=5000 + TlvChanWidth:1=80 + TlvChanNum:1=48 + TlvPwr:6='-7,-4,-1,2,5,8' + } + + PwrVal.TlvType:2=0x0244 + PwrVal.TlvLength:2={ + TLVStartFreq:2=5000 + TlvChanWidth:1=80 + TlvChanNum:1=52 + TlvPwr:6='-8,-5,-2,1,4,7' + } + + PwrVal.TlvType:2=0x0244 + PwrVal.TlvLength:2={ + TLVStartFreq:2=5000 + TlvChanWidth:1=80 + TlvChanNum:1=56 + TlvPwr:6='-8,-5,-2,1,4,7' + } + + PwrVal.TlvType:2=0x0244 + PwrVal.TlvLength:2={ + TLVStartFreq:2=5000 + TlvChanWidth:1=80 + TlvChanNum:1=60 + TlvPwr:6='-8,-5,-2,1,4,7' + } + + PwrVal.TlvType:2=0x0244 + PwrVal.TlvLength:2={ + TLVStartFreq:2=5000 + TlvChanWidth:1=80 + TlvChanNum:1=64 + TlvPwr:6='-8,-5,-2,1,4,7' + } + + PwrVal.TlvType:2=0x0244 + PwrVal.TlvLength:2={ + TLVStartFreq:2=5000 + TlvChanWidth:1=80 + TlvChanNum:1=100 + TlvPwr:6='-7,-4,-1,2,5,8' + } + + PwrVal.TlvType:2=0x0244 + PwrVal.TlvLength:2={ + TLVStartFreq:2=5000 + TlvChanWidth:1=80 + TlvChanNum:1=104 + TlvPwr:6='-7,-4,-1,2,5,8' + } + + PwrVal.TlvType:2=0x0244 + PwrVal.TlvLength:2={ + TLVStartFreq:2=5000 + TlvChanWidth:1=80 + TlvChanNum:1=108 + TlvPwr:6='-7,-4,-1,2,5,8' + } + + PwrVal.TlvType:2=0x0244 + PwrVal.TlvLength:2={ + TLVStartFreq:2=5000 + TlvChanWidth:1=80 + TlvChanNum:1=112 + TlvPwr:6='-7,-4,-1,2,5,8' + } + + PwrVal.TlvType:2=0x0244 + PwrVal.TlvLength:2={ + TLVStartFreq:2=5000 + TlvChanWidth:1=80 + TlvChanNum:1=116 + TlvPwr:6='-7,-4,-1,2,5,8' + } + + PwrVal.TlvType:2=0x0244 + PwrVal.TlvLength:2={ + TLVStartFreq:2=5000 + TlvChanWidth:1=80 + TlvChanNum:1=120 + TlvPwr:6='-7,-4,-1,2,5,8' + } + + PwrVal.TlvType:2=0x0244 + PwrVal.TlvLength:2={ + TLVStartFreq:2=5000 + TlvChanWidth:1=80 + TlvChanNum:1=124 + TlvPwr:6='-7,-4,-1,2,5,8' + } + + PwrVal.TlvType:2=0x0244 + PwrVal.TlvLength:2={ + TLVStartFreq:2=5000 + TlvChanWidth:1=80 + TlvChanNum:1=128 + TlvPwr:6='-7,-4,-1,2,5,8' + } + + PwrVal.TlvType:2=0x0244 + PwrVal.TlvLength:2={ + TLVStartFreq:2=5000 + TlvChanWidth:1=80 + TlvChanNum:1=149 + TlvPwr:6='-7,-4,-1,2,5,8' + } + + PwrVal.TlvType:2=0x0244 + PwrVal.TlvLength:2={ + TLVStartFreq:2=5000 + TlvChanWidth:1=80 + TlvChanNum:1=153 + TlvPwr:6='-7,-4,-1,2,5,8' + } + + PwrVal.TlvType:2=0x0244 + PwrVal.TlvLength:2={ + TLVStartFreq:2=5000 + TlvChanWidth:1=80 + TlvChanNum:1=157 + TlvPwr:6='-7,-4,-1,2,5,8' + } + + PwrVal.TlvType:2=0x0244 + PwrVal.TlvLength:2={ + TLVStartFreq:2=5000 + TlvChanWidth:1=80 + TlvChanNum:1=161 + TlvPwr:6='-7,-4,-1,2,5,8' + } +} diff --git a/mxm_wifiex/wlan_src/mapp/mlanconfig/config/sdio_pulldown.conf b/mxm_wifiex/wlan_src/mapp/mlanconfig/config/sdio_pulldown.conf new file mode 100644 index 0000000..745978b --- /dev/null +++ b/mxm_wifiex/wlan_src/mapp/mlanconfig/config/sdio_pulldown.conf @@ -0,0 +1,27 @@ +# File : sdio_pulldown.conf + +######################### SDIO Pulldown command ############### +sdio_pulldown_get={ + CmdCode=0x0093 # do NOT change this line + + Action:2=0 # GET + PullUpDelay:2=0 + PullDownDelay:2=0 +} + +sdio_pulldown_set={ + CmdCode=0x0093 # do NOT change this line + + Action:2=1 # SET + PullUpDelay:2=0 + PullDownDelay:2=0 +} + +sdio_pulldown_disable={ + CmdCode=0x0093 # do NOT change this line + + Action:2=1 # SET + PullUpDelay:2=0xffff + PullDownDelay:2=0xffff +} +######################### SDIO Pulldown command ############### diff --git a/mxm_wifiex/wlan_src/mapp/mlanconfig/config/small_debug.conf b/mxm_wifiex/wlan_src/mapp/mlanconfig/config/small_debug.conf new file mode 100644 index 0000000..1457426 --- /dev/null +++ b/mxm_wifiex/wlan_src/mapp/mlanconfig/config/small_debug.conf @@ -0,0 +1,62 @@ +# File : small_debug.conf + +######################### DBG Config command ############### +small_debug_enable={ + CmdCode=0x008b # do NOT change this line + + Dst:1=0x06 # dbgs_cfg_t + Air_Chan:1=0x00 + RSVD:1=0 + Num_Entries:1=0x81 # one entry global enable + + # dbgs_t + En_Mask:2=0x0000 # en_mask_id + BaseId:2=0x0000 # base_id +} + +small_debug_disable={ + CmdCode=0x008b # do NOT change this line + + Dst:1=0x00 + Air_Chan:1=0x00 + RSVD:1=0 + Num_Entries:1=0x00 +} + +######################### DBG Get Trace Memory ############### +# Disable Air and Host destinations to disable dbgs_drain +# Enable only the Power save ID - Host interface is a course enable - not on specific event +trace_enable={ + CmdCode=0x008b # do NOT change this line + + Dst:1=0x00 # dbgs_cfg_t - don't drain debug + Air_Chan:1=0x00 + RSVD:1=0 + Num_Entries:1=0x02 # 2 entry + + # dbgs_t + En_Mask:2=0x5fff # en_mask_id - enable single ID=0x80 + BaseId:2=0x0020 # base_id + En_Mask:2=0x5fff # en_mask_id - enable single ID=0x80 + BaseId:2=0x0021 # base_id +} + +get_trace={ + CmdCode=0x008c # do NOT change this line + + startAddress:4=0x02 # read trace memeory - not a generic memory read + len:2=0x0000 # First read=0 - for next reads use the returned next start +} + +trace_disable={ + CmdCode=0x008b # do NOT change this line + + Dst:1=0x00 # dbgs_cfg_t - don't drain debug + Air_Chan:1=0x00 + RSVD:1=0 + Num_Entries:1=0x01 # one entry + + # dbgs_t + En_Mask:2=0x0000 # en_mask_id + BaseId:2=0x0000 # base_id +} diff --git a/mxm_wifiex/wlan_src/mapp/mlanconfig/config/smc.conf b/mxm_wifiex/wlan_src/mapp/mlanconfig/config/smc.conf new file mode 100644 index 0000000..3c58de7 --- /dev/null +++ b/mxm_wifiex/wlan_src/mapp/mlanconfig/config/smc.conf @@ -0,0 +1,124 @@ +# File : smc.conf + +smc_get={ + CmdCode=0x012d #do not change this + + Action:2=0 # GET +} + +smc_set={ + CmdCode=0x012d #do not change this + + Action:2=1 # SET + +# SSID + SSIDHeaderType:2=0x0000 + SSIDHeaderLen:2={ + SSID:10="NXP_SMC_1" + } + +# Beacon Period. +# This should be smaller than than MinScanTime. + BeaconHeaderType:2=0x012c + BeaconHeaderLen:2={ + beaconPeriod:2=30 + } + +# Channel list. +# ChanNumber, MinScanTime and ScanTime are mandatory. +# MinScanTime is minimum dwelling time for ChanNumber channel. +# ScanTime is maximum dwelling time for ChanNumber channel. + ChannHeaderType:2=0x0101 + ChannHeaderLen:2={ + +# Following four line define one channel. +# Please add similar four lines with different channel number for new channel. + Chan1_RadioType:1=0 + Chan1_ChanNumber:1=1 + Chan1_ScanType:1=2 + Chan1_MinScanTime:2=40 + Chan1_ScanTime:2=200 + + Chan2_RadioType:1=0 + Chan2_ChanNumber:1=6 + Chan2_ScanType:1=3 + Chan2_MinScanTime:2=40 + Chan2_ScanTime:2=200 + + Chan3_RadioType:1=0 + Chan3_ChanNumber:1=9 + Chan3_ScanType:1=2 + Chan3_MinScanTime:2=40 + Chan3_ScanTime:2=100 + + Chan2_RadioType:1=0 + Chan2_ChanNumber:1=11 + Chan2_ScanType:1=3 + Chan2_MinScanTime:2=40 + Chan2_ScanTime:2=200 + } + +#Custom IE +#Currently max size of custom IE supported is 50 bytes. +# +# CustomHeaderType:2=0x010a +# CustomHeaderLen:2={ +# start:1=0xdd +# start:1=0x10 +# start:1=0x00 +# start:1=0x01 +# start:1=0x02 +# start:1=0x03 +# start:1=0x04 +# start:1=0x05 +# start:1=0x06 +# start:1=0x07 +# start:1=0x08 +# start:1=0x09 +# start:1=0x0a +# start:1=0x0b +# start:1=0x0c +# start:1=0x0d +# start:1=0x0e +# start:1=0x0f +# } + +#Multicast mac filtering address +#All the multicast packets from starting mac address to ending mac address would +#be captured and sent to the host. + MACHeaderType:2=0x01cc + MACHeaderLen:2={ +#Staring Multicast mac address + start:1=0x01 + start:1=0x00 + start:1=0x5e + start:1=0x00 + start:1=0x00 + start:1=0x01 + +#Ending Multicast mac address + end:1=0x01 + end:1=0x00 + end:1=0x5e + end:1=0x7f + end:1=0xff + end:1=0xff + +#FilterType +# 1 for RX AP frames +# 2 for RX STA frames +# 3 for both + Filter:2=0x3 + } + +} +smc_start={ + CmdCode=0x012d #do not change this + + Action:2=2 # START +} +smc_stop={ + CmdCode=0x012d #do not change this + + Action:2=3 # STOP +} diff --git a/mxm_wifiex/wlan_src/mapp/mlanconfig/config/ssu.conf b/mxm_wifiex/wlan_src/mapp/mlanconfig/config/ssu.conf new file mode 100644 index 0000000..6b6de37 --- /dev/null +++ b/mxm_wifiex/wlan_src/mapp/mlanconfig/config/ssu.conf @@ -0,0 +1,13 @@ +# File ssu.conf +ssu_params_cfg={ + nskip=3 #0-3; # of FFT samples to skip + nsel=2 #0-3: # of FFT samples selected to dump + adcdownsample=1 #0-3: Down sample ADC input for buffering + mask_adc_pkt=1 #0-1: Mask out ADC Data from spectral packet + out_16bits=1 #0-1: Enable 16-Bit FFT output data precision in spectral packet + spec_pwr_enable=1 #0-1: Enable power spectrum in dB for spectral packet + rate_reduction=1 #0-1: Enable spectral packet rae reduction in DB output format + n_pkt_avg=6 #0-7: Number of spectral packets over which spectral data is to be averaged. +} + + diff --git a/mxm_wifiex/wlan_src/mapp/mlanconfig/config/subevent.conf b/mxm_wifiex/wlan_src/mapp/mlanconfig/config/subevent.conf new file mode 100644 index 0000000..ac7f333 --- /dev/null +++ b/mxm_wifiex/wlan_src/mapp/mlanconfig/config/subevent.conf @@ -0,0 +1,103 @@ +# File : subevent.conf + +######################### Subscribe Events command ################## +subevent_get={ + CmdCode=0x0075 # do NOT change this line + + Action:2=0 # GET + Events:2=0 +} + +subevent_set={ + CmdCode=0x0075 # do NOT change this line + + Action:2=1 # SET + Events:2=0xbc8 # bit0 - Beacon RSSI_LOW + # bit1 - Beacon SNR_LOW + # bit2 - FAILED_COUNT + # bit3 - Beacon Missed + # bit4 - Beacon RSSI_HIGH + # bit5 - Beacon SNR_HIGH + # bit6 - Data RSSI_LOW + # bit7 - Data SNR_LOW + # bit8 - Data RSSI_HIGH + # bit9 - Data SNR_HIGH + # bit10 - LINK_QUALITY + # bit11 - PRE_BCN_LOST + # bit12-15 - Reserved + + LowRssiTlvType:2=0x0104 + LowRssiTlvLength:2={ + Threshold:1=70 + ReportingFreq:1=0 + } + + LowSnrTlvType:2=0x0105 + LowSnrTlvLength:2={ + Threshold:1=56 + ReportingFreq:1=0 + } + + FailedCountTlvType:2=0x0106 + FailedCountTlvLength:2={ + Threshold:1=5 + ReportingFreq:1=0 + } + + BeaconMissTlvType:2=0x0107 + BeaconMissTlvLength:2={ + BeaconMissed:1=60 + Reserved:1=0 + } + + HighRssiTlvType:2=0x0116 + HighRssiTlvLength:2={ + Threshold:1=40 + ReportingFreq:1=0 + } + + HighSnrTlvType:2=0x0117 + HighSnrTlvLength:2={ + Threshold:1=86 + ReportingFreq:1=0 + } + + DataLowRssiTlvType:2=0x0126 + DataLowRssiTlvLength:2={ + Threshold:1=10 + ReportingFreq:1=0 + } + + DataLowSnrTlvType:2=0x0127 + DataLowSnrTlvLength:2={ + Threshold:1=66 + ReportingFreq:1=0 + } + + DataHighRssiTlvType:2=0x0128 + DataHighRssiTlvLength:2={ + Threshold:1=50 + ReportingFreq:1=0 + } + + DataHighSnrTlvType:2=0x0129 + DataHighSnrTlvLength:2={ + Threshold:1=96 + ReportingFreq:1=1 + } + LinkQualityTlvType:2=0x0124 + LinkQualityTlvType:2={ + LinkSNRThreshold:2=0x0056 + LinkSNRFrequency:2=0x0003 + MinRateVal:2=0x0014 + MinRateFreq:2=0x0003 + TxLatencyVal:4=0x00C8 + TxLatencyThreshold:4=0x0003 + } + PreBcnLostTlvType:2=0x0149 + PreBcnLostTlvLength:2={ + PreBeaconCnt:1=30 + Reserved:1=0 + } +} +######################### Subscribe Events command ################## diff --git a/mxm_wifiex/wlan_src/mapp/mlanconfig/config/tspecs.conf b/mxm_wifiex/wlan_src/mapp/mlanconfig/config/tspecs.conf new file mode 100644 index 0000000..86c1ac6 --- /dev/null +++ b/mxm_wifiex/wlan_src/mapp/mlanconfig/config/tspecs.conf @@ -0,0 +1,100 @@ +# TSPEC contents for TID=0, UserPriority = 6 +[tspec0] +# Element ID +dd +# Length +3d +# OUI +00 50 f2 +# OUI Type +02 +# OUI SubType +02 +# Version +01 +# TSInfo +e0 34 00 +# Nominal MSDU Size +d0 80 +# Maximum MSDU Size +d0 00 +# Min Service Interval +20 4e 00 00 +# Max Service Interval +20 4e 00 00 +# Inactivity Interval +80 96 98 00 +# Suspension Interval +ff ff ff ff +# Service Start Time +00 00 00 00 +# Minimum Data Rate +00 45 01 00 +# Mean Data Rate +00 45 01 00 +# Peak Data Rate +00 45 01 00 +# Max Burst Size +00 00 00 00 +# Delay Bound +00 00 00 00 +# Min PHY Rate +00 1b b7 00 +# Surplus Bandwidth Allowance +00 30 +# Medium Time +00 00 +# Extra Data Bytes +[/tspec0] + + +# TSPEC contents for TID=1, UserPriority = 4 +[tspec1] +# Element ID +dd +# Length +3d +# OUI +00 50 f2 +# OUI Type +02 +# OUI SubType +02 +# Version +01 +# TSInfo +e3 20 00 +# Nominal MSDU Size +96 00 +# Maximum MSDU Size +dc 05 +# Min Service Interval +00 00 00 00 +# Max Service Interval +00 00 00 00 +# Inactivity Interval +00 00 00 00 +# Suspension Interval +ff ff ff ff +# Service Start Time +00 00 00 00 +# Minimum Data Rate +a0 00 00 00 +# Mean Data Rate +a0 00 00 00 +# Peak Data Rate +a0 00 00 00 +# Max Burst Size +00 00 00 00 +# Delay Bound +00 00 00 00 +# Min PHY Rate +80 8d 5b 00 +# Surplus Bandwidth Allowance +00 30 +# Medium Time +00 00 +# Extra Data Bytes +dd 04 00 50 43 ff +[/tspec1] + diff --git a/mxm_wifiex/wlan_src/mapp/mlanconfig/config/turbo_mode.conf b/mxm_wifiex/wlan_src/mapp/mlanconfig/config/turbo_mode.conf new file mode 100644 index 0000000..a258673 --- /dev/null +++ b/mxm_wifiex/wlan_src/mapp/mlanconfig/config/turbo_mode.conf @@ -0,0 +1,12 @@ +#File : turbo_mode.conf +## WMM turbo mode config command +turbo_mode_set={ + CmdCode=0x0016 # do NOT change this line + Action:2=1 # 1 - SET + OID:2=0x27 # OID_WMM_TURBO_MODE + Size:2=1 + Value:1=3 # 1 -- Enable turbo_mode_1; + # 2 -- Enable turbo_mode_2; + # 3 -- Enable turbo_mode_3; + # otherwise, disable turbo_mode +} diff --git a/mxm_wifiex/wlan_src/mapp/mlanconfig/config/tx_ctrl.conf b/mxm_wifiex/wlan_src/mapp/mlanconfig/config/tx_ctrl.conf new file mode 100644 index 0000000..013065b --- /dev/null +++ b/mxm_wifiex/wlan_src/mapp/mlanconfig/config/tx_ctrl.conf @@ -0,0 +1,58 @@ +#protocol +Protocol=0x88dc + +# configure data rate in unit of 0.5Mbps +# 0 - auto rate determined by firmware +# Any other data rate except these data rates will +# be overwritten by default data rate. +# datarate index, unit in 0.5Mbps +# Index | 20MHz | 10MHz +# 12 | 6Mbps | 3Mbps +# 18 | 9Mbps | 4.5Mbps +# 24 | 12Mbps | 6Mbps +# 36 | 18Mbps | 9Mbps +# 48 | 24Mbps | 12Mbps +# 72 | 36Mbps | 18Mbps +# 96 | 48Mbps | 24Mbps +# 108 | 54Mbps | 27.5Mbps +Datarate=12 + +# configure Channel for the packet +# 0 - the channel set during the enable would be used +Channel=0 + +# configure Bandwith (only for 11p) +# 0: auto bandwith setting by firmware +# bit4: 1 use bit[3:0] bandwith setting +# bit[3:0]: +# 0 - 5MHz +# 1 - 10MHz +# 2 - 20MHz +# 3 - 40MHz +# 4 - 80MHz +Bandwidth=0x00 + +# configure power settings +# bit[7] host tx power control flag +# 0x0: use fw setting for tx power +# 0x1: value specified in bit[6] and bit[5:0] are valid +# bit[6] sign of the power specified in bit[5:0] +# 0x0: power specified in bit[5:0] is postive (+) +# 0x1: power specified in bit[5:0] is negative (-) +# bit[5:0] power to be used for transmission (in dBm) +Power=0x00 + +# configure Priority of the packet +# 1,2 - BK +# 0,3 - BE +# 4,5 - VI +# 6,7 - VO +Priority=0 + +# configure tx retry time +Retry_limit=0 + +# Destination MAC Address +Addr=00:50:43:22:0f:b0 + +Data=0x1,0x2,0x3,0x4,0x5,0x6,0x7,0x8,0x8,0x9,0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1,0x2,0x3,0x4,0x5,0x6,0x7,0x8,0x8,0x9,0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1,0x2,0x3,0x4,0x5,0x6,0x7,0x8,0x8,0x9,0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19 diff --git a/mxm_wifiex/wlan_src/mapp/mlanconfig/config/txpwrlimit_cfg.conf b/mxm_wifiex/wlan_src/mapp/mlanconfig/config/txpwrlimit_cfg.conf new file mode 100644 index 0000000..c3e788d --- /dev/null +++ b/mxm_wifiex/wlan_src/mapp/mlanconfig/config/txpwrlimit_cfg.conf @@ -0,0 +1,617 @@ +# File : txpwrlimit_cfg.conf +## Get CFG data for Tx power limitation +txpwrlimit_2g_cfg_get={ + CmdCode=0x00fb # do NOT change this line + Action:2=0 # 0 - GET + SubBand:2=0x00 # 0x00 2G subband (2.4G: channel 1-14) + # 0x10 5G subband0 (5G: channel 36,40,44,48, + # 52,56,60,64) + # 0x11 5G subband1 (5G: channel 100,104,108,112, + # 116,120,124,128, + # 132,136,140,144) + # 0x12 5G subband2 (5G: channel 149,153,157,161,165,172) + # 0x13 5G subband3 (5G: channel 183,184,185,187,188, + # 189, 192,196; + # 5G: channel 7,8,11,12,16,34) +} + + +txpwrlimit_5g_cfg_get_sub0={ + CmdCode=0x00fb # do NOT change this line + Action:2=0 # 0 - GET + SubBand:2=0x10 # 0x00 2G subband (2.4G: channel 1-14) + # 0x10 5G subband0 (5G: channel 36,40,44,48, + # 52,56,60,64) + # 0x11 5G subband1 (5G: channel 100,104,108,112, + # 116,120,124,128, + # 132,136,140,144) + # 0x12 5G subband2 (5G: channel 149,153,157,161,165,172) + # 0x13 5G subband3 (5G: channel 183,184,185,187,188, + # 189, 192,196; + # 5G: channel 7,8,11,12,16,34) +} + + +txpwrlimit_5g_cfg_get_sub1={ + CmdCode=0x00fb # do NOT change this line + Action:2=0 # 0 - GET + SubBand:2=0x11 # 0x00 2G subband (2.4G: channel 1-14) + # 0x10 5G subband0 (5G: channel 36,40,44,48, + # 52,56,60,64) + # 0x11 5G subband1 (5G: channel 100,104,108,112, + # 116,120,124,128, + # 132,136,140,144) + # 0x12 5G subband2 (5G: channel 149,153,157,161,165,172) + # 0x13 5G subband3 (5G: channel 183,184,185,187,188, + # 189, 192,196; + # 5G: channel 7,8,11,12,16,34) +} + + +txpwrlimit_5g_cfg_get_sub2={ + CmdCode=0x00fb # do NOT change this line + Action:2=0 # 0 - GET + SubBand:2=0x12 # 0x00 2G subband (2.4G: channel 1-14) + # 0x10 5G subband0 (5G: channel 36,40,44,48, + # 52,56,60,64) + # 0x11 5G subband1 (5G: channel 100,104,108,112, + # 116,120,124,128, + # 132,136,140,144) + # 0x12 5G subband2 (5G: channel 149,153,157,161,165,172) + # 0x13 5G subband3 (5G: channel 183,184,185,187,188, + # 189, 192,196; + # 5G: channel 7,8,11,12,16,34) +} + + +txpwrlimit_5g_cfg_get_sub3={ + CmdCode=0x00fb # do NOT change this line + Action:2=0 # 0 - GET + SubBand:2=0x13 # 0x00 2G subband (2.4G: channel 1-14) + # 0x10 5G subband0 (5G: channel 36,40,44,48, + # 52,56,60,64) + # 0x11 5G subband1 (5G: channel 100,104,108,112, + # 116,120,124,128, + # 132,136,140,144) + # 0x12 5G subband2 (5G: channel 149,153,157,161,165,172) + # 0x13 5G subband3 (5G: channel 183,184,185,187,188, + # 189, 192,196; + # 5G: channel 7,8,11,12,16,34) +} + +## Set CFG data for Tx power limitation +## +## TLVStartFreq: Starting Frequency of the band for this channel +## 2407, 2414 or 2400 for 2.4 GHz +## 5000 +## 4000 +## TLVChanWidth: Channel Width +## 20 +## TLVChanNum : Channel Number +## TLVPwr[] : ModulationGroup +## 0: CCK (1,2,5.5,11 Mbps) +## 1: OFDM (6,9,12,18 Mbps) +## 2: OFDM (24,36 Mbps) +## 3: OFDM (48,54 Mbps) +## 4: HT20 (MCS0,1,2) +## 5: HT20 (MCS3,4) +## 6: HT20 (MCS5,6,7) +## 7: HT40 (MCS0,1,2) +## 8: HT40 (MCS3,4) +## 9: HT40 (MCS5,6,7) +## 10: HT2_20 (MCS8,9,10) +## 11: HT2_20 (MCS11,12) +## 12: HT2_20 (MCS13,14,15) +## 13: HT2_40 (MCS8,9,10) +## 14: HT2_40 (MCS11,12) +## 15: HT2_40 (MCS13,14,15) +## 16: VHT_QAM256 (MCS8) +## 17: VHT_40_QAM256 (MCS8,9) +## 18: VHT_80_PSK (MCS0,1,2) +## 19: VHT_80_QAM16 (MCS3,4) +## 20: VHT_80_QAM64 (MCS5,6,7) +## 21: VHT_80_QAM256 (MCS8,9) +## 22: VHT2_20_QAM256 (MCS8,9) +## 23: VHT2_40_QAM256 (MCS8,9) +## 24: VHT2_80_PSK (MCS0, 1, 2) +## 25: VHT2_80_QAM16 (MCS3,4) +## 26: VHT2_80_QAM64 (MCS5,6,7) +## 27: VHT2_80_QAM256 (MCS8,9) +## 28: HE_20_QAM256 (MCS8,9) +## 29: HE_20_QAM1024 (MCS10,11) +## 30: HE_40_QAM1024 (MCS10,11) +## 31: HE_80_QAM1024 (MCS10,11) +## 32: HE2_20_QAM256 (MCS8,9) +## 33: HE2_20_QAM1024 (MCS10,11) +## 34: HE2_40_QAM1024 (MCS10,11) +## 35: HE2_80_QAM1024 (MCS10,11) +## Power Limit in dBm +## +## Note: For KF, add VHT 20/40/80 1SS/2SS mod group. + +## 2G subband0 Tx power limit CFG +txpwrlimit_2g_cfg_set={ + CmdCode=0x00fb # do NOT change this line + Action:2=1 # 1 - SET + SubBand:2=0 # do NOT use this member in set cmd + + ChanTRPC.TlvType:2=0x0189 + ChanTRPC.TlvLength:2={ + TLVStartFreq:2=2407 + TLVChanWidth:1=20 + TLVChanNum:1=1 + TLVPwr:32='0,17,1,15,2,15,3,13,4,15,5,15,6,13,7,15,8,15,9,13,10,15,11,15,12,15,13,15,14,15,15,15' + } + ChanTRPC.TlvType:2=0x0189 + ChanTRPC.TlvLength:2={ + TLVStartFreq:2=2407 + TLVChanWidth:1=20 + TLVChanNum:1=2 + TLVPwr:32='0,17,1,15,2,15,3,13,4,15,5,15,6,13,7,15,8,15,9,13,10,15,11,15,12,15,13,15,14,15,15,15' + } + + ChanTRPC.TlvType:2=0x0189 + ChanTRPC.TlvLength:2={ + TLVStartFreq:2=2407 + TLVChanWidth:1=20 + TLVChanNum:1=3 + TLVPwr:32='0,17,1,15,2,15,3,13,4,15,5,15,6,13,7,15,8,15,9,13,10,15,11,15,12,15,13,15,14,15,15,15' + } + ChanTRPC.TlvType:2=0x0189 + ChanTRPC.TlvLength:2={ + TLVStartFreq:2=2407 + TLVChanWidth:1=20 + TLVChanNum:1=4 + TLVPwr:32='0,17,1,15,2,15,3,13,4,15,5,15,6,13,7,15,8,15,9,13,10,15,11,15,12,15,13,15,14,15,15,15' + } + + ChanTRPC.TlvType:2=0x0189 + ChanTRPC.TlvLength:2={ + TLVStartFreq:2=2407 + TLVChanWidth:1=20 + TLVChanNum:1=5 + TLVPwr:32='0,17,1,15,2,15,3,13,4,15,5,15,6,13,7,15,8,15,9,13,10,15,11,15,12,15,13,15,14,15,15,15' + } + ChanTRPC.TlvType:2=0x0189 + ChanTRPC.TlvLength:2={ + TLVStartFreq:2=2407 + TLVChanWidth:1=20 + TLVChanNum:1=6 + TLVPwr:32='0,17,1,15,2,15,3,13,4,15,5,15,6,13,7,15,8,15,9,13,10,15,11,15,12,15,13,15,14,15,15,15' + } + + ChanTRPC.TlvType:2=0x0189 + ChanTRPC.TlvLength:2={ + TLVStartFreq:2=2407 + TLVChanWidth:1=20 + TLVChanNum:1=7 + TLVPwr:32='0,17,1,15,2,15,3,13,4,15,5,15,6,13,7,15,8,15,9,13,10,15,11,15,12,15,13,15,14,15,15,15' + } + ChanTRPC.TlvType:2=0x0189 + ChanTRPC.TlvLength:2={ + TLVStartFreq:2=2407 + TLVChanWidth:1=20 + TLVChanNum:1=8 + TLVPwr:32='0,17,1,15,2,15,3,13,4,15,5,15,6,13,7,15,8,15,9,13,10,15,11,15,12,15,13,15,14,15,15,15' + } + + ChanTRPC.TlvType:2=0x0189 + ChanTRPC.TlvLength:2={ + TLVStartFreq:2=2407 + TLVChanWidth:1=20 + TLVChanNum:1=9 + TLVPwr:32='0,17,1,15,2,15,3,13,4,15,5,15,6,13,7,15,8,15,9,13,10,15,11,15,12,15,13,15,14,15,15,15' + } + ChanTRPC.TlvType:2=0x0189 + ChanTRPC.TlvLength:2={ + TLVStartFreq:2=2407 + TLVChanWidth:1=20 + TLVChanNum:1=10 + TLVPwr:32='0,17,1,15,2,15,3,13,4,15,5,15,6,13,7,15,8,15,9,13,10,15,11,15,12,15,13,15,14,15,15,15' + } + + ChanTRPC.TlvType:2=0x0189 + ChanTRPC.TlvLength:2={ + TLVStartFreq:2=2407 + TLVChanWidth:1=20 + TLVChanNum:1=11 + TLVPwr:32='0,17,1,15,2,15,3,13,4,15,5,15,6,13,7,15,8,15,9,13,10,15,11,15,12,15,13,15,14,15,15,15' + } + ChanTRPC.TlvType:2=0x0189 + ChanTRPC.TlvLength:2={ + TLVStartFreq:2=2407 + TLVChanWidth:1=20 + TLVChanNum:1=12 + TLVPwr:32='0,17,1,15,2,15,3,13,4,15,5,15,6,13,7,15,8,15,9,13,10,15,11,15,12,15,13,15,14,15,15,15' + } + + ChanTRPC.TlvType:2=0x0189 + ChanTRPC.TlvLength:2={ + TLVStartFreq:2=2407 + TLVChanWidth:1=20 + TLVChanNum:1=13 + TLVPwr:32='0,17,1,15,2,15,3,13,4,15,5,15,6,13,7,15,8,15,9,13,10,15,11,15,12,15,13,15,14,15,15,15' + } + ChanTRPC.TlvType:2=0x0189 + ChanTRPC.TlvLength:2={ + TLVStartFreq:2=2407 + TLVChanWidth:1=20 + TLVChanNum:1=14 + TLVPwr:32='0,12,1,12,2,12,3,12,4,12,5,12,6,12,7,12,8,12,9,12,10,12,11,12,12,12,13,12,14,12,15,12' + } +} + + +## 5G subband1 Tx power limit CFG +txpwrlimit_5g_cfg_set_sub0={ + CmdCode=0x00fb # do NOT change this line + Action:2=1 # 1 - SET + SubBand:2=0 # do NOT use this member in set cmd + + ChanTRPC.TlvType:2=0x0189 + ChanTRPC.TlvLength:2={ + TLVStartFreq:2=5000 + TLVChanWidth:1=20 + TLVChanNum:1=36 + TLVPwr:72='0,0,1,20,2,20,3,19,4,20,5,20,6,18,7,20,8,20,9,18,10,20,11,20,12,18,13,20,14,20,15,18,16,17,17,17,18,20,19,19,20,17,21,16,22,17,23,17,24,20,25,19,26,17,27,16,28,5,29,5,30,5,31,5,32,5,33,5,34,5,35,5' + } + + ChanTRPC.TlvType:2=0x0189 + ChanTRPC.TlvLength:2={ + TLVStartFreq:2=5000 + TLVChanWidth:1=20 + TLVChanNum:1=40 + TLVPwr:72='0,0,1,20,2,20,3,19,4,20,5,20,6,18,7,20,8,20,9,18,10,20,11,20,12,18,13,20,14,20,15,18,16,17,17,17,18,20,19,19,20,17,21,16,22,17,23,17,24,20,25,19,26,17,27,16,28,5,29,5,30,5,31,5,32,5,33,5,34,5,35,5' + } + + ChanTRPC.TlvType:2=0x0189 + ChanTRPC.TlvLength:2={ + TLVStartFreq:2=5000 + TLVChanWidth:1=20 + TLVChanNum:1=44 + TLVPwr:72='0,0,1,20,2,20,3,19,4,20,5,20,6,18,7,20,8,20,9,18,10,20,11,20,12,18,13,20,14,20,15,18,16,18,17,17,18,20,19,19,20,17,21,16,22,18,23,17,24,20,25,19,26,17,27,16,28,5,29,5,30,5,31,5,32,5,33,5,34,5,35,5' + } + + ChanTRPC.TlvType:2=0x0189 + ChanTRPC.TlvLength:2={ + TLVStartFreq:2=5000 + TLVChanWidth:1=20 + TLVChanNum:1=48 + TLVPwr:72='0,0,1,20,2,20,3,19,4,20,5,20,6,18,7,20,8,20,9,18,10,20,11,20,12,18,13,20,14,20,15,18,16,18,17,17,18,20,19,19,20,17,21,16,22,18,23,17,24,20,25,19,26,17,27,16,28,5,29,5,30,5,31,5,32,5,33,5,34,5,35,5' + } + + ChanTRPC.TlvType:2=0x0189 + ChanTRPC.TlvLength:2={ + TLVStartFreq:2=5000 + TLVChanWidth:1=20 + TLVChanNum:1=52 + TLVPwr:72='0,0,1,20,2,20,3,19,4,20,5,20,6,18,7,20,8,20,9,19,10,20,11,20,12,18,13,20,14,20,15,19,16,18,17,17,18,19,19,19,20,18,21,17,22,18,23,17,24,19,25,19,26,18,27,17,28,5,29,5,30,5,31,5,32,5,33,5,34,5,35,5' + } + + ChanTRPC.TlvType:2=0x0189 + ChanTRPC.TlvLength:2={ + TLVStartFreq:2=5000 + TLVChanWidth:1=20 + TLVChanNum:1=56 + TLVPwr:72='0,0,1,20,2,20,3,19,4,20,5,20,6,18,7,20,8,20,9,19,10,20,11,20,12,18,13,20,14,20,15,19,16,18,17,17,18,19,19,19,20,18,21,17,22,18,23,17,24,19,25,19,26,18,27,17,28,5,29,5,30,5,31,5,32,5,33,5,34,5,35,5' + } + + ChanTRPC.TlvType:2=0x0189 + ChanTRPC.TlvLength:2={ + TLVStartFreq:2=5000 + TLVChanWidth:1=20 + TLVChanNum:1=60 + TLVPwr:72='0,0,1,20,2,20,3,19,4,20,5,20,6,18,7,20,8,20,9,19,10,20,11,20,12,18,13,20,14,20,15,19,16,18,17,17,18,19,19,19,20,18,21,17,22,18,23,17,24,19,25,19,26,18,27,17,28,5,29,5,30,5,31,5,32,5,33,5,34,5,35,5' + } + + ChanTRPC.TlvType:2=0x0189 + ChanTRPC.TlvLength:2={ + TLVStartFreq:2=5000 + TLVChanWidth:1=20 + TLVChanNum:1=64 + TLVPwr:72='0,0,1,20,2,20,3,19,4,20,5,20,6,18,7,20,8,20,9,19,10,20,11,20,12,18,13,20,14,20,15,19,16,18,17,17,18,19,19,19,20,18,21,17,22,18,23,17,24,19,25,19,26,18,27,17,28,5,29,5,30,5,31,5,32,5,33,5,34,5,35,5' + } +} + +## 5G subband2 Tx power limit CFG +txpwrlimit_5g_cfg_set_sub1={ + CmdCode=0x00fb # do NOT change this line + Action:2=1 # 1 - SET + SubBand:2=0 # do NOT use this member in set cmd + + + ChanTRPC.TlvType:2=0x0189 + ChanTRPC.TlvLength:2={ + TLVStartFreq:2=5000 + TLVChanWidth:1=20 + TLVChanNum:1=100 + TLVPwr:72='0,0,1,20,2,20,3,20,4,18,5,18,6,19,7,18,8,18,9,18,10,18,11,18,12,19,13,18,14,18,15,18,16,18,17,16,18,18,19,19,20,18,21,16,22,18,23,16,24,18,25,19,26,18,27,16,28,5,29,5,30,5,31,5,32,5,33,5,34,5,35,5' + } + + + ChanTRPC.TlvType:2=0x0189 + ChanTRPC.TlvLength:2={ + TLVStartFreq:2=5000 + TLVChanWidth:1=20 + TLVChanNum:1=104 + TLVPwr:72='0,0,1,20,2,20,3,20,4,18,5,18,6,18,7,18,8,18,9,18,10,18,11,18,12,18,13,18,14,18,15,18,16,18,17,16,18,18,19,19,20,18,21,16,22,18,23,16,24,18,25,19,26,18,27,16,28,5,29,5,30,5,31,5,32,5,33,5,34,5,35,5' + } + + + ChanTRPC.TlvType:2=0x0189 + ChanTRPC.TlvLength:2={ + TLVStartFreq:2=5000 + TLVChanWidth:1=20 + TLVChanNum:1=108 + TLVPwr:72='0,0,1,20,2,20,3,20,4,18,5,18,6,19,7,18,8,18,9,17,10,18,11,18,12,19,13,18,14,18,15,17,16,18,17,16,18,18,19,19,20,18,21,16,22,18,23,16,24,18,25,19,26,18,27,16,28,5,29,5,30,5,31,5,32,5,33,5,34,5,35,5' + } + + + ChanTRPC.TlvType:2=0x0189 + ChanTRPC.TlvLength:2={ + TLVStartFreq:2=5000 + TLVChanWidth:1=20 + TLVChanNum:1=112 + TLVPwr:72='0,0,1,20,2,20,3,20,4,18,5,18,6,19,7,18,8,18,9,17,10,18,11,18,12,19,13,18,14,18,15,17,16,17,17,16,18,18,19,19,20,18,21,16,22,17,23,16,24,18,25,19,26,18,27,16,28,5,29,5,30,5,31,5,32,5,33,5,34,5,35,5' + } + + + ChanTRPC.TlvType:2=0x0189 + ChanTRPC.TlvLength:2={ + TLVStartFreq:2=5000 + TLVChanWidth:1=20 + TLVChanNum:1=116 + TLVPwr:72='0,0,1,20,2,20,3,19,4,18,5,18,6,18,7,18,8,18,9,17,10,18,11,18,12,18,13,18,14,18,15,17,16,16,17,15,18,18,19,18,20,17,21,15,22,16,23,15,24,18,25,18,26,17,27,15,28,5,29,5,30,5,31,5,32,5,33,5,34,5,35,5' + } + + + ChanTRPC.TlvType:2=0x0189 + ChanTRPC.TlvLength:2={ + TLVStartFreq:2=5000 + TLVChanWidth:1=20 + TLVChanNum:1=120 + TLVPwr:72='0,0,1,20,2,20,3,19,4,18,5,18,6,18,7,18,8,18,9,17,10,18,11,18,12,18,13,18,14,18,15,17,16,17,17,15,18,18,19,18,20,17,21,15,22,17,23,15,24,18,25,18,26,17,27,15,28,5,29,5,30,5,31,5,32,5,33,5,34,5,35,5' + } + + + ChanTRPC.TlvType:2=0x0189 + ChanTRPC.TlvLength:2={ + TLVStartFreq:2=5000 + TLVChanWidth:1=20 + TLVChanNum:1=124 + TLVPwr:72='0,0,1,20,2,20,3,19,4,18,5,18,6,18,7,18,8,18,9,18,10,18,11,18,12,18,13,18,14,18,15,18,16,17,17,15,18,18,19,18,20,17,21,15,22,17,23,15,24,18,25,18,26,17,27,15,28,5,29,5,30,5,31,5,32,5,33,5,34,5,35,5' + } + + + ChanTRPC.TlvType:2=0x0189 + ChanTRPC.TlvLength:2={ + TLVStartFreq:2=5000 + TLVChanWidth:1=20 + TLVChanNum:1=128 + TLVPwr:72='0,0,1,20,2,20,3,19,4,18,5,18,6,18,7,18,8,18,9,18,10,18,11,18,12,18,13,18,14,18,15,18,16,17,17,15,18,18,19,18,20,17,21,15,22,17,23,15,24,18,25,18,26,17,27,15,28,5,29,5,30,5,31,5,32,5,33,5,34,5,35,5' + } + + + ChanTRPC.TlvType:2=0x0189 + ChanTRPC.TlvLength:2={ + TLVStartFreq:2=5000 + TLVChanWidth:1=20 + TLVChanNum:1=132 + TLVPwr:72='0,0,1,20,2,20,3,19,4,18,5,18,6,18,7,18,8,17,9,18,10,18,11,18,12,18,13,18,14,17,15,18,16,16,17,15,18,18,19,18,20,18,21,15,22,16,23,15,24,18,25,18,26,18,27,15,28,5,29,5,30,5,31,5,32,5,33,5,34,5,35,5' + } + + ChanTRPC.TlvType:2=0x0189 + ChanTRPC.TlvLength:2={ + TLVStartFreq:2=5000 + TLVChanWidth:1=20 + TLVChanNum:1=136 + TLVPwr:72='0,0,1,20,2,20,3,19,4,18,5,18,6,18,7,18,8,17,9,18,10,18,11,18,12,18,13,18,14,17,15,18,16,17,17,15,18,18,19,18,20,18,21,15,22,17,23,15,24,18,25,18,26,18,27,15,28,5,29,5,30,5,31,5,32,5,33,5,34,5,35,5' + } + + ChanTRPC.TlvType:2=0x0189 + ChanTRPC.TlvLength:2={ + TLVStartFreq:2=5000 + TLVChanWidth:1=20 + TLVChanNum:1=140 + TLVPwr:72='0,0,1,20,2,20,3,19,4,18,5,18,6,18,7,18,8,17,9,17,10,18,11,18,12,18,13,18,14,17,15,17,16,18,17,16,18,18,19,18,20,18,21,15,22,18,23,16,24,18,25,18,26,18,27,15,28,5,29,5,30,5,31,5,32,5,33,5,34,5,35,5' + } + + + ChanTRPC.TlvType:2=0x0189 + ChanTRPC.TlvLength:2={ + TLVStartFreq:2=5000 + TLVChanWidth:1=20 + TLVChanNum:1=144 + TLVPwr:72='0,0,1,20,2,20,3,19,4,18,5,18,6,18,7,18,8,17,9,17,10,18,11,18,12,18,13,18,14,17,15,17,16,18,17,16,18,18,19,18,20,18,21,15,22,18,23,16,24,18,25,18,26,18,27,15,28,5,29,5,30,5,31,5,32,5,33,5,34,5,35,5' + } + +} + + +## 5G subband3 Tx power limit CFG +txpwrlimit_5g_cfg_set_sub2={ + CmdCode=0x00fb # do NOT change this line + Action:2=1 # 1 - SET + SubBand:2=0 # do NOT use this member in set cmd + + + ChanTRPC.TlvType:2=0x0189 + ChanTRPC.TlvLength:2={ + TLVStartFreq:2=5000 + TLVChanWidth:1=20 + TLVChanNum:1=149 + TLVPwr:72='0,0,1,20,2,20,3,19,4,18,5,19,6,18,7,18,8,18,9,18,10,18,11,19,12,18,13,18,14,18,15,18,16,17,17,17,18,18,19,19,20,17,21,15,22,17,23,17,24,18,25,19,26,17,27,15,28,5,29,5,30,5,31,5,32,5,33,5,34,5,35,5' + } + + + ChanTRPC.TlvType:2=0x0189 + ChanTRPC.TlvLength:2={ + TLVStartFreq:2=5000 + TLVChanWidth:1=20 + TLVChanNum:1=153 + TLVPwr:72='0,0,1,20,2,20,3,19,4,18,5,19,6,19,7,18,8,18,9,18,10,18,11,19,12,19,13,18,14,18,15,18,16,17,17,17,18,18,19,19,20,17,21,15,22,17,23,17,24,18,25,19,26,17,27,15,28,5,29,5,30,5,31,5,32,5,33,5,34,5,35,5' + } + + + ChanTRPC.TlvType:2=0x0189 + ChanTRPC.TlvLength:2={ + TLVStartFreq:2=5000 + TLVChanWidth:1=20 + TLVChanNum:1=157 + TLVPwr:72='0,0,1,20,2,20,3,19,4,18,5,19,6,19,7,18,8,18,9,18,10,18,11,19,12,19,13,18,14,18,15,18,16,17,17,17,18,18,19,19,20,17,21,15,22,17,23,17,24,18,25,19,26,17,27,15,28,5,29,5,30,5,31,5,32,5,33,5,34,5,35,5' + } + + + ChanTRPC.TlvType:2=0x0189 + ChanTRPC.TlvLength:2={ + TLVStartFreq:2=5000 + TLVChanWidth:1=20 + TLVChanNum:1=161 + TLVPwr:72='0,0,1,20,2,20,3,19,4,18,5,19,6,19,7,18,8,18,9,18,10,18,11,19,12,19,13,18,14,18,15,18,16,17,17,17,18,18,19,19,20,17,21,15,22,17,23,17,24,18,25,19,26,17,27,15,28,5,29,5,30,5,31,5,32,5,33,5,34,5,35,5' + } + + + ChanTRPC.TlvType:2=0x0189 + ChanTRPC.TlvLength:2={ + TLVStartFreq:2=5000 + TLVChanWidth:1=20 + TLVChanNum:1=165 + TLVPwr:72='0,0,1,20,2,20,3,19,4,18,5,19,6,19,7,18,8,18,9,18,10,18,11,19,12,19,13,18,14,18,15,18,16,17,17,17,18,18,19,19,20,17,21,15,22,17,23,17,24,18,25,19,26,17,27,15,28,5,29,5,30,5,31,5,32,5,33,5,34,5,35,5' + } + +} + + +## 5G subband4 Tx power limit CFG +txpwrlimit_5g_cfg_set_sub3={ + CmdCode=0x00fb # do NOT change this line + Action:2=1 # 1 - SET + SubBand:2=0 # do NOT use this in set cmd + + + ChanTRPC.TlvType:2=0x0189 + ChanTRPC.TlvLength:2={ + TLVStartFreq:2=4000 + TLVChanWidth:1=20 + TLVChanNum:1=183 + TLVPwr:72='0,0,1,20,2,20,3,19,4,18,5,19,6,19,7,18,8,18,9,18,10,18,11,19,12,19,13,18,14,18,15,18,16,17,17,17,18,18,19,19,20,17,21,15,22,17,23,17,24,18,25,19,26,17,27,15,28,5,29,5,30,5,31,5,32,5,33,5,34,5,35,5' + } + + + ChanTRPC.TlvType:2=0x0189 + ChanTRPC.TlvLength:2={ + TLVStartFreq:2=4000 + TLVChanWidth:1=20 + TLVChanNum:1=184 + TLVPwr:72='0,0,1,20,2,20,3,19,4,18,5,19,6,19,7,18,8,18,9,18,10,18,11,19,12,19,13,18,14,18,15,18,16,17,17,17,18,18,19,19,20,17,21,15,22,17,23,17,24,18,25,19,26,17,27,15,28,5,29,5,30,5,31,5,32,5,33,5,34,5,35,5' + } + + + ChanTRPC.TlvType:2=0x0189 + ChanTRPC.TlvLength:2={ + TLVStartFreq:2=4000 + TLVChanWidth:1=20 + TLVChanNum:1=185 + TLVPwr:72='0,0,1,20,2,20,3,19,4,18,5,19,6,19,7,18,8,18,9,18,10,18,11,19,12,19,13,18,14,18,15,18,16,17,17,17,18,18,19,19,20,17,21,15,22,17,23,17,24,18,25,19,26,17,27,15,28,5,29,5,30,5,31,5,32,5,33,5,34,5,35,5' + } + + + ChanTRPC.TlvType:2=0x0189 + ChanTRPC.TlvLength:2={ + TLVStartFreq:2=4000 + TLVChanWidth:1=20 + TLVChanNum:1=187 + TLVPwr:72='0,0,1,20,2,20,3,19,4,18,5,19,6,19,7,18,8,18,9,18,10,18,11,19,12,19,13,18,14,18,15,18,16,17,17,17,18,18,19,19,20,17,21,15,22,17,23,17,24,18,25,19,26,17,27,15,28,5,29,5,30,5,31,5,32,5,33,5,34,5,35,5' + } + + + ChanTRPC.TlvType:2=0x0189 + ChanTRPC.TlvLength:2={ + TLVStartFreq:2=4000 + TLVChanWidth:1=20 + TLVChanNum:1=188 + TLVPwr:72='0,0,1,20,2,20,3,19,4,18,5,19,6,19,7,18,8,18,9,18,10,18,11,19,12,19,13,18,14,18,15,18,16,17,17,17,18,18,19,19,20,17,21,15,22,17,23,17,24,18,25,19,26,17,27,15,28,5,29,5,30,5,31,5,32,5,33,5,34,5,35,5' + } + + + ChanTRPC.TlvType:2=0x0189 + ChanTRPC.TlvLength:2={ + TLVStartFreq:2=4000 + TLVChanWidth:1=20 + TLVChanNum:1=189 + TLVPwr:72='0,0,1,20,2,20,3,19,4,18,5,19,6,19,7,18,8,18,9,18,10,18,11,19,12,19,13,18,14,18,15,18,16,17,17,17,18,18,19,19,20,17,21,15,22,17,23,17,24,18,25,19,26,17,27,15,28,5,29,5,30,5,31,5,32,5,33,5,34,5,35,5' + } + + + ChanTRPC.TlvType:2=0x0189 + ChanTRPC.TlvLength:2={ + TLVStartFreq:2=4000 + TLVChanWidth:1=20 + TLVChanNum:1=192 + TLVPwr:72='0,0,1,20,2,20,3,19,4,18,5,19,6,19,7,18,8,18,9,18,10,18,11,19,12,19,13,18,14,18,15,18,16,17,17,17,18,18,19,19,20,17,21,15,22,17,23,17,24,18,25,19,26,17,27,15,28,5,29,5,30,5,31,5,32,5,33,5,34,5,35,5' + } + + + ChanTRPC.TlvType:2=0x0189 + ChanTRPC.TlvLength:2={ + TLVStartFreq:2=4000 + TLVChanWidth:1=20 + TLVChanNum:1=196 + TLVPwr:72='0,0,1,20,2,20,3,19,4,18,5,19,6,19,7,18,8,18,9,18,10,18,11,19,12,19,13,18,14,18,15,18,16,17,17,17,18,18,19,19,20,17,21,15,22,17,23,17,24,18,25,19,26,17,27,15,28,5,29,5,30,5,31,5,32,5,33,5,34,5,35,5' + } + + + ChanTRPC.TlvType:2=0x0189 + ChanTRPC.TlvLength:2={ + TLVStartFreq:2=5000 + TLVChanWidth:1=20 + TLVChanNum:1=7 + TLVPwr:72='0,0,1,20,2,20,3,19,4,18,5,19,6,19,7,18,8,18,9,18,10,18,11,19,12,19,13,18,14,18,15,18,16,17,17,17,18,18,19,19,20,17,21,15,22,17,23,17,24,18,25,19,26,17,27,15,28,5,29,5,30,5,31,5,32,5,33,5,34,5,35,5' + } + + + ChanTRPC.TlvType:2=0x0189 + ChanTRPC.TlvLength:2={ + TLVStartFreq:2=5000 + TLVChanWidth:1=20 + TLVChanNum:1=8 + TLVPwr:72='0,0,1,20,2,20,3,19,4,18,5,19,6,19,7,18,8,18,9,18,10,18,11,19,12,19,13,18,14,18,15,18,16,17,17,17,18,18,19,19,20,17,21,15,22,17,23,17,24,18,25,19,26,17,27,15,28,5,29,5,30,5,31,5,32,5,33,5,34,5,35,5' + } + + + ChanTRPC.TlvType:2=0x0189 + ChanTRPC.TlvLength:2={ + TLVStartFreq:2=5000 + TLVChanWidth:1=20 + TLVChanNum:1=11 + TLVPwr:72='0,0,1,20,2,20,3,19,4,18,5,19,6,19,7,18,8,18,9,18,10,18,11,19,12,19,13,18,14,18,15,18,16,17,17,17,18,18,19,19,20,17,21,15,22,17,23,17,24,18,25,19,26,17,27,15,28,5,29,5,30,5,31,5,32,5,33,5,34,5,35,5' + } + + + ChanTRPC.TlvType:2=0x0189 + ChanTRPC.TlvLength:2={ + TLVStartFreq:2=5000 + TLVChanWidth:1=20 + TLVChanNum:1=12 + TLVPwr:72='0,0,1,20,2,20,3,19,4,18,5,19,6,19,7,18,8,18,9,18,10,18,11,19,12,19,13,18,14,18,15,18,16,17,17,17,18,18,19,19,20,17,21,15,22,17,23,17,24,18,25,19,26,17,27,15,28,5,29,5,30,5,31,5,32,5,33,5,34,5,35,5' + } + + + ChanTRPC.TlvType:2=0x0189 + ChanTRPC.TlvLength:2={ + TLVStartFreq:2=5000 + TLVChanWidth:1=20 + TLVChanNum:1=16 + TLVPwr:72='0,0,1,20,2,20,3,19,4,18,5,19,6,19,7,18,8,18,9,18,10,18,11,19,12,19,13,18,14,18,15,18,16,17,17,17,18,18,19,19,20,17,21,15,22,17,23,17,24,18,25,19,26,17,27,15,28,5,29,5,30,5,31,5,32,5,33,5,34,5,35,5' + } + + + ChanTRPC.TlvType:2=0x0189 + ChanTRPC.TlvLength:2={ + TLVStartFreq:2=5000 + TLVChanWidth:1=20 + TLVChanNum:1=34 + TLVPwr:72='0,0,1,20,2,20,3,19,4,18,5,19,6,19,7,18,8,18,9,18,10,18,11,19,12,19,13,18,14,18,15,18,16,17,17,17,18,18,19,19,20,17,21,15,22,17,23,17,24,18,25,19,26,17,27,15,28,5,29,5,30,5,31,5,32,5,33,5,34,5,35,5' + } + } + diff --git a/mxm_wifiex/wlan_src/mapp/mlanconfig/config/txrate_cfg.conf b/mxm_wifiex/wlan_src/mapp/mlanconfig/config/txrate_cfg.conf new file mode 100644 index 0000000..fbe4846 --- /dev/null +++ b/mxm_wifiex/wlan_src/mapp/mlanconfig/config/txrate_cfg.conf @@ -0,0 +1,172 @@ +# File : txrate_cfg.conf + +## Tx Rate Configuration command +txrate_cfg_get={ + CmdCode=0x00d6 # do NOT change this line + Action:2=0 # 0 - GET + Index:2=0 # do NOT change this line + + TxRateScope.TlvType:2=0x0153 + TxRateScope.TlvLength:2={ + } +} + +txrate_cfg_set_bg={ + CmdCode=0x00d6 # do NOT change this line + + Action:2=1 # 1 - SET + Index:2=0 # do NOT change this line + + TxRateScope.TlvType:2=0x0153 + TxRateScope.TlvLength:2={ + ################# TXRATE SCOPE ###################### + + # The following table shows the bitmap of the rates: + # (bit 0 is the least significant bit) + # Bit Data rate + # 0 1 Mbps + # 1 2 Mbps + # 2 5.5 Mbps + # 3 11 Mbps + # 4 Reserved + HRDSSS.RateScope:2=0x0000 + + # The following table shows the bitmap of the rates: + # (bit 0 is the least significant bit) + # Bit Data rate + # 0 6 Mbps + # 1 9 Mbps + # 2 12 Mbps + # 3 18 Mbps + # 4 24 Mbps + # 5 36 Mbps + # 6 48 Mbps + # 7 54 Mbps + OFDM.RateScope:2=0x0080 + + # The following table shows the bitmap of the rates: + # (bit 0 is the least significant bit) + # Bit Data rate + # 0 MCS0 + # 1 MCS1 + # 2 MCS2 + # 3 MCS3 + # 4 MCS4 + # 5 MCS5 + # 6 MCS6 + # 7 MCS7 + # 32 MCS32 + HT.RateScopeDword0:4=0x00000000 + HT.RateScopeDword1:4=0x00000000 + HT.RateScopeDword2:4=0x00000000 + HT.RateScopeDword3:4=0x00000000 + } + + TxRateDrop.TlvType:2=0x0151 + TxRateDrop.TlvLength:2={ + RateDrop.Mode:4=0x00000001 + } +} + +txrate_cfg_set_bgn={ + CmdCode=0x00d6 # do NOT change this line + + Action:2=1 # 1 - SET + Index:2=0 # do NOT change this line + + TxRateScope.TlvType:2=0x0153 + TxRateScope.TlvLength:2={ + ################# TXRATE SCOPE ###################### + + # The following table shows the bitmap of the rates: + # (bit 0 is the least significant bit) + # Bit Data rate + # 0 1 Mbps + # 1 2 Mbps + # 2 5.5 Mbps + # 3 11 Mbps + # 4 Reserved + HRDSSS.RateScope:2=0x0000 + + # The following table shows the bitmap of the rates: + # (bit 0 is the least significant bit) + # Bit Data rate + # 0 6 Mbps + # 1 9 Mbps + # 2 12 Mbps + # 3 18 Mbps + # 4 24 Mbps + # 5 36 Mbps + # 6 48 Mbps + # 7 54 Mbps + OFDM.RateScope:2=0x0000 + + # The following table shows the bitmap of the rates: + # (bit 0 is the least significant bit) + # Bit Data rate + # 0 MCS0 + # 1 MCS1 + # 2 MCS2 + # 3 MCS3 + # 4 MCS4 + # 5 MCS5 + # 6 MCS6 + # 7 MCS7 + # 32 MCS32 + HT.RateScopeDword0:4=0x00000080 + HT.RateScopeDword1:4=0x00000000 + HT.RateScopeDword2:4=0x00000000 + HT.RateScopeDword3:4=0x00000000 + } + + TxRateDrop.TlvType:2=0x0151 + TxRateDrop.TlvLength:2={ + RateDrop.Mode:4=0x00000001 + } +} + +########supported BasicRate setting########### +basic_rate_get={ + CmdCode=0x00d6 # do NOT change this line + Action:2=0 # 0 - GET + Index:2=0 # do NOT change this line + + TlvType:2=0x21a + TlvLength:2={ + } +} + +basic_rate_set={ + CmdCode=0x00d6 # do NOT change this line + + Action:2=1 # 1 - SET + Index:2=0 # do NOT change this line + + TlvType:2=0x21a + TlvLength:2={ + BasicRateSupport:2=0x000f #defalt value + + # The following table shows the bitmap of the rates: + # (bit 0 is the least significant bit) + # Bit BasicRateSupport + # 0 DBPSK1Mbps + # 1 DQPSK2Mbps + # 2 CCK5_5Mbps + # 3 CCK11Mbps + # 4 Not used. + # 5 OFDM6Mbps + # 6 OFDM9Mbps + # 7 OFDM12Mbps + # 8 OFDM18Mbps + # 9 OFDM24Mbps + # 10 OFDM36Mbps + # 11 OFDM48Mbps + # 12 OFDM54Mbps + # 13-15 Reserved + #note: value0x0 represents no setting value + #For example: + #BasicRateSupport:2=0x3 set supported BasicRate to DBPSK1Mbps, DQPSK2Mbps + #BasicRateSupport:2=0x180 set supported BasicRate to OFDM18Mbps, OFDM12Mbps + } +} + diff --git a/mxm_wifiex/wlan_src/mapp/mlanconfig/config/wifi_mod_para.conf b/mxm_wifiex/wlan_src/mapp/mlanconfig/config/wifi_mod_para.conf new file mode 100644 index 0000000..a88d0a2 --- /dev/null +++ b/mxm_wifiex/wlan_src/mapp/mlanconfig/config/wifi_mod_para.conf @@ -0,0 +1,179 @@ +# Not matter how many spaces or tabs are inserted in a line, +# components and ending format must be exactly same as given +# example: +# +# [_] = { +# key=value +# } +# +# card_type : 8XXX (mandatory) +# block_id : configuration block id (optional ) +# key : module parameter name +# value : value for module parameter +# for string value, no need to add "" +# +# card_type supported: 8887/8897/8997/8977/8987/9098 +# block_id: support same chipset with +# different module parameter. +# For example to support mutiple SD8997 cards, usr can +# specify the configuration block id number [0 - 9], if not +# specified, it is taken as 0 by default. +# +# debug related module parameters could not be set via module +# configure file, ex. drvdbg could not be set in this file +# +# line started with "#" will be ignored +# refer to the USB8997_1 for parameters that could be set in +# this configuration file, and set the corresponding value +# according to your real needs + +SD8997 = { + cfg80211_wext=0xf + wfd_name=p2p + max_vir_bss=1 + cal_data_cfg=nxp/WlanCalData_ext_8997_QFN_TB.conf + drv_mode=7 +} + +#SD8997_1 = { +# cfg80211_wext=0xf +# wfd_name=wfd0 +# max_vir_bss=1 +# cal_data_cfg=nxp/WlanCalData_ext_8997_QFN_TB.conf +# drv_mode=5 +#} + +#SD8887 = { +# cfg80211_wext=0xf +# wfd_name=p2p +# max_vir_bss=1 +# cal_data_cfg=nxp/WlanCalData_ext_8997_QFN_TB.conf +# drv_mode=7 +#} + +#SD8897 = { +# cfg80211_wext=0xf +# wfd_name=p2p +# max_vir_bss=1 +# cal_data_cfg=nxp/WlanCalData_ext_8997_QFN_TB.conf +# drv_mode=7 +#} + +#SD8977 = { +# cfg80211_wext=0xf +# wfd_name=p2p +# max_vir_bss=1 +# cal_data_cfg=nxp/WlanCalData_ext_8997_QFN_TB.conf +# drv_mode=7 +#} + +#SD8987 = { +# cfg80211_wext=0xf +# wfd_name=p2p +# max_vir_bss=1 +# cal_data_cfg=nxp/WlanCalData_ext_8997_QFN_TB.conf +# drv_mode=7 +#} + +USB8997 = { + cfg80211_wext=0xf + wfd_name=p2p + max_vir_bss=1 + cal_data_cfg=nxp/WlanCalData_ext_8997_QFN_TB.conf + drv_mode=7 +} + +PCIE8997 = { + cfg80211_wext=0xf + wfd_name=p2p + max_vir_bss=1 + cal_data_cfg=nxp/WlanCalData_ext_8997_QFN_TB.conf + drv_mode=7 +} + +PCIE9098_0 = { + cfg80211_wext=0xf + wfd_name=p2p + max_vir_bss=1 + cal_data_cfg=none + drv_mode=7 + mac_addr=00:50:43:20:12:34 +} + +PCIE9098_1 = { + cfg80211_wext=0xf + wfd_name=p2p + max_vir_bss=1 + cal_data_cfg=none + drv_mode=7 + mac_addr=00:50:43:20:52:56 +} + +#USB8997 = { +# hw_test=0 +# fw_name="nxp/usbusb8997_combo_v4.bin" +# req_fw_nowait=1 +# fw_reload=3 +# fw_serial=1 +# fw_region=0 +# mac_addr=00:50:43:22:1e:3d +# mfg_mode=0 +# drv_mode=0x5 +# max_sta_bss=1 +# sta_name=wlan +# max_uap_bss=1 +# uap_name=uap +# wfd_name=p2p +# max_vir_bss=1 +# max_mpl_bss=1 +# nan_name=nan +# max_nan_bss=1 +# max_11p_bss=1 +# auto_ds=0 +# ps_mode=1 +# max_tx_buf=4096 +# intmode=0 +# gpiopin=0 +# pm_keep_power=0 +# shutdown_hs=1 +# cfg_11d=1 +# start_11ai_scan=0 +# oob_mode=0 +# sdio_pd=1 +# cal_data_cfg=nxp/WlanCalData_ext_8997_QFN_TB.conf +# txpwrtlimit_cfg=nxp/txpwr_limit.conf +# cntry_txpwrt=0 +# init_hostcmd_cfg=nxp/init_hostcmd_cfg.conf +# minicard_pwrup=0 +# cfg80211_wext=0xf +# skip_fwdnld=0 +# wq_sched_prio=0 +# wq_sched_policy=0 +# rx_work=1 +# aggrctrl=1 +# usb_aggr=1 +# pcie_int_mode=1 +# low_power_mode_enable=1 +# wakelock_timeout=10 +# dev_cap_mask=0xffffffff +# sdio_rx_aggr=1 +# pmic=1 +# antcfg=0 +# uap_oper_ctrl=0 +# hs_wake_interval=400 +# indication_gpio=0xff +# disconnect_on_suspend=0 +# hs_mimo_switch=1 +# indrstcfg=0xffffffff +# fixed_beacon_buffer=0 +# GoAgeoutTime=0 +# gtk_rekey_offload=1 +# multi_dtim=0 +# inact_tmo=0 +# usb_fw_option=1 +# napi=1 +# dfs_offload=1 +# cfg80211_drcs=1 +# drcs_chantime_mode=0 +# reg_alpha2=US +#} diff --git a/mxm_wifiex/wlan_src/mapp/mlanconfig/mlanconfig.c b/mxm_wifiex/wlan_src/mapp/mlanconfig/mlanconfig.c new file mode 100644 index 0000000..2ab4054 --- /dev/null +++ b/mxm_wifiex/wlan_src/mapp/mlanconfig/mlanconfig.c @@ -0,0 +1,2970 @@ +/** @file mlanconfig.c + * + * @brief Program to configure addition parameters into the mlandriver + * + * Usage: mlanconfig mlanX cmd [...] + * + * + * Copyright 2014-2020 NXP + * + * NXP CONFIDENTIAL + * The source code contained or described herein and all documents related to + * the source code (Materials) are owned by NXP, its + * suppliers and/or its licensors. Title to the Materials remains with NXP, + * its suppliers and/or its licensors. The Materials contain + * trade secrets and proprietary and confidential information of NXP, its + * suppliers and/or its licensors. The Materials are protected by worldwide copyright + * and trade secret laws and treaty provisions. No part of the Materials may be + * used, copied, reproduced, modified, published, uploaded, posted, + * transmitted, distributed, or disclosed in any way without NXP's prior + * express written permission. + * + * No license under any patent, copyright, trade secret or other intellectual + * property right is granted to or conferred upon you by disclosure or delivery + * of the Materials, either expressly, by implication, inducement, estoppel or + * otherwise. Any license under such intellectual property rights must be + * express and approved by NXP in writing. + * + */ +/************************************************************************ +Change log: + 11/26/2008: initial version + 03/10/2009: add setuserscan, getscantable etc. commands + 08/11/2009: add addts, regclass, setra, scanagent etc. commands +************************************************************************/ + +#include "mlanconfig.h" +#include "mlanhostcmd.h" +#include "mlanmisc.h" + +/** mlanconfig version number */ +#define MLANCONFIG_VER "M2.0" + +/** Initial number of total private ioctl calls */ +#define IW_INIT_PRIV_NUM 128 +/** Maximum number of total private ioctl calls supported */ +#define IW_MAX_PRIV_NUM 1024 + +/******************************************************** + Local Variables +********************************************************/ + +/** Private ioctl commands */ +enum COMMANDS { + CMD_HOSTCMD, + CMD_MEFCFG, + CMD_CFG_DATA, +#ifdef SDIO + CMD_CMD52RW, + CMD_CMD53RW, +#endif + CMD_GET_SCAN_RSP, + CMD_SET_USER_SCAN, + CMD_ADD_TS, + CMD_DEL_TS, + CMD_QCONFIG, + CMD_QSTATS, + CMD_TS_STATUS, + CMD_WMM_QSTATUS, + CMD_REGRW, + CMD_MEMRW, + CMD_STA_CUSTOM_IE, + CMD_STA_MGMT_FRAME_TX, +#ifdef OPCHAN + CMD_OPCHAN, + CMD_CHANGROUP, +#endif +}; + +static t_s8 *commands[] = { + "hostcmd", + "mefcfg", + "cfgdata", +#ifdef SDIO + "sdcmd52rw", + "sdcmd53rw", +#endif + "getscantable", + "setuserscan", + "addts", + "delts", + "qconfig", + "qstats", + "ts_status", + "qstatus", + "regrdwr", + "memrdwr", + "customie", + "mgmtframetx", +#ifdef OPCHAN + "opchan", + "changroup", +#endif +}; + +static t_s8 *usage[] = { + "Usage: ", + " mlanconfig -v (version)", + " mlanconfig [...]", + " where", + " mlanX : wireless network interface", + " cmd : hostcmd", + " : mefcfg", + " : customie", + " : mgmtframetx", + " : cfgdata", +#ifdef SDIO + " : sdcmd52rw, sdcmd53rw", +#endif + " : getscantable, setuserscan", + " : addts, delts, qconfig, qstats, ts_status, qstatus", + " : regrdwr, memrdwr", +#ifdef OPCHAN + " : opchan, changroup", +#endif + " : additional parameter for hostcmd", + " : ", + " : additional parameters for mefcfg are:", + " : ", + " : additional parameters for customie are:", + " : ", + " : additional parameters for mgmtframetx are:", + " : ", + " : additional parameter for cfgdata", + " : ", +#ifdef SDIO + " : additional parameter for sdcmd52rw", + " : ", + " : additional parameter for sdcmd53rw", + " : ... ... ", +#endif + " : additional parameter for addts", + " : ", + " : additional parameter for delts", + " : ", + " : additional parameter for qconfig", + " : <[set msdu [Queue Id: 0-3]]", + " : [get [Queue Id: 0-3]] [def [Queue Id: 0-3]]>", + " : additional parameter for qstats", + " : <[get [User Priority: 0-7]]>", + " : additional parameter for regrdwr", + " : [value]", + " : additional parameter for memrdwr", + " :
[value]", +}; + +t_s32 sockfd; /**< socket */ +t_s8 dev_name[IFNAMSIZ + 1]; /**< device name */ +static struct iw_priv_args *priv_args = NULL; /**< private args */ +static int we_version_compiled = 0; + /**< version compiled */ + +/******************************************************** + Global Variables +********************************************************/ + +/******************************************************** + Local Functions +********************************************************/ +/** + * @brief isdigit for String. + * + * @param x Char string + * @return MLAN_STATUS_FAILURE for non-digit. + * MLAN_STATUS_SUCCESS for digit + */ +static int +ISDIGIT(t_s8 *x) +{ + unsigned int i; + for (i = 0; i < strlen(x); i++) + if (isdigit(x[i]) == 0) + return MLAN_STATUS_FAILURE; + return MLAN_STATUS_SUCCESS; +} + +/** + * Check of decimal or hex string + * @param num string + */ +#define IS_HEX_OR_DIGIT(num) \ + (strncasecmp("0x", (num), 2)?ISDIGIT((num)):ishexstring((num))) + +/** + * @brief Get private info. + * + * @param ifname A pointer to net name + * @return MLAN_STATUS_SUCCESS--success, otherwise --fail + */ +static int +get_private_info(const t_s8 *ifname) +{ + /* This function sends the SIOCGIWPRIV command, which is + * handled by the kernel and gets the total number of + * private ioctl's available in the host driver. + */ + struct iwreq iwr; + int s, ret = MLAN_STATUS_SUCCESS; + struct iw_priv_args *ppriv = NULL; + struct iw_priv_args *new_priv; + int result = 0; + size_t size = IW_INIT_PRIV_NUM; + + s = socket(PF_INET, SOCK_DGRAM, 0); + if (s < 0) { + perror("socket[PF_INET,SOCK_DGRAM]"); + return MLAN_STATUS_FAILURE; + } + + memset(&iwr, 0, sizeof(iwr)); + strncpy(iwr.ifr_name, ifname, IFNAMSIZ - 1); + + do { + /* (Re)allocate the buffer */ + new_priv = realloc(ppriv, size * sizeof(ppriv[0])); + if (new_priv == NULL) { + printf("Error: Buffer allocation failed\n"); + ret = MLAN_STATUS_FAILURE; + break; + } + ppriv = new_priv; + + iwr.u.data.pointer = (caddr_t) ppriv; + iwr.u.data.length = size; + iwr.u.data.flags = 0; + + if (ioctl(s, SIOCGIWPRIV, &iwr) < 0) { + result = errno; + ret = MLAN_STATUS_FAILURE; + if (result == E2BIG) { + /* We need a bigger buffer. Check if kernel gave us any hints. */ + if (iwr.u.data.length > size) { + /* Kernel provided required size */ + size = iwr.u.data.length; + } else { + /* No hint from kernel, double the buffer size */ + size *= 2; + } + } else { + /* ioctl error */ + perror("ioctl[SIOCGIWPRIV]"); + break; + } + } else { + /* Success. Return the number of private ioctls */ + priv_args = ppriv; + ret = iwr.u.data.length; + break; + } + } while (size <= IW_MAX_PRIV_NUM); + + if ((ret == MLAN_STATUS_FAILURE) && (ppriv)) + free(ppriv); + + close(s); + + return ret; +} + +/** + * @brief Get Sub command ioctl number + * + * @param i command index + * @param priv_cnt Total number of private ioctls availabe in driver + * @param ioctl_val A pointer to return ioctl number + * @param subioctl_val A pointer to return sub-ioctl number + * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE + */ +static int +nxp_get_subioctl_no(t_s32 i, t_s32 priv_cnt, int *ioctl_val, int *subioctl_val) +{ + t_s32 j; + + if (priv_args[i].cmd >= SIOCDEVPRIVATE) { + *ioctl_val = priv_args[i].cmd; + *subioctl_val = 0; + return MLAN_STATUS_SUCCESS; + } + + j = -1; + + /* Find the matching *real* ioctl */ + + while ((++j < priv_cnt) + && ((priv_args[j].name[0] != '\0') || + (priv_args[j].set_args != priv_args[i].set_args) || + (priv_args[j].get_args != priv_args[i].get_args))) { + } + + /* If not found... */ + if (j == priv_cnt) { + printf("%s: Invalid private ioctl definition for: 0x%x\n", + dev_name, priv_args[i].cmd); + return MLAN_STATUS_FAILURE; + } + + /* Save ioctl numbers */ + *ioctl_val = priv_args[j].cmd; + *subioctl_val = priv_args[i].cmd; + + return MLAN_STATUS_SUCCESS; +} + +/** + * @brief Get ioctl number + * + * @param ifname A pointer to net name + * @param priv_cmd A pointer to priv command buffer + * @param ioctl_val A pointer to return ioctl number + * @param subioctl_val A pointer to return sub-ioctl number + * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE + */ +static int +nxp_get_ioctl_no(const t_s8 *ifname, + const t_s8 *priv_cmd, int *ioctl_val, int *subioctl_val) +{ + t_s32 i; + t_s32 priv_cnt; + int ret = MLAN_STATUS_FAILURE; + + priv_cnt = get_private_info(ifname); + + /* Are there any private ioctls? */ + if (priv_cnt <= 0 || priv_cnt > IW_MAX_PRIV_NUM) { + /* Could skip this message ? */ + printf("%-8.8s no private ioctls.\n", ifname); + } else { + for (i = 0; i < priv_cnt; i++) { + if (priv_args[i].name[0] && + !strcmp(priv_args[i].name, priv_cmd)) { + ret = nxp_get_subioctl_no(i, priv_cnt, + ioctl_val, + subioctl_val); + break; + } + } + } + + if (priv_args) { + free(priv_args); + priv_args = NULL; + } + + return ret; +} + +/** + * @brief Retrieve the ioctl and sub-ioctl numbers for the given ioctl string + * + * @param ioctl_name Private IOCTL string name + * @param ioctl_val A pointer to return ioctl number + * @param subioctl_val A pointer to return sub-ioctl number + * + * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE + */ +int +get_priv_ioctl(char *ioctl_name, int *ioctl_val, int *subioctl_val) +{ + int retval; + + retval = nxp_get_ioctl_no(dev_name, + ioctl_name, ioctl_val, subioctl_val); + + return retval; +} + +/** + * @brief Process host_cmd + * @param argc number of arguments + * @param argv A pointer to arguments array + * @return MLAN_STATUS_SUCCESS--success, otherwise--fail + */ +static int +process_host_cmd(int argc, char *argv[]) +{ + t_s8 cmdname[256]; + t_u8 *buf; + HostCmd_DS_GEN *hostcmd; + struct iwreq iwr; + int ret = MLAN_STATUS_SUCCESS; + int ioctl_val, subioctl_val; + FILE *fp = NULL; + + if (get_priv_ioctl("hostcmd", + &ioctl_val, &subioctl_val) == MLAN_STATUS_FAILURE) { + return -EOPNOTSUPP; + } + + if (argc < 5) { + printf("Error: invalid no of arguments\n"); + printf("Syntax: ./mlanconfig mlanX hostcmd \n"); + exit(1); + } + + if ((fp = fopen(argv[3], "r")) == NULL) { + fprintf(stderr, "Cannot open file %s\n", argv[3]); + exit(1); + } + + buf = (t_u8 *)malloc(MRVDRV_SIZE_OF_CMD_BUFFER); + if (buf == NULL) { + printf("Error: allocate memory for hostcmd failed\n"); + fclose(fp); + return -ENOMEM; + } + snprintf(cmdname, sizeof(cmdname), "%s", argv[4]); + ret = prepare_host_cmd_buffer(fp, cmdname, buf); + fclose(fp); + + if (ret == MLAN_STATUS_FAILURE) + goto _exit_; + + hostcmd = (HostCmd_DS_GEN *)buf; + memset(&iwr, 0, sizeof(iwr)); + strncpy(iwr.ifr_name, dev_name, IFNAMSIZ - 1); + iwr.u.data.pointer = (t_u8 *)hostcmd; + iwr.u.data.length = le16_to_cpu(hostcmd->size); + + iwr.u.data.flags = 0; + if (ioctl(sockfd, ioctl_val, &iwr)) { + fprintf(stderr, + "mlanconfig: MLANHOSTCMD is not supported by %s\n", + dev_name); + ret = MLAN_STATUS_FAILURE; + goto _exit_; + } + ret = process_host_cmd_resp(buf); + +_exit_: + if (buf) + free(buf); + + return ret; +} + +/** + * @brief get range + * + * @return MLAN_STATUS_SUCCESS--success, otherwise --fail + */ +static int +get_range(t_void) +{ + struct iw_range *range; + struct iwreq iwr; + size_t buf_len; + + buf_len = sizeof(struct iw_range) + 500; + range = malloc(buf_len); + if (range == NULL) { + printf("Error: allocate memory for iw_range failed\n"); + return -ENOMEM; + } + memset(range, 0, buf_len); + memset(&iwr, 0, sizeof(struct iwreq)); + iwr.u.data.pointer = (caddr_t) range; + iwr.u.data.length = buf_len; + strncpy(iwr.ifr_name, dev_name, IFNAMSIZ - 1); + + if ((ioctl(sockfd, SIOCGIWRANGE, &iwr)) < 0) { + printf("Get Range Results Failed\n"); + free(range); + return MLAN_STATUS_FAILURE; + } + we_version_compiled = range->we_version_compiled; + printf("Driver build with Wireless Extension %d\n", + range->we_version_compiled); + free(range); + return MLAN_STATUS_SUCCESS; +} + +/** + * @brief Display usage + * + * @return NA + */ +static t_void +display_usage(t_void) +{ + t_u32 i; + for (i = 0; i < NELEMENTS(usage); i++) + fprintf(stderr, "%s\n", usage[i]); +} + +/** + * @brief Find command + * + * @param maxcmds max command number + * @param cmds A pointer to commands buffer + * @param cmd A pointer to command buffer + * @return index of command or MLAN_STATUS_FAILURE + */ +static int +findcommand(t_s32 maxcmds, t_s8 *cmds[], t_s8 *cmd) +{ + t_s32 i; + + for (i = 0; i < maxcmds; i++) { + if (!strcasecmp(cmds[i], cmd)) { + return i; + } + } + + return MLAN_STATUS_FAILURE; +} + +/** + * @brief Process cfgdata + * @param argc number of arguments + * @param argv A pointer to arguments array + * @return MLAN_STATUS_SUCCESS--success, otherwise--fail + */ +static int +process_cfg_data(int argc, char *argv[]) +{ + t_u8 *buf; + HostCmd_DS_GEN *hostcmd; + struct iwreq iwr; + int ret = MLAN_STATUS_SUCCESS; + int ioctl_val, subioctl_val; + FILE *fp = NULL; + + if (get_priv_ioctl("hostcmd", + &ioctl_val, &subioctl_val) == MLAN_STATUS_FAILURE) { + return -EOPNOTSUPP; + } + + if (argc < 4 || argc > 5) { + printf("Error: invalid no of arguments\n"); + printf("Syntax: ./mlanconfig mlanX cfgdata \n"); + exit(1); + } + + if (argc == 5) { + if ((fp = fopen(argv[4], "r")) == NULL) { + fprintf(stderr, "Cannot open file %s\n", argv[3]); + exit(1); + } + } + buf = (t_u8 *)malloc(MRVDRV_SIZE_OF_CMD_BUFFER); + if (buf == NULL) { + printf("Error: allocate memory for hostcmd failed\n"); + if (argc == 5) + fclose(fp); + return -ENOMEM; + } + ret = prepare_cfg_data_buffer(argc, argv, fp, buf); + if (argc == 5) + fclose(fp); + + if (ret == MLAN_STATUS_FAILURE) + goto _exit_; + + hostcmd = (HostCmd_DS_GEN *)buf; + memset(&iwr, 0, sizeof(iwr)); + strncpy(iwr.ifr_name, dev_name, IFNAMSIZ - 1); + iwr.u.data.pointer = (t_u8 *)hostcmd; + iwr.u.data.length = le16_to_cpu(hostcmd->size); + + iwr.u.data.flags = 0; + if (ioctl(sockfd, ioctl_val, &iwr)) { + fprintf(stderr, + "mlanconfig: MLANHOSTCMD is not supported by %s\n", + dev_name); + ret = MLAN_STATUS_FAILURE; + goto _exit_; + } + ret = process_host_cmd_resp(buf); + +_exit_: + if (buf) + free(buf); + + return ret; +} + +/** + * @brief read current command + * @param ptr A pointer to data + * @param curCmd A pointer to the buf which will hold current command + * @return NULL or the pointer to the left command buf + */ +static t_s8 * +readCurCmd(t_s8 *ptr, t_s8 *curCmd) +{ + t_s32 i = 0; +#define MAX_CMD_SIZE 64 /**< Max command size */ + + while (*ptr != ']' && i < (MAX_CMD_SIZE - 1)) + curCmd[i++] = *(++ptr); + + if (*ptr != ']') + return NULL; + + curCmd[i - 1] = '\0'; + + return ++ptr; +} + +/** + * @brief parse command and hex data + * @param fp A pointer to FILE stream + * @param dst A pointer to the dest buf + * @param cmd A pointer to command buf for search + * @return Length of hex data or MLAN_STATUS_FAILURE + */ +static int +fparse_for_cmd_and_hex(FILE * fp, t_u8 *dst, t_u8 *cmd) +{ + t_s8 *ptr; + t_u8 *dptr; + t_s8 buf[256], curCmd[64]; + t_s32 isCurCmd = 0; + + dptr = dst; + while (fgets(buf, sizeof(buf), fp)) { + ptr = buf; + + while (*ptr) { + /* skip leading spaces */ + while (*ptr && isspace(*ptr)) + ptr++; + + /* skip blank lines and lines beginning with '#' */ + if (*ptr == '\0' || *ptr == '#') + break; + + if (*ptr == '[' && *(ptr + 1) != '/') { + if (!(ptr = readCurCmd(ptr, curCmd))) + return MLAN_STATUS_FAILURE; + + if (strcasecmp(curCmd, (char *)cmd)) /* Not equal */ + isCurCmd = 0; + else + isCurCmd = 1; + } + + /* Ignore the rest if it is not correct cmd */ + if (!isCurCmd) + break; + + if (*ptr == '[' && *(ptr + 1) == '/') + return (dptr - dst); + + if (isxdigit(*ptr)) { + ptr = convert2hex(ptr, dptr++); + } else { + /* Invalid character on data line */ + ptr++; + } + } + } + + return MLAN_STATUS_FAILURE; +} + +/** + * @brief Send an ADDTS command to the associated AP + * + * Process a given conf file for a specific TSPEC data block. Send the + * TSPEC along with any other IEs to the driver/firmware for transmission + * in an ADDTS request to the associated AP. + * + * Return the execution status of the command as well as the ADDTS response + * from the AP if any. + * + * mlanconfig mlanX addts + * + * @param argc number of arguments + * @param argv A pointer to arguments array + * + * @return MLAN_STATUS_SUCCESS--success, otherwise--fail + */ +static int +process_addts(int argc, char *argv[]) +{ + int ioctl_val, subioctl_val; + struct iwreq iwr; + wlan_ioctl_wmm_addts_req_t addtsReq; + + FILE *fp = NULL; + char filename[48]; + char config_id[20]; + + memset(&addtsReq, 0x00, sizeof(addtsReq)); + memset(filename, 0x00, sizeof(filename)); + + if (get_priv_ioctl("addts", + &ioctl_val, &subioctl_val) == MLAN_STATUS_FAILURE) { + return -EOPNOTSUPP; + } + + if (argc != 6) { + fprintf(stderr, "Invalid number of parameters!\n"); + return -EINVAL; + } + + strncpy(filename, argv[3], sizeof(filename) - 1); + + if ((fp = fopen(filename, "r")) == NULL) { + perror("fopen"); + fprintf(stderr, "Cannot open file %s\n", argv[3]); + return -EFAULT;; + } + + snprintf(config_id, sizeof(config_id), "tspec%d", atoi(argv[4])); + + addtsReq.ieDataLen = fparse_for_cmd_and_hex(fp, + addtsReq.ieData, + (t_u8 *)config_id); + + if (addtsReq.ieDataLen > 0) { + printf("Found %d bytes in the %s section of conf file %s\n", + (int)addtsReq.ieDataLen, config_id, filename); + } else { + fprintf(stderr, "section %s not found in %s\n", + config_id, filename); + if (fp) + fclose(fp); + return -EFAULT; + } + + addtsReq.timeout_ms = atoi(argv[5]); + + printf("Cmd Input:\n"); + hexdump(config_id, addtsReq.ieData, addtsReq.ieDataLen, ' '); + + strncpy(iwr.ifr_name, dev_name, IFNAMSIZ - 1); + iwr.u.data.flags = subioctl_val; + iwr.u.data.pointer = (caddr_t) & addtsReq; + iwr.u.data.length = (sizeof(addtsReq) + - sizeof(addtsReq.ieData) + + addtsReq.ieDataLen); + + if (ioctl(sockfd, ioctl_val, &iwr) < 0) { + perror("mlanconfig: addts ioctl"); + if (fp) + fclose(fp); + return -EFAULT; + } + + printf("Cmd Output:\n"); + printf("ADDTS Command Result = %d\n", addtsReq.commandResult); + printf("ADDTS IEEE Status = %d\n", addtsReq.ieeeStatusCode); + hexdump(config_id, addtsReq.ieData, addtsReq.ieDataLen, ' '); + + if (fp) + fclose(fp); + + return MLAN_STATUS_SUCCESS; +} + +/** + * @brief Send a DELTS command to the associated AP + * + * Process a given conf file for a specific TSPEC data block. Send the + * TSPEC along with any other IEs to the driver/firmware for transmission + * in a DELTS request to the associated AP. + * + * Return the execution status of the command. There is no response to a + * DELTS from the AP. + * + * mlanconfig mlanX delts + * + * @param argc number of arguments + * @param argv A pointer to arguments array + * + * @return MLAN_STATUS_SUCCESS--success, otherwise--fail + */ +static int +process_delts(int argc, char *argv[]) +{ + int ioctl_val, subioctl_val; + struct iwreq iwr; + wlan_ioctl_wmm_delts_req_t deltsReq; + + FILE *fp = NULL; + char filename[48]; + char config_id[20]; + + memset(&deltsReq, 0x00, sizeof(deltsReq)); + memset(filename, 0x00, sizeof(filename)); + + if (get_priv_ioctl("delts", + &ioctl_val, &subioctl_val) == MLAN_STATUS_FAILURE) { + return -EOPNOTSUPP; + } + + if (argc != 5) { + fprintf(stderr, "Invalid number of parameters!\n"); + return -EINVAL; + } + + strncpy(filename, argv[3], sizeof(filename) - 1); + + if ((fp = fopen(filename, "r")) == NULL) { + perror("fopen"); + fprintf(stderr, "Cannot open file %s\n", argv[3]); + return -EFAULT; + } + + snprintf(config_id, sizeof(config_id), "tspec%d", atoi(argv[4])); + + deltsReq.ieDataLen = fparse_for_cmd_and_hex(fp, + deltsReq.ieData, + (t_u8 *)config_id); + + if (deltsReq.ieDataLen > 0) { + printf("Found %d bytes in the %s section of conf file %s\n", + (int)deltsReq.ieDataLen, config_id, filename); + } else { + fprintf(stderr, "section %s not found in %s\n", + config_id, filename); + if (fp) + fclose(fp); + return -EFAULT; + } + + printf("Cmd Input:\n"); + hexdump(config_id, deltsReq.ieData, deltsReq.ieDataLen, ' '); + + strncpy(iwr.ifr_name, dev_name, IFNAMSIZ - 1); + iwr.u.data.flags = subioctl_val; + iwr.u.data.pointer = (caddr_t) & deltsReq; + iwr.u.data.length = (sizeof(deltsReq) + - sizeof(deltsReq.ieData) + + deltsReq.ieDataLen); + + if (ioctl(sockfd, ioctl_val, &iwr) < 0) { + perror("mlanconfig: delts ioctl"); + if (fp) + fclose(fp); + return -EFAULT; + } + + printf("Cmd Output:\n"); + printf("DELTS Command Result = %d\n", deltsReq.commandResult); + if (fp) + fclose(fp); + + return MLAN_STATUS_SUCCESS; +} + +/** + * @brief Send a WMM AC Queue configuration command to get/set/default params + * + * Configure or get the parameters of a WMM AC queue. The command takes + * an optional Queue Id as a last parameter. Without the queue id, all + * queues will be acted upon. + * + * mlanconfig mlanX qconfig set msdu [Queue Id: 0-3] + * mlanconfig mlanX qconfig get [Queue Id: 0-3] + * mlanconfig mlanX qconfig def [Queue Id: 0-3] + * + * @param argc number of arguments + * @param argv A pointer to arguments array + * + * @return MLAN_STATUS_SUCCESS--success, otherwise--fail + */ +static int +process_qconfig(int argc, char *argv[]) +{ + int ioctl_val, subioctl_val; + struct iwreq iwr; + wlan_ioctl_wmm_queue_config_t queue_config_cmd; + mlan_wmm_ac_e ac_idx; + mlan_wmm_ac_e ac_idx_start; + mlan_wmm_ac_e ac_idx_stop; + + const char *ac_str_tbl[] = { "BK", "BE", "VI", "VO" }; + + if (argc < 4) { + fprintf(stderr, "Invalid number of parameters!\n"); + return -EINVAL; + } + + if (get_priv_ioctl("qconfig", + &ioctl_val, &subioctl_val) == MLAN_STATUS_FAILURE) { + return -EOPNOTSUPP; + } + + memset(&queue_config_cmd, 0x00, sizeof(queue_config_cmd)); + strncpy(iwr.ifr_name, dev_name, IFNAMSIZ - 1); + iwr.u.data.pointer = (caddr_t) & queue_config_cmd; + iwr.u.data.length = sizeof(queue_config_cmd); + iwr.u.data.flags = subioctl_val; + + if (strcmp(argv[3], "get") == 0) { + /* 3 4 5 */ + /* qconfig get [qid] */ + if (argc == 4) { + ac_idx_start = WMM_AC_BK; + ac_idx_stop = WMM_AC_VO; + } else if (argc == 5) { + if (atoi(argv[4]) < WMM_AC_BK || + atoi(argv[4]) > WMM_AC_VO) { + fprintf(stderr, "ERROR: Invalid Queue ID!\n"); + return -EINVAL; + } + ac_idx_start = atoi(argv[4]); + ac_idx_stop = ac_idx_start; + } else { + fprintf(stderr, "Invalid number of parameters!\n"); + return -EINVAL; + } + queue_config_cmd.action = WMM_QUEUE_CONFIG_ACTION_GET; + + for (ac_idx = ac_idx_start; ac_idx <= ac_idx_stop; ac_idx++) { + queue_config_cmd.accessCategory = ac_idx; + if (ioctl(sockfd, ioctl_val, &iwr) < 0) { + perror("qconfig ioctl"); + } else { + printf("qconfig %s(%d): MSDU Lifetime GET = 0x%04x (%d)\n", ac_str_tbl[ac_idx], ac_idx, queue_config_cmd.msduLifetimeExpiry, queue_config_cmd.msduLifetimeExpiry); + } + } + } else if (strcmp(argv[3], "set") == 0) { + if ((argc >= 5) && strcmp(argv[4], "msdu") == 0) { + /* 3 4 5 6 7 */ + /* qconfig set msdu [qid] */ + if (argc == 6) { + ac_idx_start = WMM_AC_BK; + ac_idx_stop = WMM_AC_VO; + } else if (argc == 7) { + if (atoi(argv[6]) < WMM_AC_BK || + atoi(argv[6]) > WMM_AC_VO) { + fprintf(stderr, + "ERROR: Invalid Queue ID!\n"); + return -EINVAL; + } + ac_idx_start = atoi(argv[6]); + ac_idx_stop = ac_idx_start; + } else { + fprintf(stderr, + "Invalid number of parameters!\n"); + return -EINVAL; + } + queue_config_cmd.action = WMM_QUEUE_CONFIG_ACTION_SET; + queue_config_cmd.msduLifetimeExpiry = atoi(argv[5]); + + for (ac_idx = ac_idx_start; ac_idx <= ac_idx_stop; + ac_idx++) { + queue_config_cmd.accessCategory = ac_idx; + if (ioctl(sockfd, ioctl_val, &iwr) < 0) { + perror("qconfig ioctl"); + } else { + printf("qconfig %s(%d): MSDU Lifetime SET = 0x%04x (%d)\n", ac_str_tbl[ac_idx], ac_idx, queue_config_cmd.msduLifetimeExpiry, queue_config_cmd.msduLifetimeExpiry); + } + } + } else { + /* Only MSDU Lifetime provisioning accepted for now */ + fprintf(stderr, "Invalid set parameter: s/b [msdu]\n"); + return -EINVAL; + } + } else if (strncmp(argv[3], "def", strlen("def")) == 0) { + /* 3 4 5 */ + /* qconfig def [qid] */ + if (argc == 4) { + ac_idx_start = WMM_AC_BK; + ac_idx_stop = WMM_AC_VO; + } else if (argc == 5) { + if (atoi(argv[4]) < WMM_AC_BK || + atoi(argv[4]) > WMM_AC_VO) { + fprintf(stderr, "ERROR: Invalid Queue ID!\n"); + return -EINVAL; + } + ac_idx_start = atoi(argv[4]); + ac_idx_stop = ac_idx_start; + } else { + fprintf(stderr, "Invalid number of parameters!\n"); + return -EINVAL; + } + queue_config_cmd.action = WMM_QUEUE_CONFIG_ACTION_DEFAULT; + + for (ac_idx = ac_idx_start; ac_idx <= ac_idx_stop; ac_idx++) { + queue_config_cmd.accessCategory = ac_idx; + if (ioctl(sockfd, ioctl_val, &iwr) < 0) { + perror("qconfig ioctl"); + } else { + printf("qconfig %s(%d): MSDU Lifetime DEFAULT = 0x%04x (%d)\n", ac_str_tbl[ac_idx], ac_idx, queue_config_cmd.msduLifetimeExpiry, queue_config_cmd.msduLifetimeExpiry); + } + } + } else { + fprintf(stderr, + "Invalid qconfig command; s/b [set, get, default]\n"); + return -EINVAL; + } + + return MLAN_STATUS_SUCCESS; +} + +/** + * @brief Turn on/off or retrieve and clear the queue statistics for a UP + * + * Turn the statistics collection on/off for a given UP or retrieve the + * current accumulated stats and clear them from the firmware. The command + * takes an optional Queue Id as a last parameter. Without the queue id, + * all queues will be acted upon. + * + * mlanconfig mlanX qstats get [User Priority: 0-7] + * + * @param argc number of arguments + * @param argv A pointer to arguments array + * + * @return MLAN_STATUS_SUCCESS--success, otherwise--fail + */ +static int +process_qstats(int argc, char *argv[]) +{ + int ioctl_val, subioctl_val; + struct iwreq iwr; + wlan_ioctl_wmm_queue_stats_t queue_stats_cmd; + t_u8 up_idx; + t_u8 up_idx_start; + t_u8 up_idx_stop; + t_u16 usedTime[MAX_USER_PRIORITIES]; + t_u16 policedTime[MAX_USER_PRIORITIES]; + + const char *ac_str_tbl[] = { "BE", "BK", "BK", "BE", + "VI", "VI", "VO", "VO" + }; + + if (argc < 3) { + fprintf(stderr, "Invalid number of parameters!\n"); + return -EINVAL; + } + + if (get_priv_ioctl("qstats", + &ioctl_val, &subioctl_val) == MLAN_STATUS_FAILURE) { + return -EOPNOTSUPP; + } + + printf("\n"); + + memset(usedTime, 0x00, sizeof(usedTime)); + memset(policedTime, 0x00, sizeof(policedTime)); + memset(&queue_stats_cmd, 0x00, sizeof(queue_stats_cmd)); + + strncpy(iwr.ifr_name, dev_name, IFNAMSIZ - 1); + iwr.u.data.pointer = (caddr_t) & queue_stats_cmd; + iwr.u.data.length = sizeof(queue_stats_cmd); + iwr.u.data.flags = subioctl_val; + + if ((argc > 3) && strcmp(argv[3], "on") == 0) { + if (argc == 4) { + up_idx_start = 0; + up_idx_stop = 7; + } else if (argc == 5) { + if (atoi(argv[4]) < 0 || atoi(argv[4]) > 7) { + fprintf(stderr, + "ERROR: Invalid User Priority!\n"); + return -EINVAL; + } + up_idx_start = atoi(argv[4]); + up_idx_stop = up_idx_start; + } else { + fprintf(stderr, "Invalid number of parameters!\n"); + return -EINVAL; + } + queue_stats_cmd.action = WMM_STATS_ACTION_START; + for (up_idx = up_idx_start; up_idx <= up_idx_stop; up_idx++) { + queue_stats_cmd.userPriority = up_idx; + if (ioctl(sockfd, ioctl_val, &iwr) < 0) { + perror("qstats ioctl"); + } else { + printf("qstats UP%d, %s turned on\n", + up_idx, ac_str_tbl[up_idx]); + } + } + } else if ((argc > 3) && strcmp(argv[3], "off") == 0) { + if (argc == 4) { + up_idx_start = 0; + up_idx_stop = 7; + } else if (argc == 5) { + if (atoi(argv[4]) < 0 || atoi(argv[4]) > 7) { + fprintf(stderr, + "ERROR: Invalid User Priority!\n"); + return -EINVAL; + } + up_idx_start = atoi(argv[4]); + up_idx_stop = up_idx_start; + } else { + fprintf(stderr, "Invalid number of parameters!\n"); + return -EINVAL; + } + queue_stats_cmd.action = WMM_STATS_ACTION_STOP; + for (up_idx = up_idx_start; up_idx <= up_idx_stop; up_idx++) { + queue_stats_cmd.userPriority = up_idx; + if (ioctl(sockfd, ioctl_val, &iwr) < 0) { + perror("qstats ioctl"); + } else { + printf("qstats UP%d, %s turned off\n", + up_idx, ac_str_tbl[up_idx]); + } + } + } else if ((argc >= 3) && + ((argc == 3) ? 1 : (strcmp(argv[3], "get") == 0))) { + /* If the user types: "mlanconfig mlanX qstats" without get argument. + * The mlanconfig application invokes "get" option for all UPs + */ + if ((argc == 4) || (argc == 3)) { + up_idx_start = 0; + up_idx_stop = 7; + } else if (argc == 5) { + if (atoi(argv[4]) < 0 || atoi(argv[4]) > 7) { + fprintf(stderr, + "ERROR: Invalid User Priority!\n"); + return -EINVAL; + } + up_idx_start = atoi(argv[4]); + up_idx_stop = up_idx_start; + } else { + fprintf(stderr, "Invalid number of parameters!\n"); + return -EINVAL; + } + printf("%s %6s %5s %8s %8s %6s %6s %6s %6s %6s %6s\n", + "AC-UP", "Count", "Loss", "TxDly", "QDly", + "<=5", "<=10", "<=20", "<=30", "<=50", ">50"); + printf("----------------------------------" + "---------------------------------------------\n"); + queue_stats_cmd.action = WMM_STATS_ACTION_GET_CLR; + + for (up_idx = up_idx_start; up_idx <= up_idx_stop; up_idx++) { + queue_stats_cmd.userPriority = up_idx; + if (ioctl(sockfd, ioctl_val, &iwr) < 0) { + perror("qstats ioctl"); + } else { + printf(" %s-%d %6u %5u %8u %8u %6u %6u %6u %6u %6u %6u\n", ac_str_tbl[up_idx], up_idx, queue_stats_cmd.pktCount, queue_stats_cmd.pktLoss, (unsigned int)queue_stats_cmd.avgTxDelay, (unsigned int)queue_stats_cmd.avgQueueDelay, queue_stats_cmd.delayHistogram[0], queue_stats_cmd.delayHistogram[1], queue_stats_cmd.delayHistogram[2], queue_stats_cmd.delayHistogram[3], (queue_stats_cmd.delayHistogram[4] + queue_stats_cmd.delayHistogram[5]), queue_stats_cmd.delayHistogram[6]); + + usedTime[up_idx] = queue_stats_cmd.usedTime; + policedTime[up_idx] = + queue_stats_cmd.policedTime; + } + } + + printf("----------------------------------" + "---------------------------------------------\n"); + printf("\nAC-UP UsedTime PolicedTime\n"); + printf("------------------------------------\n"); + + for (up_idx = up_idx_start; up_idx <= up_idx_stop; up_idx++) { + printf(" %s-%d %6u %6u\n", + ac_str_tbl[up_idx], + up_idx, + (unsigned int)usedTime[up_idx], + (unsigned int)policedTime[up_idx]); + } + } else { + fprintf(stderr, "Invalid qstats command;\n"); + return -EINVAL; + } + printf("\n"); + + return MLAN_STATUS_SUCCESS; +} + +/** + * @brief Get the current status of the WMM Queues + * + * Command: mlanconfig mlanX qstatus + * + * Retrieve the following information for each AC if wmm is enabled: + * - WMM IE ACM Required + * - Firmware Flow Required + * - Firmware Flow Established + * - Firmware Queue Enabled + * + * @param argc number of arguments + * @param argv A pointer to arguments array + * + * @return MLAN_STATUS_SUCCESS--success, otherwise--fail + */ +static int +process_wmm_qstatus(int argc, char *argv[]) +{ + int ioctl_val, subioctl_val; + struct iwreq iwr; + wlan_ioctl_wmm_queue_status_t qstatus; + mlan_wmm_ac_e acVal; + + if (get_priv_ioctl("qstatus", + &ioctl_val, &subioctl_val) == MLAN_STATUS_FAILURE) { + return -EOPNOTSUPP; + } + + memset(&qstatus, 0x00, sizeof(qstatus)); + + strncpy(iwr.ifr_name, dev_name, IFNAMSIZ - 1); + iwr.u.data.flags = subioctl_val; + iwr.u.data.pointer = (caddr_t) & qstatus; + iwr.u.data.length = (sizeof(qstatus)); + + if (ioctl(sockfd, ioctl_val, &iwr) < 0) { + perror("mlanconfig: qstatus ioctl"); + return -EFAULT; + } + + for (acVal = WMM_AC_BK; acVal <= WMM_AC_VO; acVal++) { + switch (acVal) { + case WMM_AC_BK: + printf("BK: "); + break; + case WMM_AC_BE: + printf("BE: "); + break; + case WMM_AC_VI: + printf("VI: "); + break; + case WMM_AC_VO: + printf("VO: "); + break; + default: + printf("??: "); + } + + printf("ACM[%c], FlowReq[%c], FlowCreated[%c], Enabled[%c]," + " DE[%c], TE[%c]\n", + (qstatus.acStatus[acVal].wmmAcm ? 'X' : ' '), + (qstatus.acStatus[acVal].flowRequired ? 'X' : ' '), + (qstatus.acStatus[acVal].flowCreated ? 'X' : ' '), + (qstatus.acStatus[acVal].disabled ? ' ' : 'X'), + (qstatus.acStatus[acVal].deliveryEnabled ? 'X' : ' '), + (qstatus.acStatus[acVal].triggerEnabled ? 'X' : ' ')); + } + + return MLAN_STATUS_SUCCESS; +} + +/** + * @brief Get the current status of the WMM Traffic Streams + * + * Command: mlanconfig mlanX ts_status + * + * @param argc number of arguments + * @param argv A pointer to arguments array + * + * @return MLAN_STATUS_SUCCESS--success, otherwise--fail + */ +static int +process_wmm_ts_status(int argc, char *argv[]) +{ + int ioctl_val, subioctl_val; + struct iwreq iwr; + wlan_ioctl_wmm_ts_status_t ts_status; + int tid; + + const char *ac_str_tbl[] = { "BK", "BE", "VI", "VO" }; + + if (get_priv_ioctl("ts_status", + &ioctl_val, &subioctl_val) == MLAN_STATUS_FAILURE) { + return -EOPNOTSUPP; + } + + printf("\nTID Valid AC UP PSB FlowDir MediumTime\n"); + printf("---------------------------------------------------\n"); + + for (tid = 0; tid <= 7; tid++) { + memset(&ts_status, 0x00, sizeof(ts_status)); + ts_status.tid = tid; + + strncpy(iwr.ifr_name, dev_name, IFNAMSIZ - 1); + iwr.u.data.flags = subioctl_val; + iwr.u.data.pointer = (caddr_t) & ts_status; + iwr.u.data.length = (sizeof(ts_status)); + + if (ioctl(sockfd, ioctl_val, &iwr) < 0) { + perror("mlanconfig: ts_status ioctl"); + return -EFAULT; + } + + printf(" %02d %3s %2s %u %c ", + ts_status.tid, + (ts_status.valid ? "Yes" : "No"), + (ts_status. + valid ? ac_str_tbl[ts_status.accessCategory] : "--"), + ts_status.userPriority, (ts_status.psb ? 'U' : 'L')); + + if ((ts_status.flowDir & 0x03) == 0) { + printf("%s", " ---- "); + } else { + printf("%2s%4s", + (ts_status.flowDir & 0x01 ? "Up" : ""), + (ts_status.flowDir & 0x02 ? "Down" : "")); + } + + printf("%12u\n", ts_status.mediumTime); + } + + printf("\n"); + + return MLAN_STATUS_SUCCESS; +} + +/** + * @brief Provides interface to perform read/write operations on regsiter + * + * Command: mlanconfig mlanX regrdwr [value] + * + * @param argc Number of arguments + * @param argv Pointer to the arguments + * + * @return MLAN_STATUS_SUCCESS--success, otherwise--fail + */ +static int +process_regrdwr(int argc, char *argv[]) +{ + struct iwreq iwr; + int ioctl_val, subioctl_val; + t_u32 type, offset, value; + t_u8 buf[100]; + HostCmd_DS_GEN *hostcmd = (HostCmd_DS_GEN *)buf; + int ret = MLAN_STATUS_SUCCESS; + + /* Check arguments */ + if ((argc < 5) || (argc > 6)) { + printf("Parameters for regrdwr: [value]\n"); + return -EINVAL; + } + + if (get_priv_ioctl("hostcmd", + &ioctl_val, &subioctl_val) == MLAN_STATUS_FAILURE) { + return -EOPNOTSUPP; + } + + type = a2hex_or_atoi(argv[3]); + offset = a2hex_or_atoi(argv[4]); + if (argc > 5) + value = a2hex_or_atoi(argv[5]); + if ((ret = prepare_hostcmd_regrdwr(type, offset, + (argc > 5) ? &value : NULL, buf))) { + return ret; + } + + memset(&iwr, 0, sizeof(iwr)); + strncpy(iwr.ifr_name, dev_name, IFNAMSIZ - 1); + iwr.u.data.pointer = buf; + iwr.u.data.length = le16_to_cpu(hostcmd->size); + iwr.u.data.flags = 0; + + if (ioctl(sockfd, ioctl_val, &iwr)) { + fprintf(stderr, + "mlanconfig: MLANHOSTCMD is not supported by %s\n", + dev_name); + return MLAN_STATUS_FAILURE; + } + ret = process_host_cmd_resp(buf); + + return ret; +} + +/** + * @brief Provides interface to perform read/write the adapter memory + * + * Command: mlanconfig mlanX memrdwr
[value] + * + * @param argc Number of arguments + * @param argv Pointer to the arguments + * + * @return MLAN_STATUS_SUCCESS--success, otherwise--fail + */ +static int +process_memrdwr(int argc, char *argv[]) +{ + struct iwreq iwr; + int ioctl_val, subioctl_val; + t_u32 address, value; + t_u8 buf[100] = { 0 }; + HostCmd_DS_MEM *pmem; + HostCmd_DS_GEN *hostcmd = (HostCmd_DS_GEN *)buf; + int ret = MLAN_STATUS_SUCCESS; + + pmem = (HostCmd_DS_MEM *)(buf + S_DS_GEN); + + /* Check arguments */ + if ((argc < 4) || (argc > 5)) { + printf("Parameters for memrdwr:
[value]\n"); + return -EINVAL; + } + + if (get_priv_ioctl("hostcmd", + &ioctl_val, &subioctl_val) == MLAN_STATUS_FAILURE) { + return -EOPNOTSUPP; + } + + address = a2hex_or_atoi(argv[3]); + pmem->addr = cpu_to_le32(address); + if (argc > 4) { + pmem->action = cpu_to_le16(HostCmd_ACT_GEN_SET); + value = a2hex_or_atoi(argv[4]); + pmem->value = cpu_to_le32(value); + } else { + pmem->action = cpu_to_le16(HostCmd_ACT_GEN_GET); + pmem->value = 0; + } + hostcmd->command = cpu_to_le16(HostCmd_CMD_MEM_ACCESS); + hostcmd->size = cpu_to_le16(S_DS_GEN + sizeof(HostCmd_DS_MEM)); + hostcmd->seq_num = 0; + hostcmd->result = 0; + + memset(&iwr, 0, sizeof(iwr)); + strncpy(iwr.ifr_name, dev_name, IFNAMSIZ - 1); + iwr.u.data.pointer = buf; + iwr.u.data.length = le16_to_cpu(hostcmd->size); + iwr.u.data.flags = 0; + + if (ioctl(sockfd, ioctl_val, &iwr)) { + fprintf(stderr, + "mlanconfig: MLANHOSTCMD is not supported by %s\n", + dev_name); + return MLAN_STATUS_FAILURE; + } + ret = process_host_cmd_resp(buf); + + return ret; +} + +/** custom IE, auto mask value */ +#define CUSTOM_IE_AUTO_MASK 0xffff + +/** + * @brief Show usage information for the customie + * command + * + * $return N/A + **/ +void +print_custom_ie_usage(void) +{ + printf("\nUsage : customie [INDEX] [MASK] [IEBuffer]"); + printf("\n empty - Get all IE settings\n"); + printf("\n INDEX: 0 - Get/Set IE index 0 setting"); + printf("\n 1 - Get/Set IE index 1 setting"); + printf("\n 2 - Get/Set IE index 2 setting"); + printf("\n 3 - Get/Set IE index 3 setting"); + printf("\n . "); + printf("\n . "); + printf("\n . "); + printf("\n -1 - Append/Delete IE automatically"); + printf("\n Delete will delete the IE from the matching IE buffer"); + printf("\n Append will append the IE to the buffer with the same mask"); + printf("\n MASK : Management subtype mask value as per bit defintions"); + printf("\n : Bit 0 - Association request."); + printf("\n : Bit 1 - Association response."); + printf("\n : Bit 2 - Reassociation request."); + printf("\n : Bit 3 - Reassociation response."); + printf("\n : Bit 4 - Probe request."); + printf("\n : Bit 5 - Probe response."); + printf("\n : Bit 8 - Beacon."); + printf("\n MASK : MASK = 0 to clear the mask and the IE buffer"); + printf("\n IEBuffer : IE Buffer in hex (max 256 bytes)\n\n"); + return; +} + +/** + * @brief Converts a string to hex value + * + * @param str A pointer to the string + * @param raw A pointer to the raw data buffer + * @return Number of bytes read + **/ +int +string2raw(char *str, unsigned char *raw) +{ + int len = (strlen(str) + 1) / 2; + + do { + if (!isxdigit(*str)) { + return -1; + } + *str = toupper(*str); + *raw = CHAR2INT(*str) << 4; + ++str; + *str = toupper(*str); + if (*str == '\0') + break; + *raw |= CHAR2INT(*str); + ++raw; + } while (*++str != '\0'); + return len; +} + +/** + * @brief Creates a hostcmd request for custom IE settings + * and sends to the driver + * + * Usage: "customie [INDEX] [MASK] [IEBuffer]" + * + * Options: INDEX : 0 - Get/Delete IE index 0 setting + * 1 - Get/Delete IE index 1 setting + * 2 - Get/Delete IE index 2 setting + * 3 - Get/Delete IE index 3 setting + * . + * . + * . + * -1 - Append IE at the IE buffer with same MASK + * MASK : Management subtype mask value + * IEBuffer: IE Buffer in hex + * empty - Get all IE settings + * + * @param argc Number of arguments + * @param argv Pointer to the arguments + * @return N/A + **/ +static int +process_custom_ie(int argc, char *argv[]) +{ + tlvbuf_custom_ie *tlv = NULL; + tlvbuf_max_mgmt_ie *max_mgmt_ie_tlv = NULL; + custom_ie *ie_ptr = NULL; + t_u8 *buffer = NULL; + t_u16 buf_len = 0; + t_u16 mgmt_subtype_mask = 0; + int ie_buf_len = 0, ie_len = 0, i = 0; + struct ifreq ifr; + + /* mlanconfig mlan0 customie idx flag buf */ + if (argc > 6) { + printf("ERR:Too many arguments.\n"); + print_custom_ie_usage(); + return MLAN_STATUS_FAILURE; + } + /* Error checks and initialize the command length */ + if (argc > 3) { + if (((IS_HEX_OR_DIGIT(argv[3]) == MLAN_STATUS_FAILURE) && + (atoi(argv[3]) != -1)) || (atoi(argv[3]) < -1)) { + printf("ERR:Illegal index %s\n", argv[3]); + print_custom_ie_usage(); + return MLAN_STATUS_FAILURE; + } + } + switch (argc) { + case 3: + buf_len = MRVDRV_SIZE_OF_CMD_BUFFER; + break; + case 4: + if (atoi(argv[3]) < 0) { + printf("ERR:Illegal index %s. Must be either greater than or equal to 0 for Get Operation \n", argv[3]); + print_custom_ie_usage(); + return MLAN_STATUS_FAILURE; + } + buf_len = MRVDRV_SIZE_OF_CMD_BUFFER; + break; + case 5: + if (MLAN_STATUS_FAILURE == ishexstring(argv[4]) || + A2HEXDECIMAL(argv[4]) != 0) { + printf("ERR: Mask value should be 0 to clear IEBuffers.\n"); + print_custom_ie_usage(); + return MLAN_STATUS_FAILURE; + } + if (atoi(argv[3]) == -1) { + printf("ERR: You must provide buffer for automatic deletion.\n"); + print_custom_ie_usage(); + return MLAN_STATUS_FAILURE; + } + buf_len = sizeof(tlvbuf_custom_ie) + sizeof(custom_ie); + break; + case 6: + /* This is to check negative numbers and special symbols */ + if (MLAN_STATUS_FAILURE == IS_HEX_OR_DIGIT(argv[4])) { + printf("ERR:Mask value must be 0 or hex digits\n"); + print_custom_ie_usage(); + return MLAN_STATUS_FAILURE; + } + /* If above check is passed and mask is not hex, then it must be 0 */ + if ((ISDIGIT(argv[4]) == MLAN_STATUS_SUCCESS) && atoi(argv[4])) { + printf("ERR:Mask value must be 0 or hex digits\n "); + print_custom_ie_usage(); + return MLAN_STATUS_FAILURE; + } + if (MLAN_STATUS_FAILURE == ishexstring(argv[5])) { + printf("ERR:Only hex digits are allowed\n"); + print_custom_ie_usage(); + return MLAN_STATUS_FAILURE; + } + ie_buf_len = strlen(argv[5]); + if (!strncasecmp("0x", argv[5], 2)) { + ie_len = (ie_buf_len - 2 + 1) / 2; + argv[5] += 2; + } else + ie_len = (ie_buf_len + 1) / 2; + if (ie_len > MAX_IE_BUFFER_LEN) { + printf("ERR:Incorrect IE length %d\n", ie_buf_len); + print_custom_ie_usage(); + return MLAN_STATUS_FAILURE; + } + mgmt_subtype_mask = (t_u16)A2HEXDECIMAL(argv[4]); + buf_len = sizeof(tlvbuf_custom_ie) + sizeof(custom_ie) + ie_len; + break; + } + /* Initialize the command buffer */ + buffer = (t_u8 *)malloc(buf_len); + if (!buffer) { + printf("ERR:Cannot allocate buffer for command!\n"); + return MLAN_STATUS_FAILURE; + } + memset(buffer, 0, buf_len); + tlv = (tlvbuf_custom_ie *)buffer; + tlv->tag = MRVL_MGMT_IE_LIST_TLV_ID; + if (argc == 3 || argc == 4) { + if (argc == 3) + tlv->length = 0; + else { + tlv->length = sizeof(t_u16); + ie_ptr = (custom_ie *)(tlv->ie_data); + ie_ptr->ie_index = (t_u16)(atoi(argv[3])); + } + } else { + /* Locate headers */ + ie_ptr = (custom_ie *)(tlv->ie_data); + /* Set TLV fields */ + tlv->length = sizeof(custom_ie) + ie_len; + ie_ptr->ie_index = atoi(argv[3]); + ie_ptr->mgmt_subtype_mask = mgmt_subtype_mask; + ie_ptr->ie_length = ie_len; + if (argc == 6) + string2raw(argv[5], ie_ptr->ie_buffer); + } + /* Initialize the ifr structure */ + memset(&ifr, 0, sizeof(ifr)); + strncpy(ifr.ifr_ifrn.ifrn_name, dev_name, strlen(dev_name)); + ifr.ifr_ifru.ifru_data = (void *)buffer; + /* Perform ioctl */ + if (ioctl(sockfd, CUSTOM_IE_CFG, &ifr)) { + perror("ioctl[CUSTOM_IE_CFG]"); + printf("ERR:Command sending failed!\n"); + if (buffer) + free(buffer); + return MLAN_STATUS_FAILURE; + } + /* Print response */ + if (argc > 4) { + printf("custom IE setting successful\n"); + } else { + printf("Querying custom IE successful\n"); + tlv = (tlvbuf_custom_ie *)buffer; + ie_len = tlv->length; + ie_ptr = (custom_ie *)(tlv->ie_data); + while ((unsigned int)ie_len >= sizeof(custom_ie)) { + printf("Index [%d]\n", ie_ptr->ie_index); + if (ie_ptr->ie_length) + printf("Management Subtype Mask = 0x%02x\n", + (ie_ptr->mgmt_subtype_mask) == 0 ? + CUSTOM_IE_AUTO_MASK : + (ie_ptr->mgmt_subtype_mask)); + else + printf("Management Subtype Mask = 0x%02x\n", + (ie_ptr->mgmt_subtype_mask)); + hexdump("IE Buffer", (void *)ie_ptr->ie_buffer, + ie_ptr->ie_length, ' '); + ie_len -= sizeof(custom_ie) + ie_ptr->ie_length; + ie_ptr = (custom_ie *)((t_u8 *)ie_ptr + + sizeof(custom_ie) + + ie_ptr->ie_length); + } + } + max_mgmt_ie_tlv = + (tlvbuf_max_mgmt_ie *)(buffer + sizeof(tlvbuf_custom_ie) + + tlv->length); + if (max_mgmt_ie_tlv) { + if (max_mgmt_ie_tlv->tag == MRVL_MAX_MGMT_IE_TLV_ID) { + for (i = 0; i < max_mgmt_ie_tlv->count; i++) { + printf("buf%d_size = %d\n", i, + max_mgmt_ie_tlv->info[i].buf_size); + printf("number of buffers = %d\n", + max_mgmt_ie_tlv->info[i].buf_count); + printf("\n"); + } + } + } + if (buffer) + free(buffer); + + return MLAN_STATUS_SUCCESS; +} + +/******************************************************** + Global Functions +********************************************************/ +/** + * @brief Get one line from the File + * + * @param fp File handler + * @param str Storage location for data. + * @param size Maximum number of characters to read. + * @param lineno A pointer to return current line number + * @return returns string or NULL + */ +char * +mlan_config_get_line(FILE * fp, t_s8 *str, t_s32 size, int *lineno) +{ + char *start, *end; + int out, next_line; + + if (!fp || !str) + return NULL; + + do { +read_line: + if (!fgets(str, size, fp)) + break; + start = str; + start[size - 1] = '\0'; + end = start + strlen(str); + (*lineno)++; + + out = 1; + while (out && (start < end)) { + next_line = 0; + /* Remove empty lines and lines starting with # */ + switch (start[0]) { + case ' ': /* White space */ + case '\t': /* Tab */ + start++; + break; + case '#': + case '\n': + case '\0': + next_line = 1; + break; + case '\r': + if (start[1] == '\n') + next_line = 1; + else + start++; + break; + default: + out = 0; + break; + } + if (next_line) + goto read_line; + } + + /* Remove # comments unless they are within a double quoted + * string. Remove trailing white space. */ + if ((end = strstr(start, "\""))) { + if (!(end = strstr(end + 1, "\""))) + end = start; + } else + end = start; + + if ((end = strstr(end + 1, "#"))) + *end-- = '\0'; + else + end = start + strlen(start) - 1; + + out = 1; + while (out && (start < end)) { + switch (*end) { + case ' ': /* White space */ + case '\t': /* Tab */ + case '\n': + case '\r': + *end = '\0'; + end--; + break; + default: + out = 0; + break; + } + } + + if (*start == '\0') + continue; + + return start; + } while (1); + + return NULL; +} + +/** + * @brief parse hex data + * @param fp File handler + * @param dst A pointer to receive hex data + * @return length of hex data + */ +int +fparse_for_hex(FILE * fp, t_u8 *dst) +{ + t_s8 *ptr; + t_u8 *dptr; + t_s8 buf[256]; + + dptr = dst; + while (fgets(buf, sizeof(buf), fp)) { + ptr = buf; + + while (*ptr) { + /* skip leading spaces */ + while (*ptr && (isspace(*ptr) || *ptr == '\t')) + ptr++; + + /* skip blank lines and lines beginning with '#' */ + if (*ptr == '\0' || *ptr == '#') + break; + + if (isxdigit(*ptr)) { + ptr = convert2hex(ptr, dptr++); + } else { + /* Invalid character on data line */ + ptr++; + } + } + } + + return (dptr - dst); +} + +#define STACK_NBYTES 100 /**< Number of bytes in stack */ +#define MAX_BYTESEQ 6 /**< Maximum byte sequence */ +#define TYPE_DNUM 1 /**< decimal number */ +#define TYPE_BYTESEQ 2 /**< byte sequence */ +#define MAX_OPERAND 0x40 /**< Maximum operands */ +#define TYPE_EQ (MAX_OPERAND+1) /**< byte comparison: == operator */ +#define TYPE_EQ_DNUM (MAX_OPERAND+2) /**< decimal comparison: =d operator */ +#define TYPE_EQ_BIT (MAX_OPERAND+3) /**< bit comparison: =b operator */ +#define TYPE_AND (MAX_OPERAND+4) /**< && operator */ +#define TYPE_OR (MAX_OPERAND+5) /**< || operator */ + +typedef struct { + t_u16 sp; /**< Stack pointer */ + t_u8 byte[STACK_NBYTES]; /**< Stack */ +} mstack_t; + +typedef struct { + t_u8 type; /**< Type */ + t_u8 reserve[3]; /**< so 4-byte align val array */ + /* byte sequence is the largest among all the operands and operators. */ + /* byte sequence format: 1 byte of num of bytes, then variable num bytes */ + t_u8 val[MAX_BYTESEQ + 1];/**< Value */ +} op_t; + +/** + * @brief push data to stack + * + * @param s a pointer to mstack_t structure + * + * @param nbytes number of byte to push to stack + * + * @param val a pointer to data buffer + * + * @return TRUE-- sucess , FALSE -- fail + * + */ +static int +push_n(mstack_t * s, t_u8 nbytes, t_u8 *val) +{ + if ((s->sp + nbytes) < STACK_NBYTES) { + memcpy((void *)(s->byte + s->sp), (const void *)val, + (size_t) nbytes); + s->sp += nbytes; + /* printf("push: n %d sp %d\n", nbytes, s->sp); */ + return TRUE; + } else /* stack full */ + return FALSE; +} + +/** + * @brief push data to stack + * + * @param s a pointer to mstack_t structure + * + * @param op a pointer to op_t structure + * + * @return TRUE-- sucess , FALSE -- fail + * + */ +static int +push(mstack_t * s, op_t * op) +{ + t_u8 nbytes; + switch (op->type) { + case TYPE_DNUM: + if (push_n(s, 4, op->val)) + return (push_n(s, 1, &op->type)); + return FALSE; + case TYPE_BYTESEQ: + nbytes = op->val[0]; + if (push_n(s, nbytes, op->val + 1) && + push_n(s, 1, op->val) && push_n(s, 1, &op->type)) + return TRUE; + return FALSE; + default: + return (push_n(s, 1, &op->type)); + } +} + +/** + * @brief parse RPN string + * + * @param s a pointer to Null-terminated string to scan. + * + * @param first_time a pointer to return first_time + * + * @return A pointer to the last token found in string. + * NULL is returned when there are no more tokens to be found. + * + */ +static char * +getop(char *s, int *first_time) +{ + const char delim[] = " \t\n"; + char *p; + if (*first_time) { + p = strtok(s, delim); + *first_time = FALSE; + } else { + p = strtok(NULL, delim); + } + return (p); +} + +/** + * @brief Verify hex digit. + * + * @param c input ascii char + * @param h a pointer to return integer value of the digit char. + * @return TURE -- c is hex digit, FALSE -- c is not hex digit. + */ +static int +ishexdigit(char c, t_u8 *h) +{ + if (c >= '0' && c <= '9') { + *h = c - '0'; + return (TRUE); + } else if (c >= 'a' && c <= 'f') { + *h = c - 'a' + 10; + return (TRUE); + } else if (c >= 'A' && c <= 'F') { + *h = c - 'A' + 10; + return (TRUE); + } + return (FALSE); +} + +/** + * @brief convert hex string to integer. + * + * @param s A pointer to hex string, string length up to 2 digits. + * @return integer value. + */ +static t_u8 +hex_atoi(char *s) +{ + int i; + t_u8 digit; /* digital value */ + t_u8 t = 0; /* total value */ + + for (i = 0, t = 0; ishexdigit(s[i], &digit) && i < 2; i++) + t = 16 * t + digit; + return (t); +} + +/** + * @brief Parse byte sequence in hex format string to a byte sequence. + * + * @param opstr A pointer to byte sequence in hex format string, with ':' as delimiter between two byte. + * @param val A pointer to return byte sequence string + * @return NA + */ +static void +parse_hex(char *opstr, t_u8 *val) +{ + char delim = ':'; + char *p; + char *q; + t_u8 i; + + /* +1 is for skipping over the preceding h character. */ + p = opstr + 1; + + /* First byte */ + val[1] = hex_atoi(p++); + + /* Parse subsequent bytes. */ + /* Each byte is preceded by the : character. */ + for (i = 1; *p; i++) { + q = strchr(p, delim); + if (!q) + break; + p = q + 1; + val[i + 1] = hex_atoi(p); + } + /* Set num of bytes */ + val[0] = i; +} + +/** + * @brief str2bin, convert RPN string to binary format + * + * @param str A pointer to rpn string + * @param stack A pointer to mstack_t structure + * @return MLAN_STATUS_SUCCESS--success, otherwise--fail + */ +static int +str2bin(char *str, mstack_t * stack) +{ + int first_time; + char *opstr; + op_t op; /* operator/operand */ + int dnum; + int ret = MLAN_STATUS_SUCCESS; + + memset(stack, 0, sizeof(mstack_t)); + first_time = TRUE; + while ((opstr = getop(str, &first_time)) != NULL) { + if (isdigit(*opstr)) { + op.type = TYPE_DNUM; + dnum = cpu_to_le32(atoi(opstr)); + memcpy((t_u8 *)op.val, &dnum, sizeof(dnum)); + if (!push(stack, &op)) { + printf("push decimal number failed\n"); + ret = MLAN_STATUS_FAILURE; + break; + } + } else if (*opstr == 'h') { + op.type = TYPE_BYTESEQ; + parse_hex(opstr, op.val); + if (!push(stack, &op)) { + printf("push byte sequence failed\n"); + ret = MLAN_STATUS_FAILURE; + break; + } + } else if (!strcmp(opstr, "==")) { + op.type = TYPE_EQ; + if (!push(stack, &op)) { + printf("push byte cmp operator failed\n"); + ret = MLAN_STATUS_FAILURE; + break; + } + } else if (!strcmp(opstr, "=d")) { + op.type = TYPE_EQ_DNUM; + if (!push(stack, &op)) { + printf("push decimal cmp operator failed\n"); + ret = MLAN_STATUS_FAILURE; + break; + } + } else if (!strcmp(opstr, "=b")) { + op.type = TYPE_EQ_BIT; + if (!push(stack, &op)) { + printf("push bit cmp operator failed\n"); + ret = MLAN_STATUS_FAILURE; + break; + } + } else if (!strcmp(opstr, "&&")) { + op.type = TYPE_AND; + if (!push(stack, &op)) { + printf("push AND operator failed\n"); + ret = MLAN_STATUS_FAILURE; + break; + } + } else if (!strcmp(opstr, "||")) { + op.type = TYPE_OR; + if (!push(stack, &op)) { + printf("push OR operator failed\n"); + ret = MLAN_STATUS_FAILURE; + break; + } + } else { + printf("Unknown operand\n"); + ret = MLAN_STATUS_FAILURE; + break; + } + } + return ret; +} + +/** + * @brief Converts colon separated MAC address to hex value + * + * @param mac A pointer to the colon separated MAC string + * @param raw A pointer to the hex data buffer + * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE + * MAC_BROADCAST - if breadcast mac + * MAC_MULTICAST - if multicast mac + */ +static int +mac2raw(char *mac, t_u8 *raw) +{ + unsigned int temp_raw[ETH_ALEN]; + int num_tokens = 0; + int i; + + if (strlen(mac) != ((2 * ETH_ALEN) + (ETH_ALEN - 1))) { + return MLAN_STATUS_FAILURE; + } + num_tokens = sscanf(mac, "%2x:%2x:%2x:%2x:%2x:%2x", + temp_raw + 0, temp_raw + 1, temp_raw + 2, + temp_raw + 3, temp_raw + 4, temp_raw + 5); + if (num_tokens != ETH_ALEN) { + return MLAN_STATUS_FAILURE; + } + for (i = 0; i < num_tokens; i++) + raw[i] = (t_u8)temp_raw[i]; + + if (memcmp(raw, "\xff\xff\xff\xff\xff\xff", ETH_ALEN) == 0) { + return MAC_BROADCAST; + } else if (raw[0] & 0x01) { + return MAC_MULTICAST; + } + return MLAN_STATUS_SUCCESS; +} + +/** + * @brief Parse function for a configuration line + * + * @param s Storage buffer for data + * @param size Maximum size of data + * @param stream File stream pointer + * @param line Pointer to current line within the file + * @param _pos Output string or NULL + * @return String or NULL + */ +static char * +config_get_line(char *s, int size, FILE * stream, int *line, char **_pos) +{ + *_pos = mlan_config_get_line(stream, s, size, line); + return *_pos; +} + +/** + * @brief Parses a command line + * + * @param line The line to parse + * @param args Pointer to the argument buffer to be filled in + * @return Number of arguments in the line or EOF + */ +static int +parse_line(char *line, char *args[]) +{ + int arg_num = 0; + int is_start = 0; + int is_quote = 0; + int length = 0; + int i = 0; + + arg_num = 0; + length = strlen(line); + /* Process line */ + + /* Find number of arguments */ + is_start = 0; + is_quote = 0; + for (i = 0; i < length; i++) { + /* Ignore leading spaces */ + if (is_start == 0) { + if (line[i] == ' ') { + continue; + } else if (line[i] == '\t') { + continue; + } else if (line[i] == '\n') { + break; + } else { + is_start = 1; + args[arg_num] = &line[i]; + arg_num++; + } + } + if (is_start == 1) { + /* Ignore comments */ + if (line[i] == '#') { + if (is_quote == 0) { + line[i] = '\0'; + arg_num--; + } + break; + } + /* Separate by '=' */ + if (line[i] == '=') { + line[i] = '\0'; + is_start = 0; + continue; + } + /* Separate by ',' */ + if (line[i] == ',') { + line[i] = '\0'; + is_start = 0; + continue; + } + /* Change ',' to ' ', but not inside quotes */ + if ((line[i] == ',') && (is_quote == 0)) { + line[i] = ' '; + continue; + } + } + /* Remove newlines */ + if (line[i] == '\n') { + line[i] = '\0'; + } + /* Check for quotes */ + if (line[i] == '"') { + is_quote = (is_quote == 1) ? 0 : 1; + continue; + } + if (((line[i] == ' ') || (line[i] == '\t')) && (is_quote == 0)) { + line[i] = '\0'; + is_start = 0; + continue; + } + } + return arg_num; +} + +#define FILTER_BYTESEQ TYPE_EQ /**< byte sequence */ +#define FILTER_DNUM TYPE_EQ_DNUM /**< decimal number */ +#define FILTER_BITSEQ TYPE_EQ_BIT /**< bit sequence */ +#define FILTER_TEST FILTER_BITSEQ+1 /**< test */ + +#define NAME_TYPE 1 /**< Field name 'type' */ +#define NAME_PATTERN 2 /**< Field name 'pattern' */ +#define NAME_OFFSET 3 /**< Field name 'offset' */ +#define NAME_NUMBYTE 4 /**< Field name 'numbyte' */ +#define NAME_REPEAT 5 /**< Field name 'repeat' */ +#define NAME_BYTE 6 /**< Field name 'byte' */ +#define NAME_MASK 7 /**< Field name 'mask' */ +#define NAME_DEST 8 /**< Field name 'dest' */ + +static struct mef_fields { + t_s8 *name; + /**< Name */ + t_s8 nameid; + /**< Name Id. */ +} mef_fields[] = { + { + "type", NAME_TYPE}, { + "pattern", NAME_PATTERN}, { + "offset", NAME_OFFSET}, { + "numbyte", NAME_NUMBYTE}, { + "repeat", NAME_REPEAT}, { + "byte", NAME_BYTE}, { + "mask", NAME_MASK}, { + "dest", NAME_DEST} +}; + +/** + * @brief get filter data + * + * @param fp A pointer to file stream + * @param ln A pointer to line number + * @param buf A pointer to hostcmd data + * @param size A pointer to the return size of hostcmd buffer + * @return MLAN_STATUS_SUCCESS--success, otherwise--fail + */ +static int +mlan_get_filter_data(FILE * fp, int *ln, t_u8 *buf, t_u16 *size) +{ + t_s32 errors = 0, i; + t_s8 line[256], *pos, *pos1; + t_u16 type = 0; + t_u32 pattern = 0; + t_u16 repeat = 0; + t_u16 offset = 0; + t_s8 byte_seq[50]; + t_s8 mask_seq[50]; + t_u16 numbyte = 0; + t_s8 type_find = 0; + t_s8 pattern_find = 0; + t_s8 offset_find = 0; + t_s8 numbyte_find = 0; + t_s8 repeat_find = 0; + t_s8 byte_find = 0; + t_s8 mask_find = 0; + t_s8 dest_find = 0; + t_s8 dest_seq[50]; + + *size = 0; + while ((pos = mlan_config_get_line(fp, line, sizeof(line), ln))) { + if (strcmp(pos, "}") == 0) { + break; + } + pos1 = strchr(pos, '='); + if (pos1 == NULL) { + printf("Line %d: Invalid mef_filter line '%s'\n", *ln, + pos); + errors++; + continue; + } + *pos1++ = '\0'; + for (i = 0; (t_u32)i < NELEMENTS(mef_fields); i++) { + if (strncmp + (pos, mef_fields[i].name, + strlen(mef_fields[i].name)) == 0) { + switch (mef_fields[i].nameid) { + case NAME_TYPE: + type = a2hex_or_atoi(pos1); + if ((type != FILTER_DNUM) && + (type != FILTER_BYTESEQ) + && (type != FILTER_BITSEQ) && + (type != FILTER_TEST)) { + printf("Invalid filter type:%d\n", type); + return MLAN_STATUS_FAILURE; + } + type_find = 1; + break; + case NAME_PATTERN: + pattern = a2hex_or_atoi(pos1); + pattern_find = 1; + break; + case NAME_OFFSET: + offset = a2hex_or_atoi(pos1); + offset_find = 1; + break; + case NAME_NUMBYTE: + numbyte = a2hex_or_atoi(pos1); + numbyte_find = 1; + break; + case NAME_REPEAT: + repeat = a2hex_or_atoi(pos1); + repeat_find = 1; + break; + case NAME_BYTE: + memset(byte_seq, 0, sizeof(byte_seq)); + strncpy(byte_seq, pos1, + (sizeof(byte_seq) - 1)); + byte_find = 1; + break; + case NAME_MASK: + memset(mask_seq, 0, sizeof(mask_seq)); + strncpy(mask_seq, pos1, + (sizeof(mask_seq) - 1)); + mask_find = 1; + break; + case NAME_DEST: + memset(dest_seq, 0, sizeof(dest_seq)); + strncpy(dest_seq, pos1, + (sizeof(dest_seq) - 1)); + dest_find = 1; + break; + } + break; + } + } + if (i == NELEMENTS(mef_fields)) { + printf("Line %d: unknown mef field '%s'.\n", + *line, pos); + errors++; + } + } + if (type_find == 0) { + printf("Can not find filter type\n"); + return MLAN_STATUS_FAILURE; + } + switch (type) { + case FILTER_DNUM: + if (!pattern_find || !offset_find || !numbyte_find) { + printf("Missing field for FILTER_DNUM: pattern=%d,offset=%d,numbyte=%d\n", pattern_find, offset_find, numbyte_find); + return MLAN_STATUS_FAILURE; + } + memset(line, 0, sizeof(line)); + snprintf(line, sizeof(line), "%d %d %d =d ", pattern, offset, + numbyte); + break; + case FILTER_BYTESEQ: + if (!byte_find || !offset_find || !repeat_find) { + printf("Missing field for FILTER_BYTESEQ: byte=%d,offset=%d,repeat=%d\n", byte_find, offset_find, repeat_find); + return MLAN_STATUS_FAILURE; + } + memset(line, 0, sizeof(line)); + snprintf(line, sizeof(line), "%d h%s %d == ", repeat, byte_seq, + offset); + break; + case FILTER_BITSEQ: + if (!byte_find || !offset_find || !mask_find) { + printf("Missing field for FILTER_BITSEQ: byte=%d,offset=%d,mask_find=%d\n", byte_find, offset_find, mask_find); + return MLAN_STATUS_FAILURE; + } + if (strlen(byte_seq) != strlen(mask_seq)) { + printf("byte string's length is different with mask's length!\n"); + return MLAN_STATUS_FAILURE; + } + memset(line, 0, sizeof(line)); + snprintf(line, sizeof(line), "h%s %d h%s =b ", byte_seq, offset, + mask_seq); + break; + case FILTER_TEST: + if (!byte_find || !offset_find || !repeat_find || !dest_find) { + printf("Missing field for FILTER_TEST: byte=%d,offset=%d,repeat=%d,dest=%d\n", byte_find, offset_find, repeat_find, dest_find); + return MLAN_STATUS_FAILURE; + } + memset(line, 0, sizeof(line)); + snprintf(line, sizeof(line), "h%s %d h%s %d ", dest_seq, repeat, + byte_seq, offset); + break; + } + memcpy(buf, line, strlen(line)); + *size = strlen(line); + return MLAN_STATUS_SUCCESS; +} + +#define NAME_MODE 1 /**< Field name 'mode' */ +#define NAME_ACTION 2 /**< Field name 'action' */ +#define NAME_FILTER_NUM 3 /**< Field name 'filter_num' */ +#define NAME_RPN 4 /**< Field name 'RPN' */ +static struct mef_entry_fields { + t_s8 *name; + /**< Name */ + t_s8 nameid; + /**< Name id */ +} mef_entry_fields[] = { + { + "mode", NAME_MODE}, { + "action", NAME_ACTION}, { + "filter_num", NAME_FILTER_NUM}, { +"RPN", NAME_RPN},}; + +typedef struct _MEF_ENTRY { + /** Mode */ + t_u8 Mode; + /** Size */ + t_u8 Action; + /** Size of expression */ + t_u16 ExprSize; +} MEF_ENTRY; + +/** + * @brief get mef_entry data + * + * @param fp A pointer to file stream + * @param ln A pointer to line number + * @param buf A pointer to hostcmd data + * @param size A pointer to the return size of hostcmd buffer + * @return MLAN_STATUS_SUCCESS--success, otherwise--fail + */ +static int +mlan_get_mef_entry_data(FILE * fp, int *ln, t_u8 *buf, t_u16 *size) +{ + t_s8 line[256], *pos, *pos1; + t_u8 mode, action, filter_num = 0; + t_s8 rpn[256]; + t_s8 mode_find = 0; + t_s8 action_find = 0; + t_s8 filter_num_find = 0; + t_s8 rpn_find = 0; + t_s8 rpn_str[256]; + int rpn_len = 0; + t_s8 filter_name[50]; + t_s8 name_found = 0; + t_u16 len = 0; + int i; + int first_time = TRUE; + char *opstr; + t_s8 filter_action[10]; + t_s32 errors = 0; + MEF_ENTRY *pMefEntry = (MEF_ENTRY *) buf; + mstack_t stack; + while ((pos = mlan_config_get_line(fp, line, sizeof(line), ln))) { + if (strcmp(pos, "}") == 0) { + break; + } + pos1 = strchr(pos, '='); + if (pos1 == NULL) { + printf("Line %d: Invalid mef_entry line '%s'\n", *ln, + pos); + errors++; + continue; + } + *pos1++ = '\0'; + if (!mode_find || !action_find || !filter_num_find || !rpn_find) { + for (i = 0; + (unsigned int)i < NELEMENTS(mef_entry_fields); + i++) { + if (strncmp + (pos, mef_entry_fields[i].name, + strlen(mef_entry_fields[i].name)) == 0) { + switch (mef_entry_fields[i].nameid) { + case NAME_MODE: + mode = a2hex_or_atoi(pos1); + if (mode & ~0x7) { + printf("invalid mode=%d\n", mode); + return MLAN_STATUS_FAILURE; + } + pMefEntry->Mode = mode; + mode_find = 1; + break; + case NAME_ACTION: + action = a2hex_or_atoi(pos1); + if (action & ~0xff) { + printf("invalid action=%d\n", action); + return MLAN_STATUS_FAILURE; + } + pMefEntry->Action = action; + action_find = 1; + break; + case NAME_FILTER_NUM: + filter_num = + a2hex_or_atoi(pos1); + filter_num_find = 1; + break; + case NAME_RPN: + memset(rpn, 0, sizeof(rpn)); + strncpy(rpn, pos1, + (sizeof(rpn) - 1)); + rpn_find = 1; + break; + } + break; + } + } + if (i == NELEMENTS(mef_fields)) { + printf("Line %d: unknown mef_entry field '%s'.\n", *line, pos); + return MLAN_STATUS_FAILURE; + } + } + if (mode_find && action_find && filter_num_find && rpn_find) { + for (i = 0; i < filter_num; i++) { + opstr = getop(rpn, &first_time); + if (opstr == NULL) + break; + snprintf(filter_name, sizeof(filter_name), + "%s={", opstr); + name_found = 0; + while ((pos = + mlan_config_get_line(fp, line, + sizeof(line), + ln))) { + if (strncmp + (pos, filter_name, + strlen(filter_name)) == 0) { + name_found = 1; + break; + } + } + if (!name_found) { + fprintf(stderr, + "mlanconfig: %s not found in file\n", + filter_name); + return MLAN_STATUS_FAILURE; + } + if (MLAN_STATUS_FAILURE == + mlan_get_filter_data(fp, ln, + (t_u8 *)(rpn_str + + rpn_len), + &len)) + break; + rpn_len += len; + if (i > 0) { + memcpy(rpn_str + rpn_len, filter_action, + strlen(filter_action)); + rpn_len += strlen(filter_action); + } + opstr = getop(rpn, &first_time); + if (opstr == NULL) + break; + memset(filter_action, 0, sizeof(filter_action)); + snprintf(filter_action, sizeof(filter_action), + "%s ", opstr); + } + /* Remove the last space */ + if (rpn_len > 0) { + rpn_len--; + rpn_str[rpn_len] = 0; + } + if (MLAN_STATUS_FAILURE == str2bin(rpn_str, &stack)) { + printf("Fail on str2bin!\n"); + return MLAN_STATUS_FAILURE; + } + *size = sizeof(MEF_ENTRY); + pMefEntry->ExprSize = cpu_to_le16(stack.sp); + memmove(buf + sizeof(MEF_ENTRY), stack.byte, stack.sp); + *size += stack.sp; + break; + } else if (mode_find && action_find && filter_num_find && + (filter_num == 0)) { + pMefEntry->ExprSize = 0; + *size = sizeof(MEF_ENTRY); + break; + } + } + return MLAN_STATUS_SUCCESS; +} + +#define MEFCFG_CMDCODE 0x009a +/** + * @brief Process mef cfg + * @param argc number of arguments + * @param argv A pointer to arguments array + * @return MLAN_STATUS_SUCCESS--success, otherwise--fail + */ +static int +process_mef_cfg(int argc, char *argv[]) +{ + int ioctl_val, subioctl_val; + t_s8 line[256], cmdname[256], *pos; + int cmdname_found = 0, name_found = 0; + int ln = 0; + int ret = MLAN_STATUS_SUCCESS; + int i; + t_u8 *buf; + t_u16 buf_len = 0; + t_u16 len = 0; + struct iwreq iwr; + HostCmd_DS_MEF_CFG *mefcmd; + HostCmd_DS_GEN *hostcmd; + FILE *fp = NULL; + + if (argc < 4) { + printf("Error: invalid no of arguments\n"); + printf("Syntax: ./mlanconfig eth1 mefcfg \n"); + exit(1); + } + if (get_priv_ioctl("hostcmd", + &ioctl_val, &subioctl_val) == MLAN_STATUS_FAILURE) { + return -EOPNOTSUPP; + } + snprintf(cmdname, sizeof(cmdname), "%s={", argv[2]); + cmdname_found = 0; + if ((fp = fopen(argv[3], "r")) == NULL) { + fprintf(stderr, "Cannot open file %s\n", argv[4]); + exit(1); + } + + buf = (t_u8 *)malloc(MRVDRV_SIZE_OF_CMD_BUFFER); + if (buf == NULL) { + fclose(fp); + fprintf(stderr, "Cannot alloc memory\n"); + exit(1); + } + memset(buf, 0, MRVDRV_SIZE_OF_CMD_BUFFER); + + hostcmd = (HostCmd_DS_GEN *)(buf); + hostcmd->command = cpu_to_le16(MEFCFG_CMDCODE); + mefcmd = (HostCmd_DS_MEF_CFG *)(buf + S_DS_GEN); + buf_len = sizeof(HostCmd_DS_MEF_CFG) + S_DS_GEN; + + while ((pos = mlan_config_get_line(fp, line, sizeof(line), &ln))) { + if (strcmp(pos, cmdname) == 0) { + cmdname_found = 1; + snprintf(cmdname, sizeof(cmdname), "Criteria="); + name_found = 0; + while ((pos = + mlan_config_get_line(fp, line, sizeof(line), + &ln))) { + if (strncmp(pos, cmdname, strlen(cmdname)) == 0) { + name_found = 1; + mefcmd->Criteria = + a2hex_or_atoi(pos + + strlen(cmdname)); + break; + } + } + if (!name_found) { + fprintf(stderr, + "mlanconfig: criteria not found in file '%s'\n", + argv[3]); + break; + } + snprintf(cmdname, sizeof(cmdname), "NumEntries="); + name_found = 0; + while ((pos = + mlan_config_get_line(fp, line, sizeof(line), + &ln))) { + if (strncmp(pos, cmdname, strlen(cmdname)) == 0) { + name_found = 1; + mefcmd->NumEntries = + a2hex_or_atoi(pos + + strlen(cmdname)); + break; + } + } + if (!name_found) { + fprintf(stderr, + "mlanconfig: NumEntries not found in file '%s'\n", + argv[3]); + break; + } + for (i = 0; i < mefcmd->NumEntries; i++) { + snprintf(cmdname, sizeof(cmdname), + "mef_entry_%d={", i); + name_found = 0; + while ((pos = + mlan_config_get_line(fp, line, + sizeof(line), + &ln))) { + if (strncmp + (pos, cmdname, + strlen(cmdname)) == 0) { + name_found = 1; + break; + } + } + if (!name_found) { + fprintf(stderr, + "mlanconfig: %s not found in file '%s'\n", + cmdname, argv[3]); + break; + } + if (MLAN_STATUS_FAILURE == + mlan_get_mef_entry_data(fp, &ln, + buf + buf_len, + &len)) { + ret = MLAN_STATUS_FAILURE; + break; + } + buf_len += len; + } + break; + } + } + fclose(fp); + /* hexdump("mef_cfg",buf,buf_len, ' '); */ + if (!cmdname_found) + fprintf(stderr, + "mlanconfig: cmdname '%s' not found in file '%s'\n", + argv[4], argv[3]); + + if (!cmdname_found || !name_found) { + ret = MLAN_STATUS_FAILURE; + goto mef_exit; + } + hostcmd->size = cpu_to_le16(buf_len); + mefcmd->Criteria = cpu_to_le32(mefcmd->Criteria); + mefcmd->NumEntries = cpu_to_le16(mefcmd->NumEntries); + + strncpy(iwr.ifr_name, dev_name, IFNAMSIZ - 1); + iwr.u.data.pointer = buf; + iwr.u.data.length = buf_len; + iwr.u.data.flags = 0; + if (ioctl(sockfd, ioctl_val, &iwr)) { + fprintf(stderr, "mlanconfig: MEFCFG is not supported by %s\n", + dev_name); + ret = MLAN_STATUS_FAILURE; + goto mef_exit; + } + ret = process_host_cmd_resp(buf); + +mef_exit: + if (buf) + free(buf); + return ret; + +} + +/** + * @brief Process transmission of mgmt frames + * @param argc number of arguments + * @param argv A pointer to arguments array + * @return MLAN_STATUS_SUCCESS--success, otherwise--fail + */ +static int +process_mgmt_frame_tx(int argc, char *argv[]) +{ + struct ifreq ifr; + char *line = NULL; + FILE *config_file = NULL; + int li = 0, arg_num = 0, ret = 0, i = 0; + char *args[100] = { NULL }, *pos = NULL, mac_addr[20]; + t_u8 peer_mac[ETH_ALEN]; + t_u16 data_len = 0, subtype = 0; + wlan_mgmt_frame_tx *pmgmt_frame; + t_u8 *buffer = NULL; + pkt_header *hdr = NULL; + + /* Check arguments */ + if (argc != 4) { + printf("ERR:Incorrect number of arguments.\n"); + printf("Syntax: ./mlanconfig mlanX mgmtframetx \n"); + exit(1); + } + + data_len = sizeof(wlan_mgmt_frame_tx); + + buffer = (t_u8 *)malloc(MRVDRV_SIZE_OF_CMD_BUFFER); + if (!buffer) { + printf("ERR:Cannot allocate memory!\n"); + goto done; + } + memset(buffer, 0, MRVDRV_SIZE_OF_CMD_BUFFER); + hdr = (pkt_header *)buffer; + pmgmt_frame = (wlan_mgmt_frame_tx *)(buffer + sizeof(pkt_header)); + + /* Check if file exists */ + config_file = fopen(argv[3], "r"); + if (config_file == NULL) { + printf("\nERR:Config file can not open.\n"); + goto done; + } + line = (char *)malloc(MAX_CONFIG_LINE); + if (!line) { + printf("ERR:Cannot allocate memory for line\n"); + goto done; + } + memset(line, 0, MAX_CONFIG_LINE); + + /* Parse file and process */ + while (config_get_line(line, MAX_CONFIG_LINE, config_file, &li, &pos)) { + arg_num = parse_line(line, args); + if (strcmp(args[0], "PktSubType") == 0) { + subtype = (t_u16)A2HEXDECIMAL(args[1]); + pmgmt_frame->frm_ctl |= subtype << 4; + } else if (strncmp(args[0], "Addr", 4) == 0) { + strncpy(mac_addr, args[1], 20); + if ((ret = + mac2raw(mac_addr, + peer_mac)) != MLAN_STATUS_SUCCESS) { + printf("ERR: %s Address \n", + ret == + MLAN_STATUS_FAILURE ? "Invalid MAC" : ret + == + MAC_BROADCAST ? "Broadcast" : + "Multicast"); + goto done; + } + i = atoi(args[0] + 4); + switch (i) { + case 1: + memcpy(pmgmt_frame->addr1, peer_mac, ETH_ALEN); + break; + case 2: + memcpy(pmgmt_frame->addr2, peer_mac, ETH_ALEN); + break; + case 3: + memcpy(pmgmt_frame->addr3, peer_mac, ETH_ALEN); + break; + case 4: + memcpy(pmgmt_frame->addr4, peer_mac, ETH_ALEN); + break; + } + } else if (strcmp(args[0], "Data") == 0) { + for (i = 0; i < arg_num - 1; i++) + pmgmt_frame->payload[i] = + (t_u8)A2HEXDECIMAL(args[i + 1]); + data_len += arg_num - 1; + } + } + pmgmt_frame->frm_len = data_len - sizeof(pmgmt_frame->frm_len); +#define MRVL_PKT_TYPE_MGMT_FRAME 0xE5 + hdr->pkt_len = data_len; + hdr->TxPktType = MRVL_PKT_TYPE_MGMT_FRAME; + hdr->TxControl = 0; + hexdump("Frame Tx", buffer, data_len + sizeof(pkt_header), ' '); + /* Send collective command */ + memset(&ifr, 0, sizeof(ifr)); + strncpy(ifr.ifr_ifrn.ifrn_name, dev_name, strlen(dev_name)); + ifr.ifr_ifru.ifru_data = (void *)buffer; + + /* Perform ioctl */ + if (ioctl(sockfd, FRAME_TX_IOCTL, &ifr)) { + perror(""); + printf("ERR:Could not send management frame.\n"); + } else { + printf("Mgmt Frame sucessfully sent.\n"); + } + +done: + if (config_file) + fclose(config_file); + if (buffer) + free(buffer); + if (line) + free(line); + return MLAN_STATUS_SUCCESS; +} + +/** + * @brief Entry function for mlanconfig + * @param argc number of arguments + * @param argv A pointer to arguments array + * @return MLAN_STATUS_SUCCESS--success, otherwise--fail + */ +int +main(int argc, char *argv[]) +{ + t_s32 cmd; + + if ((argc == 2) && (strcmp(argv[1], "-v") == 0)) { + fprintf(stdout, "NXP mlanconfig version %s\n", MLANCONFIG_VER); + exit(0); + } + if (argc < 3) { + fprintf(stderr, "Invalid number of parameters!\n"); + display_usage(); + exit(1); + } + + strncpy(dev_name, argv[1], IFNAMSIZ - 1); + + /* + * create a socket + */ + if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) { + fprintf(stderr, "mlanconfig: Cannot open socket.\n"); + exit(1); + } + if (get_range() < 0) { + fprintf(stderr, "mlanconfig: Cannot get range.\n"); + close(sockfd); + exit(1); + } + switch ((cmd = findcommand(NELEMENTS(commands), commands, argv[2]))) { + case CMD_HOSTCMD: + process_host_cmd(argc, argv); + break; + case CMD_MEFCFG: + process_mef_cfg(argc, argv); + break; + case CMD_CFG_DATA: + process_cfg_data(argc, argv); + break; +#ifdef SDIO + case CMD_CMD52RW: + process_sdcmd52rw(argc, argv); + break; + case CMD_CMD53RW: + process_sdcmd53rw(argc, argv); + break; +#endif + case CMD_GET_SCAN_RSP: + process_getscantable(argc, argv); + break; + case CMD_SET_USER_SCAN: + process_setuserscan(argc, argv); + break; + case CMD_ADD_TS: + process_addts(argc, argv); + break; + case CMD_DEL_TS: + process_delts(argc, argv); + break; + case CMD_QCONFIG: + process_qconfig(argc, argv); + break; + case CMD_QSTATS: + process_qstats(argc, argv); + break; + case CMD_TS_STATUS: + process_wmm_ts_status(argc, argv); + break; + case CMD_WMM_QSTATUS: + process_wmm_qstatus(argc, argv); + break; + case CMD_REGRW: + process_regrdwr(argc, argv); + break; + case CMD_MEMRW: + process_memrdwr(argc, argv); + break; +#ifdef OPCHAN + case CMD_OPCHAN: + process_opchan(argc, argv); + break; + + case CMD_CHANGROUP: + process_changroup(argc, argv); + break; +#endif + case CMD_STA_CUSTOM_IE: + process_custom_ie(argc, argv); + break; + case CMD_STA_MGMT_FRAME_TX: + process_mgmt_frame_tx(argc, argv); + break; + default: + fprintf(stderr, "Invalid command specified!\n"); + display_usage(); + close(sockfd); + exit(1); + } + + close(sockfd); + return MLAN_STATUS_SUCCESS; +} diff --git a/mxm_wifiex/wlan_src/mapp/mlanconfig/mlanconfig.h b/mxm_wifiex/wlan_src/mapp/mlanconfig/mlanconfig.h new file mode 100644 index 0000000..1b944c7 --- /dev/null +++ b/mxm_wifiex/wlan_src/mapp/mlanconfig/mlanconfig.h @@ -0,0 +1,254 @@ +/** @file mlanconfig.h + * + * @brief This file contains definitions for application + * + * + * Copyright 2014-2020 NXP + * + * NXP CONFIDENTIAL + * The source code contained or described herein and all documents related to + * the source code (Materials) are owned by NXP, its + * suppliers and/or its licensors. Title to the Materials remains with NXP, + * its suppliers and/or its licensors. The Materials contain + * trade secrets and proprietary and confidential information of NXP, its + * suppliers and/or its licensors. The Materials are protected by worldwide copyright + * and trade secret laws and treaty provisions. No part of the Materials may be + * used, copied, reproduced, modified, published, uploaded, posted, + * transmitted, distributed, or disclosed in any way without NXP's prior + * express written permission. + * + * No license under any patent, copyright, trade secret or other intellectual + * property right is granted to or conferred upon you by disclosure or delivery + * of the Materials, either expressly, by implication, inducement, estoppel or + * otherwise. Any license under such intellectual property rights must be + * express and approved by NXP in writing. + * + */ +/************************************************************************ +Change log: + 11/26/2008: initial version +************************************************************************/ +#ifndef _MLANCONFIG_H_ +#define _MLANCONFIG_H_ + +/** Include header files */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if (BYTE_ORDER == LITTLE_ENDIAN) +#undef BIG_ENDIAN_SUPPORT +#endif + +/** Type definition: boolean */ +typedef enum { FALSE, TRUE } boolean; + +/** + * This macro specifies the attribute pack used for structure packing + */ +#ifndef __ATTRIB_PACK__ +#define __ATTRIB_PACK__ __attribute__((packed)) +#endif + +/** 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))) + +/** Convert to correct endian format */ +#ifdef BIG_ENDIAN_SUPPORT +/** CPU to little-endian convert for 16-bit */ +#define cpu_to_le16(x) swap_byte_16(x) +/** CPU to little-endian convert for 32-bit */ +#define cpu_to_le32(x) swap_byte_32(x) +/** Little-endian to CPU convert for 16-bit */ +#define le16_to_cpu(x) swap_byte_16(x) +/** Little-endian to CPU convert for 32-bit */ +#define le32_to_cpu(x) swap_byte_32(x) +#else +/** Do nothing */ +#define cpu_to_le16(x) (x) +/** Do nothing */ +#define cpu_to_le32(x) (x) +/** Do nothing */ +#define le16_to_cpu(x) (x) +/** Do nothing */ +#define le32_to_cpu(x) (x) +#endif + +/** Character, 1 byte */ +typedef char t_s8; +/** Unsigned character, 1 byte */ +typedef unsigned char t_u8; + +/** Short integer */ +typedef signed short t_s16; +/** Unsigned short integer */ +typedef unsigned short t_u16; + +/** Integer */ +typedef signed int t_s32; +/** Unsigned integer */ +typedef unsigned int t_u32; + +/** Long long integer */ +typedef signed long long t_s64; +/** Unsigned long long integer */ +typedef unsigned long long t_u64; + +/** Void pointer (4-bytes) */ +typedef void t_void; + +/** Success */ +#define MLAN_STATUS_SUCCESS (0) +/** Failure */ +#define MLAN_STATUS_FAILURE (-1) + +t_s8 *mlan_config_get_line(FILE * fp, t_s8 *s, t_s32 size, int *line); +int get_priv_ioctl(char *ioctl_name, int *ioctl_val, int *subioctl_val); +int fparse_for_hex(FILE * fp, t_u8 *dst); + +/** + * Hex or Decimal to Integer + * @param num string to convert into decimal or hex + */ +#define A2HEXDECIMAL(num) \ + (strncasecmp("0x", (num), 2)?(unsigned int) strtoll((num),NULL,0):a2hex((num))) + +/** Convert character to integer */ +#define CHAR2INT(x) (((x) >= 'A') ? ((x) - 'A' + 10) : ((x) - '0')) + +/** Convert TLV header from little endian format to CPU format */ +#define endian_convert_tlv_header_in(x) \ + { \ + (x)->tag = le16_to_cpu((x)->tag); \ + (x)->length = le16_to_cpu((x)->length); \ + } + +/** Convert TLV header to little endian format from CPU format */ +#define endian_convert_tlv_header_out(x) \ + { \ + (x)->tag = cpu_to_le16((x)->tag); \ + (x)->length = cpu_to_le16((x)->length); \ + } +/** Private command ID to pass custom IE list */ +#define CUSTOM_IE_CFG (SIOCDEVPRIVATE + 13) +/* TLV Definitions */ +/** TLV header */ +#define TLVHEADER /** Tag */ \ + t_u16 tag; \ + /** Length */ \ + t_u16 length + +/** Maximum IE buffer length */ +#define MAX_IE_BUFFER_LEN 256 + +/** TLV: Management IE list */ +#define MRVL_MGMT_IE_LIST_TLV_ID (PROPRIETARY_TLV_BASE_ID + 0x69) //0x0169 + +/** TLV: Max Management IE */ +#define MRVL_MAX_MGMT_IE_TLV_ID (PROPRIETARY_TLV_BASE_ID + 0xaa) //0x01aa + +/** custom IE info */ +typedef struct _custom_ie_info { + /** size of buffer */ + t_u16 buf_size; + /** no of buffers of buf_size */ + t_u16 buf_count; +} __ATTRIB_PACK__ custom_ie_info; + +/** TLV buffer : custom IE */ +typedef struct _tlvbuf_max_mgmt_ie { + /** Header */ + TLVHEADER; + /** No of tuples */ + t_u16 count; + /** custom IE info tuples */ + custom_ie_info info[]; +} __ATTRIB_PACK__ tlvbuf_max_mgmt_ie; + +/** custom IE */ +typedef 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[]; +} __ATTRIB_PACK__ custom_ie; + +/** TLV buffer : custom IE */ +typedef struct _tlvbuf_custom_ie { + /** Header */ + TLVHEADER; + /** custom IE data */ + custom_ie ie_data[]; +} __ATTRIB_PACK__ tlvbuf_custom_ie; + +/** Maximum length of lines in configuration file */ +#define MAX_CONFIG_LINE 1024 +/** Ethernet address length */ +#define ETH_ALEN 6 +/** MAC BROADCAST */ +#define MAC_BROADCAST 0x1FF +/** MAC MULTICAST */ +#define MAC_MULTICAST 0x1FE + +/** pkt_header */ +typedef struct _pkt_header { + /** pkt_len */ + t_u32 pkt_len; + /** pkt_type */ + t_u32 TxPktType; + /** tx control */ + t_u32 TxControl; +} pkt_header; + +/** wlan_802_11_header packet from FW with length */ +typedef struct _wlan_mgmt_frame_tx { + /** Packet Length */ + t_u16 frm_len; + /** Frame Control */ + t_u16 frm_ctl; + /** Duration ID */ + t_u16 duration_id; + /** Address1 */ + t_u8 addr1[ETH_ALEN]; + /** Address2 */ + t_u8 addr2[ETH_ALEN]; + /** Address3 */ + t_u8 addr3[ETH_ALEN]; + /** Sequence Control */ + t_u16 seq_ctl; + /** Address4 */ + t_u8 addr4[ETH_ALEN]; + /** Frame payload */ + t_u8 payload[]; +} __ATTRIB_PACK__ wlan_mgmt_frame_tx; + +/** frame tx ioctl number */ +#define FRAME_TX_IOCTL (SIOCDEVPRIVATE + 12) + +extern t_s32 sockfd; /**< socket */ +extern t_s8 dev_name[IFNAMSIZ + 1]; /**< device name */ + +#endif /* _MLANCONFIG_H_ */ diff --git a/mxm_wifiex/wlan_src/mapp/mlanconfig/mlanhostcmd.c b/mxm_wifiex/wlan_src/mapp/mlanconfig/mlanhostcmd.c new file mode 100644 index 0000000..e7af384 --- /dev/null +++ b/mxm_wifiex/wlan_src/mapp/mlanconfig/mlanhostcmd.c @@ -0,0 +1,928 @@ +/** @file mlanhostcmd.c + * + * @brief This file contains mlanconfig helper functions + * + * + * Copyright 2014-2020 NXP + * + * NXP CONFIDENTIAL + * The source code contained or described herein and all documents related to + * the source code (Materials) are owned by NXP, its + * suppliers and/or its licensors. Title to the Materials remains with NXP, + * its suppliers and/or its licensors. The Materials contain + * trade secrets and proprietary and confidential information of NXP, its + * suppliers and/or its licensors. The Materials are protected by worldwide copyright + * and trade secret laws and treaty provisions. No part of the Materials may be + * used, copied, reproduced, modified, published, uploaded, posted, + * transmitted, distributed, or disclosed in any way without NXP's prior + * express written permission. + * + * No license under any patent, copyright, trade secret or other intellectual + * property right is granted to or conferred upon you by disclosure or delivery + * of the Materials, either expressly, by implication, inducement, estoppel or + * otherwise. Any license under such intellectual property rights must be + * express and approved by NXP in writing. + * + */ +/************************************************************************ +Change log: + 11/26/2008: initial version +************************************************************************/ + +#include "mlanconfig.h" +#include "mlanhostcmd.h" + +#ifndef MIN +/** Find minimum value */ +#define MIN(a, b) ((a) < (b) ? (a) : (b)) +#endif /* MIN */ + +/******************************************************** + Local Variables +********************************************************/ + +/******************************************************** + Global Variables +********************************************************/ + +/******************************************************** + Local Functions +********************************************************/ +/** + * @brief get hostcmd data + * + * @param ln A pointer to line number + * @param buf A pointer to hostcmd data + * @param size A pointer to the return size of hostcmd buffer + * @return MLAN_STATUS_SUCCESS + */ +static int +mlan_get_hostcmd_data(FILE * fp, int *ln, t_u8 *buf, t_u16 *size) +{ + t_s32 errors = 0, i; + t_s8 line[512], *pos, *pos1, *pos2, *pos3; + t_u16 len; + + while ((pos = mlan_config_get_line(fp, line, sizeof(line), ln))) { + (*ln)++; + if (strcmp(pos, "}") == 0) { + break; + } + + pos1 = strchr(pos, ':'); + if (pos1 == NULL) { + printf("Line %d: Invalid hostcmd line '%s'\n", *ln, + pos); + errors++; + continue; + } + *pos1++ = '\0'; + + pos2 = strchr(pos1, '='); + if (pos2 == NULL) { + printf("Line %d: Invalid hostcmd line '%s'\n", *ln, + pos); + errors++; + continue; + } + *pos2++ = '\0'; + + len = a2hex_or_atoi(pos1); + if (len < 1 || len > MRVDRV_SIZE_OF_CMD_BUFFER) { + printf("Line %d: Invalid hostcmd line '%s'\n", *ln, + pos); + errors++; + continue; + } + + *size += len; + + if (*pos2 == '"') { + pos2++; + if ((pos3 = strchr(pos2, '"')) == NULL) { + printf("Line %d: invalid quotation '%s'\n", *ln, + pos); + errors++; + continue; + } + *pos3 = '\0'; + memset(buf, 0, len); + memmove(buf, pos2, MIN(strlen(pos2), len)); + buf += len; + } else if (*pos2 == '\'') { + pos2++; + if ((pos3 = strchr(pos2, '\'')) == NULL) { + printf("Line %d: invalid quotation '%s'\n", *ln, + pos); + errors++; + continue; + } + *pos3 = ','; + for (i = 0; i < len; i++) { + if ((pos3 = strchr(pos2, ',')) != NULL) { + *pos3 = '\0'; + *buf++ = (t_u8)a2hex_or_atoi(pos2); + pos2 = pos3 + 1; + } else + *buf++ = 0; + } + } else if (*pos2 == '{') { + t_u16 tlvlen = 0, tmp_tlvlen; + mlan_get_hostcmd_data(fp, ln, buf + len, &tlvlen); + tmp_tlvlen = tlvlen; + while (len--) { + *buf++ = (t_u8)(tmp_tlvlen & 0xff); + tmp_tlvlen >>= 8; + } + *size += tlvlen; + buf += tlvlen; + } else { + t_u32 value = a2hex_or_atoi(pos2); + while (len--) { + *buf++ = (t_u8)(value & 0xff); + value >>= 8; + } + } + } + return MLAN_STATUS_SUCCESS; +} + +/******************************************************** + Global Functions +********************************************************/ +/** + * @brief convert char to hex integer + * + * @param chr char to convert + * @return hex integer or 0 + */ +int +hexval(t_s32 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 Hump hex data + * + * @param prompt A pointer prompt buffer + * @param p A pointer to data buffer + * @param len the len of data buffer + * @param delim delim char + * @return hex integer + */ +t_void +hexdump(t_s8 *prompt, t_void *p, t_s32 len, t_s8 delim) +{ + t_s32 i; + t_u8 *s = p; + + if (prompt) { + printf("%s: len=%d\n", prompt, (int)len); + } + for (i = 0; i < len; i++) { + if (i != len - 1) + printf("%02x%c", *s++, delim); + else + printf("%02x\n", *s); + if ((i + 1) % 16 == 0) + printf("\n"); + } + printf("\n"); +} + +/** + * @brief convert char to hex integer + * + * @param chr char + * @return hex integer + */ +t_u8 +hexc2bin(t_s8 chr) +{ + if (chr >= '0' && chr <= '9') + chr -= '0'; + else if (chr >= 'A' && chr <= 'F') + chr -= ('A' - 10); + else if (chr >= 'a' && chr <= 'f') + chr -= ('a' - 10); + + return chr; +} + +/** + * @brief convert string to hex integer + * + * @param s A pointer string buffer + * @return hex integer + */ +t_u32 +a2hex(t_s8 *s) +{ + t_u32 val = 0; + + if (!strncasecmp("0x", s, 2)) { + s += 2; + } + + while (*s && isxdigit(*s)) { + val = (val << 4) + hexc2bin(*s++); + } + + return val; +} + +/* + * @brief convert String to integer + * + * @param value A pointer to string + * @return integer + */ +t_u32 +a2hex_or_atoi(t_s8 *value) +{ + if (value[0] == '0' && (value[1] == 'X' || value[1] == 'x')) { + return a2hex(value + 2); + } else if (isdigit(*value)) { + return atoi(value); + } else { + return *value; + } +} + +/** + * @brief convert string to hex + * + * @param ptr A pointer to data buffer + * @param chr A pointer to return integer + * @return A pointer to next data field + */ +t_s8 * +convert2hex(t_s8 *ptr, t_u8 *chr) +{ + t_u8 val; + + for (val = 0; *ptr && isxdigit(*ptr); ptr++) { + val = (val * 16) + hexval(*ptr); + } + + *chr = val; + + return ptr; +} + +/** + * @brief Check the Hex String + * @param s A pointer to the string + * @return MLAN_STATUS_SUCCESS --HexString, MLAN_STATUS_FAILURE --not HexString + */ +int +ishexstring(t_s8 *s) +{ + int ret = MLAN_STATUS_FAILURE; + t_s32 tmp; + + if (!strncasecmp("0x", s, 2)) { + s += 2; + } + while (*s) { + tmp = toupper(*s); + if (((tmp >= 'A') && (tmp <= 'F')) || + ((tmp >= '0') && (tmp <= '9'))) { + ret = MLAN_STATUS_SUCCESS; + } else { + ret = MLAN_STATUS_FAILURE; + break; + } + s++; + } + + return ret; +} + +/** + * @brief Convert String to Integer + * @param buf A pointer to the string + * @return Integer + */ +int +atoval(t_s8 *buf) +{ + if (!strncasecmp(buf, "0x", 2)) + return a2hex(buf + 2); + else if (!ishexstring(buf)) + return a2hex(buf); + else + return atoi(buf); +} + +/** + * @brief Prepare host-command buffer + * @param fp File handler + * @param cmd_name Command name + * @param buf A pointer to comand buffer + * @return MLAN_STATUS_SUCCESS--success, otherwise--fail + */ +int +prepare_host_cmd_buffer(FILE * fp, char *cmd_name, t_u8 *buf) +{ + t_s8 line[256], cmdname[256], *pos, cmdcode[10]; + HostCmd_DS_GEN *hostcmd; + int ln = 0; + int cmdname_found = 0, cmdcode_found = 0; + + memset(buf, 0, MRVDRV_SIZE_OF_CMD_BUFFER); + hostcmd = (HostCmd_DS_GEN *)buf; + hostcmd->command = 0xffff; + + snprintf(cmdname, sizeof(cmdname), "%s={", cmd_name); + cmdname_found = 0; + while ((pos = mlan_config_get_line(fp, line, sizeof(line), &ln))) { + if (strcmp(pos, cmdname) == 0) { + t_u16 len = 0; + cmdname_found = 1; + snprintf(cmdcode, sizeof(cmdcode), "CmdCode="); + cmdcode_found = 0; + while ((pos = + mlan_config_get_line(fp, line, sizeof(line), + &ln))) { + if (strncmp(pos, cmdcode, strlen(cmdcode)) == 0) { + cmdcode_found = 1; + hostcmd->command = + a2hex_or_atoi(pos + + strlen(cmdcode)); + hostcmd->size = S_DS_GEN; + mlan_get_hostcmd_data(fp, &ln, + buf + + hostcmd->size, + &len); + hostcmd->size += len; + break; + } + } + if (!cmdcode_found) { + fprintf(stderr, + "mlanconfig: CmdCode not found in conf file\n"); + return MLAN_STATUS_FAILURE; + } + break; + } + } + + if (!cmdname_found) { + fprintf(stderr, + "mlanconfig: cmdname '%s' is not found in conf file\n", + cmd_name); + return MLAN_STATUS_FAILURE; + } + + hostcmd->seq_num = 0; + hostcmd->result = 0; + hostcmd->command = cpu_to_le16(hostcmd->command); + hostcmd->size = cpu_to_le16(hostcmd->size); + return MLAN_STATUS_SUCCESS; +} + +/** Config data header length */ +#define CFG_DATA_HEADER_LEN 6 + +/** + * @brief Prepare cfg-data buffer + * @param argc number of arguments + * @param argv A pointer to arguments array + * @param fp File handler + * @param buf A pointer to comand buffer + * @return MLAN_STATUS_SUCCESS--success, otherwise--fail + */ +int +prepare_cfg_data_buffer(int argc, char *argv[], FILE * fp, t_u8 *buf) +{ + int ln = 0, type; + HostCmd_DS_GEN *hostcmd; + HostCmd_DS_802_11_CFG_DATA *pcfg_data; + + memset(buf, 0, MRVDRV_SIZE_OF_CMD_BUFFER); + hostcmd = (HostCmd_DS_GEN *)buf; + hostcmd->command = cpu_to_le16(HostCmd_CMD_CFG_DATA); + pcfg_data = (HostCmd_DS_802_11_CFG_DATA *)(buf + S_DS_GEN); + pcfg_data->action = + (argc == 4) ? HostCmd_ACT_GEN_GET : HostCmd_ACT_GEN_SET; + type = atoi(argv[3]); + if ((type < 1) || (type > 2)) { + fprintf(stderr, "mlanconfig: Invalid register type\n"); + return MLAN_STATUS_FAILURE; + } else { + pcfg_data->type = type; + } + if (argc == 5) { + ln = fparse_for_hex(fp, pcfg_data->data); + } + pcfg_data->data_len = ln; + hostcmd->size = + cpu_to_le16(pcfg_data->data_len + S_DS_GEN + + CFG_DATA_HEADER_LEN); + pcfg_data->data_len = cpu_to_le16(pcfg_data->data_len); + pcfg_data->type = cpu_to_le16(pcfg_data->type); + pcfg_data->action = cpu_to_le16(pcfg_data->action); + + hostcmd->seq_num = 0; + hostcmd->result = 0; + return MLAN_STATUS_SUCCESS; +} + +/** + * @brief Process host_cmd response + * @param buf A pointer to the response buffer + * @return MLAN_STATUS_SUCCESS--success, otherwise--fail + */ +int +process_host_cmd_resp(t_u8 *buf) +{ + HostCmd_DS_GEN *hostcmd = (HostCmd_DS_GEN *)buf; + int ret = MLAN_STATUS_SUCCESS; + + hostcmd->command = le16_to_cpu(hostcmd->command); + hostcmd->size = le16_to_cpu(hostcmd->size); + hostcmd->seq_num = le16_to_cpu(hostcmd->seq_num); + hostcmd->result = le16_to_cpu(hostcmd->result); + + hostcmd->command &= ~HostCmd_RET_BIT; + if (!hostcmd->result) { + switch (hostcmd->command) { + case HostCmd_CMD_CFG_DATA: + { + HostCmd_DS_802_11_CFG_DATA *pstcfgData = + (HostCmd_DS_802_11_CFG_DATA *)(buf + + S_DS_GEN); + pstcfgData->data_len = + le16_to_cpu(pstcfgData->data_len); + pstcfgData->action = + le16_to_cpu(pstcfgData->action); + + if (pstcfgData->action == HostCmd_ACT_GEN_GET) { + hexdump("cfgdata", pstcfgData->data, + pstcfgData->data_len, ' '); + } + break; + } + case HostCmd_CMD_802_11_TPC_ADAPT_REQ: + { + mlan_ioctl_11h_tpc_resp *tpcIoctlResp = + (mlan_ioctl_11h_tpc_resp *)(buf + + S_DS_GEN); + if (tpcIoctlResp->status_code == 0) { + printf("tpcrequest: txPower(%d), linkMargin(%d), rssi(%d)\n", tpcIoctlResp->tx_power, tpcIoctlResp->link_margin, tpcIoctlResp->rssi); + } else { + printf("tpcrequest: failure, status = %d\n", tpcIoctlResp->status_code); + } + break; + } + case HostCmd_CMD_802_11_CRYPTO: + { + t_u16 alg = + le16_to_cpu((t_u16) + *(buf + S_DS_GEN + + sizeof(t_u16))); + if (alg == CIPHER_TEST_AES_CCM || + alg == CIPHER_TEST_GCMP) { + HostCmd_DS_802_11_CRYPTO_AES_CCM + *cmd_aes_ccm = + (HostCmd_DS_802_11_CRYPTO_AES_CCM + *)(buf + S_DS_GEN); + + cmd_aes_ccm->encdec + = + le16_to_cpu(cmd_aes_ccm-> + encdec); + cmd_aes_ccm->algorithm = + le16_to_cpu(cmd_aes_ccm-> + algorithm); + cmd_aes_ccm->key_length = + le16_to_cpu(cmd_aes_ccm-> + key_length); + cmd_aes_ccm->nonce_length = + le16_to_cpu(cmd_aes_ccm-> + nonce_length); + cmd_aes_ccm->AAD_length = + le16_to_cpu(cmd_aes_ccm-> + AAD_length); + cmd_aes_ccm->data.header.type = + le16_to_cpu(cmd_aes_ccm->data. + header.type); + cmd_aes_ccm->data.header.len = + le16_to_cpu(cmd_aes_ccm->data. + header.len); + + printf("crypto_result: encdec=%d algorithm=%d, KeyLen=%d," " NonceLen=%d,AADLen=%d,dataLen=%d\n", cmd_aes_ccm->encdec, cmd_aes_ccm->algorithm, cmd_aes_ccm->key_length, cmd_aes_ccm->nonce_length, cmd_aes_ccm->AAD_length, cmd_aes_ccm->data.header.len); + + hexdump("Key", cmd_aes_ccm->key, + cmd_aes_ccm->key_length, ' '); + hexdump("Nonce", cmd_aes_ccm->nonce, + cmd_aes_ccm->nonce_length, ' '); + hexdump("AAD", cmd_aes_ccm->AAD, + cmd_aes_ccm->AAD_length, ' '); + hexdump("Data", cmd_aes_ccm->data.data, + cmd_aes_ccm->data.header.len, + ' '); + } else if (alg == CIPHER_TEST_WAPI) { + HostCmd_DS_802_11_CRYPTO_WAPI *cmd_wapi + = + (HostCmd_DS_802_11_CRYPTO_WAPI + *) (buf + S_DS_GEN); + + cmd_wapi->encdec + = le16_to_cpu(cmd_wapi->encdec); + cmd_wapi->algorithm + = + le16_to_cpu(cmd_wapi-> + algorithm); + cmd_wapi->key_length = + le16_to_cpu(cmd_wapi-> + key_length); + cmd_wapi->nonce_length = + le16_to_cpu(cmd_wapi-> + nonce_length); + cmd_wapi->AAD_length = + le16_to_cpu(cmd_wapi-> + AAD_length); + + printf("crypto_result: encdec=%d algorithm=%d, KeyLen=%d," " NonceLen=%d,AADLen=%d,dataLen=%d\n", cmd_wapi->encdec, cmd_wapi->algorithm, cmd_wapi->key_length, cmd_wapi->nonce_length, cmd_wapi->AAD_length, cmd_wapi->data_length); + + hexdump("Key", cmd_wapi->key, + cmd_wapi->key_length, ' '); + hexdump("Nonce", cmd_wapi->nonce, + cmd_wapi->nonce_length, ' '); + hexdump("AAD", cmd_wapi->AAD, + cmd_wapi->AAD_length, ' '); + } else { + HostCmd_DS_802_11_CRYPTO *cmd = + (HostCmd_DS_802_11_CRYPTO *)(buf + + + S_DS_GEN); + cmd->encdec = le16_to_cpu(cmd->encdec); + cmd->algorithm = + le16_to_cpu(cmd->algorithm); + cmd->key_IV_length = + le16_to_cpu(cmd->key_IV_length); + cmd->key_length = + le16_to_cpu(cmd->key_length); + cmd->data.header.type = + le16_to_cpu(cmd->data.header. + type); + cmd->data.header.len = + le16_to_cpu(cmd->data.header. + len); + + printf("crypto_result: encdec=%d algorithm=%d,KeyIVLen=%d," " KeyLen=%d,dataLen=%d\n", cmd->encdec, cmd->algorithm, cmd->key_IV_length, cmd->key_length, cmd->data.header.len); + hexdump("KeyIV", cmd->keyIV, + cmd->key_IV_length, ' '); + hexdump("Key", cmd->key, + cmd->key_length, ' '); + hexdump("Data", cmd->data.data, + cmd->data.header.len, ' '); + } + break; + } + case HostCmd_CMD_802_11_AUTO_TX: + { + HostCmd_DS_802_11_AUTO_TX *at = + (HostCmd_DS_802_11_AUTO_TX *)(buf + + S_DS_GEN); + + if (le16_to_cpu(at->action) == + HostCmd_ACT_GEN_GET) { + if (S_DS_GEN + sizeof(at->action) == + hostcmd->size) { + printf("auto_tx not configured\n"); + + } else { + MrvlIEtypesHeader_t *header = + &at->auto_tx.header; + + header->type = + le16_to_cpu(header-> + type); + header->len = + le16_to_cpu(header-> + len); + + if ((S_DS_GEN + + sizeof(at->action) + + + sizeof(MrvlIEtypesHeader_t) + + header->len == + hostcmd->size) && + (header->type == + TLV_TYPE_AUTO_TX)) { + + AutoTx_MacFrame_t *atmf + = + &at->auto_tx. + auto_tx_mac_frame; + + printf("Interval: %d second(s)\n", le16_to_cpu(atmf->interval)); + printf("Priority: %#x\n", atmf->priority); + printf("Frame Length: %d\n", le16_to_cpu(atmf->frame_len)); + printf("Dest Mac Address: " "%02x:%02x:%02x:%02x:%02x:%02x\n", atmf->dest_mac_addr[0], atmf->dest_mac_addr[1], atmf->dest_mac_addr[2], atmf->dest_mac_addr[3], atmf->dest_mac_addr[4], atmf->dest_mac_addr[5]); + printf("Src Mac Address: " "%02x:%02x:%02x:%02x:%02x:%02x\n", atmf->src_mac_addr[0], atmf->src_mac_addr[1], atmf->src_mac_addr[2], atmf->src_mac_addr[3], atmf->src_mac_addr[4], atmf->src_mac_addr[5]); + + hexdump("Frame Payload", + atmf->payload, + le16_to_cpu + (atmf-> + frame_len) + - + MLAN_MAC_ADDR_LENGTH + * 2, ' '); + } else { + printf("incorrect auto_tx command response\n"); + } + } + } + break; + } + case HostCmd_CMD_802_11_SUBSCRIBE_EVENT: + { + HostCmd_DS_802_11_SUBSCRIBE_EVENT *se = + (HostCmd_DS_802_11_SUBSCRIBE_EVENT + *)(buf + S_DS_GEN); + if (le16_to_cpu(se->action) == + HostCmd_ACT_GEN_GET) { + int len = + S_DS_GEN + + sizeof + (HostCmd_DS_802_11_SUBSCRIBE_EVENT); + printf("\nEvent\t\tValue\tFreq\tsubscribed\n\n"); + while (len < hostcmd->size) { + MrvlIEtypesHeader_t *header = + (MrvlIEtypesHeader_t + *)(buf + len); + switch (le16_to_cpu + (header->type)) { + case TLV_TYPE_RSSI_LOW: + { + MrvlIEtypes_RssiThreshold_t + *low_rssi + = + (MrvlIEtypes_RssiThreshold_t + *)(buf + + + len); + printf("Beacon Low RSSI\t%d\t%d\t%s\n", low_rssi->RSSI_value, low_rssi->RSSI_freq, (le16_to_cpu(se->events) & 0x0001) ? "yes" : "no"); + break; + } + case TLV_TYPE_SNR_LOW: + { + MrvlIEtypes_SnrThreshold_t + *low_snr + = + (MrvlIEtypes_SnrThreshold_t + *)(buf + + + len); + printf("Beacon Low SNR\t%d\t%d\t%s\n", low_snr->SNR_value, low_snr->SNR_freq, (le16_to_cpu(se->events) & 0x0002) ? "yes" : "no"); + break; + } + case TLV_TYPE_FAILCOUNT: + { + MrvlIEtypes_FailureCount_t + *failure_count + = + (MrvlIEtypes_FailureCount_t + *)(buf + + + len); + printf("Failure Count\t%d\t%d\t%s\n", failure_count->fail_value, failure_count->fail_freq, (le16_to_cpu(se->events) & 0x0004) ? "yes" : "no"); + break; + } + case TLV_TYPE_BCNMISS: + { + MrvlIEtypes_BeaconsMissed_t + *bcn_missed + = + (MrvlIEtypes_BeaconsMissed_t + *)(buf + + + len); + printf("Beacon Missed\t%d\tN/A\t%s\n", bcn_missed->beacon_missed, (le16_to_cpu(se->events) & 0x0008) ? "yes" : "no"); + break; + } + case TLV_TYPE_RSSI_HIGH: + { + MrvlIEtypes_RssiThreshold_t + *high_rssi + = + (MrvlIEtypes_RssiThreshold_t + *)(buf + + + len); + printf("Bcn High RSSI\t%d\t%d\t%s\n", high_rssi->RSSI_value, high_rssi->RSSI_freq, (le16_to_cpu(se->events) & 0x0010) ? "yes" : "no"); + break; + } + + case TLV_TYPE_SNR_HIGH: + { + MrvlIEtypes_SnrThreshold_t + *high_snr + = + (MrvlIEtypes_SnrThreshold_t + *)(buf + + + len); + printf("Beacon High SNR\t%d\t%d\t%s\n", high_snr->SNR_value, high_snr->SNR_freq, (le16_to_cpu(se->events) & 0x0020) ? "yes" : "no"); + break; + } + case TLV_TYPE_RSSI_LOW_DATA: + { + MrvlIEtypes_RssiThreshold_t + *low_rssi + = + (MrvlIEtypes_RssiThreshold_t + *)(buf + + + len); + printf("Data Low RSSI\t%d\t%d\t%s\n", low_rssi->RSSI_value, low_rssi->RSSI_freq, (le16_to_cpu(se->events) & 0x0040) ? "yes" : "no"); + break; + } + case TLV_TYPE_SNR_LOW_DATA: + { + MrvlIEtypes_SnrThreshold_t + *low_snr + = + (MrvlIEtypes_SnrThreshold_t + *)(buf + + + len); + printf("Data Low SNR\t%d\t%d\t%s\n", low_snr->SNR_value, low_snr->SNR_freq, (le16_to_cpu(se->events) & 0x0080) ? "yes" : "no"); + break; + } + case TLV_TYPE_RSSI_HIGH_DATA: + { + MrvlIEtypes_RssiThreshold_t + *high_rssi + = + (MrvlIEtypes_RssiThreshold_t + *)(buf + + + len); + printf("Data High RSSI\t%d\t%d\t%s\n", high_rssi->RSSI_value, high_rssi->RSSI_freq, (le16_to_cpu(se->events) & 0x0100) ? "yes" : "no"); + break; + } + case TLV_TYPE_SNR_HIGH_DATA: + { + MrvlIEtypes_SnrThreshold_t + *high_snr + = + (MrvlIEtypes_SnrThreshold_t + *)(buf + + + len); + printf("Data High SNR\t%d\t%d\t%s\n", high_snr->SNR_value, high_snr->SNR_freq, (le16_to_cpu(se->events) & 0x0200) ? "yes" : "no"); + break; + } + case TLV_TYPE_LINK_QUALITY: + { + MrvlIEtypes_LinkQuality_t + *link_qual + = + (MrvlIEtypes_LinkQuality_t + *)(buf + + + len); + printf("Link Quality Parameters:\n"); + printf("------------------------\n"); + printf("Link Quality Event Subscribed\t%s\n", (le16_to_cpu(se->events) & 0x0400) ? "yes" : "no"); + printf("Link SNR Threshold = %d\n", le16_to_cpu(link_qual->link_SNR_thrs)); + printf("Link SNR Frequency = %d\n", le16_to_cpu(link_qual->link_SNR_freq)); + printf("Min Rate Value = %d\n", le16_to_cpu(link_qual->min_rate_val)); + printf("Min Rate Frequency = %d\n", le16_to_cpu(link_qual->min_rate_freq)); + printf("Tx Latency Value = %d\n", le32_to_cpu(link_qual->tx_latency_val)); + printf("Tx Latency Threshold = %d\n", le32_to_cpu(link_qual->tx_latency_thrs)); + + break; + } + case TLV_TYPE_PRE_BEACON_LOST: + { + MrvlIEtypes_PreBeaconLost_t + *pre_bcn_lost + = + (MrvlIEtypes_PreBeaconLost_t + *)(buf + + + len); + printf("------------------------\n"); + printf("Pre-Beacon Lost Event Subscribed\t%s\n", (le16_to_cpu(se->events) & 0x0800) ? "yes" : "no"); + printf("Pre-Beacon Lost: %d\n", pre_bcn_lost->pre_beacon_lost); + break; + } + default: + printf("Unknown subscribed event TLV Type=%#x," " Len=%d\n", le16_to_cpu(header->type), le16_to_cpu(header->len)); + break; + } + + len += (sizeof + (MrvlIEtypesHeader_t) + + + le16_to_cpu(header-> + len)); + } + } + 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: + { + HostCmd_DS_REG *preg = + (HostCmd_DS_REG *)(buf + S_DS_GEN); + preg->action = le16_to_cpu(preg->action); + if (preg->action == HostCmd_ACT_GEN_GET) { + preg->value = le32_to_cpu(preg->value); + printf("value = 0x%08x\n", preg->value); + } + break; + } + case HostCmd_CMD_MEM_ACCESS: + { + HostCmd_DS_MEM *pmem = + (HostCmd_DS_MEM *)(buf + S_DS_GEN); + pmem->action = le16_to_cpu(pmem->action); + if (pmem->action == HostCmd_ACT_GEN_GET) { + pmem->value = le32_to_cpu(pmem->value); + printf("value = 0x%08x\n", pmem->value); + } + break; + } + default: + printf("HOSTCMD_RESP: CmdCode=%#04x, Size=%#04x," + " SeqNum=%#04x, Result=%#04x\n", + hostcmd->command, hostcmd->size, + hostcmd->seq_num, hostcmd->result); + hexdump("payload", + (t_void *)(buf + S_DS_GEN), + hostcmd->size - S_DS_GEN, ' '); + break; + } + } else { + printf("HOSTCMD failed: CmdCode=%#04x, Size=%#04x," + " SeqNum=%#04x, Result=%#04x\n", + hostcmd->command, hostcmd->size, + hostcmd->seq_num, hostcmd->result); + } + return ret; +} + +/** + * @brief Prepare the hostcmd for register access + * @param type Register type + * @param offset Register offset + * @param value Pointer to value (NULL for read) + * @param buf Pointer to hostcmd buffer + * @return MLAN_STATUS_SUCCESS--success, otherwise--fail + */ +int +prepare_hostcmd_regrdwr(t_u32 type, t_u32 offset, t_u32 *value, t_u8 *buf) +{ + HostCmd_DS_GEN *hostcmd; + HostCmd_DS_REG *preg; + + hostcmd = (HostCmd_DS_GEN *)buf; + switch (type) { + case 1: + hostcmd->command = cpu_to_le16(HostCmd_CMD_MAC_REG_ACCESS); + break; + case 2: + hostcmd->command = cpu_to_le16(HostCmd_CMD_BBP_REG_ACCESS); + break; + case 3: + hostcmd->command = cpu_to_le16(HostCmd_CMD_RF_REG_ACCESS); + break; + case 5: + hostcmd->command = cpu_to_le16(HostCmd_CMD_CAU_REG_ACCESS); + break; + default: + printf("Invalid register set specified\n"); + return -EINVAL; + } + preg = (HostCmd_DS_REG *)(buf + S_DS_GEN); + preg->action = (value) ? HostCmd_ACT_GEN_SET : HostCmd_ACT_GEN_GET; + preg->action = cpu_to_le16(preg->action); + preg->offset = cpu_to_le16((t_u16)offset); + if (value) + preg->value = cpu_to_le32(*value); + else + preg->value = 0; + hostcmd->size = cpu_to_le16(S_DS_GEN + sizeof(HostCmd_DS_REG)); + hostcmd->seq_num = 0; + hostcmd->result = 0; + + return MLAN_STATUS_SUCCESS; +} diff --git a/mxm_wifiex/wlan_src/mapp/mlanconfig/mlanhostcmd.h b/mxm_wifiex/wlan_src/mapp/mlanconfig/mlanhostcmd.h new file mode 100644 index 0000000..47da38f --- /dev/null +++ b/mxm_wifiex/wlan_src/mapp/mlanconfig/mlanhostcmd.h @@ -0,0 +1,390 @@ +/** @file mlanhostcmd.h + * + * @brief This file contains command structures for mlanconfig application + * + * + * Copyright 2014-2020 NXP + * + * NXP CONFIDENTIAL + * The source code contained or described herein and all documents related to + * the source code (Materials) are owned by NXP, its + * suppliers and/or its licensors. Title to the Materials remains with NXP, + * its suppliers and/or its licensors. The Materials contain + * trade secrets and proprietary and confidential information of NXP, its + * suppliers and/or its licensors. The Materials are protected by worldwide copyright + * and trade secret laws and treaty provisions. No part of the Materials may be + * used, copied, reproduced, modified, published, uploaded, posted, + * transmitted, distributed, or disclosed in any way without NXP's prior + * express written permission. + * + * No license under any patent, copyright, trade secret or other intellectual + * property right is granted to or conferred upon you by disclosure or delivery + * of the Materials, either expressly, by implication, inducement, estoppel or + * otherwise. Any license under such intellectual property rights must be + * express and approved by NXP in writing. + * + */ +/************************************************************************ +Change log: + 11/26/2008: initial version +************************************************************************/ +#ifndef _MLANHOSTCMD_H_ +#define _MLANHOSTCMD_H_ + +/** Find number of elements */ +#define NELEMENTS(x) (sizeof(x)/sizeof(x[0])) + +/** MLAN MAC Address Length */ +#define MLAN_MAC_ADDR_LENGTH (6) +/** Size of command buffer */ +#define MRVDRV_SIZE_OF_CMD_BUFFER (3 * 1024) + +/** 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 : Clear */ +#define HostCmd_ACT_GEN_CLEAR 0x0004 +/** General purpose action : Remove */ +#define HostCmd_ACT_GEN_REMOVE 0x0004 + +/** Host Command ID : Memory access */ +#define HostCmd_CMD_MEM_ACCESS 0x0086 + +/** Pre-Authenticate - 11r only */ +#define HostCmd_CMD_802_11_AUTHENTICATE 0x0011 + +/** Read/Write Mac register */ +#define HostCmd_CMD_MAC_REG_ACCESS 0x0019 +/** Read/Write BBP register */ +#define HostCmd_CMD_BBP_REG_ACCESS 0x001a +/** Read/Write RF register */ +#define HostCmd_CMD_RF_REG_ACCESS 0x001b +/** Get TX Power data */ +#define HostCmd_CMD_802_11_RF_TX_POWER 0x001e +/** Get the current TSF */ +#define HostCmd_CMD_GET_TSF 0x0080 +/** Host Command ID : CAU register access */ +#define HostCmd_CMD_CAU_REG_ACCESS 0x00ed + +/** Host Command ID : 802.11 BG scan configuration */ +#define HostCmd_CMD_802_11_BG_SCAN_CONFIG 0x006b +/** Host Command ID : Configuration data */ +#define HostCmd_CMD_CFG_DATA 0x008f +/** Host Command ID : 802.11 TPC adapt req */ +#define HostCmd_CMD_802_11_TPC_ADAPT_REQ 0x0060 +/** Host Command ID : 802.11 crypto */ +#define HostCmd_CMD_802_11_CRYPTO 0x0078 +/** Host Command ID : 802.11 auto Tx */ +#define HostCmd_CMD_802_11_AUTO_TX 0x0082 + +/** Host Command ID : 802.11 subscribe event */ +#define HostCmd_CMD_802_11_SUBSCRIBE_EVENT 0x0075 + +#ifdef OPCHAN +/** Host Command ID : Operating channel config */ +#define HostCmd_CMD_OPCHAN_CONFIG 0x00f8 +/** Host Command ID : Opchan channel group config */ +#define HostCmd_CMD_OPCHAN_CHANGROUP_CONFIG 0x00f9 +#endif + +/** Host Command ID : Channel TRPC config */ +#define HostCmd_CMD_CHAN_TRPC_CONFIG 0x00fb + +/** TLV type ID definition */ +#define PROPRIETARY_TLV_BASE_ID 0x0100 +/** 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 : 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 : Auto Tx */ +#define TLV_TYPE_AUTO_TX (PROPRIETARY_TLV_BASE_ID + 0x18) //0x0118 +/** 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: Pre-Beacon Lost */ +#define TLV_TYPE_PRE_BEACON_LOST (PROPRIETARY_TLV_BASE_ID + 0x49) //0x0149 + +#ifdef OPCHAN +/** TLV type : Operating channel control description */ +#define TLV_TYPE_OPCHAN_CONTROL_DESC (PROPRIETARY_TLV_BASE_ID + 0x79) //0x0179 +/** TLV type : Operating channel group control */ +#define TLV_TYPE_OPCHAN_CHANGRP_CTRL (PROPRIETARY_TLV_BASE_ID + 0x7a) //0x017a +#endif + +/** TLV type : Channel TRPC */ +#define TLV_TYPE_CHAN_TRPC (PROPRIETARY_TLV_BASE_ID + 0x89) //0x0189 + +/* Define general hostcmd data structure */ +/** HostCmd_DS_GEN */ +typedef struct MAPP_HostCmd_DS_GEN { + /** Command */ + t_u16 command; + /** Size */ + t_u16 size; + /** Sequence number */ + t_u16 seq_num; + /** Result */ + t_u16 result; +} __ATTRIB_PACK__ HostCmd_DS_GEN; + +typedef struct _HostCmd_DS_MEF_CFG { + /** Criteria */ + t_u32 Criteria; + /** Number of entries */ + t_u16 NumEntries; +} __ATTRIB_PACK__ HostCmd_DS_MEF_CFG; + +typedef struct _MEF_CFG_DATA { + /** Size */ + t_u16 size; + /** Data */ + HostCmd_DS_MEF_CFG data; +} __ATTRIB_PACK__ MEF_CFG_DATA; + +/** Size of HostCmd_DS_GEN */ +#define S_DS_GEN sizeof(HostCmd_DS_GEN) + +/** HostCmd_DS_REG */ +typedef struct MAPP_HostCmd_DS_REG { + /** Read or write */ + t_u16 action; + /** Register offset */ + t_u16 offset; + /** Value */ + t_u32 value; +} __ATTRIB_PACK__ HostCmd_DS_REG; + +/** HostCmd_DS_MEM */ +typedef struct MAPP_HostCmd_DS_MEM { + /** Read or write */ + t_u16 action; + /** Reserved */ + t_u16 reserved; + /** Address */ + t_u32 addr; + /** Value */ + t_u32 value; +} __ATTRIB_PACK__ HostCmd_DS_MEM; + +/** HostCmd_DS_802_11_CFG_DATA */ +typedef struct MAPP_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; + +/** mlan_ioctl_11h_tpc_resp */ +typedef struct { + int status_code; + /**< Firmware command result status code */ + int tx_power;/**< Reported TX Power from the TPC Report */ + int link_margin; + /**< Reported Link margin from the TPC Report */ + int rssi; /**< RSSI of the received TPC Report frame */ +} __ATTRIB_PACK__ mlan_ioctl_11h_tpc_resp; + +/** MrvlIEtypesHeader_t */ +typedef struct MrvlIEtypesHeader { + /** Header type */ + t_u16 type; + /** Header length */ + t_u16 len; +} __ATTRIB_PACK__ MrvlIEtypesHeader_t; + +/** MrvlIEtypes_Data_t */ +typedef struct MrvlIEtypes_Data_t { + /** Header */ + MrvlIEtypesHeader_t header; + /** Data */ + t_u8 data[1]; +} __ATTRIB_PACK__ MrvlIEtypes_Data_t; + +/** HostCmd_DS_802_11_CRYPTO */ +typedef struct MAPP_HostCmd_DS_802_11_CRYPTO { + t_u16 encdec; /**< Decrypt=0, Encrypt=1 */ + t_u16 algorithm; /**< RC4=1 AES=2 , AES_KEY_WRAP=3 */ + t_u16 key_IV_length;/**< Length of Key IV (bytes) */ + t_u8 keyIV[32]; /**< Key IV */ + t_u16 key_length; /**< Length of Key (bytes) */ + t_u8 key[32]; /**< Key */ + MrvlIEtypes_Data_t data; /**< Plain text if encdec=Encrypt, Ciphertext data if encdec=Decrypt*/ +} __ATTRIB_PACK__ HostCmd_DS_802_11_CRYPTO; + +/** HostCmd_DS_802_11_CRYPTO_AES_CCM */ +typedef struct MAPP_HostCmd_DS_802_11_CRYPTO_AES_CCM { + t_u16 encdec; /**< Decrypt=0, Encrypt=1 */ + t_u16 algorithm; /**< AES_CCM=4 */ + t_u16 key_length; /**< Length of Key (bytes) */ + t_u8 key[32]; /**< Key */ + t_u16 nonce_length;/**< Length of Nonce (bytes) */ + t_u8 nonce[14]; /**< Nonce */ + t_u16 AAD_length; /**< Length of AAD (bytes) */ + t_u8 AAD[32]; /**< AAD */ + MrvlIEtypes_Data_t data; /**< Plain text if encdec=Encrypt, Ciphertext data if encdec=Decrypt*/ +} __ATTRIB_PACK__ HostCmd_DS_802_11_CRYPTO_AES_CCM; + +/** HostCmd_DS_802_11_CRYPTO_WAPI */ +typedef struct MAPP_HostCmd_DS_802_11_CRYPTO_WAPI { + t_u16 encdec; /**< Decrypt=0, Encrypt=1 */ + t_u16 algorithm; /**< WAPI =5 */ + t_u16 key_length; /**< Length of Key (bytes) */ + t_u8 key[32]; /**< Key */ + t_u16 nonce_length;/**< Length of Nonce (bytes) */ + t_u8 nonce[16]; /**< Nonce */ + t_u16 AAD_length; /**< Length of AAD (bytes) */ + t_u8 AAD[48]; /**< AAD */ + t_u16 data_length; /**< Length of data (bytes) */ +} __ATTRIB_PACK__ HostCmd_DS_802_11_CRYPTO_WAPI; +/** WAPI cipher test */ +#define CIPHER_TEST_WAPI (5) +/** AES CCM cipher test */ +#define CIPHER_TEST_AES_CCM (4) +/** GCMP cipher test */ +#define CIPHER_TEST_GCMP (6) +/** AutoTx_MacFrame_t */ +typedef struct AutoTx_MacFrame { + t_u16 interval; /**< in seconds */ + t_u8 priority; /**< User Priority: 0~7, ignored if non-WMM */ + t_u8 reserved; /**< set to 0 */ + t_u16 frame_len; /**< Length of MAC frame payload */ + t_u8 dest_mac_addr[MLAN_MAC_ADDR_LENGTH]; /**< Destination MAC address */ + t_u8 src_mac_addr[MLAN_MAC_ADDR_LENGTH]; /**< Source MAC address */ + t_u8 payload[]; /**< Payload */ +} __ATTRIB_PACK__ AutoTx_MacFrame_t; + +/** MrvlIEtypes_AutoTx_t */ +typedef struct MrvlIEtypes_AutoTx { + MrvlIEtypesHeader_t header; /**< Header */ + AutoTx_MacFrame_t auto_tx_mac_frame; /**< Auto Tx MAC frame */ +} __ATTRIB_PACK__ MrvlIEtypes_AutoTx_t; + +/** HostCmd_DS_802_11_AUTO_TX */ +typedef struct MAPP_HostCmd_DS_802_11_AUTO_TX { + /** Action */ + t_u16 action; /* 0 = ACT_GET; 1 = ACT_SET; */ + MrvlIEtypes_AutoTx_t auto_tx; /**< Auto Tx */ +} __ATTRIB_PACK__ HostCmd_DS_802_11_AUTO_TX; + +/** HostCmd_DS_802_11_SUBSCRIBE_EVENT */ +typedef struct MAPP_HostCmd_DS_802_11_SUBSCRIBE_EVENT { + /** Action */ + t_u16 action; + /** Events */ + t_u16 events; +} __ATTRIB_PACK__ HostCmd_DS_802_11_SUBSCRIBE_EVENT; + +/** MrvlIEtypes_RssiParamSet_t */ +typedef struct MrvlIEtypes_RssiThreshold { + /** Header */ + MrvlIEtypesHeader_t header; + /** RSSI value */ + t_u8 RSSI_value; + /** RSSI frequency */ + t_u8 RSSI_freq; +} __ATTRIB_PACK__ MrvlIEtypes_RssiThreshold_t; + +/** MrvlIEtypes_SnrThreshold_t */ +typedef struct MrvlIEtypes_SnrThreshold { + /** Header */ + MrvlIEtypesHeader_t header; + /** SNR value */ + t_u8 SNR_value; + /** SNR frequency */ + t_u8 SNR_freq; +} __ATTRIB_PACK__ MrvlIEtypes_SnrThreshold_t; + +/** MrvlIEtypes_FailureCount_t */ +typedef struct MrvlIEtypes_FailureCount { + /** Header */ + MrvlIEtypesHeader_t header; + /** Failure value */ + t_u8 fail_value; + /** Failure frequency */ + t_u8 fail_freq; +} __ATTRIB_PACK__ MrvlIEtypes_FailureCount_t; + +/** MrvlIEtypes_BeaconsMissed_t */ +typedef struct MrvlIEtypes_BeaconsMissed { + /** Header */ + MrvlIEtypesHeader_t header; + /** Number of beacons missed */ + t_u8 beacon_missed; + /** Reserved */ + t_u8 reserved; +} __ATTRIB_PACK__ MrvlIEtypes_BeaconsMissed_t; + +/** MrvlIEtypes_LinkQuality_t */ +typedef struct MrvlIEtypes_LinkQuality { + /** Header */ + MrvlIEtypesHeader_t header; + /** Link SNR threshold */ + t_u16 link_SNR_thrs; + /** Link SNR frequency */ + t_u16 link_SNR_freq; + /** Minimum rate value */ + t_u16 min_rate_val; + /** Minimum rate frequency */ + t_u16 min_rate_freq; + /** Tx latency value */ + t_u32 tx_latency_val; + /** Tx latency threshold */ + t_u32 tx_latency_thrs; +} __ATTRIB_PACK__ MrvlIEtypes_LinkQuality_t; + +/** MrvlIEtypes_PreBeaconLost_t */ +typedef struct MrvlIEtypes_PreBeaconLost { + /** Header */ + MrvlIEtypesHeader_t header; + /** Pre-Beacon Lost */ + t_u8 pre_beacon_lost; + /** Reserved */ + t_u8 reserved; +} __ATTRIB_PACK__ MrvlIEtypes_PreBeaconLost_t; + +/* String helper functions */ +/** Convert char to hex integer */ +int hexval(t_s32 chr); +/** Convert char to hex integer */ +t_u8 hexc2bin(t_s8 chr); +/** Convert string to hex integer */ +t_u32 a2hex(t_s8 *s); +/** Check the Hex String */ +int ishexstring(t_s8 *s); +/** Convert String to integer */ +t_u32 a2hex_or_atoi(t_s8 *value); +/** Convert String to Integer */ +int atoval(t_s8 *buf); +/** Hump hex data */ +void hexdump(t_s8 *prompt, void *p, t_s32 len, t_s8 delim); +/** Convert String to Hex */ +t_s8 *convert2hex(t_s8 *ptr, t_u8 *chr); + +int process_host_cmd_resp(t_u8 *buf); +int prepare_host_cmd_buffer(FILE * fp, char *cmd_name, t_u8 *buf); +int prepare_cfg_data_buffer(int argc, char *argv[], FILE * fp, t_u8 *buf); +int prepare_hostcmd_regrdwr(t_u32 type, t_u32 offset, t_u32 *value, t_u8 *buf); + +#endif /* _MLANHOSTCMD_H_ */ diff --git a/mxm_wifiex/wlan_src/mapp/mlanconfig/mlanmisc.c b/mxm_wifiex/wlan_src/mapp/mlanconfig/mlanmisc.c new file mode 100644 index 0000000..56aa606 --- /dev/null +++ b/mxm_wifiex/wlan_src/mapp/mlanconfig/mlanmisc.c @@ -0,0 +1,1167 @@ +/** @file mlanmisc.c + * + * @brief Program to prepare command buffer + * + * + * Copyright 2014-2020 NXP + * + * NXP CONFIDENTIAL + * The source code contained or described herein and all documents related to + * the source code (Materials) are owned by NXP, its + * suppliers and/or its licensors. Title to the Materials remains with NXP, + * its suppliers and/or its licensors. The Materials contain + * trade secrets and proprietary and confidential information of NXP, its + * suppliers and/or its licensors. The Materials are protected by worldwide copyright + * and trade secret laws and treaty provisions. No part of the Materials may be + * used, copied, reproduced, modified, published, uploaded, posted, + * transmitted, distributed, or disclosed in any way without NXP's prior + * express written permission. + * + * No license under any patent, copyright, trade secret or other intellectual + * property right is granted to or conferred upon you by disclosure or delivery + * of the Materials, either expressly, by implication, inducement, estoppel or + * otherwise. Any license under such intellectual property rights must be + * express and approved by NXP in writing. + * + */ + +/************************************************************************ +Change log: + 03/10/2009: initial version +************************************************************************/ + +#include "mlanconfig.h" +#include "mlanhostcmd.h" +#include "mlanmisc.h" + +/******************************************************** + Local Variables +********************************************************/ + +/******************************************************** + Global Variables +********************************************************/ + +/******************************************************** + Local Functions +********************************************************/ + +/** + * @brief Helper function for process_getscantable_idx + * + * @param pbuf A pointer to the buffer + * @param buf_len buffer length + * + * @return NA + * + */ +static void +dump_scan_elems(const t_u8 *pbuf, uint buf_len) +{ + uint idx; + uint marker = 2 + pbuf[1]; + + for (idx = 0; idx < buf_len; idx++) { + if (idx % 0x10 == 0) { + printf("\n%04x: ", idx); + } + + if (idx == marker) { + printf("|"); + marker = idx + pbuf[idx + 1] + 2; + } else { + printf(" "); + } + + printf("%02x ", pbuf[idx]); + } + + printf("\n"); +} + +/** + * @brief Helper function for process_getscantable_idx + * Find next element + * + * @param pp_ie_out pointer of a IEEEtypes_Generic_t structure pointer + * @param p_buf_left integer pointer, which contains the number of left p_buf + * + * @return MLAN_STATUS_SUCCESS on success, otherwise MLAN_STATUS_FAILURE + */ +static int +scantable_elem_next(IEEEtypes_Generic_t **pp_ie_out, int *p_buf_left) +{ + IEEEtypes_Generic_t *pie_gen; + t_u8 *p_next; + + if (*p_buf_left < 2) { + return MLAN_STATUS_FAILURE; + } + + pie_gen = *pp_ie_out; + + p_next = (t_u8 *)pie_gen + (pie_gen->ieee_hdr.len + + sizeof(pie_gen->ieee_hdr)); + *p_buf_left -= (p_next - (t_u8 *)pie_gen); + + *pp_ie_out = (IEEEtypes_Generic_t *)p_next; + + if (*p_buf_left <= 0) { + return MLAN_STATUS_FAILURE; + } + + return MLAN_STATUS_SUCCESS; +} + + /** + * @brief Helper function for process_getscantable_idx + * scantable find element + * + * @param ie_buf pointer of the IE buffer + * @param ie_buf_len IE buffer length + * @param ie_type IE type + * @param ppie_out pointer to the IEEEtypes_Generic_t structure pointer + * @return MLAN_STATUS_SUCCESS on success, otherwise MLAN_STATUS_FAILURE + */ +static int +scantable_find_elem(t_u8 *ie_buf, + unsigned int ie_buf_len, + IEEEtypes_ElementId_e ie_type, + IEEEtypes_Generic_t **ppie_out) +{ + int found; + unsigned int ie_buf_left; + + ie_buf_left = ie_buf_len; + + found = FALSE; + + *ppie_out = (IEEEtypes_Generic_t *)ie_buf; + + do { + found = ((*ppie_out)->ieee_hdr.element_id == ie_type); + + } while (!found && + (scantable_elem_next(ppie_out, (int *)&ie_buf_left) == 0)); + + if (!found) { + *ppie_out = NULL; + } + + return (found ? MLAN_STATUS_SUCCESS : MLAN_STATUS_FAILURE); +} + + /** + * @brief Helper function for process_getscantable_idx + * It gets SSID from IE + * + * @param ie_buf IE buffer + * @param ie_buf_len IE buffer length + * @param pssid SSID + * @param ssid_buf_max size of SSID + * @return MLAN_STATUS_SUCCESS on success, otherwise MLAN_STATUS_FAILURE + */ +static int +scantable_get_ssid_from_ie(t_u8 *ie_buf, + unsigned int ie_buf_len, + t_u8 *pssid, unsigned int ssid_buf_max) +{ + int retval; + IEEEtypes_Generic_t *pie_gen; + + retval = scantable_find_elem(ie_buf, ie_buf_len, SSID, &pie_gen); + if (retval == MLAN_STATUS_SUCCESS) + memcpy(pssid, pie_gen->data, + MIN(pie_gen->ieee_hdr.len, ssid_buf_max)); + + return retval; +} + +/** + * @brief Display detailed information for a specific scan table entry + * + * @param prsp_info_req Scan table entry request structure + * @return MLAN_STATUS_SUCCESS--success, otherwise--fail + */ +int +process_getscantable_idx(wlan_ioctl_get_scan_table_info *prsp_info_req) +{ + int ioctl_val, subioctl_val; + struct iwreq iwr; + t_u8 *pcurrent; + int ret = 0; + char ssid[33]; + t_u16 tmp_cap; + t_u8 tsf[8]; + t_u16 beacon_interval; + t_u8 *scan_rsp_buf = NULL; + t_u16 cap_info; + wlan_ioctl_get_scan_table_info *prsp_info; + + wlan_get_scan_table_fixed fixed_fields; + t_u32 fixed_field_length; + t_u32 bss_info_length; + + scan_rsp_buf = (t_u8 *)malloc(SCAN_RESP_BUF_SIZE); + if (scan_rsp_buf == NULL) { + printf("Error: allocate memory for scan_rsp_buf failed\n"); + return -ENOMEM; + } + memset(ssid, 0x00, sizeof(ssid)); + + prsp_info = (wlan_ioctl_get_scan_table_info *)scan_rsp_buf; + + memcpy(prsp_info, prsp_info_req, + sizeof(wlan_ioctl_get_scan_table_info)); + + if (get_priv_ioctl("getscantable", + &ioctl_val, &subioctl_val) == MLAN_STATUS_FAILURE) { + ret = -EOPNOTSUPP; + goto done; + } + + /* + * Set up and execute the ioctl call + */ + strncpy(iwr.ifr_name, dev_name, IFNAMSIZ - 1); + iwr.u.data.pointer = (caddr_t) prsp_info; + iwr.u.data.length = SCAN_RESP_BUF_SIZE; + iwr.u.data.flags = subioctl_val; + + if (ioctl(sockfd, ioctl_val, &iwr) < 0) { + perror("mlanconfig: getscantable ioctl"); + ret = -EFAULT; + goto done; + } + + if (prsp_info->scan_number == 0) { + printf("mlanconfig: getscantable ioctl - index out of range\n"); + ret = -EINVAL; + goto done; + } + + pcurrent = prsp_info->scan_table_entry_buf; + + memcpy((t_u8 *)&fixed_field_length, + (t_u8 *)pcurrent, sizeof(fixed_field_length)); + pcurrent += sizeof(fixed_field_length); + + memcpy((t_u8 *)&bss_info_length, + (t_u8 *)pcurrent, sizeof(bss_info_length)); + pcurrent += sizeof(bss_info_length); + + memcpy((t_u8 *)&fixed_fields, (t_u8 *)pcurrent, sizeof(fixed_fields)); + pcurrent += fixed_field_length; + + /* time stamp is 8 byte long */ + memcpy(tsf, pcurrent, sizeof(tsf)); + pcurrent += sizeof(tsf); + bss_info_length -= sizeof(tsf); + + /* beacon interval is 2 byte long */ + memcpy(&beacon_interval, pcurrent, sizeof(beacon_interval)); + pcurrent += sizeof(beacon_interval); + bss_info_length -= sizeof(beacon_interval); + + /* capability information is 2 byte long */ + memcpy(&cap_info, pcurrent, sizeof(cap_info)); + pcurrent += sizeof(cap_info); + bss_info_length -= sizeof(cap_info); + + scantable_get_ssid_from_ie(pcurrent, + bss_info_length, (t_u8 *)ssid, sizeof(ssid)); + + printf("\n*** [%s], %02x:%02x:%02x:%02x:%02x:%2x\n", + ssid, + fixed_fields.bssid[0], + fixed_fields.bssid[1], + fixed_fields.bssid[2], + fixed_fields.bssid[3], + fixed_fields.bssid[4], fixed_fields.bssid[5]); + memcpy(&tmp_cap, &cap_info, sizeof(tmp_cap)); + printf("Channel = %d, SS = %d, CapInfo = 0x%04x, BcnIntvl = %d\n", + fixed_fields.channel, + 255 - fixed_fields.rssi, tmp_cap, beacon_interval); + + printf("TSF Values: AP(0x%02x%02x%02x%02x%02x%02x%02x%02x), ", + tsf[7], tsf[6], tsf[5], tsf[4], tsf[3], tsf[2], tsf[1], tsf[0]); + + printf("Network(0x%016llx)\n", fixed_fields.network_tsf); + printf("\n"); + printf("Element Data (%d bytes)\n", (int)bss_info_length); + printf("------------"); + dump_scan_elems(pcurrent, bss_info_length); + printf("\n"); + +done: + + if (scan_rsp_buf) + free(scan_rsp_buf); + + return ret; +} + +/******************************************************** + Global Functions +********************************************************/ +#ifdef SDIO +/** Maximum SDIO command-52 buffer length */ +#define CMD52_BUF_LEN 3 + +/** + * @brief SD comand52 read/write + * @param argc number of arguments + * @param argv A pointer to arguments array + * @return MLAN_STATUS_SUCCESS--success, otherwise--fail + */ +int +process_sdcmd52rw(int argc, char *argv[]) +{ + struct iwreq iwr; + int ioctl_val, subioctl_val, buf[CMD52_BUF_LEN]; + + if (get_priv_ioctl("sdcmd52rw", + &ioctl_val, &subioctl_val) == MLAN_STATUS_FAILURE) { + return -EOPNOTSUPP; + } + + if (argc == 5) { + /* CMD52 read */ + iwr.u.data.length = CMD52_BUF_LEN - 1; + } else if (argc == 6) { + /* CMD52 write */ + buf[2] = atoval(argv[5]); /* data */ + iwr.u.data.length = CMD52_BUF_LEN; + } else { + fprintf(stderr, "Invalid number of parameters!\n"); + return MLAN_STATUS_FAILURE; + } + buf[0] = atoval(argv[3]); /* func */ + buf[1] = atoval(argv[4]); /* reg */ + strncpy(iwr.ifr_name, dev_name, IFNAMSIZ - 1); + iwr.u.data.flags = subioctl_val; + iwr.u.data.pointer = (caddr_t) buf; + + if (ioctl(sockfd, ioctl_val, &iwr)) { + perror("mlanconfig"); + fprintf(stderr, + "mlanconfig: CMD52 R/W not supported by " + "interface %s\n", dev_name); + return MLAN_STATUS_FAILURE; + } + printf("sdcmd52rw returns 0x%02X\n", buf[0]); + + return MLAN_STATUS_SUCCESS; +} + +/** Maximum SDIO command-53 buffer length */ +#define CMD53_BUF_LEN 2000 + +/** + * @brief SD comand53 read/write + * + * @param argc number of arguments + * @param argv A pointer to arguments array + * @return MLAN_STATUS_SUCCESS--success, otherwise--fail + */ +int +process_sdcmd53rw(int argc, char *argv[]) +{ + struct iwreq iwr; + t_s8 *buf = NULL; + int addr, mode, blklen, blknum, i, rw; + int ioctl_val, subioctl_val; + + if (get_priv_ioctl("sdcmd53rw", + &ioctl_val, &subioctl_val) == MLAN_STATUS_FAILURE) { + return -EOPNOTSUPP; + } + + if (argc < 8) { + fprintf(stderr, "Invalid number of parameters!\n"); + return MLAN_STATUS_FAILURE; + } + + if (!(buf = malloc(CMD53_BUF_LEN))) + return -ENOMEM; + memset(buf, 0, CMD53_BUF_LEN); + + if (argc == 8) { + rw = buf[0] = 0; /* CMD53 read */ + } else { + rw = buf[0] = 1; /* CMD53 write */ + } + buf[1] = atoval(argv[3]); /* func */ + addr = atoval(argv[4]); /* address */ + buf[2] = addr & 0xff; + buf[3] = (addr >> 8) & 0xff; + buf[4] = (addr >> 16) & 0xff; + buf[5] = (addr >> 24) & 0xff; + mode = atoval(argv[5]); /* mode */ + buf[6] = (t_u8)mode; + blklen = atoval(argv[6]); /* block size */ + buf[7] = blklen & 0xff; + buf[8] = (blklen >> 8) & 0xff; + blknum = atoval(argv[7]); /* block number or byte number */ + buf[9] = blknum & 0xff; + buf[10] = (blknum >> 8) & 0xff; + iwr.u.data.length = 11; + if (buf[0]) { + for (i = 0; i < (argc - 8); i++) + buf[11 + i] = atoval(argv[8 + i]); + iwr.u.data.length += (argc - 8); + } + strncpy(iwr.ifr_name, dev_name, IFNAMSIZ - 1); + iwr.u.data.flags = subioctl_val; + iwr.u.data.pointer = (caddr_t) buf; + + if (ioctl(sockfd, ioctl_val, &iwr)) { + perror("mlanconfig"); + fprintf(stderr, + "mlanconfig: CMD53 R/W not supported by " + "interface %s\n", dev_name); + free(buf); + return MLAN_STATUS_FAILURE; + } + + if (mode) { + fprintf(stderr, "CMD53rw blklen = %d, blknum = %d\n", blklen, + blknum); + } else { + blklen = 1; + fprintf(stderr, "CMD53rw bytelen = %d\n", blknum); + } + if (!rw) + hexdump("data", buf, blklen * blknum, ' '); + + free(buf); + return MLAN_STATUS_SUCCESS; +} +#endif + +/** + * @brief Retrieve and display the contents of the driver scan table. + * + * The ioctl to retrieve the scan table contents will be invoked, and portions + * of the scan data will be displayed on stdout. The entire beacon or + * probe response is also retrieved (if available in the driver). This + * data would be needed in case the application was explicitly controlling + * the association (inserting IEs, TLVs, etc). + * + * @param argc number of arguments + * @param argv A pointer to arguments array + * + * @return MLAN_STATUS_SUCCESS--success, otherwise--fail + */ +int +process_getscantable(int argc, char *argv[]) +{ + int ioctl_val, subioctl_val; + struct iwreq iwr; + t_u8 *scan_rsp_buf = NULL; + + struct wlan_ioctl_get_scan_list *scan_list_head = NULL; + struct wlan_ioctl_get_scan_list *scan_list_node = NULL; + struct wlan_ioctl_get_scan_list *curr = NULL, *prev = NULL, *next = + NULL; + + t_u32 total_scan_res = 0; + + unsigned int scan_start; + int idx, ret = 0; + + t_u8 *pcurrent; + t_u8 *pnext; + IEEEtypes_ElementId_e *pelement_id; + t_u8 *pelement_len; + int ssid_idx; + t_u8 *pbyte; + t_u16 new_ss; + t_u16 curr_ss; + + IEEEtypes_VendorSpecific_t *pwpa_ie; + const t_u8 wpa_oui[4] = { 0x00, 0x50, 0xf2, 0x01 }; + + IEEEtypes_WmmParameter_t *pwmm_ie; + const t_u8 wmm_oui[4] = { 0x00, 0x50, 0xf2, 0x02 }; + IEEEtypes_VendorSpecific_t *pwps_ie; + const t_u8 wps_oui[4] = { 0x00, 0x50, 0xf2, 0x04 }; + + int displayed_info; + + wlan_ioctl_get_scan_table_info rspInfoReq; + wlan_ioctl_get_scan_table_info *prsp_info; + + wlan_get_scan_table_fixed fixed_fields; + t_u32 fixed_field_length; + t_u32 bss_info_length; + wlan_ioctl_get_bss_info *bss_info; + + scan_rsp_buf = (t_u8 *)malloc(SCAN_RESP_BUF_SIZE); + if (scan_rsp_buf == NULL) { + printf("Error: allocate memory for scan_rsp_buf failed\n"); + return -ENOMEM; + } + prsp_info = (wlan_ioctl_get_scan_table_info *)scan_rsp_buf; + + if (get_priv_ioctl("getscantable", + &ioctl_val, &subioctl_val) == MLAN_STATUS_FAILURE) { + ret = -EOPNOTSUPP; + goto done; + } + + if (argc > 3 && (strcmp(argv[3], "tsf") != 0) + && (strcmp(argv[3], "help") != 0)) { + + idx = strtol(argv[3], NULL, 10); + + if (idx >= 0) { + if (scan_rsp_buf) { + free(scan_rsp_buf); + } + rspInfoReq.scan_number = idx; + return process_getscantable_idx(&rspInfoReq); + } + } + + displayed_info = FALSE; + scan_start = 1; + + do { + prsp_info->scan_number = scan_start; + + /* + * Set up and execute the ioctl call + */ + strncpy(iwr.ifr_name, dev_name, IFNAMSIZ - 1); + iwr.u.data.pointer = (caddr_t) prsp_info; + iwr.u.data.length = SCAN_RESP_BUF_SIZE; + iwr.u.data.flags = subioctl_val; + + if (ioctl(sockfd, ioctl_val, &iwr) < 0) { + perror("mlanconfig: getscantable ioctl"); + ret = -EFAULT; + goto done; + } + total_scan_res += prsp_info->scan_number; + + pcurrent = 0; + pnext = prsp_info->scan_table_entry_buf; + + for (idx = 0; (unsigned int)idx < prsp_info->scan_number; idx++) { + + /* Alloc memory for new node for next BSS */ + scan_list_node = (struct wlan_ioctl_get_scan_list *) + malloc(sizeof(struct wlan_ioctl_get_scan_list)); + if (scan_list_node == NULL) { + printf("Error: allocate memory for scan_list_head failed\n"); + return -ENOMEM; + } + memset(scan_list_node, 0, + sizeof(struct wlan_ioctl_get_scan_list)); + + /* + * Set pcurrent to pnext in case pad bytes are at the end + * of the last IE we processed. + */ + pcurrent = pnext; + + /* Start extracting each BSS to prepare a linked list */ + memcpy((t_u8 *)&fixed_field_length, + (t_u8 *)pcurrent, sizeof(fixed_field_length)); + pcurrent += sizeof(fixed_field_length); + + memcpy((t_u8 *)&bss_info_length, + (t_u8 *)pcurrent, sizeof(bss_info_length)); + pcurrent += sizeof(bss_info_length); + + memcpy((t_u8 *)&fixed_fields, + (t_u8 *)pcurrent, sizeof(fixed_fields)); + pcurrent += fixed_field_length; + + scan_list_node->fixed_buf.fixed_field_length = + fixed_field_length; + scan_list_node->fixed_buf.bss_info_length = + bss_info_length; + scan_list_node->fixed_buf.fixed_fields = fixed_fields; + + bss_info = &scan_list_node->bss_info_buf; + + /* Set next to be the start of the next scan entry */ + pnext = pcurrent + bss_info_length; + + if (bss_info_length >= + (sizeof(bss_info->tsf) + + sizeof(bss_info->beacon_interval) + + sizeof(bss_info->cap_info))) { + + /* time stamp is 8 byte long */ + memcpy(bss_info->tsf, pcurrent, + sizeof(bss_info->tsf)); + pcurrent += sizeof(bss_info->tsf); + bss_info_length -= sizeof(bss_info->tsf); + + /* beacon interval is 2 byte long */ + memcpy(&bss_info->beacon_interval, pcurrent, + sizeof(bss_info->beacon_interval)); + pcurrent += sizeof(bss_info->beacon_interval); + bss_info_length -= + sizeof(bss_info->beacon_interval); + + /* capability information is 2 byte long */ + memcpy(&bss_info->cap_info, pcurrent, + sizeof(bss_info->cap_info)); + pcurrent += sizeof(bss_info->cap_info); + bss_info_length -= sizeof(bss_info->cap_info); + } + + bss_info->wmm_cap = ' '; /* M (WMM), C (WMM-Call Admission Control) */ + bss_info->wps_cap = ' '; /* "S" */ + bss_info->dot11k_cap = ' '; /* "K" */ + bss_info->dot11r_cap = ' '; /* "R" */ + bss_info->ht_cap = ' '; /* "N" */ + + /* "P" for Privacy (WEP) since "W" is WPA, and "2" is RSN/WPA2 */ + bss_info->priv_cap = + bss_info->cap_info.privacy ? 'P' : ' '; + + memset(bss_info->ssid, 0, MRVDRV_MAX_SSID_LENGTH + 1); + bss_info->ssid_len = 0; + + while (bss_info_length >= 2) { + pelement_id = (IEEEtypes_ElementId_e *)pcurrent; + pelement_len = pcurrent + 1; + pcurrent += 2; + + switch (*pelement_id) { + + case SSID: + if (*pelement_len && + *pelement_len <= + MRVDRV_MAX_SSID_LENGTH) { + memcpy(bss_info->ssid, pcurrent, + *pelement_len); + bss_info->ssid_len = + *pelement_len; + } + break; + + case WPA_IE: + pwpa_ie = + (IEEEtypes_VendorSpecific_t *) + pelement_id; + if ((memcmp + (pwpa_ie->vend_hdr.oui, wpa_oui, + sizeof(pwpa_ie->vend_hdr.oui)) == + 0) + && (pwpa_ie->vend_hdr.oui_type == + wpa_oui[3])) { + /* WPA IE found, 'W' for WPA */ + bss_info->priv_cap = 'W'; + } else { + pwmm_ie = + (IEEEtypes_WmmParameter_t + *)pelement_id; + if ((memcmp + (pwmm_ie->vend_hdr.oui, + wmm_oui, + sizeof(pwmm_ie->vend_hdr. + oui)) == 0) + && (pwmm_ie->vend_hdr. + oui_type == + wmm_oui[3])) { + /* Check the subtype: 1 == parameter, 0 == info */ + if ((pwmm_ie->vend_hdr. + oui_subtype == 1) + && pwmm_ie-> + ac_params + [WMM_AC_VO]. + aci_aifsn.acm) { + /* Call admission on VO; 'C' for CAC */ + bss_info-> + wmm_cap + = 'C'; + } else { + /* No CAC; 'M' for uh, WMM */ + bss_info-> + wmm_cap + = 'M'; + } + } else { + pwps_ie = + (IEEEtypes_VendorSpecific_t + *)pelement_id; + if ((memcmp + (pwps_ie->vend_hdr. + oui, wps_oui, + sizeof(pwps_ie-> + vend_hdr. + oui)) == 0) + && (pwps_ie-> + vend_hdr. + oui_type == + wps_oui[3])) { + bss_info-> + wps_cap + = 'S'; + } + } + } + break; + + case RSN_IE: + /* RSN IE found; '2' for WPA2 (RSN) */ + bss_info->priv_cap = '2'; + break; + case HT_CAPABILITY: + bss_info->ht_cap = 'N'; + break; + case VHT_CAPABILITY: + bss_info->vht_cap[0] = 'A'; + bss_info->vht_cap[1] = 'C'; + break; + default: + break; + } + + pcurrent += *pelement_len; + bss_info_length -= (2 + *pelement_len); + } + + /* Create a sorted list of BSS using Insertion Sort. + Sort as per Signal Strength (descending order) */ + new_ss = 255 - fixed_fields.rssi; + + if (scan_list_head == NULL) { + // Node is the first element in the list. + scan_list_head = scan_list_node; + scan_list_node->next = NULL; + } else { + + curr_ss = + 255 - + scan_list_head->fixed_buf.fixed_fields. + rssi; + + if (new_ss > curr_ss) { + // Insert the node to head of the list + scan_list_node->next = scan_list_head; + scan_list_head = scan_list_node; + } else { + for (curr = scan_list_head; + curr != NULL; curr = curr->next) { + curr_ss = + 255 - + curr->fixed_buf. + fixed_fields.rssi; + if (prev && (new_ss > curr_ss)) { + // Insert the node to current position in list + scan_list_node->next = + curr; + prev->next = + scan_list_node; + break; + } + prev = curr; + } + if (prev && (curr == NULL)) { + // Insert the node to tail of the list + prev->next = scan_list_node; + scan_list_node->next = NULL; + } + } + } + } + + scan_start += prsp_info->scan_number; + } while (prsp_info->scan_number); + + // Display scan results + printf("---------------------------------------"); + printf("---------------------------------------\n"); + printf("# | ch | ss | bssid | cap | SSID \n"); + printf("---------------------------------------"); + printf("---------------------------------------\n"); + + for (curr = scan_list_head, idx = 0; + (curr != NULL) && ((unsigned int)idx < total_scan_res); + curr = curr->next, idx++) { + + fixed_fields = curr->fixed_buf.fixed_fields; + bss_info = &curr->bss_info_buf; + + printf("%02u| %03d | %03d | %02x:%02x:%02x:%02x:%02x:%02x |", + idx, + fixed_fields.channel, + 255 - fixed_fields.rssi, + fixed_fields.bssid[0], + fixed_fields.bssid[1], + fixed_fields.bssid[2], + fixed_fields.bssid[3], + fixed_fields.bssid[4], fixed_fields.bssid[5]); + + displayed_info = TRUE; + + /* "A" for Adhoc + * "I" for Infrastructure, + * "D" for DFS (Spectrum Mgmt) + */ + printf(" %c%c%c%c%c%c%c%c%c%c | ", bss_info->cap_info.ibss ? 'A' : 'I', bss_info->priv_cap, /* P (WEP), W (WPA), 2 (WPA2) */ + bss_info->cap_info.spectrum_mgmt ? 'D' : ' ', bss_info->wmm_cap, /* M (WMM), C (WMM-Call Admission Control) */ + bss_info->dot11k_cap, /* K */ + bss_info->dot11r_cap, /* R */ + bss_info->wps_cap, /* S */ + bss_info->ht_cap, /* N */ + bss_info->vht_cap[0], /* AC */ + bss_info->vht_cap[1]); + + /* Print out the ssid or the hex values if non-printable */ + for (ssid_idx = 0; ssid_idx < bss_info->ssid_len; ssid_idx++) { + if (isprint(bss_info->ssid[ssid_idx])) { + printf("%c", bss_info->ssid[ssid_idx]); + } else { + printf("\\%02x", bss_info->ssid[ssid_idx]); + } + } + + printf("\n"); + + if (argc > 3 && strcmp(argv[3], "tsf") == 0) { + /* TSF is a u64, some formatted printing libs have trouble + printing long longs, so cast and dump as bytes */ + pbyte = (t_u8 *)&fixed_fields.network_tsf; + printf(" TSF=%02x%02x%02x%02x%02x%02x%02x%02x\n", + pbyte[7], pbyte[6], pbyte[5], pbyte[4], + pbyte[3], pbyte[2], pbyte[1], pbyte[0]); + } + } + + if (displayed_info == TRUE) { + if (argc > 3 && strcmp(argv[3], "help") == 0) { + printf("\n\n" + "Capability Legend (Not all may be supported)\n" + "-----------------\n" + " I [ Infrastructure ]\n" + " A [ Ad-hoc ]\n" + " W [ WPA IE ]\n" + " 2 [ WPA2/RSN IE ]\n" + " M [ WMM IE ]\n" + " C [ Call Admission Control - WMM IE, VO ACM set ]\n" + " D [ Spectrum Management - DFS (11h) ]\n" + " K [ 11k ]\n" + " R [ 11r ]\n" + " S [ WPS ]\n" + " N [ HT (11n) ]\n" + " AC [VHT (11ac) ]\n" "\n\n"); + } + } else { + printf("< No Scan Results >\n"); + } + +done: + if (scan_rsp_buf) + free(scan_rsp_buf); + for (curr = scan_list_head; curr != NULL; curr = next) { + next = curr->next; + free(curr); + } + return ret; +} + +/** Maximum channel scratch */ +#define MAX_CHAN_SCRATCH 100 + +/** Maximum channel number for b/g band */ +#define MAX_CHAN_BG_BAND 14 + +/** Maximum number of probes to send on each channel */ +#define MAX_PROBES 5 + +/** Scan all the channels in specified band */ +#define BAND_SPECIFIED 0x80 +/** + * @brief Request a scan from the driver and display the scan table afterwards + * + * Command line interface for performing a specific immediate scan based + * on the following keyword parsing: + * + * chan=[chan#][band][mode] where band is [a,b,g,n] and mode is + * blank for active or 'p' for passive + * bssid=xx:xx:xx:xx:xx:xx specify a BSSID filter for the scan + * ssid="[SSID]" specify a SSID filter for the scan + * keep=[0 or 1] keep the previous scan results (1), discard (0) + * dur=[scan time] time to scan for each channel in milliseconds + * probes=[#] number of probe requests to send on each chan + * type=[1,2,3] BSS type: 1 (Infra), 2(Adhoc), 3(Any) + * + * Any combination of the above arguments can be supplied on the command line. + * If the chan token is absent, a full channel scan will be completed by + * the driver. If the dur or probes tokens are absent, the drivers default + * setting will be used. The bssid and ssid fields, if blank, + * will produce an unfiltered scan. The type field will default to 3 (Any) + * and the keep field will default to 0 (Discard). + * + * @param argc number of arguments + * @param argv A pointer to arguments array + * + * @return MLAN_STATUS_SUCCESS--success, otherwise--fail + */ +int +process_setuserscan(int argc, char *argv[]) +{ + wlan_ioctl_user_scan_cfg scan_req; + int ioctl_val, subioctl_val; + struct iwreq iwr; + char *parg_tok; + char *pchan_tok; + char *parg_cookie; + char *pchan_cookie; + int arg_idx; + int chan_parse_idx; + int chan_cmd_idx; + char chan_scratch[MAX_CHAN_SCRATCH]; + char *pscratch; + int tmp_idx; + int scan_time; + int num_ssid; + int is_radio_set; + unsigned int mac[ETH_ALEN]; + + memset(&scan_req, 0x00, sizeof(scan_req)); + chan_cmd_idx = 0; + scan_time = 0; + num_ssid = 0; + + if (get_priv_ioctl("setuserscan", + &ioctl_val, &subioctl_val) == MLAN_STATUS_FAILURE) { + return -EOPNOTSUPP; + } + + for (arg_idx = 0; arg_idx < argc; arg_idx++) { + + if (strncmp(argv[arg_idx], "ssid=", strlen("ssid=")) == 0) { + /* + * "ssid" token string handler + */ + if (num_ssid < MRVDRV_MAX_SSID_LIST_LENGTH) { + strncpy(scan_req.ssid_list[num_ssid].ssid, + argv[arg_idx] + strlen("ssid="), + sizeof(scan_req.ssid_list[num_ssid]. + ssid)); + + scan_req.ssid_list[num_ssid].max_len = 0; + + num_ssid++; + } + } else if (strncmp(argv[arg_idx], "bssid=", strlen("bssid=")) == + 0) { + /* + * "bssid" token string handler + */ + sscanf(argv[arg_idx] + strlen("bssid="), + "%2x:%2x:%2x:%2x:%2x:%2x", mac + 0, mac + 1, + mac + 2, mac + 3, mac + 4, mac + 5); + + for (tmp_idx = 0; + (unsigned int)tmp_idx < NELEMENTS(mac); + tmp_idx++) { + scan_req.specific_bssid[tmp_idx] = + (t_u8)mac[tmp_idx]; + } + } else if (strncmp(argv[arg_idx], "chan=", strlen("chan=")) == + 0) { + /* + * "chan" token string handler + */ + parg_tok = argv[arg_idx] + strlen("chan="); + + if (strlen(parg_tok) > MAX_CHAN_SCRATCH) { + printf("Error: Specified channels exceeds max limit\n"); + return MLAN_STATUS_FAILURE; + } + is_radio_set = FALSE; + + while ((parg_tok = + strtok_r(parg_tok, ",", + &parg_cookie)) != NULL) { + + memset(chan_scratch, 0x00, + sizeof(chan_scratch)); + pscratch = chan_scratch; + + for (chan_parse_idx = 0; + (unsigned int)chan_parse_idx < + strlen(parg_tok); chan_parse_idx++) { + if (isalpha + (*(parg_tok + chan_parse_idx))) { + *pscratch++ = ' '; + } + + *pscratch++ = + *(parg_tok + chan_parse_idx); + } + *pscratch = 0; + parg_tok = NULL; + + pchan_tok = chan_scratch; + + while ((pchan_tok = strtok_r(pchan_tok, " ", + &pchan_cookie)) != + NULL) { + if (isdigit(*pchan_tok)) { + scan_req. + chan_list[chan_cmd_idx]. + chan_number = + atoi(pchan_tok); + if (scan_req. + chan_list[chan_cmd_idx]. + chan_number > + MAX_CHAN_BG_BAND) + scan_req. + chan_list + [chan_cmd_idx]. + radio_type = 1; + } else { + switch (toupper(*pchan_tok)) { + case 'A': + scan_req. + chan_list + [chan_cmd_idx]. + radio_type = 1; + is_radio_set = TRUE; + break; + case 'B': + case 'G': + scan_req. + chan_list + [chan_cmd_idx]. + radio_type = 0; + is_radio_set = TRUE; + break; + case 'N': + break; + case 'P': + scan_req. + chan_list + [chan_cmd_idx]. + scan_type = + MLAN_SCAN_TYPE_PASSIVE; + break; + default: + printf("Error: Band type not supported!\n"); + return -EOPNOTSUPP; + } + if (!chan_cmd_idx && + !scan_req. + chan_list[chan_cmd_idx]. + chan_number && is_radio_set) + scan_req. + chan_list + [chan_cmd_idx]. + radio_type |= + BAND_SPECIFIED; + } + pchan_tok = NULL; + } + chan_cmd_idx++; + } + } else if (strncmp(argv[arg_idx], "keep=", strlen("keep=")) == + 0) { + /* + * "keep" token string handler + */ + scan_req.keep_previous_scan = + atoi(argv[arg_idx] + strlen("keep=")); + } else if (strncmp(argv[arg_idx], "dur=", strlen("dur=")) == 0) { + /* + * "dur" token string handler + */ + scan_time = atoi(argv[arg_idx] + strlen("dur=")); + scan_req.chan_list[0].scan_time = scan_time; + + } else if (strncmp(argv[arg_idx], "wc=", strlen("wc=")) == 0) { + + if (num_ssid < MRVDRV_MAX_SSID_LIST_LENGTH) { + /* + * "wc" token string handler + */ + pscratch = strrchr(argv[arg_idx], ','); + + if (pscratch) { + *pscratch = 0; + pscratch++; + + if (isdigit(*pscratch)) { + scan_req.ssid_list[num_ssid]. + max_len = + atoi(pscratch); + } else { + scan_req.ssid_list[num_ssid]. + max_len = *pscratch; + } + } else { + /* Standard wildcard matching */ + scan_req.ssid_list[num_ssid].max_len = + 0xFF; + } + + strncpy(scan_req.ssid_list[num_ssid].ssid, + argv[arg_idx] + strlen("wc="), + sizeof(scan_req.ssid_list[num_ssid]. + ssid)); + + num_ssid++; + } + } else if (strncmp(argv[arg_idx], "probes=", strlen("probes=")) + == 0) { + /* + * "probes" token string handler + */ + scan_req.num_probes = + atoi(argv[arg_idx] + strlen("probes=")); + if (scan_req.num_probes > MAX_PROBES) { + fprintf(stderr, "Invalid probes (> %d)\n", + MAX_PROBES); + return -EOPNOTSUPP; + } + } else if (strncmp(argv[arg_idx], "type=", strlen("type=")) == + 0) { + /* + * "type" token string handler + */ + scan_req.bss_mode = + atoi(argv[arg_idx] + strlen("type=")); + switch (scan_req.bss_mode) { + case MLAN_SCAN_MODE_BSS: + case MLAN_SCAN_MODE_IBSS: + break; + case MLAN_SCAN_MODE_ANY: + default: + /* Set any unknown types to ANY */ + scan_req.bss_mode = MLAN_SCAN_MODE_ANY; + break; + } + } + } + + /* + * Update all the channels to have the same scan time + */ + for (tmp_idx = 1; tmp_idx < chan_cmd_idx; tmp_idx++) { + scan_req.chan_list[tmp_idx].scan_time = scan_time; + } + + strncpy(iwr.ifr_name, dev_name, IFNAMSIZ - 1); + iwr.u.data.pointer = (caddr_t) & scan_req; + iwr.u.data.length = sizeof(scan_req); + iwr.u.data.flags = subioctl_val; + + if (ioctl(sockfd, ioctl_val, &iwr) < 0) { + perror("mlanconfig: setuserscan ioctl"); + return -EFAULT; + } + + process_getscantable(0, 0); + + return MLAN_STATUS_SUCCESS; +} diff --git a/mxm_wifiex/wlan_src/mapp/mlanconfig/mlanmisc.h b/mxm_wifiex/wlan_src/mapp/mlanconfig/mlanmisc.h new file mode 100644 index 0000000..77ccfb8 --- /dev/null +++ b/mxm_wifiex/wlan_src/mapp/mlanconfig/mlanmisc.h @@ -0,0 +1,710 @@ +/** @file mlanmisc.h + * + * @brief This file contains command definitions for application + * + * + * Copyright 2014-2020 NXP + * + * NXP CONFIDENTIAL + * The source code contained or described herein and all documents related to + * the source code (Materials) are owned by NXP, its + * suppliers and/or its licensors. Title to the Materials remains with NXP, + * its suppliers and/or its licensors. The Materials contain + * trade secrets and proprietary and confidential information of NXP, its + * suppliers and/or its licensors. The Materials are protected by worldwide copyright + * and trade secret laws and treaty provisions. No part of the Materials may be + * used, copied, reproduced, modified, published, uploaded, posted, + * transmitted, distributed, or disclosed in any way without NXP's prior + * express written permission. + * + * No license under any patent, copyright, trade secret or other intellectual + * property right is granted to or conferred upon you by disclosure or delivery + * of the Materials, either expressly, by implication, inducement, estoppel or + * otherwise. Any license under such intellectual property rights must be + * express and approved by NXP in writing. + * + */ +/************************************************************************ +Change log: + 03/10/2009: initial version +************************************************************************/ + +#ifndef _MLANMISC_H_ +#define _MLANMISC_H_ + +/** Maximum size of IEEE Information Elements */ +#define IEEE_MAX_IE_SIZE 256 + +/** Maximum scan response buffer size */ +#define SCAN_RESP_BUF_SIZE 2000 + +#ifdef FALSE +#undef FALSE +#endif + +#ifdef TRUE +#undef TRUE +#endif + +#ifndef MIN +/** Find minimum value */ +#define MIN(a, b) ((a) < (b) ? (a) : (b)) +#endif /* MIN */ + +#ifndef MAX +/** Find maximum value */ +#define MAX(a, b) ((a) > (b) ? (a) : (b)) +#endif /* MAX */ + +/** Type enumeration of WMM AC_QUEUES */ +typedef enum _mlan_wmm_ac_e { + WMM_AC_BK, + WMM_AC_BE, + WMM_AC_VI, + WMM_AC_VO +} __ATTRIB_PACK__ mlan_wmm_ac_e; + +/** Maximum length of SSID */ +#define MRVDRV_MAX_SSID_LENGTH 32 + +/** Enumeration for scan mode */ +enum { + 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_UNCHANGED = 0, + MLAN_SCAN_TYPE_ACTIVE, + MLAN_SCAN_TYPE_PASSIVE +}; + +/** Length of ethernet address */ +#ifndef ETH_ALEN +#define ETH_ALEN 6 +#endif +/** Maximum length of SSID list */ +#define MRVDRV_MAX_SSID_LIST_LENGTH 10 + +/** Maximum number of channels that can be sent in a setuserscan ioctl */ +#define WLAN_IOCTL_USER_SCAN_CHAN_MAX 50 + +/** IEEE Type definitions */ +typedef 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, + + COUNTRY_INFO = 7, + + 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, + + VHT_CAPABILITY = 191, + VHT_OPERATION = 192, + EXT_BSS_LOAD = 193, + BW_CHANNEL_SWITCH = 194, + VHT_TX_POWER_ENV = 195, + EXT_POWER_CONSTR = 196, + AID_INFO = 197, + QUIET_CHAN = 198, + + 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, +} __ATTRIB_PACK__ IEEEtypes_ElementId_e; + +/** Capability Bit Map*/ +#ifdef BIG_ENDIAN_SUPPORT +typedef 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; +} __ATTRIB_PACK__ IEEEtypes_CapInfo_t, *pIEEEtypes_CapInfo_t; +#else +typedef 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; +} __ATTRIB_PACK__ IEEEtypes_CapInfo_t, *pIEEEtypes_CapInfo_t; +#endif /* BIG_ENDIAN_SUPPORT */ + +/** IEEE IE header */ +typedef struct _IEEEtypes_Header_t { + /** Element ID */ + t_u8 element_id; + /** Length */ + t_u8 len; +} __ATTRIB_PACK__ IEEEtypes_Header_t, *pIEEEtypes_Header_t; + +/** IEEE IE header */ +#define IEEE_HEADER_LEN sizeof(IEEEtypes_Header_t) + +/** Vendor specific IE header */ +typedef 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; +} __ATTRIB_PACK__ IEEEtypes_VendorHeader_t, *pIEEEtypes_VendorHeader_t; + +/** Vendor specific IE */ +typedef 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)]; +} __ATTRIB_PACK__ IEEEtypes_VendorSpecific_t, *pIEEEtypes_VendorSpecific_t; + +/** IEEE IE */ +typedef 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)]; +} __ATTRIB_PACK__ IEEEtypes_Generic_t, *pIEEEtypes_Generic_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 + +/** Maximum number of User Priorities */ +#define MAX_USER_PRIORITIES 8 + +/** Extra IE bytes allocated in messages for appended IEs after a TSPEC */ +#define WMM_ADDTS_EXTRA_IE_BYTES 256 + +/** + * @brief Enumeration for the command result from an ADDTS or DELTS command + */ +typedef enum { + TSPEC_RESULT_SUCCESS = 0, + TSPEC_RESULT_EXEC_FAILURE = 1, + TSPEC_RESULT_TIMEOUT = 2, + TSPEC_RESULT_DATA_INVALID = 3, +} __ATTRIB_PACK__ mlan_wmm_tspec_result_e; + +/** + * @brief Enumeration for the action field in the Queue configure command + */ +typedef enum { + WMM_QUEUE_CONFIG_ACTION_GET = 0, + WMM_QUEUE_CONFIG_ACTION_SET = 1, + WMM_QUEUE_CONFIG_ACTION_DEFAULT = 2, + + WMM_QUEUE_CONFIG_ACTION_MAX +} __ATTRIB_PACK__ mlan_wmm_queue_config_action_e; + +/** + * @brief Enumeration for the action field in the queue stats command + */ +typedef enum { + WMM_STATS_ACTION_START = 0, + WMM_STATS_ACTION_STOP = 1, + WMM_STATS_ACTION_GET_CLR = 2, + WMM_STATS_ACTION_SET_CFG = 3, /* Not currently used */ + WMM_STATS_ACTION_GET_CFG = 4, /* Not currently used */ + + WMM_STATS_ACTION_MAX +} __ATTRIB_PACK__ mlan_wmm_stats_action_e; + +/** Data structure of WMM QoS information */ +typedef 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 +} __ATTRIB_PACK__ IEEEtypes_WmmQosInfo_t, *pIEEEtypes_WmmQosInfo_t; + +/** Data structure of WMM Aci/Aifsn */ +typedef 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 +} __ATTRIB_PACK__ IEEEtypes_WmmAciAifsn_t, *pIEEEtypes_WmmAciAifsn_t; + +/** Data structure of WMM ECW */ +typedef 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 +} __ATTRIB_PACK__ IEEEtypes_WmmEcw_t, *pIEEEtypes_WmmEcw_t; + +/** Data structure of WMM AC parameters */ +typedef struct _IEEEtypes_WmmAcParameters_t { + IEEEtypes_WmmAciAifsn_t aci_aifsn; /**< AciAifSn */ + IEEEtypes_WmmEcw_t ecw; /**< Ecw */ + t_u16 tx_op_limit; /**< Tx op limit */ +} __ATTRIB_PACK__ IEEEtypes_WmmAcParameters_t, *pIEEEtypes_WmmAcParameters_t; + +/** Data structure of WMM Info IE */ +typedef 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; + +} __ATTRIB_PACK__ IEEEtypes_WmmInfo_t, *pIEEEtypes_WmmInfo_t; + +/** Data structure of WMM parameter IE */ +typedef 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]; + +} __ATTRIB_PACK__ IEEEtypes_WmmParameter_t, *pIEEEtypes_WmmParameter_t; + +/** + * @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 wlan_wmm_addts_req_ioctl + */ +typedef struct { + mlan_wmm_tspec_result_e commandResult; + /**< Firmware execution result */ + + t_u32 timeout_ms; /**< Timeout value in milliseconds */ + t_u8 ieeeStatusCode; /**< IEEE status code */ + + t_u32 ieDataLen; + t_u8 ieData[WMM_TSPEC_SIZE + /**< TSPEC to send in the ADDTS */ + + WMM_ADDTS_EXTRA_IE_BYTES]; + /**< ADDTS 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 wlan_wmm_delts_req_ioctl + */ +typedef struct { + mlan_wmm_tspec_result_e commandResult; + /**< Firmware execution result */ + t_u8 ieeeReasonCode; /**< IEEE reason code sent, unused for WMM */ + + t_u32 ieDataLen; + t_u8 ieData[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. + * + * - msduLifetimeExpiry is ignored if set to 0 on a set command + * + * @sa wlan_wmm_queue_config_ioctl + */ +typedef struct { + mlan_wmm_queue_config_action_e action; + /**< Set, Get, or Default */ + mlan_wmm_ac_e accessCategory; /**< WMM_AC_BK(0) to WMM_AC_VO(3) */ + t_u16 msduLifetimeExpiry; /**< lifetime expiry in TUs */ + t_u8 supportedRates[10]; /**< Not supported yet */ +} wlan_ioctl_wmm_queue_config_t; + +/** Number of bins in the histogram for the HostCmd_DS_WMM_QUEUE_STATS */ +#define WMM_STATS_PKTS_HIST_BINS 7 + +/** + * @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 wlan_wmm_queue_stats_ioctl + */ +typedef struct { + mlan_wmm_stats_action_e action; + /**< Start, Stop, or Get */ + t_u8 userPriority; + /**< User Priority (0 to 7) */ + t_u16 pktCount; /**< Number of successful packets transmitted */ + t_u16 pktLoss; /**< Packets lost; not included in pktCount */ + t_u32 avgQueueDelay; + /**< Average Queue delay in microseconds */ + t_u32 avgTxDelay;/**< Average Transmission delay in microseconds */ + t_u16 usedTime; /**< Calculated used time - units of 32 microsec */ + t_u16 policedTime; + /**< Calculated 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 delayHistogram[WMM_STATS_PKTS_HIST_BINS]; +} wlan_ioctl_wmm_queue_stats_t; + +/** + * @brief IOCTL and command sub structure for a Traffic stream status. + */ +typedef struct { + t_u8 tid; /**< TSID: Range: 0->7 */ + t_u8 valid; /**< TSID specified is valid */ + t_u8 accessCategory;/**< AC TSID is active on */ + t_u8 userPriority; /**< UP specified for the TSID */ + + t_u8 psb; /**< Power save mode for TSID: 0 (legacy), 1 (UAPSD) */ + t_u8 flowDir; /**< Upstream (0), Downlink(1), Bidirectional(3) */ + t_u16 mediumTime; /**< Medium time granted for the TSID */ +} __ATTRIB_PACK__ HostCmd_DS_WMM_TS_STATUS, + wlan_ioctl_wmm_ts_status_t, wlan_cmd_wmm_ts_status_t; + +/** + * @brief IOCTL sub structure for a specific WMM AC Status + */ +typedef struct { + /** WMM Acm */ + t_u8 wmmAcm; + /** Flow required flag */ + t_u8 flowRequired; + /** Flow created flag */ + t_u8 flowCreated; + /** Disabled flag */ + t_u8 disabled; + /** delivery enabled */ + t_u8 deliveryEnabled; + /** trigger enabled */ + t_u8 triggerEnabled; +} 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 wlan_wmm_queue_status_ioctl + */ +typedef struct { + /** WMM AC queue status */ + wlan_ioctl_wmm_queue_status_ac_t acStatus[MAX_AC_QUEUES]; +} wlan_ioctl_wmm_queue_status_t; + +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 from the firmware at packet reception */ + t_u64 network_tsf; +} wlan_get_scan_table_fixed; + +/** + * 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[1]; */ +} wlan_ioctl_get_scan_table_entry; + +/** + * Structure to store BSS info (probe resp or beacon) & IEEE IE info for each + * BSS returned in WLAN_GET_SCAN_RESP IOCTL + */ +typedef struct _wlan_ioctl_get_bss_info { + /** + * Length of the BSS Information (probe resp or beacon) that + * follows after the fixed_field + */ + t_u32 bss_info_length; + + /** + * Probe response or beacon scanned for the BSS. + * + * Field layout: + */ + /** TSF 8 octets */ + t_u8 tsf[8]; + /** Beacon Interval 2 octets */ + t_u16 beacon_interval; + /** Capability Info 2 octets */ + IEEEtypes_CapInfo_t cap_info; + + /** + * IEEE Infomation Elements; variable number & length per 802.11 spec + */ + /** SSID */ + char ssid[MRVDRV_MAX_SSID_LENGTH + 1]; + /** SSID Length */ + t_u32 ssid_len; + /** WMM Capability */ + char wmm_cap; + /** WPS Capability */ + char wps_cap; + /** Privacy Capability - WEP/WPA/RSN */ + char priv_cap; + /** HT (11N) Capability */ + char ht_cap; + /** VHT (11AC) Capability */ + char vht_cap[2]; + /* 802.11k Capability */ + char dot11k_cap; + /** 802.11r Capability */ + char dot11r_cap; +} wlan_ioctl_get_bss_info; + +/** + * Structure to save of scan table info for each BSS returned + * in WLAN_GET_SCAN_RESP IOCTL + */ +struct wlan_ioctl_get_scan_list { + /** fixed info */ + wlan_ioctl_get_scan_table_entry fixed_buf; + /** variable info - BSS info (probe resp or beacon) & IEEE IE info */ + wlan_ioctl_get_bss_info bss_info_buf; + /** pointer to next node in list */ + struct wlan_ioctl_get_scan_list *next; +}; + +/** + * 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; + +typedef struct { + t_u8 chan_number; + /**< Channel Number to scan */ + t_u8 radio_type; + /**< Radio type: 'B/G' Band = 0, 'A' Band = 1 */ + t_u8 scan_type;/**< Scan type: Active = 1, Passive = 2 */ + t_u8 reserved;/**< Reserved */ + t_u32 scan_time; + /**< Scan duration in milliseconds; if 0 default used */ +} __ATTRIB_PACK__ wlan_ioctl_user_scan_chan; + +typedef struct { + char ssid[MRVDRV_MAX_SSID_LENGTH + 1]; + /**< SSID */ + t_u8 max_len; /**< Maximum length of SSID */ +} __ATTRIB_PACK__ wlan_ioctl_user_scan_ssid; + +typedef struct { + + /** Flag set to keep the previous scan table intact */ + t_u8 keep_previous_scan; /* Do not erase the existing scan results */ + + /** BSS mode to be sent in the firmware command */ + t_u8 bss_mode; + + /** Configure the number of probe requests for active chan scans */ + t_u8 num_probes; + + /** Reserved */ + t_u8 reserved; + + /** BSSID filter sent in the firmware command to limit the results */ + t_u8 specific_bssid[ETH_ALEN]; + + /** SSID filter list used in the to limit the scan results */ + wlan_ioctl_user_scan_ssid ssid_list[MRVDRV_MAX_SSID_LIST_LENGTH]; + + /** Variable number (fixed maximum) of channels to scan up */ + wlan_ioctl_user_scan_chan chan_list[WLAN_IOCTL_USER_SCAN_CHAN_MAX]; + +} __ATTRIB_PACK__ wlan_ioctl_user_scan_cfg; + +#ifdef SDIO +int process_sdcmd52rw(int argc, char *argv[]); +int process_sdcmd53rw(int argc, char *argv[]); +#endif +int process_setuserscan(int argc, char *argv[]); +int process_getscantable(int argc, char *argv[]); +int process_getscantable_idx(wlan_ioctl_get_scan_table_info *prsp_info_req); + +#endif /* _MLANMISC_H_ */ diff --git a/mxm_wifiex/wlan_src/mapp/mlanevent/Makefile b/mxm_wifiex/wlan_src/mapp/mlanevent/Makefile new file mode 100644 index 0000000..0254778 --- /dev/null +++ b/mxm_wifiex/wlan_src/mapp/mlanevent/Makefile @@ -0,0 +1,52 @@ +# File : mlanevent/Makefile +# +# Copyright 2014-2020 NXP + +# Path to the top directory of the wlan distribution +PATH_TO_TOP = ../.. + +# Determine how we should copy things to the install directory +ABSPATH := $(filter /%, $(INSTALLDIR)) +RELPATH := $(filter-out /%, $(INSTALLDIR)) +INSTALLPATH := $(ABSPATH) +ifeq ($(strip $(INSTALLPATH)),) +INSTALLPATH := $(PATH_TO_TOP)/$(RELPATH) +endif + +# Override CFLAGS for application sources, remove __ kernel namespace defines +CFLAGS := $(filter-out -D__%, $(ccflags-y)) +# remove KERNEL include dir +CFLAGS := $(filter-out -I$(KERNELDIR)%, $(CFLAGS)) + + +#CFLAGS += -DAP22 -fshort-enums +CFLAGS += -Wall +#ECHO = @ +LIBS = -lrt + + +.PHONY: default tags all + +OBJECTS = mlanevent.o +HEADERS = mlanevent.h + +TARGET = mlanevent.exe + +build default: $(TARGET) + @cp -f $(TARGET) $(INSTALLPATH) + +all : tags default + +$(TARGET): $(OBJECTS) $(HEADERS) + $(ECHO)$(CC) $(LIBS) -o $@ $(OBJECTS) + +%.o: %.c $(HEADERS) + $(ECHO)$(CC) $(CFLAGS) -c -o $@ $< + +tags: + ctags -R -f tags.txt + +distclean clean: + $(ECHO)$(RM) $(OBJECTS) $(TARGET) + $(ECHO)$(RM) tags.txt + diff --git a/mxm_wifiex/wlan_src/mapp/mlanevent/mlanevent.c b/mxm_wifiex/wlan_src/mapp/mlanevent/mlanevent.c new file mode 100644 index 0000000..4fd0990 --- /dev/null +++ b/mxm_wifiex/wlan_src/mapp/mlanevent/mlanevent.c @@ -0,0 +1,2572 @@ +/** @file mlanevent.c + * + * @brief Program to receive events from the driver/firmware of the uAP + * driver. + * + * Usage: mlanevent.exe [-option] + * + * + * Copyright 2014-2020 NXP + * + * NXP CONFIDENTIAL + * The source code contained or described herein and all documents related to + * the source code (Materials) are owned by NXP, its + * suppliers and/or its licensors. Title to the Materials remains with NXP, + * its suppliers and/or its licensors. The Materials contain + * trade secrets and proprietary and confidential information of NXP, its + * suppliers and/or its licensors. The Materials are protected by worldwide copyright + * and trade secret laws and treaty provisions. No part of the Materials may be + * used, copied, reproduced, modified, published, uploaded, posted, + * transmitted, distributed, or disclosed in any way without NXP's prior + * express written permission. + * + * No license under any patent, copyright, trade secret or other intellectual + * property right is granted to or conferred upon you by disclosure or delivery + * of the Materials, either expressly, by implication, inducement, estoppel or + * otherwise. Any license under such intellectual property rights must be + * express and approved by NXP in writing. + * + */ +/**************************************************************************** +Change log: + 03/18/08: Initial creation +****************************************************************************/ + +/**************************************************************************** + Header files +****************************************************************************/ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include "mlanevent.h" +#ifdef WIFI_DIRECT_SUPPORT +#include +#endif + +/**************************************************************************** + Definitions +****************************************************************************/ +/** Enable or disable debug outputs */ +#define DEBUG 0 + +/**************************************************************************** + Global variables +****************************************************************************/ +/** Termination flag */ +int terminate_flag = 0; + +/**************************************************************************** + Local functions +****************************************************************************/ +/** + * @brief Signal handler + * + * @param sig Received signal number + * @return N/A + */ +void +sig_handler(int sig) +{ + printf("Stopping application.\n"); +#if DEBUG + printf("Process ID of process killed = %d\n", getpid()); +#endif + terminate_flag = 1; +} + +/** + * @brief Dump hex data + * + * @param p A pointer to data buffer + * @param len The len of data buffer + * @param delim Deliminator character + * @return Hex integer + */ +static void +hexdump(void *p, t_s32 len, char delim) +{ + t_s32 i; + t_u8 *s = p; + for (i = 0; i < len; i++) { + if (i != len - 1) + printf("%02x%c", *s++, delim); + else + printf("%02x\n", *s); + if ((i + 1) % 16 == 0) + printf("\n"); + } +} + +/** + * @brief Hex to number + * + * @param c Hex value + * @return Integer value or -1 + */ +int +hex2num(char c) +{ + if (c >= '0' && c <= '9') + return c - '0'; + if (c >= 'a' && c <= 'f') + return c - 'a' + 10; + if (c >= 'A' && c <= 'F') + return c - 'A' + 10; + + return -1; +} + +/** + * @brief Check hex string + * + * @param hex A pointer to hex string + * @return 0 or MLAN_EVENT_FAILURE + */ +int +ishexstring(void *hex) +{ + int i, a; + char *p = hex; + int len = strlen(p); + if (!strncasecmp("0x", p, 2)) { + p += 2; + len -= 2; + } + for (i = 0; i < len; i++) { + a = hex2num(*p); + if (a < 0) + return MLAN_EVENT_FAILURE; + p++; + } + return 0; +} + +/** + * @brief Convert char to hex integer + * + * @param chr Char + * @return Hex integer + */ +unsigned char +hexc2bin(char chr) +{ + if (chr >= '0' && chr <= '9') + chr -= '0'; + else if (chr >= 'A' && chr <= 'F') + chr -= ('A' - 10); + else if (chr >= 'a' && chr <= 'f') + chr -= ('a' - 10); + + return chr; +} + +/** + * @brief Convert string to hex integer + * + * @param s A pointer string buffer + * @return Hex integer + */ +unsigned int +a2hex(char *s) +{ + unsigned int val = 0; + if (!strncasecmp("0x", s, 2)) { + s += 2; + } + while (*s && isxdigit(*s)) { + val = (val << 4) + hexc2bin(*s++); + } + return val; +} + +/** + * @brief Prints a MAC address in colon separated form from raw data + * + * @param raw A pointer to the hex data buffer + * @return N/A + */ +void +print_mac(t_u8 *raw) +{ + printf("%02x:%02x:%02x:%02x:%02x:%02x", (unsigned int)raw[0], + (unsigned int)raw[1], (unsigned int)raw[2], (unsigned int)raw[3], + (unsigned int)raw[4], (unsigned int)raw[5]); + return; +} + +/** + * @brief Print usage information + * + * @return N/A + */ +void +print_usage(void) +{ + printf("\n"); + printf("Usage : mlanevent.exe [-v] [-h]\n"); + printf(" -v : Print version information\n"); + printf(" -h : Print help information\n"); + printf(" -i : Specify device number from 0 to %d\n", + MAX_NO_OF_DEVICES - 1); + printf(" 0xff for all devices\n"); + printf("\n"); +} + +/** + * @brief Parse and print STA deauthentication event data + * + * @param buffer Pointer to received event buffer + * @param size Length of the received event data + * @return N/A + */ +void +print_event_sta_deauth(t_u8 *buffer, t_u16 size) +{ + eventbuf_sta_deauth *event_body = NULL; + + if (size < sizeof(eventbuf_sta_deauth)) { + printf("ERR:Event buffer too small!\n"); + return; + } + event_body = (eventbuf_sta_deauth *)buffer; + event_body->reason_code = uap_le16_to_cpu(event_body->reason_code); + printf("EVENT: STA_DEAUTH\n"); + printf("Deauthenticated STA MAC: "); + print_mac(event_body->sta_mac_address); + printf("\nReason: "); + switch (event_body->reason_code) { + case 1: + printf("Client station leaving the network\n"); + break; + case 2: + printf("Client station aged out\n"); + break; + case 3: + printf("Client station deauthenticated by user's request\n"); + break; + case 4: + printf("Client station authentication failure\n"); + break; + case 5: + printf("Client station association failure\n"); + break; + case 6: + printf("Client mac address is blocked by ACL filter\n"); + break; + case 7: + printf("Client station table is full\n"); + break; + case 8: + printf("Client 4-way handshake timeout\n"); + break; + case 9: + printf("Client group key handshake timeout\n"); + break; + default: + printf("Unspecified\n"); + break; + } + return; +} + +/** + * @brief Parse and print WEP ICV error event data + * + * @param buffer Pointer to received event buffer + * @param size Length of the received event data + * @return N/A + */ +void +print_event_wep_icv_error(t_u8 *buffer, t_u16 size) +{ + int i = 0; + eventbuf_wep_icv_error *event_body = NULL; + + if (size < sizeof(eventbuf_wep_icv_error)) { + printf("ERR:Event buffer too small!\n"); + return; + } + event_body = (eventbuf_wep_icv_error *)buffer; + event_body->reason_code = uap_le16_to_cpu(event_body->reason_code); + printf("EVENT: WEP_ICV_ERROR\n"); + printf("Deauthenticated STA MAC: "); + print_mac(event_body->sta_mac_address); + printf("WEP key index = %d\n", event_body->wep_key_index); + printf("WEP key length = %d\n", event_body->wep_key_length); + printf("WEP key : \n"); + for (i = 0; i < event_body->wep_key_length; i++) { + printf("%02x ", event_body->wep_key[i]); + } + printf("\n"); + return; +} + +/** + * @brief Prints mgmt frame + * + * @param mgmt_tlv A pointer to mgmt_tlv + * @param tlv_len Length of tlv payload + * @return N/A + */ +void +print_mgmt_frame(MrvlIETypes_MgmtFrameSet_t *mgmt_tlv, int tlv_len) +{ + IEEEtypes_AssocRqst_t *assoc_req = NULL; + IEEEtypes_ReAssocRqst_t *reassoc_req = NULL; + IEEEtypes_AssocRsp_t *assoc_resp = NULL; + t_u16 frm_ctl = 0; + printf("\nMgmt Frame:\n"); + memcpy(&frm_ctl, &mgmt_tlv->frame_control, sizeof(t_u16)); + printf("FrameControl: 0x%x\n", frm_ctl); + if (mgmt_tlv->frame_control.type != 0) { + printf("Frame type=%d subtype=%d:\n", + mgmt_tlv->frame_control.type, + mgmt_tlv->frame_control.sub_type); + hexdump(mgmt_tlv->frame_contents, tlv_len - sizeof(t_u16), ' '); + return; + } + switch (mgmt_tlv->frame_control.sub_type) { + case SUBTYPE_ASSOC_REQUEST: + printf("Assoc Request:\n"); + assoc_req = (IEEEtypes_AssocRqst_t *)mgmt_tlv->frame_contents; + printf("CapInfo: 0x%x ListenInterval: 0x%x \n", + uap_le16_to_cpu(assoc_req->cap_info), + uap_le16_to_cpu(assoc_req->listen_interval)); + printf("AssocReqIE:\n"); + hexdump(assoc_req->ie_buffer, + tlv_len - sizeof(IEEEtypes_AssocRqst_t) + - sizeof(IEEEtypes_FrameCtl_t), ' '); + break; + case SUBTYPE_REASSOC_REQUEST: + printf("ReAssoc Request:\n"); + reassoc_req = + (IEEEtypes_ReAssocRqst_t *)mgmt_tlv->frame_contents; + printf("CapInfo: 0x%x ListenInterval: 0x%x \n", + uap_le16_to_cpu(reassoc_req->cap_info), + uap_le16_to_cpu(reassoc_req->listen_interval)); + printf("Current AP address: "); + print_mac(reassoc_req->current_ap_addr); + printf("\nReAssocReqIE:\n"); + hexdump(reassoc_req->ie_buffer, + tlv_len - sizeof(IEEEtypes_ReAssocRqst_t) + - sizeof(IEEEtypes_FrameCtl_t), ' '); + break; + case SUBTYPE_ASSOC_RESPONSE: + case SUBTYPE_REASSOC_RESPONSE: + if (mgmt_tlv->frame_control.sub_type == SUBTYPE_ASSOC_RESPONSE) + printf("Assoc Response:\n"); + else + printf("ReAssoc Response:\n"); + assoc_resp = (IEEEtypes_AssocRsp_t *)mgmt_tlv->frame_contents; + printf("CapInfo: 0x%x StatusCode: %d AID: 0x%x \n", + uap_le16_to_cpu(assoc_resp->cap_info), + (int)(uap_le16_to_cpu(assoc_resp->status_code)), + uap_le16_to_cpu(assoc_resp->aid) & 0x3fff); + break; + default: + printf("Frame subtype = %d:\n", + mgmt_tlv->frame_control.sub_type); + hexdump(mgmt_tlv->frame_contents, tlv_len - sizeof(t_u16), ' '); + break; + } + return; +} + +/** + * @brief Parse and print RSN connect event data + * + * @param buffer Pointer to received buffer + * @param size Length of the received event data + * @return N/A + */ +void +print_event_rsn_connect(t_u8 *buffer, t_u16 size) +{ + int tlv_buf_left = size; + t_u16 tlv_type, tlv_len; + tlvbuf_header *tlv = NULL; + eventbuf_rsn_connect *event_body = NULL; + if (size < sizeof(eventbuf_rsn_connect)) { + printf("ERR:Event buffer too small!\n"); + return; + } + event_body = (eventbuf_rsn_connect *)buffer; + printf("EVENT: RSN_CONNECT\n"); + printf("Station MAC: "); + print_mac(event_body->sta_mac_address); + printf("\n"); + tlv_buf_left = size - sizeof(eventbuf_rsn_connect); + if (tlv_buf_left < (int)sizeof(tlvbuf_header)) + return; + tlv = (tlvbuf_header *)(buffer + sizeof(eventbuf_rsn_connect)); + + while (tlv_buf_left >= (int)sizeof(tlvbuf_header)) { + tlv_type = uap_le16_to_cpu(tlv->type); + tlv_len = uap_le16_to_cpu(tlv->len); + if ((sizeof(tlvbuf_header) + tlv_len) > + (unsigned int)tlv_buf_left) { + printf("wrong tlv: tlvLen=%d, tlvBufLeft=%d\n", tlv_len, + tlv_buf_left); + break; + } + switch (tlv_type) { + case IEEE_WPA_IE: + printf("WPA IE:\n"); + hexdump((t_u8 *)tlv + sizeof(tlvbuf_header), tlv_len, + ' '); + break; + case IEEE_RSN_IE: + printf("RSN IE:\n"); + hexdump((t_u8 *)tlv + sizeof(tlvbuf_header), tlv_len, + ' '); + break; + default: + printf("unknown tlv: %d\n", tlv_type); + break; + } + tlv_buf_left -= (sizeof(tlvbuf_header) + tlv_len); + tlv = (tlvbuf_header *)((t_u8 *)tlv + tlv_len + + sizeof(tlvbuf_header)); + } + return; +} + +/** + * @brief Parse and print STA associate event data + * + * @param buffer Pointer to received buffer + * @param size Length of the received event data + * @return N/A + */ +void +print_event_sta_assoc(t_u8 *buffer, t_u16 size) +{ + int tlv_buf_left = size; + t_u16 tlv_type, tlv_len; + tlvbuf_header *tlv = NULL; + MrvlIEtypes_WapiInfoSet_t *wapi_tlv = NULL; + MrvlIETypes_MgmtFrameSet_t *mgmt_tlv = NULL; + eventbuf_sta_assoc *event_body = NULL; + if (size < sizeof(eventbuf_sta_assoc)) { + printf("ERR:Event buffer too small!\n"); + return; + } + event_body = (eventbuf_sta_assoc *)buffer; + printf("EVENT: STA_ASSOCIATE\n"); + printf("Associated STA MAC: "); + print_mac(event_body->sta_mac_address); + printf("\n"); + tlv_buf_left = size - sizeof(eventbuf_sta_assoc); + if (tlv_buf_left < (int)sizeof(tlvbuf_header)) + return; + tlv = (tlvbuf_header *)(buffer + sizeof(eventbuf_sta_assoc)); + + while (tlv_buf_left >= (int)sizeof(tlvbuf_header)) { + tlv_type = uap_le16_to_cpu(tlv->type); + tlv_len = uap_le16_to_cpu(tlv->len); + if ((sizeof(tlvbuf_header) + tlv_len) > + (unsigned int)tlv_buf_left) { + printf("wrong tlv: tlvLen=%d, tlvBufLeft=%d\n", tlv_len, + tlv_buf_left); + break; + } + switch (tlv_type) { + case MRVL_WAPI_INFO_TLV_ID: + wapi_tlv = (MrvlIEtypes_WapiInfoSet_t *)tlv; + printf("WAPI Multicast PN:\n"); + hexdump(wapi_tlv->multicast_PN, tlv_len, ' '); + break; + case MRVL_MGMT_FRAME_TLV_ID: + mgmt_tlv = (MrvlIETypes_MgmtFrameSet_t *)tlv; + print_mgmt_frame(mgmt_tlv, tlv_len); + break; + default: + printf("unknown tlv: %d\n", tlv_type); + break; + } + tlv_buf_left -= (sizeof(tlvbuf_header) + tlv_len); + tlv = (tlvbuf_header *)((t_u8 *)tlv + tlv_len + + sizeof(tlvbuf_header)); + } + return; +} + +/** + * @brief Parse and print BSS start event data + * + * @param buffer Pointer to received buffer + * @param size Length of the received event data + * @return N/A + */ +void +print_event_bss_start(t_u8 *buffer, t_u16 size) +{ + eventbuf_bss_start *event_body = NULL; + int tlv_buf_left = size; + t_u16 tlv_type, tlv_len; + tlvbuf_header *tlv = NULL; + tlvbuf_channel_config *channel_tlv = NULL; + + if (size < sizeof(eventbuf_bss_start)) { + printf("ERR:Event buffer too small!\n"); + return; + } + event_body = (eventbuf_bss_start *)buffer; + printf("EVENT: BSS_START "); + printf("BSS MAC: "); + print_mac(event_body->ap_mac_address); + printf("\n"); + tlv_buf_left = size - sizeof(eventbuf_bss_start); + if (tlv_buf_left < (int)sizeof(tlvbuf_header)) + return; + tlv = (tlvbuf_header *)(buffer + sizeof(eventbuf_bss_start)); + + while (tlv_buf_left >= (int)sizeof(tlvbuf_header)) { + tlv_type = uap_le16_to_cpu(tlv->type); + tlv_len = uap_le16_to_cpu(tlv->len); + if ((sizeof(tlvbuf_header) + tlv_len) > + (unsigned int)tlv_buf_left) { + printf("wrong tlv: tlvLen=%d, tlvBufLeft=%d\n", tlv_len, + tlv_buf_left); + break; + } + switch (tlv_type) { + case MRVL_CHANNELCONFIG_TLV_ID: + channel_tlv = (tlvbuf_channel_config *)tlv; + printf("Channel = %d\n", channel_tlv->chan_number); + printf("Band = %s\n", + (channel_tlv->bandcfg.chanBand == + BAND_5GHZ) ? "5GHz" : "2.4GHz"); + printf("Channel Select Mode = %s\n", + (channel_tlv->bandcfg.scanMode == + SCAN_MODE_ACS) ? "ACS" : "Manual"); + if (channel_tlv->bandcfg.chan2Offset == SEC_CHAN_NONE) + printf("no secondary channel\n"); + else if (channel_tlv->bandcfg.chan2Offset == + SEC_CHAN_ABOVE) + printf("secondary channel is above primary channel\n"); + else if (channel_tlv->bandcfg.chan2Offset == + SEC_CHAN_BELOW) + printf("secondary channel is below primary channel\n"); + break; + default: +#if DEBUG + printf("unknown tlv: %d\n", tlv_type); +#endif + break; + } + tlv_buf_left -= (sizeof(tlvbuf_header) + tlv_len); + tlv = (tlvbuf_header *)((t_u8 *)tlv + tlv_len + + sizeof(tlvbuf_header)); + } + + return; +} + +/** + * @brief Parse and print MIC Countermeasures state + * + * @param buffer Pointer to received buffer + * @param size Length of the received event data + * @return N/A + */ +void +print_event_mic_countermeasures(t_u8 *buffer, t_u16 size) +{ + eventbuf_mic_countermeasures *event_body = NULL; + + if (size < sizeof(eventbuf_mic_countermeasures)) { + printf("ERR:Event buffer too small!\n"); + return; + } + event_body = (eventbuf_mic_countermeasures *)buffer; + if (event_body->status) + printf("EVENT: Countermeasures active.\n"); + else + printf("EVENT: Countermeasures inactive\n"); + return; +} + +#ifdef WIFI_DIRECT_SUPPORT +/** + * @brief Print WIFI_WPS IE elements from event payload + * + * @param buffer Pointer to received buffer + * @param size Length of the received event data + * @return N/A + */ +void +print_wifi_wps_ie_elements(t_u8 *buffer, t_u16 size) +{ + t_u8 *ptr = buffer; + t_u8 *array_ptr; + int i; + t_u16 wps_len = 0, wps_type = 0; + t_u16 ie_len_wps = size; + + while (ie_len_wps > sizeof(tlvbuf_wps_ie)) { + memcpy(&wps_type, ptr, sizeof(t_u16)); + memcpy(&wps_len, ptr + 2, sizeof(t_u16)); + endian_convert_tlv_wps_header_in(wps_type, wps_len); + switch (wps_type) { + case SC_Version: + { + tlvbuf_wps_ie *wps_tlv = (tlvbuf_wps_ie *)ptr; + printf("\t WPS Version = 0x%2x\n", + *(wps_tlv->data)); + } + break; + case SC_Simple_Config_State: + { + tlvbuf_wps_ie *wps_tlv = (tlvbuf_wps_ie *)ptr; + printf("\t WPS setupstate = 0x%x\n", + *(wps_tlv->data)); + } + break; + case SC_Request_Type: + { + tlvbuf_wps_ie *wps_tlv = (tlvbuf_wps_ie *)ptr; + printf("\t WPS RequestType = 0x%x\n", + *(wps_tlv->data)); + } + break; + case SC_Response_Type: + { + tlvbuf_wps_ie *wps_tlv = (tlvbuf_wps_ie *)ptr; + printf("\t WPS ResponseType = 0x%x\n", + *(wps_tlv->data)); + } + break; + case SC_Config_Methods: + { + t_u16 wps_config_methods = 0; + tlvbuf_wps_ie *wps_tlv = (tlvbuf_wps_ie *)ptr; + memcpy(&wps_config_methods, wps_tlv->data, + sizeof(t_u16)); + wps_config_methods = ntohs(wps_config_methods); + printf("\t WPS SpecConfigMethods = 0x%x\n", + wps_config_methods); + } + break; + case SC_UUID_E: + { + tlvbuf_wps_ie *wps_tlv = (tlvbuf_wps_ie *)ptr; + array_ptr = wps_tlv->data; + printf("\t WPS UUID = "); + for (i = 0; i < wps_len; i++) + printf("0x%02X ", *array_ptr++); + printf("\n"); + } + break; + case SC_Primary_Device_Type: + { + tlvbuf_wps_ie *wps_tlv = (tlvbuf_wps_ie *)ptr; + array_ptr = wps_tlv->data; + printf("\t WPS Primary Device Type = "); + for (i = 0; i < wps_len; i++) + printf("0x%02X ", *array_ptr++); + printf("\n"); + } + break; + case SC_RF_Band: + { + tlvbuf_wps_ie *wps_tlv = (tlvbuf_wps_ie *)ptr; + printf("\t WPS RF Band = 0x%x\n", + *(wps_tlv->data)); + } + break; + case SC_Association_State: + { + t_u16 wps_association_state = 0; + tlvbuf_wps_ie *wps_tlv = (tlvbuf_wps_ie *)ptr; + memcpy(&wps_association_state, wps_tlv->data, + sizeof(t_u16)); + wps_association_state = + ntohs(wps_association_state); + printf("\t WPS Association State = 0x%x\n", + wps_association_state); + } + break; + case SC_Configuration_Error: + { + t_u16 wps_configuration_error = 0; + tlvbuf_wps_ie *wps_tlv = (tlvbuf_wps_ie *)ptr; + memcpy(&wps_configuration_error, wps_tlv->data, + sizeof(t_u16)); + wps_configuration_error = + ntohs(wps_configuration_error); + printf("\t WPS Configuration Error = 0x%x\n", + wps_configuration_error); + } + break; + case SC_Device_Password_ID: + { + t_u16 wps_device_password_id = 0; + tlvbuf_wps_ie *wps_tlv = (tlvbuf_wps_ie *)ptr; + memcpy(&wps_device_password_id, wps_tlv->data, + sizeof(t_u16)); + wps_device_password_id = + ntohs(wps_device_password_id); + printf("\t WPS Device Password ID = 0x%x\n", + wps_device_password_id); + } + break; + case SC_Device_Name: + { + tlvbuf_wps_ie *wps_tlv = (tlvbuf_wps_ie *)ptr; + array_ptr = wps_tlv->data; + printf("\t WPS Device Name = "); + for (i = 0; i < wps_len; i++) + printf("%c", *array_ptr++); + printf("\n"); + } + break; + case SC_Manufacturer: + { + tlvbuf_wps_ie *wps_tlv = (tlvbuf_wps_ie *)ptr; + array_ptr = wps_tlv->data; + printf("\t WPS Manufacturer = "); + for (i = 0; i < wps_len; i++) + printf("%c", *array_ptr++); + printf("\n"); + } + break; + case SC_Model_Name: + { + tlvbuf_wps_ie *wps_tlv = (tlvbuf_wps_ie *)ptr; + array_ptr = wps_tlv->data; + printf("\t WPS Model Name = "); + for (i = 0; i < wps_len; i++) + printf("%c", *array_ptr++); + printf("\n"); + } + break; + case SC_Model_Number: + { + tlvbuf_wps_ie *wps_tlv = (tlvbuf_wps_ie *)ptr; + array_ptr = wps_tlv->data; + printf("\t WPS Model Number = "); + for (i = 0; i < wps_len; i++) + printf("%c", *array_ptr++); + printf("\n"); + } + break; + case SC_Serial_Number: + { + tlvbuf_wps_ie *wps_tlv = (tlvbuf_wps_ie *)ptr; + array_ptr = wps_tlv->data; + printf("\t WPS Serial Number = "); + for (i = 0; i < wps_len; i++) + printf("%c", *array_ptr++); + printf("\n"); + } + break; + case SC_Vendor_Extension: + { + tlvbuf_wps_ie *wps_tlv = (tlvbuf_wps_ie *)ptr; + array_ptr = wps_tlv->data; + printf("\t WPS 2.0 Vendor Extension = "); + for (i = 0; i < wps_len; i++) + printf("%x", *array_ptr++); + printf("\n"); + } + break; + case SC_Selected_Registrar: + { + tlvbuf_wps_ie *wps_tlv = (tlvbuf_wps_ie *)ptr; + printf("\t Selected Registrar = %d\n", + *(wps_tlv->data)); + } + break; + case SC_SelectedRegistrarConfigMethods: + { + t_u16 sr_config_methods = 0; + tlvbuf_wps_ie *wps_tlv = (tlvbuf_wps_ie *)ptr; + memcpy(&sr_config_methods, wps_tlv->data, + sizeof(t_u16)); + sr_config_methods = ntohs(sr_config_methods); + printf("\t Selected Registrar Configuration Methods = 0x%x\n", sr_config_methods); + } + break; + default: + printf("unknown ie=0x%x, len=%d\n", wps_type, wps_len); + break; + } + ptr += wps_len + sizeof(tlvbuf_wps_ie); + /* Take care of error condition */ + if (wps_len + sizeof(tlvbuf_wps_ie) <= ie_len_wps) + ie_len_wps -= wps_len + sizeof(tlvbuf_wps_ie); + else + ie_len_wps = 0; + } +} + +/** + * @brief Print WIFIDIRECT IE elements from event payload + * + * @param buffer Pointer to received buffer + * @param size Length of the received event data + * @return N/A + */ +void +print_wifidirect_ie_elements(t_u8 *buffer, t_u16 size) +{ + t_u8 *ptr = buffer; + t_u8 *array_ptr, *orig_ptr = NULL; + int i; + static t_u16 len = 0; + static t_u16 saved_len = 0; + static t_u16 pending_len = 0; + static t_u8 type = 0; + static t_u8 next_byte = WIFIDIRECT_OVERLAP_TYPE; + static t_u8 saved_data[WIFI_IE_MAX_PAYLOAD] = { 0 }; + t_u16 temp; + t_u16 left_len = size; + + while (left_len > 0) { + if (next_byte == WIFIDIRECT_OVERLAP_TYPE) { + type = *ptr; + next_byte = WIFIDIRECT_OVERLAP_LEN; + left_len--; + ptr++; + } + if (left_len >= sizeof(len) && + next_byte == WIFIDIRECT_OVERLAP_LEN) { + memcpy(&len, ptr, sizeof(t_u16)); + len = uap_le16_to_cpu(len); + next_byte = WIFIDIRECT_OVERLAP_DATA; + left_len -= sizeof(t_u16); + ptr += sizeof(t_u16); + + /* case when Type, Len in one frame and data in next */ + if (left_len == 0) { + memcpy(saved_data, + ptr - WIFIDIRECT_IE_HEADER_LEN, + WIFIDIRECT_IE_HEADER_LEN); + saved_len = WIFIDIRECT_IE_HEADER_LEN; + pending_len = len; + } + } + if (left_len > 0 && next_byte == WIFIDIRECT_OVERLAP_DATA) { + /* copy next data */ + if (pending_len > 0 && + (left_len <= (WIFI_IE_MAX_PAYLOAD - saved_len))) { + memcpy(saved_data + saved_len, ptr, + pending_len); + orig_ptr = ptr; + ptr = saved_data; + } else { + ptr -= WIFIDIRECT_IE_HEADER_LEN; + } + + if (!pending_len && !orig_ptr && left_len < len) { + /* save along with type and len */ + memcpy(saved_data, + ptr - WIFIDIRECT_IE_HEADER_LEN, + left_len + WIFIDIRECT_IE_HEADER_LEN); + saved_len = left_len + WIFIDIRECT_IE_HEADER_LEN; + pending_len = len - left_len; + break; + } + switch (type) { + case TLV_TYPE_WIFIDIRECT_DEVICE_ID: + { + tlvbuf_wifidirect_device_id + *wifidirect_tlv = + (tlvbuf_wifidirect_device_id *) + ptr; + printf("\t Device ID - "); + print_mac(wifidirect_tlv-> + dev_mac_address); + printf("\n"); + } + break; + case TLV_TYPE_WIFIDIRECT_CAPABILITY: + { + tlvbuf_wifidirect_capability + *wifidirect_tlv = + (tlvbuf_wifidirect_capability *) + ptr; + printf("\t Device capability = %d\n", + (int)wifidirect_tlv-> + dev_capability); + printf("\t Group capability = %d\n", + (int)wifidirect_tlv-> + group_capability); + } + break; + case TLV_TYPE_WIFIDIRECT_GROUPOWNER_INTENT: + { + tlvbuf_wifidirect_group_owner_intent + *wifidirect_tlv = + (tlvbuf_wifidirect_group_owner_intent + *)ptr; + printf("\t Group owner intent = %d\n", + (int)wifidirect_tlv->dev_intent); + } + break; + case TLV_TYPE_WIFIDIRECT_MANAGEABILITY: + { + tlvbuf_wifidirect_manageability + *wifidirect_tlv = + (tlvbuf_wifidirect_manageability + *)ptr; + printf("\t Manageability = %d\n", + (int)wifidirect_tlv-> + manageability); + } + break; + case TLV_TYPE_WIFIDIRECT_INVITATION_FLAG: + { + tlvbuf_wifidirect_invitation_flag + *wifidirect_tlv = + (tlvbuf_wifidirect_invitation_flag + *)ptr; + printf("\t Invitation Flag = %d\n", + (int)wifidirect_tlv-> + invitation_flag & + INVITATION_FLAG_MASK); + } + break; + case TLV_TYPE_WIFIDIRECT_CHANNEL_LIST: + { + tlvbuf_wifidirect_channel_list + *wifidirect_tlv = + (tlvbuf_wifidirect_channel_list + *)ptr; + chan_entry *temp_ptr; + printf("\t Country String %c%c", + wifidirect_tlv-> + country_string[0], + wifidirect_tlv-> + country_string[1]); + if (isalpha + (wifidirect_tlv->country_string[2])) + printf("%c", + wifidirect_tlv-> + country_string[2]); + printf("\n"); + temp_ptr = + (chan_entry *)wifidirect_tlv-> + wifidirect_chan_entry_list; + temp = uap_le16_to_cpu(wifidirect_tlv-> + length) - + (sizeof + (tlvbuf_wifidirect_channel_list) + - WIFIDIRECT_IE_HEADER_LEN); + while (temp) { + printf("\t Regulatory_class = %d\n", (int)(temp_ptr->regulatory_class)); + printf("\t No of channels = %d\n", (int)temp_ptr->num_of_channels); + printf("\t Channel list = "); + for (i = 0; + i < + temp_ptr->num_of_channels; + i++) { + printf("%d ", + *(temp_ptr-> + chan_list + + i)); + } + printf("\n"); + temp -= sizeof(chan_entry) + + temp_ptr-> + num_of_channels; + temp_ptr = + (chan_entry *)((t_u8 *) + temp_ptr + + + sizeof + (chan_entry) + + + temp_ptr-> + num_of_channels); + } + printf("\n"); + } + break; + case TLV_TYPE_WIFIDIRECT_NOTICE_OF_ABSENCE: + { + tlvbuf_wifidirect_notice_of_absence + *wifidirect_tlv = + (tlvbuf_wifidirect_notice_of_absence + *)ptr; + noa_descriptor *temp_ptr; + printf("\t Instance of Notice of absence timing %d\n", (int)wifidirect_tlv->noa_index); + printf("\t CTWindow and Opportunistic power save parameters %d\n", (int)wifidirect_tlv->ctwindow_opp_ps); + temp_ptr = + (noa_descriptor *) + wifidirect_tlv-> + wifidirect_noa_descriptor_list; + temp = uap_le16_to_cpu(wifidirect_tlv-> + length) - + (sizeof + (tlvbuf_wifidirect_notice_of_absence) + - WIFIDIRECT_IE_HEADER_LEN); + while (temp) { + printf("\t Count or Type = %d\n", (int)temp_ptr->count_type); + printf("\t Duration = %dms\n", + uap_le32_to_cpu + (temp_ptr->duration)); + printf("\t Interval = %dms\n", + uap_le32_to_cpu + (temp_ptr->interval)); + printf("\t Start Time = %d\n", + uap_le32_to_cpu + (temp_ptr->start_time)); + printf("\n"); + temp_ptr += + sizeof(noa_descriptor); + temp -= sizeof(noa_descriptor); + } + } + break; + case TLV_TYPE_WIFIDIRECT_DEVICE_INFO: + { + tlvbuf_wifidirect_device_info + *wifidirect_tlv = + (tlvbuf_wifidirect_device_info + *)ptr; + printf("\t Device address - "); + print_mac(wifidirect_tlv->dev_address); + printf("\n"); + printf("\t Config methods - 0x%02X\n", + ntohs(wifidirect_tlv-> + config_methods)); + printf("\t Primay device type = %02d-%02X%02X%02X%02X-%02d\n", (int)ntohs(wifidirect_tlv->primary_category), (int)wifidirect_tlv->primary_oui[0], (int)wifidirect_tlv->primary_oui[1], (int)wifidirect_tlv->primary_oui[2], (int)wifidirect_tlv->primary_oui[3], (int)ntohs(wifidirect_tlv->primary_subcategory)); + printf("\t Secondary Device Count = %d\n", (int)wifidirect_tlv->secondary_dev_count); + array_ptr = + wifidirect_tlv-> + secondary_dev_info; + for (i = 0; + i < + wifidirect_tlv-> + secondary_dev_count; i++) { + memcpy(&temp, array_ptr, + sizeof(t_u16)); + printf("\t Secondary device type = %02d-", ntohs(temp)); + array_ptr += sizeof(temp); + printf("%02X%02X%02X%02X", + array_ptr[0], + array_ptr[1], + array_ptr[2], + array_ptr[3]); + array_ptr += 4; + memcpy(&temp, array_ptr, + sizeof(t_u16)); + printf("-%02d\n", ntohs(temp)); + array_ptr += sizeof(temp); + } + /* display device name */ + array_ptr = + wifidirect_tlv->device_name + + wifidirect_tlv-> + secondary_dev_count * + WPS_DEVICE_TYPE_LEN; + if (*(t_u16 *) + (((t_u8 *)(&wifidirect_tlv-> + device_name_len)) + + wifidirect_tlv-> + secondary_dev_count * + WPS_DEVICE_TYPE_LEN)) + printf("\t Device Name = "); + memcpy(&temp, + (((t_u8 *)(&wifidirect_tlv-> + device_name_len)) + + wifidirect_tlv-> + secondary_dev_count * + WPS_DEVICE_TYPE_LEN), + sizeof(t_u16)); + temp = ntohs(temp); + for (i = 0; i < temp; i++) + printf("%c", *array_ptr++); + printf("\n"); + } + break; + case TLV_TYPE_WIFIDIRECT_GROUP_INFO: + { + tlvbuf_wifidirect_group_info + *wifidirect_tlv = + (tlvbuf_wifidirect_group_info *) + ptr; + t_u8 wifidirect_client_dev_length; + wifidirect_client_dev_info *temp_ptr; + temp_ptr = + (wifidirect_client_dev_info *) + wifidirect_tlv-> + wifidirect_client_dev_list; + if (temp_ptr == NULL) + break; + wifidirect_client_dev_length = + temp_ptr->dev_length; + temp = uap_le16_to_cpu(wifidirect_tlv-> + length) - + wifidirect_client_dev_length; + while (temp_ptr) { + + printf("\t Group WifiDirect Client Device address - "); + print_mac(temp_ptr-> + wifidirect_dev_address); + printf("\n"); + printf("\t Group WifiDirect Client Interface address - "); + print_mac(temp_ptr-> + wifidirect_intf_address); + printf("\n"); + printf("\t Group WifiDirect Client Device capability = %d\n", (int)temp_ptr->wifidirect_dev_capability); + printf("\t Group WifiDirect Client Config methods - 0x%02X\n", ntohs(temp_ptr->config_methods)); + printf("\t Group WifiDirect Client Primay device type = %02d-%02X%02X%02X%02X-%02d\n", (int)ntohs(temp_ptr->primary_category), (int)temp_ptr->primary_oui[0], (int)temp_ptr->primary_oui[1], (int)temp_ptr->primary_oui[2], (int)temp_ptr->primary_oui[3], (int)ntohs(temp_ptr->primary_subcategory)); + printf("\t Group WifiDirect Client Secondary Device Count = %d\n", (int)temp_ptr->wifidirect_secondary_dev_count); + array_ptr = + temp_ptr-> + wifidirect_secondary_dev_info; + for (i = 0; + i < + temp_ptr-> + wifidirect_secondary_dev_count; + i++) { + memcpy(&temp, array_ptr, + sizeof(t_u16)); + printf("\t Group WifiDirect Client Secondary device type = %02d-", ntohs(temp)); + array_ptr += + sizeof(temp); + printf("%02X%02X%02X%02X", array_ptr[0], array_ptr[1], array_ptr[2], array_ptr[3]); + array_ptr += 4; + memcpy(&temp, array_ptr, + sizeof(t_u16)); + printf("-%02d\n", + ntohs(temp)); + array_ptr += + sizeof(temp); + } + /* display device name */ + array_ptr = + temp_ptr-> + wifidirect_device_name + + temp_ptr-> + wifidirect_secondary_dev_count + * WPS_DEVICE_TYPE_LEN; + printf("\t Group WifiDirect Device Name = "); + memcpy(&temp, + (((t_u8 *)(&temp_ptr-> + wifidirect_device_name_len)) + + + temp_ptr-> + wifidirect_secondary_dev_count + * WPS_DEVICE_TYPE_LEN), + sizeof(t_u16)); + temp = ntohs(temp); + for (i = 0; i < temp; i++) + printf("%c", + *array_ptr++); + printf("\n"); + temp_ptr += + wifidirect_client_dev_length; + temp -= wifidirect_client_dev_length; + if (temp_ptr) + wifidirect_client_dev_length + = + temp_ptr-> + dev_length; + } + printf("\n"); + } + break; + case TLV_TYPE_WIFIDIRECT_GROUP_ID: + { + tlvbuf_wifidirect_group_id + *wifidirect_tlv = + (tlvbuf_wifidirect_group_id *) + ptr; + printf("\t Group address - "); + print_mac(wifidirect_tlv-> + group_address); + printf("\n"); + printf("\t Group ssid = "); + for (i = 0; + (unsigned int)i < + uap_le16_to_cpu(wifidirect_tlv-> + length) + - + (sizeof(tlvbuf_wifidirect_group_id) + - WIFIDIRECT_IE_HEADER_LEN); i++) + printf("%c", + wifidirect_tlv-> + group_ssid[i]); + printf("\n"); + } + break; + case TLV_TYPE_WIFIDIRECT_GROUP_BSS_ID: + { + tlvbuf_wifidirect_group_bss_id + *wifidirect_tlv = + (tlvbuf_wifidirect_group_bss_id + *)ptr; + printf("\t Group BSS Id - "); + print_mac(wifidirect_tlv->group_bssid); + printf("\n"); + } + break; + case TLV_TYPE_WIFIDIRECT_INTERFACE: + { + tlvbuf_wifidirect_interface + *wifidirect_tlv = + (tlvbuf_wifidirect_interface *) + ptr; + printf("\t Interface Id - "); + print_mac(wifidirect_tlv->interface_id); + printf("\t Interface count = %d", + (int)wifidirect_tlv-> + interface_count); + for (i = 0; + i < + wifidirect_tlv->interface_count; + i++) { + printf("\n\t Interface address [%d]", i + 1); + print_mac(&wifidirect_tlv-> + interface_idlist[i * + ETH_ALEN]); + } + printf("\n"); + } + break; + case TLV_TYPE_WIFIDIRECT_CHANNEL: + { + tlvbuf_wifidirect_channel + *wifidirect_tlv = + (tlvbuf_wifidirect_channel *) + ptr; + printf("\t Listen Channel Country String %c%c", wifidirect_tlv->country_string[0], wifidirect_tlv->country_string[1]); + if (isalpha + (wifidirect_tlv->country_string[2])) + printf("%c", + wifidirect_tlv-> + country_string[2]); + printf("\n"); + printf("\t Listen Channel regulatory class = %d\n", (int)wifidirect_tlv->regulatory_class); + printf("\t Listen Channel number = %d\n", (int)wifidirect_tlv->channel_number); + } + break; + + case TLV_TYPE_WIFIDIRECT_OPCHANNEL: + { + tlvbuf_wifidirect_channel + *wifidirect_tlv = + (tlvbuf_wifidirect_channel *) + ptr; + printf("\t Operating Channel Country String %c%c", wifidirect_tlv->country_string[0], wifidirect_tlv->country_string[1]); + if (isalpha + (wifidirect_tlv->country_string[2])) + printf("%c", + wifidirect_tlv-> + country_string[2]); + printf("\n"); + printf("\t Operating Channel regulatory class = %d\n", (int)wifidirect_tlv->regulatory_class); + printf("\t Operating Channel number = %d\n", (int)wifidirect_tlv->channel_number); + } + break; + + case TLV_TYPE_WIFIDIRECT_CONFIG_TIMEOUT: + { + tlvbuf_wifidirect_config_timeout + *wifidirect_tlv = + (tlvbuf_wifidirect_config_timeout + *)ptr; + printf("\t GO configuration timeout = %d msec\n", (int)wifidirect_tlv->group_config_timeout * 10); + printf("\t Client configuration timeout = %d msec\n", (int)wifidirect_tlv->device_config_timeout * 10); + } + break; + case TLV_TYPE_WIFIDIRECT_EXTENDED_LISTEN_TIME: + { + tlvbuf_wifidirect_ext_listen_time + *wifidirect_tlv = + (tlvbuf_wifidirect_ext_listen_time + *)ptr; + printf("\t Availability Period = %d msec\n", (int)wifidirect_tlv->availability_period); + printf("\t Availability Interval = %d msec\n", (int)wifidirect_tlv->availability_interval); + } + break; + case TLV_TYPE_WIFIDIRECT_INTENDED_ADDRESS: + { + tlvbuf_wifidirect_intended_addr + *wifidirect_tlv = + (tlvbuf_wifidirect_intended_addr + *)ptr; + printf("\t Intended Interface Address - "); + print_mac(wifidirect_tlv-> + group_address); + printf("\n"); + } + break; + + case TLV_TYPE_WIFIDIRECT_STATUS: + { + tlvbuf_wifidirect_status *wifidirect_tlv + = + (tlvbuf_wifidirect_status *)ptr; + printf("\t Status = %d\n", + wifidirect_tlv->status_code); + } + break; + + default: + printf("unknown ie=0x%x, len=%d\n", type, len); + break; + } + next_byte = WIFIDIRECT_OVERLAP_TYPE; + if (orig_ptr) + ptr = orig_ptr + pending_len; + } + ptr += len + WIFIDIRECT_IE_HEADER_LEN; + left_len -= len; + } + printf("\n"); + return; +} + +/** + * @brief Parse and print WIFIDIRECT generic event data + * + * @param buffer Pointer to received buffer + * @param size Length of the received event data + * @return N/A + */ +void +print_event_wifidirect_generic(t_u8 *buffer, t_u16 size) +{ + const t_u8 wifi_oui[3] = { 0x50, 0x6F, 0x9A }; + const t_u8 wps_oui[3] = { 0x00, 0x50, 0xF2 }; + apeventbuf_wifidirect_generic *wifidirect_event; + wifidirect_ie_header *wifidirect_wps_header; + t_u16 wifidirect_wps_len = 0, type, sub_type; + printf("EVENT: WIFIDIRECT \n"); + wifidirect_event = (apeventbuf_wifidirect_generic *)(buffer); + printf("Event length = %d\n", + uap_le16_to_cpu(wifidirect_event->event_length)); + printf("Event Type = "); + type = uap_le16_to_cpu(wifidirect_event->event_type); + switch (type) { + case 0: + printf("Negotiation Request\n"); + break; + case 1: + printf("Negotiation Response\n"); + break; + case 2: + printf("Negotiation Result\n"); + break; + case 3: + printf("Invitation Request\n"); + break; + case 4: + printf("Invitation Response\n"); + break; + case 5: + printf("Discoverability Request\n"); + break; + case 6: + printf("Discoverability Response\n"); + break; + case 7: + printf("Provision Discovery Request\n"); + break; + case 8: + printf("Provision Discovery Response\n"); + break; + case 9: + printf("GO Negotiation response Tx Event\n"); + break; + case 10: + printf("GO Negotiation confirm Tx Event\n"); + break; + case 14: + printf("Peer Detected event\n"); + break; + case 15: + printf("Client associated event\n"); + break; + case 16: + printf("FW debug event: %s\n", + wifidirect_event->entire_ie_list); + return; + default: + printf("Unknown\n"); + break; + } + sub_type = uap_le16_to_cpu(wifidirect_event->event_sub_type); + if (type == 2) { + switch (sub_type) { + case 0: + printf("Event SubType = No Role\n"); + break; + case 1: + printf("Event SubType = Group Owner Role\n"); + break; + case 2: + printf("Event SubType = Client Role\n"); + break; + default: + printf("Event SubType = %d\n", sub_type); + break; + } + } else if (type == 3 || type == 4) { + switch (sub_type & 0x03) { /* lower 2 bits */ + case 0: + printf("Event SubType = No Role\n"); + break; + case 1: + printf("Event SubType = Group Owner Role\n"); + break; + case 2: + printf("Event SubType = Client Role\n"); + break; + } + switch ((sub_type & 0x1C) >> 2) { /* next 3 bits */ + case 0: + printf("Packet processing state = None\n"); + break; + case 1: + printf("Packet processing state = Processing\n"); + break; + case 2: + printf("Packet processing state = Insufficient information, Dropped\n"); + break; + case 3: + printf("Packet processing state = Success\n"); + break; + case 4: + printf("Packet processing state = Fail\n"); + break; + default: + printf("Event SubType = %d\n", sub_type); + break; + } + } else if (type == 7 || type == 8) { + switch (sub_type) { + case 0: + printf("Event SubType = No Config Method\n"); + break; + case 8: + printf("Event SubType = Config Method Display\n"); + break; + case 0x80: + printf("Event SubType = Config Method Push Button\n"); + break; + case 0x100: + printf("Event SubType = Config Method Keypad\n"); + break; + default: + printf("Event SubType = %d\n", sub_type); + break; + } + } + printf("Peer Mac Address - "); + print_mac(wifidirect_event->peer_mac_addr); + printf("\n"); + /* Print rest of IE elements */ + wifidirect_wps_header = + (wifidirect_ie_header *)(wifidirect_event->entire_ie_list); + wifidirect_wps_len = uap_le16_to_cpu(wifidirect_event->event_length) + - sizeof(apeventbuf_wifidirect_generic); + + while (wifidirect_wps_len >= sizeof(wifidirect_ie_header)) { + if (!memcmp + (wifidirect_wps_header->oui, wifi_oui, sizeof(wifi_oui)) || + !(memcmp + (wifidirect_wps_header->oui, wps_oui, sizeof(wps_oui)))) { + switch (wifidirect_wps_header->oui_type) { + case WIFIDIRECT_OUI_TYPE: + print_wifidirect_ie_elements + (wifidirect_wps_header->ie_list, + wifidirect_wps_header->ie_length - + sizeof(wifidirect_wps_header->oui) + - + sizeof(wifidirect_wps_header-> + oui_type)); + printf("\n"); + break; + case WIFI_WPS_OUI_TYPE: + print_wifi_wps_ie_elements + (wifidirect_wps_header->ie_list, + wifidirect_wps_header->ie_length - + sizeof(wifidirect_wps_header->oui) + - + sizeof(wifidirect_wps_header-> + oui_type)); + printf("\n"); + break; + } + } + wifidirect_wps_len -= + wifidirect_wps_header->ie_length + IE_HEADER_LEN; + wifidirect_wps_header = + (wifidirect_ie_header *)(((t_u8 *)wifidirect_wps_header) + + + wifidirect_wps_header-> + ie_length + IE_HEADER_LEN); + } +} + +/** + * @brief Parse and print WIFIDIRECT service discovery event data + * + * @param buffer Pointer to received buffer + * @param size Length of the received event data + * @return N/A + */ +void +print_event_wifidirect_service_discovery(t_u8 *buffer, t_u16 size) +{ + unsigned int i; + t_u16 event_len = 0; + t_u16 dns_len = 0, dns_type; + t_u8 action = 0; /* req = 0, resp = 1 */ + apeventbuf_wifidirect_discovery_request *wifidirect_disc_req; + apeventbuf_wifidirect_discovery_response *wifidirect_disc_resp; + printf("EVENT: WIFIDIRECT SERVICE DISCOVERY\n"); + memcpy(&event_len, buffer, sizeof(t_u16)); + event_len = uap_le16_to_cpu(event_len); + printf("Event length = %d\n", event_len); + printf("Service Discovery packet:\n"); + /* check request /response Byte at offset 2+6+2 */ + action = *(buffer + sizeof(t_u16) + ETH_ALEN + sizeof(t_u8)); + if (action == WIFIDIRECT_DISCOVERY_REQUEST_ACTION) { + wifidirect_disc_req = + (apeventbuf_wifidirect_discovery_request *)(buffer + + sizeof + (t_u16)); + printf("\t Peer Mac Address - "); + print_mac(wifidirect_disc_req->peer_mac_addr); + printf("\n\t Category = %d\n", wifidirect_disc_req->category); + printf("\t Action = %d\n", wifidirect_disc_req->action); + printf("\t Dialog taken = %d\n", + wifidirect_disc_req->dialog_taken); + printf("\t Advertize protocol IE - 0x%02x, 0x%02x, 0x%02x, 0x%02x\n", wifidirect_disc_req->advertize_protocol_ie[0], wifidirect_disc_req->advertize_protocol_ie[1], wifidirect_disc_req->advertize_protocol_ie[2], wifidirect_disc_req->advertize_protocol_ie[3]); + printf("\t Request query length = %d\n", + uap_le16_to_cpu(wifidirect_disc_req->query_len)); + printf("\t Information Id - 0x%02x, 0x%02x\n", + wifidirect_disc_req->info_id[0], + wifidirect_disc_req->info_id[1]); + printf("\t Request length = %d\n", + uap_le16_to_cpu(wifidirect_disc_req->request_len)); + printf("\t OUI - 0x%02x, 0x%02x, 0x%02x\n", + wifidirect_disc_req->oui[0], wifidirect_disc_req->oui[1], + wifidirect_disc_req->oui[2]); + printf("\t OUI sub type = %d\n", + wifidirect_disc_req->oui_sub_type); + printf("\t Service update Indicator = %d\n", + uap_le16_to_cpu(wifidirect_disc_req-> + service_update_indicator)); + printf("\t Vendor length = %d\n", + uap_le16_to_cpu(wifidirect_disc_req->vendor_len)); + printf("\t Service protocol = %d\n", + wifidirect_disc_req->service_protocol); + printf("\t Service transaction Id = %d\n", + wifidirect_disc_req->service_transaction_id); + printf("\t Query Data = "); + if (wifidirect_disc_req->service_protocol == 1) { + printf(" * Bonjour * \n"); + printf("\t\t DNS = "); + dns_len = + uap_le16_to_cpu(wifidirect_disc_req-> + vendor_len) - + WIFIDIRECT_DISCOVERY_BONJOUR_FIXED_LEN; + for (i = 0; i < dns_len; i++) + printf("%02x ", + (int)*(wifidirect_disc_req->disc_query.u. + bonjour.dns + i)); + memcpy(&dns_type, + (&wifidirect_disc_req->disc_query.u.bonjour. + dns_type + dns_len), sizeof(dns_type)); + dns_type = uap_le16_to_cpu(dns_type); + printf("\n\t\t DNS Type = %d\n", dns_type); + printf("\t\t Version = %d\n", + *(&wifidirect_disc_req->disc_query.u.bonjour. + version + dns_len)); + } else if (wifidirect_disc_req->service_protocol == 2) { + printf(" * uPnP * \n"); + printf("\t\t Version = %d\n", + wifidirect_disc_req->disc_query.u.upnp.version); + dns_len = + uap_le16_to_cpu(wifidirect_disc_req-> + vendor_len) - + WIFIDIRECT_DISCOVERY_UPNP_FIXED_LEN; + printf("\t\t Value = "); + for (i = 0; i < dns_len; i++) + printf("%02x ", + (int)*(wifidirect_disc_req->disc_query.u. + upnp.value + i)); + } + printf("\n"); + } else if (action == WIFIDIRECT_DISCOVERY_RESPONSE_ACTION) { + wifidirect_disc_resp = + (apeventbuf_wifidirect_discovery_response *)(buffer + + sizeof + (t_u16)); + printf("\t Peer Mac Address - "); + print_mac(wifidirect_disc_resp->peer_mac_addr); + printf("\n\t Category = %d\n", wifidirect_disc_resp->category); + printf("\t Action = %d\n", wifidirect_disc_resp->action); + printf("\t Dialog taken = %d\n", + wifidirect_disc_resp->dialog_taken); + printf("\t Status code = %d\n", + wifidirect_disc_resp->status_code); + printf("\t GAS reply - 0x%02x\n", + uap_le16_to_cpu(wifidirect_disc_resp->gas_reply)); + printf("\t Advertize protocol IE - 0x%02x, 0x%02x, 0x%02x, 0x%02x\n", wifidirect_disc_resp->advertize_protocol_ie[0], wifidirect_disc_resp->advertize_protocol_ie[1], wifidirect_disc_resp->advertize_protocol_ie[2], wifidirect_disc_resp->advertize_protocol_ie[3]); + printf("\t Response query length = %d\n", + uap_le16_to_cpu(wifidirect_disc_resp->query_len)); + printf("\t Information Id - 0x%02x, 0x%02x\n", + wifidirect_disc_resp->info_id[0], + wifidirect_disc_resp->info_id[1]); + printf("\t Response length = %d\n", + uap_le16_to_cpu(wifidirect_disc_resp->response_len)); + printf("\t OUI - 0x%02x, 0x%02x, 0x%02x\n", + wifidirect_disc_resp->oui[0], + wifidirect_disc_resp->oui[1], + wifidirect_disc_resp->oui[2]); + printf("\t OUI sub type = %d\n", + wifidirect_disc_resp->oui_sub_type); + printf("\t Service update Indicator = %d\n", + uap_le16_to_cpu(wifidirect_disc_resp-> + service_update_indicator)); + printf("\t Vendor length = %d\n", + uap_le16_to_cpu(wifidirect_disc_resp->vendor_len)); + printf("\t Service protocol = %d\n", + wifidirect_disc_resp->service_protocol); + printf("\t Service transaction Id = %d\n", + wifidirect_disc_resp->service_transaction_id); + printf("\t Status Code = %d\n", + wifidirect_disc_resp->disc_status_code); + printf("\t Response Data = "); + if (wifidirect_disc_resp->service_protocol == 1) { + printf(" * Bonjour * \n"); + /* + printf("\t\t DNS = "); + dns_len = uap_le16_to_cpu(wifidirect_disc_resp->vendor_len) - + (WIFIDIRECT_DISCOVERY_BONJOUR_FIXED_LEN + 1); + for( i=0; i < dns_len; i++) + printf("%c",*(wifidirect_disc_resp->disc_resp.u.bonjour.dns + i)); + memcpy(&dns_type, (&wifidirect_disc_req->disc_query.u.bonjour.dns_type + + dns_len), sizeof(dns_type)); + dns_type = uap_le16_to_cpu(dns_type); + printf("\n\t\t DNS Type = %d\n", dns_type); + printf("\t\t Version = %d\n", *(&wifidirect_disc_resp->disc_resp.u.bonjour.version + + dns_len)); + */ + } else if (wifidirect_disc_resp->service_protocol == 2) { + printf(" * uPnP * \n"); + printf("\t\t Version = %d\n", + wifidirect_disc_resp->disc_resp.u.upnp.version); + dns_len = + uap_le16_to_cpu(wifidirect_disc_resp-> + vendor_len) - + WIFIDIRECT_DISCOVERY_UPNP_FIXED_LEN; + printf("\t\t Value = "); + for (i = 0; i < dns_len; i++) + printf("%02x ", + (int)*(wifidirect_disc_resp->disc_resp.u. + upnp.value + i)); + } + printf("\n"); + } +} +#endif + +/** + * @brief Prints station reject state + * + * @param state Fail state + * @return N/A + */ +void +print_reject_state(t_u8 state) +{ + switch (state) { + case REJECT_STATE_FAIL_EAPOL_2: + printf("Reject state: FAIL_EAPOL_2\n"); + break; + case REJECT_STATE_FAIL_EAPOL_4: + printf("Reject state: FAIL_EAPOL_4:\n"); + break; + case REJECT_STATE_FAIL_EAPOL_GROUP_2: + printf("Reject state: FAIL_EAPOL_GROUP_2\n"); + break; + default: + printf("ERR: unknown reject state %d\n", state); + break; + } + return; +} + +/** + * @brief Prints station reject reason + * + * @param reason Reason code + * @return N/A + */ +void +print_reject_reason(t_u16 reason) +{ + switch (reason) { + case IEEEtypes_REASON_INVALID_IE: + printf("Reject reason: Invalid IE\n"); + break; + case IEEEtypes_REASON_MIC_FAILURE: + printf("Reject reason: Mic Failure\n"); + break; + default: + printf("Reject reason: %d\n", reason); + break; + } + return; +} + +/** + * @brief Prints EAPOL state + * + * @param state Eapol state + * @return N/A + */ +void +print_eapol_state(t_u8 state) +{ + switch (state) { + case EAPOL_START: + printf("Eapol state: EAPOL_START\n"); + break; + case EAPOL_WAIT_PWK2: + printf("Eapol state: EAPOL_WAIT_PWK2\n"); + break; + case EAPOL_WAIT_PWK4: + printf("Eapol state: EAPOL_WAIT_PWK4\n"); + break; + case EAPOL_WAIT_GTK2: + printf("Eapol state: EAPOL_WAIT_GTK2\n"); + break; + case EAPOL_END: + printf("Eapol state: EAPOL_END\n"); + break; + default: + printf("ERR: unknow eapol state%d\n", state); + break; + } + return; +} + +/** + * @brief Parse and print debug event data + * + * @param buffer Pointer to received buffer + * @param size Length of the received event data + * @return N/A + */ +void +print_event_debug(t_u8 *buffer, t_u16 size) +{ + eventbuf_debug *event_body = NULL; + if (size < sizeof(eventbuf_debug)) { + printf("ERR:Event buffer too small!\n"); + return; + } + event_body = (eventbuf_debug *)buffer; + printf("Debug Event Type: %s\n", + (event_body->debug_type == 0) ? "EVENT" : "INFO"); + printf("%s log:\n", + (uap_le32_to_cpu(event_body->debug_id_major) == + DEBUG_ID_MAJ_AUTHENTICATOR) ? "Authenticator" : "Assoc_agent"); + if (uap_le32_to_cpu(event_body->debug_id_major) == + DEBUG_ID_MAJ_AUTHENTICATOR) { + switch (uap_le32_to_cpu(event_body->debug_id_minor)) { + case DEBUG_MAJ_AUTH_MIN_PWK1: + printf("EAPOL Key message 1 (PWK):\n"); + hexdump((t_u8 *)&event_body->info.eapol_pwkmsg, + sizeof(eapol_keymsg_debug_t), ' '); + break; + case DEBUG_MAJ_AUTH_MIN_PWK2: + printf("EAPOL Key message 2 (PWK):\n"); + hexdump((t_u8 *)&event_body->info.eapol_pwkmsg, + sizeof(eapol_keymsg_debug_t), ' '); + break; + case DEBUG_MAJ_AUTH_MIN_PWK3: + printf("EAPOL Key message 3 (PWK):\n"); + hexdump((t_u8 *)&event_body->info.eapol_pwkmsg, + sizeof(eapol_keymsg_debug_t), ' '); + break; + case DEBUG_MAJ_AUTH_MIN_PWK4: + printf("EAPOL Key message 4: (PWK)\n"); + hexdump((t_u8 *)&event_body->info.eapol_pwkmsg, + sizeof(eapol_keymsg_debug_t), ' '); + break; + case DEBUG_MAJ_AUTH_MIN_GWK1: + printf("EAPOL Key message 1: (GWK)\n"); + hexdump((t_u8 *)&event_body->info.eapol_pwkmsg, + sizeof(eapol_keymsg_debug_t), ' '); + break; + case DEBUG_MAJ_AUTH_MIN_GWK2: + printf("EAPOL Key message 2: (GWK)\n"); + hexdump((t_u8 *)&event_body->info.eapol_pwkmsg, + sizeof(eapol_keymsg_debug_t), ' '); + break; + case DEBUG_MAJ_AUTH_MIN_STA_REJ: + printf("Reject STA MAC: "); + print_mac(event_body->info.sta_reject.sta_mac_addr); + printf("\n"); + print_reject_state(event_body->info.sta_reject. + reject_state); + print_reject_reason(uap_le16_to_cpu + (event_body->info.sta_reject. + reject_reason)); + break; + case DEBUG_MAJ_AUTH_MIN_EAPOL_TR: + printf("STA MAC: "); + print_mac(event_body->info.eapol_state.sta_mac_addr); + printf("\n"); + print_eapol_state(event_body->info.eapol_state. + eapol_state); + break; + default: + printf("ERR: unknow debug_id_minor: %d\n", + (int)uap_le32_to_cpu(event_body-> + debug_id_minor)); + hexdump(buffer, size, ' '); + return; + } + } else if (uap_le32_to_cpu(event_body->debug_id_major) == + DEBUG_ID_MAJ_ASSOC_AGENT) { + switch (uap_le32_to_cpu(event_body->debug_id_minor)) { + case DEBUG_ID_MAJ_ASSOC_MIN_WPA_IE: + printf("STA MAC: "); + print_mac(event_body->info.wpaie.sta_mac_addr); + printf("\n"); + printf("wpa ie:\n"); + hexdump(event_body->info.wpaie.wpa_ie, MAX_WPA_IE_LEN, + ' '); + break; + case DEBUG_ID_MAJ_ASSOC_MIN_STA_REJ: + printf("Reject STA MAC: "); + print_mac(event_body->info.sta_reject.sta_mac_addr); + printf("\n"); + print_reject_state(event_body->info.sta_reject. + reject_state); + print_reject_reason(uap_le16_to_cpu + (event_body->info.sta_reject. + reject_reason)); + break; + default: + printf("ERR: unknow debug_id_minor: %d\n", + (int)uap_le32_to_cpu(event_body-> + debug_id_minor)); + hexdump(buffer, size, ' '); + return; + } + } + return; +} + +/** + * @brief Parse and print received event information + * + * @param event Pointer to received event + * @param size Length of the received event + * @return N/A + */ +void +print_event(event_header *event, t_u16 size, char *if_name) +{ + t_u32 event_id = event->event_id; + switch (event_id) { + case MICRO_AP_EV_ID_STA_DEAUTH: + print_event_sta_deauth(event->event_data, size - EVENT_ID_LEN); + break; + case MICRO_AP_EV_ID_STA_ASSOC: + print_event_sta_assoc(event->event_data, size - EVENT_ID_LEN); + break; + case MICRO_AP_EV_ID_BSS_START: + print_event_bss_start(event->event_data, size - EVENT_ID_LEN); + break; + case MICRO_AP_EV_ID_DEBUG: + print_event_debug(event->event_data, size - EVENT_ID_LEN); + break; + case MICRO_AP_EV_BSS_IDLE: + printf("EVENT: BSS_IDLE\n"); + break; + case MICRO_AP_EV_BSS_ACTIVE: + printf("EVENT: BSS_ACTIVE\n"); + break; + case MICRO_AP_EV_RSN_CONNECT: + print_event_rsn_connect(event->event_data, size - EVENT_ID_LEN); + break; + case MICRO_AP_EV_ID_MIC_COUNTERMEASURES: + print_event_mic_countermeasures(event->event_data, + size - EVENT_ID_LEN); + break; +#ifdef WIFI_DIRECT_SUPPORT + case EVENT_WIFIDIRECT_GENERIC: + print_event_wifidirect_generic(event->event_data, + size - EVENT_ID_LEN); + break; + case EVENT_WIFIDIRECT_SERVICE_DISCOVERY: + print_event_wifidirect_service_discovery(event->event_data, + size - EVENT_ID_LEN); + break; +#endif + + case UAP_EVENT_ID_DRV_HS_ACTIVATED: + printf("EVENT: uAP HS_ACTIVATED\n"); + break; + case UAP_EVENT_ID_DRV_HS_DEACTIVATED: + printf("EVENT: uAP HS_DEACTIVATED\n"); + break; + case UAP_EVENT_ID_HS_WAKEUP: + printf("EVENT: uAP HS_WAKEUP\n"); + break; + case UAP_EVENT_HOST_SLEEP_AWAKE: + break; + case UAP_EVENT_ID_DRV_MGMT_FRAME: + printf("EVENT: Mgmt frame from FW\n"); + hexdump((void *)event, size, ' '); + break; + case MICRO_AP_EV_WMM_STATUS_CHANGE: + printf("EVENT: WMM_STATUS_CHANGE\n"); + break; + case EVENT_RADAR_DETECTED: + printf("EVENT: RADAR_DETECTED\n"); + break; + case EVENT_CHANNEL_REPORT_RDY: + printf("EVENT: CHANNEL_REPORT_READY\n"); + hexdump((void *)event, size, ' '); + break; + case EVENT_WEP_ICV_ERROR: + print_event_wep_icv_error(event->event_data, + size - EVENT_ID_LEN); + break; + case EVENT_ID_DRV_SCAN_REPORT: + printf("Scan request completed.\n"); + break; + + default: + /* Handle string based events */ +#define CUS_EVT_PORT_RELEASE "EVENT=PORT_RELEASE" + if (!strncmp + ((char *)event, CUS_EVT_PORT_RELEASE, + strlen(CUS_EVT_PORT_RELEASE))) { + printf("EVENT: PORT_RELEASE.\n"); + break; + } +#define CUS_EVT_TDLS_CONNECTED "EVENT=TDLS_CONNECTED" + if (!strncmp + ((char *)event, CUS_EVT_TDLS_CONNECTED, + strlen(CUS_EVT_TDLS_CONNECTED))) { + printf("EVENT: TDLS_CONNECTED\n"); + print_mac((t_u8 *)event + + strlen(CUS_EVT_TDLS_CONNECTED)); + printf("\n"); + break; + } +#define CUS_EVT_TDLS_TEARDOWN "EVENT=TDLS_TEARDOWN" + if (!strncmp + ((char *)event, CUS_EVT_TDLS_TEARDOWN, + strlen(CUS_EVT_TDLS_TEARDOWN))) { + printf("EVENT: TDLS_TEARDOWN\n"); + print_mac((t_u8 *)event + + strlen(CUS_EVT_TDLS_TEARDOWN)); + printf("\n"); + break; + } +#define CUS_EVT_STA_CONNECTED "EVENT=STA_CONNECTED" + if (!strncmp + ((char *)event, CUS_EVT_STA_CONNECTED, + strlen(CUS_EVT_STA_CONNECTED))) { + printf("EVENT: STA_CONNECTED\n"); + print_mac((t_u8 *)event + + strlen(CUS_EVT_STA_CONNECTED) + 1); + printf("\n"); + break; + } +#define CUS_EVT_STA_DISCONNECTED "EVENT=STA_DISCONNECTED" + if (!strncmp + ((char *)event, CUS_EVT_STA_DISCONNECTED, + strlen(CUS_EVT_STA_DISCONNECTED))) { + printf("EVENT: STA_DISCONNECTED\n"); + break; + } +#define CUS_EVT_AP_CONNECTED "EVENT=AP_CONNECTED" + if (!strncmp + ((char *)event, CUS_EVT_AP_CONNECTED, + strlen(CUS_EVT_AP_CONNECTED))) { + printf("EVENT: AP_CONNECTED\n"); + print_mac((t_u8 *)event + strlen(CUS_EVT_AP_CONNECTED)); + printf("\n"); + break; + } +#define CUS_EVT_ADHOC_LINK_SENSED "EVENT=ADHOC_LINK_SENSED" + if (!strncmp + ((char *)event, CUS_EVT_ADHOC_LINK_SENSED, + strlen(CUS_EVT_ADHOC_LINK_SENSED))) { + printf("EVENT: ADHOC_LINK_SENSED\n"); + break; + } +#define CUS_EVT_ADHOC_LINK_LOST "EVENT=ADHOC_LINK_LOST" + if (!strncmp + ((char *)event, CUS_EVT_ADHOC_LINK_LOST, + strlen(CUS_EVT_ADHOC_LINK_LOST))) { + printf("EVENT: ADHOC_LINK_LOST\n"); + break; + } +#define CUS_EVT_OBSS_SCAN_PARAM "EVENT=OBSS_SCAN_PARAM" + if (!strncmp + ((char *)event, CUS_EVT_OBSS_SCAN_PARAM, + strlen(CUS_EVT_OBSS_SCAN_PARAM))) { + printf("EVENT: OBSS_SCAN_PARAM\n"); + break; + } +#define CUS_EVT_BW_CHANGED "EVENT=BW_CHANGED" + if (!strncmp + ((char *)event, CUS_EVT_BW_CHANGED, + strlen(CUS_EVT_BW_CHANGED))) { + printf("EVENT: BW_CHANGED\n"); + break; + } +#define CUS_EVT_MLME_MIC_ERR_UNI "MLME-MICHAELMICFAILURE.indication unicast" + if (!strncmp + ((char *)event, CUS_EVT_MLME_MIC_ERR_UNI, + strlen(CUS_EVT_MLME_MIC_ERR_UNI))) { + printf("EVENT: MLME-MICHAELMICFAILURE.indication unicast\n"); + break; + } +#define CUS_EVT_MLME_MIC_ERR_MUL "MLME-MICHAELMICFAILURE.indication multicast" + if (!strncmp + ((char *)event, CUS_EVT_MLME_MIC_ERR_MUL, + strlen(CUS_EVT_MLME_MIC_ERR_MUL))) { + printf("EVENT: MLME-MICHAELMICFAILURE.indication multicast\n"); + break; + } +#define CUS_EVT_BEACON_RSSI_LOW "EVENT=BEACON_RSSI_LOW" + if (!strncmp + ((char *)event, CUS_EVT_BEACON_RSSI_LOW, + strlen(CUS_EVT_BEACON_RSSI_LOW))) { + printf("EVENT: BEACON_RSSI_LOW\n"); + break; + } +#define CUS_EVT_BEACON_RSSI_HIGH "EVENT=BEACON_RSSI_HIGH" + if (!strncmp + ((char *)event, CUS_EVT_BEACON_RSSI_HIGH, + strlen(CUS_EVT_BEACON_RSSI_HIGH))) { + printf("EVENT: BEACON_RSSI_HIGH\n"); + break; + } +#define CUS_EVT_BEACON_SNR_LOW "EVENT=BEACON_SNR_LOW" + if (!strncmp + ((char *)event, CUS_EVT_BEACON_SNR_LOW, + strlen(CUS_EVT_BEACON_SNR_LOW))) { + printf("EVENT: BEACON_SNR_LOW\n"); + break; + } +#define CUS_EVT_BEACON_SNR_HIGH "EVENT=BEACON_SNR_HIGH" + if (!strncmp + ((char *)event, CUS_EVT_BEACON_SNR_HIGH, + strlen(CUS_EVT_BEACON_SNR_HIGH))) { + printf("EVENT: BEACON_SNR_HIGH\n"); + break; + } +#define CUS_EVT_MAX_FAIL "EVENT=MAX_FAIL" + if (!strncmp + ((char *)event, CUS_EVT_MAX_FAIL, + strlen(CUS_EVT_MAX_FAIL))) { + printf("EVENT: MAX_FAIL\n"); + break; + } +#define CUS_EVT_DATA_RSSI_LOW "EVENT=DATA_RSSI_LOW" + if (!strncmp + ((char *)event, CUS_EVT_DATA_RSSI_LOW, + strlen(CUS_EVT_DATA_RSSI_LOW))) { + printf("EVENT: DATA_RSSI_LOW\n"); + break; + } +#define CUS_EVT_DATA_SNR_LOW "EVENT=DATA_SNR_LOW" + if (!strncmp + ((char *)event, CUS_EVT_DATA_SNR_LOW, + strlen(CUS_EVT_DATA_SNR_LOW))) { + printf("EVENT: DATA_SNR_LOW\n"); + break; + } +#define CUS_EVT_DATA_RSSI_HIGH "EVENT=DATA_RSSI_HIGH" + if (!strncmp + ((char *)event, CUS_EVT_DATA_RSSI_HIGH, + strlen(CUS_EVT_DATA_RSSI_HIGH))) { + printf("EVENT: DATA_RSSI_HIGH\n"); + break; + } +#define CUS_EVT_DATA_SNR_HIGH "EVENT=DATA_SNR_HIGH" + if (!strncmp + ((char *)event, CUS_EVT_DATA_SNR_HIGH, + strlen(CUS_EVT_DATA_SNR_HIGH))) { + printf("EVENT: DATA_SNR_HIGH\n"); + break; + } +#define CUS_EVT_LINK_QUALITY "EVENT=LINK_QUALITY" + if (!strncmp + ((char *)event, CUS_EVT_LINK_QUALITY, + strlen(CUS_EVT_LINK_QUALITY))) { + printf("EVENT: LINK_QUALITY\n"); + break; + } +#define CUS_EVT_WEP_ICV_ERR "EVENT=WEP_ICV_ERR" + if (!strncmp + ((char *)event, CUS_EVT_WEP_ICV_ERR, + strlen(CUS_EVT_WEP_ICV_ERR))) { + printf("EVENT: WEP_ICV_ERR\n"); + break; + } +#define CUS_EVT_CHANNEL_SWITCH_ANN "EVENT=CHANNEL_SWITCH_ANN" + if (!strncmp + ((char *)event, CUS_EVT_CHANNEL_SWITCH_ANN, + strlen(CUS_EVT_CHANNEL_SWITCH_ANN))) { + printf("EVENT: CHANNEL_SWITCH_ANN\n"); + break; + } +#define CUS_EVT_HS_WAKEUP "HS_WAKEUP" + if (!strncmp + ((char *)event, CUS_EVT_HS_WAKEUP, + strlen(CUS_EVT_HS_WAKEUP))) { + printf("EVENT: HS_WAKEUP\n"); + break; + } +#define CUS_EVT_HS_ACTIVATED "HS_ACTIVATED" + if (!strncmp + ((char *)event, CUS_EVT_HS_ACTIVATED, + strlen(CUS_EVT_HS_ACTIVATED))) { + printf("EVENT: HS_ACTIVATED\n"); + break; + } +#define CUS_EVT_HS_DEACTIVATED "HS_DEACTIVATED" + if (!strncmp + ((char *)event, CUS_EVT_HS_DEACTIVATED, + strlen(CUS_EVT_HS_DEACTIVATED))) { + printf("EVENT: HS_DEACTIVATED\n"); + break; + } +/** Custom indication message sent to the application layer for WMM changes */ +#define WMM_CONFIG_CHANGE_INDICATION "WMM_CONFIG_CHANGE.indication" + if (!strncmp + ((char *)event, WMM_CONFIG_CHANGE_INDICATION, + strlen(WMM_CONFIG_CHANGE_INDICATION))) { + printf("EVENT: STA_DISCONNECTED\n"); + break; + } +#define CUS_EVT_DRIVER_HANG "EVENT=DRIVER_HANG" + if (!strncmp + ((char *)event, CUS_EVT_DRIVER_HANG, + strlen(CUS_EVT_DRIVER_HANG))) { + printf("EVENT: DRIVER_HANG\n"); + break; + } +#define FW_DEBUG_INFO "EVENT=FW_DEBUG_INFO" + if (!strncmp + ((char *)event, FW_DEBUG_INFO, strlen(FW_DEBUG_INFO))) { + printf("EVENT: FW_DEBUG_INFO\n"); + printf("%s\n", + (t_u8 *)event + strlen(CUS_EVT_STA_CONNECTED) + + 1); + printf("\n"); + break; + } + printf("ERR:Undefined event type (0x%X). Dumping event buffer:\n", (unsigned int)event_id); + hexdump((void *)event, size, ' '); + break; + } + return; +} + +/** + * @brief Read event data from netlink socket + * + * @param sk_fd Netlink socket handler + * @param buffer Pointer to the data buffer + * @param nlh Pointer to netlink message header + * @param msg Pointer to message header + * @return Number of bytes read or MLAN_EVENT_FAILURE + */ +int +read_event_netlink_socket(int sk_fd, unsigned char *buffer, + struct nlmsghdr *nlh, struct msghdr *msg) +{ + int count = -1; + count = recvmsg(sk_fd, msg, 0); +#if DEBUG + printf("DBG:Waiting for message from NETLINK.\n"); +#endif + if (count < 0) { + printf("ERR:NETLINK read failed!\n"); + return MLAN_EVENT_FAILURE; + } +#if DEBUG + printf("DBG:Received message payload (%d)\n", count); +#endif + if (count > NLMSG_SPACE(NL_MAX_PAYLOAD)) { + printf("ERR:Buffer overflow!\n"); + return MLAN_EVENT_FAILURE; + } + memset(buffer, 0, NL_MAX_PAYLOAD); + memcpy(buffer, NLMSG_DATA(nlh), count - NLMSG_HDRLEN); +#if DEBUG + hexdump(buffer, count - NLMSG_HDRLEN, ' '); +#endif + return count - NLMSG_HDRLEN; +} + +/** + * @brief Configure and read event data from netlink socket + * + * @param sk_fd Array of netlink sockets + * @param no_of_sk Number of netlink sockets opened + * @param recv_buf Pointer to the array of evt_buf structures + * @param timeout Socket listen timeout value + * @param nlh Pointer to netlink message header + * @param msg Pointer to message header + * @return Number of bytes read or MLAN_EVENT_FAILURE + */ +int +read_event(int *sk_fd, int no_of_sk, evt_buf *recv_buf, int timeout, + struct nlmsghdr *nlh, struct msghdr *msg) +{ + struct timeval tv; + fd_set rfds; + int i = 0, max_sk_fd = sk_fd[0]; + int ret = MLAN_EVENT_FAILURE; + + /* Setup read fds */ + FD_ZERO(&rfds); + for (i = 0; i < no_of_sk; i++) { + if (sk_fd[i] > max_sk_fd) + max_sk_fd = sk_fd[i]; + + if (sk_fd[i] > 0) + FD_SET(sk_fd[i], &rfds); + } + + /* Initialize timeout value */ + if (timeout != 0) + tv.tv_sec = timeout; + else + tv.tv_sec = UAP_RECV_WAIT_DEFAULT; + tv.tv_usec = 0; + + /* Wait for reply */ + ret = select(max_sk_fd + 1, &rfds, NULL, NULL, &tv); + if (ret == -1) { + /* Error */ + terminate_flag++; + return MLAN_EVENT_FAILURE; + } else if (!ret) { + /* Timeout. Try again */ + return MLAN_EVENT_FAILURE; + } + for (i = 0; i < no_of_sk; i++) { + if (sk_fd[i] > 0) { + if (FD_ISSET(sk_fd[i], &rfds)) { + /* Success */ + recv_buf[i].flag = 1; + recv_buf[i].length = + read_event_netlink_socket(sk_fd[i], + recv_buf[i]. + buffer, nlh, + msg); + ret += recv_buf[i].length; + } + } + } + return ret; +} + +/* Command line options */ +static const struct option long_opts[] = { + {"help", no_argument, NULL, 'h'}, + {"version", no_argument, NULL, 'v'}, + {NULL, 0, NULL, 0} +}; + +/** + * @brief Determine the netlink number + * + * @param i socket number + * + * @return Netlink number to use + */ +static int +get_netlink_num(int i) +{ + FILE *fp; + int netlink_num = NETLINK_NXP; + char str[64]; + char *srch = "netlink_num"; + char filename[64]; + + /* Try to open old driver proc: /proc/mwlan/configX first */ + if (i == 0) + strcpy(filename, "/proc/mwlan/config"); + else if (i > 0) + sprintf(filename, "/proc/mwlan/config%d", i); + fp = fopen(filename, "r"); + if (!fp) { + /* Try to open multi-adapter driver proc: /proc/mwlan/adapterX/config if old proc access fail */ + snprintf(filename, sizeof(filename), + "/proc/mwlan/adapter%d/config", i); + fp = fopen(filename, "r"); + } + + if (fp) { + while (fgets(str, sizeof(str), fp)) { + if (strncmp(str, srch, strlen(srch)) == 0) { + netlink_num = atoi(str + strlen(srch) + 1); + break; + } + } + fclose(fp); + } else { + return -1; + } + printf("Netlink number = %d\n", netlink_num); + return netlink_num; +} + +/**************************************************************************** + Global functions +****************************************************************************/ +/** + * @brief The main function + * + * @param argc Number of arguments + * @param argv Pointer to the arguments + * @return 0 or 1 + */ +int +main(int argc, char *argv[]) +{ + int opt; + int nl_sk[MAX_NO_OF_DEVICES]; + struct nlmsghdr *nlh = NULL; + struct sockaddr_nl src_addr, dest_addr; + struct msghdr msg; + struct iovec iov; + evt_buf evt_recv_buf[MAX_NO_OF_DEVICES]; + struct timeval current_time; + struct tm *timeinfo; + int num_events = 0; + event_header *event = NULL; + int ret = MLAN_EVENT_FAILURE; + int netlink_num[MAX_NO_OF_DEVICES]; + char if_name[IFNAMSIZ + 1]; + t_u32 event_id = 0; + int i = 0, no_of_sk = 0, dev_index = -1; + + /* Check command line options */ + while ((opt = getopt_long(argc, argv, "hvti:", long_opts, NULL)) > 0) { + switch (opt) { + case 'h': + print_usage(); + return 0; + case 'v': + printf("mlanevent version : %s\n", MLAN_EVENT_VERSION); + return 0; + break; + case 'i': + if ((IS_HEX_OR_DIGIT(argv[2]) == MLAN_EVENT_FAILURE) + || ((A2HEXDECIMAL(argv[2]) >= MAX_NO_OF_DEVICES) && + (A2HEXDECIMAL(argv[2]) != 0xff))) { + print_usage(); + return 1; + } else { + dev_index = A2HEXDECIMAL(argv[2]); + argc -= optind; + argv += optind; + } + break; + default: + print_usage(); + return 1; + } + } + + if (optind < argc) { + fputs("Too many arguments.\n", stderr); + print_usage(); + return 1; + } + if ((dev_index >= 0) && (dev_index < MAX_NO_OF_DEVICES)) { + no_of_sk = 1; + } else { + /* Currently, we support maximum 4 devices */ + /* TODO: determine no_of_sk at run time */ + no_of_sk = MAX_NO_OF_DEVICES; + } + + for (i = 0; i < no_of_sk; i++) { + /* Initialise */ + nl_sk[i] = -1; + if (no_of_sk == 1) { + netlink_num[i] = get_netlink_num(dev_index); + if (netlink_num[i] < 0) { + printf("ERR:Could not get netlink socket. Invalid device number.\n"); + ret = MLAN_EVENT_FAILURE; + goto done; + } + } else { + netlink_num[i] = get_netlink_num(i); + } + if (netlink_num[i] >= 0) { + /* Open netlink socket */ + nl_sk[i] = socket(PF_NETLINK, SOCK_RAW, netlink_num[i]); + if (nl_sk[i] < 0) { + printf("ERR:Could not open netlink socket.\n"); + ret = MLAN_EVENT_FAILURE; + goto done; + } + + /* Set source address */ + memset(&src_addr, 0, sizeof(src_addr)); + src_addr.nl_family = AF_NETLINK; + src_addr.nl_pid = getpid(); /* Our PID */ + src_addr.nl_groups = NL_MULTICAST_GROUP; + + /* Bind socket with source address */ + if (bind + (nl_sk[i], (struct sockaddr *)&src_addr, + sizeof(src_addr)) < 0) { + printf("ERR:Could not bind socket!\n"); + ret = MLAN_EVENT_FAILURE; + goto done; + } + + /* Set destination address */ + memset(&dest_addr, 0, sizeof(dest_addr)); + dest_addr.nl_family = AF_NETLINK; + dest_addr.nl_pid = 0; /* Kernel */ + dest_addr.nl_groups = NL_MULTICAST_GROUP; + + /* Initialize netlink header */ + nlh = (struct nlmsghdr *) + malloc(NLMSG_SPACE(NL_MAX_PAYLOAD)); + if (!nlh) { + printf("ERR: Could not alloc buffer\n"); + ret = MLAN_EVENT_FAILURE; + goto done; + } + memset(nlh, 0, NLMSG_SPACE(NL_MAX_PAYLOAD)); + + /* Initialize I/O vector */ + iov.iov_base = (void *)nlh; + iov.iov_len = NLMSG_SPACE(NL_MAX_PAYLOAD); + + /* Initialize message header */ + memset(&msg, 0, sizeof(struct msghdr)); + msg.msg_name = (void *)&dest_addr; + msg.msg_namelen = sizeof(dest_addr); + msg.msg_iov = &iov; + msg.msg_iovlen = 1; + + memset(&evt_recv_buf[i], 0, sizeof(evt_buf)); + } + } + gettimeofday(¤t_time, NULL); + + printf("\n"); + printf("**********************************************\n"); + if ((timeinfo = localtime(&(current_time.tv_sec)))) + printf("mlanevent start time : %s", asctime(timeinfo)); + printf(" %u usecs\n", + (unsigned int)current_time.tv_usec); + printf("**********************************************\n"); + + signal(SIGTERM, sig_handler); + signal(SIGINT, sig_handler); + signal(SIGALRM, sig_handler); + while (1) { + if (terminate_flag) { + printf("Stopping!\n"); + break; + } + ret = read_event(nl_sk, no_of_sk, evt_recv_buf, 0, nlh, &msg); + + /* No result. Loop again */ + if (ret == MLAN_EVENT_FAILURE) { + continue; + } + if (ret == 0) { + /* Zero bytes received */ + printf("ERR:Received zero bytes!\n"); + continue; + } + for (i = 0; i < no_of_sk; i++) { + if (evt_recv_buf[i].flag == 1) { + num_events++; + gettimeofday(¤t_time, NULL); + printf("\n"); + printf("============================================\n"); + printf("Received event"); + if ((timeinfo = + localtime(&(current_time.tv_sec)))) + printf(": %s", asctime(timeinfo)); + printf(" %u usecs\n", + (unsigned int)current_time.tv_usec); + printf("============================================\n"); + + memcpy(&event_id, evt_recv_buf[i].buffer, + sizeof(event_id)); + if (((event_id & 0xFF000000) == 0x80000000) || + ((event_id & 0xFF000000) == 0)) { + event = (event_header + *)(evt_recv_buf[i].buffer); + } else { + memset(if_name, 0, IFNAMSIZ + 1); + memcpy(if_name, evt_recv_buf[i].buffer, + IFNAMSIZ); + printf("EVENT for interface %s\n", + if_name); + event = (event_header + *)((t_u8 *)(evt_recv_buf[i]. + buffer) + + IFNAMSIZ); + ret -= IFNAMSIZ; + evt_recv_buf[i].length -= IFNAMSIZ; + } +#if DEBUG + printf("DBG:Received buffer =\n"); + hexdump(evt_recv_buf[i].buffer, + evt_recv_buf[i].length + IFNAMSIZ, ' '); +#endif + print_event(event, evt_recv_buf[i].length, + if_name); + /* Reset event flag after reading */ + evt_recv_buf[i].flag = 0; + } + } + fflush(stdout); + } + gettimeofday(¤t_time, NULL); + printf("\n"); + printf("*********************************************\n"); + if ((timeinfo = localtime(&(current_time.tv_sec)))) + printf("mlanevent end time : %s", asctime(timeinfo)); + printf(" %u usecs\n", + (unsigned int)current_time.tv_usec); + printf("Total events : %u\n", num_events); + printf("*********************************************\n"); +done: + for (i = 0; i < no_of_sk; i++) { + if (nl_sk[i] > 0) + close(nl_sk[i]); + } + if (nlh) + free(nlh); + return 0; +} diff --git a/mxm_wifiex/wlan_src/mapp/mlanevent/mlanevent.h b/mxm_wifiex/wlan_src/mapp/mlanevent/mlanevent.h new file mode 100644 index 0000000..e866415 --- /dev/null +++ b/mxm_wifiex/wlan_src/mapp/mlanevent/mlanevent.h @@ -0,0 +1,1269 @@ +/** @file mlanevent.h + * + * @brief Header file for mlanevent application + * + * + * Copyright 2014-2020 NXP + * + * NXP CONFIDENTIAL + * The source code contained or described herein and all documents related to + * the source code (Materials) are owned by NXP, its + * suppliers and/or its licensors. Title to the Materials remains with NXP, + * its suppliers and/or its licensors. The Materials contain + * trade secrets and proprietary and confidential information of NXP, its + * suppliers and/or its licensors. The Materials are protected by worldwide copyright + * and trade secret laws and treaty provisions. No part of the Materials may be + * used, copied, reproduced, modified, published, uploaded, posted, + * transmitted, distributed, or disclosed in any way without NXP's prior + * express written permission. + * + * No license under any patent, copyright, trade secret or other intellectual + * property right is granted to or conferred upon you by disclosure or delivery + * of the Materials, either expressly, by implication, inducement, estoppel or + * otherwise. Any license under such intellectual property rights must be + * express and approved by NXP in writing. + * + */ +/************************************************************************ +Change log: + 03/18/08: Initial creation +************************************************************************/ + +#ifndef _MLAN_EVENT_H +#define _MLAN_EVENT_H + +/** Character, 1 byte */ +typedef signed char t_s8; +/** Unsigned character, 1 byte */ +typedef unsigned char t_u8; + +/** Short integer */ +typedef signed short t_s16; +/** Unsigned short integer */ +typedef unsigned short t_u16; + +/** Integer */ +typedef signed int t_s32; +/** Unsigned integer */ +typedef unsigned int t_u32; + +/** Long long integer */ +typedef long long t_s64; +/** Unsigned long long integer */ +typedef unsigned long long t_u64; + +#if (BYTE_ORDER == LITTLE_ENDIAN) +#undef BIG_ENDIAN_SUPPORT +#endif + +/** 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 from 16 bit little endian format to CPU format */ +#define uap_le16_to_cpu(x) swap_byte_16(x) +/** Convert from 32 bit little endian format to CPU format */ +#define uap_le32_to_cpu(x) swap_byte_32(x) +/** Convert from 64 bit little endian format to CPU format */ +#define uap_le64_to_cpu(x) swap_byte_64(x) +/** Convert to 16 bit little endian format from CPU format */ +#define uap_cpu_to_le16(x) swap_byte_16(x) +/** Convert to 32 bit little endian format from CPU format */ +#define uap_cpu_to_le32(x) swap_byte_32(x) +/** Convert to 64 bit little endian format from CPU format */ +#define uap_cpu_to_le64(x) swap_byte_64(x) +#else /* BIG_ENDIAN_SUPPORT */ +/** Do nothing */ +#define uap_le16_to_cpu(x) x +/** Do nothing */ +#define uap_le32_to_cpu(x) x +/** Do nothing */ +#define uap_le64_to_cpu(x) x +/** Do nothing */ +#define uap_cpu_to_le16(x) x +/** Do nothing */ +#define uap_cpu_to_le32(x) x +/** Do nothing */ +#define uap_cpu_to_le64(x) x +#endif /* BIG_ENDIAN_SUPPORT */ + +/** Convert WPS TLV header from network to host order */ +#define endian_convert_tlv_wps_header_in(t,l) \ + { \ + (t) = ntohs(t); \ + (l) = ntohs(l); \ + } + +/** + * Hex or Decimal to Integer + * @param num string to convert into decimal or hex + */ +#define A2HEXDECIMAL(num) \ + (strncasecmp("0x", (num), 2)?(unsigned int) strtoll((num),NULL,0):a2hex((num)))\ + +/** + * Check of decimal or hex string + * @param num string + */ +#define IS_HEX_OR_DIGIT(num) \ + (strncasecmp("0x", (num), 2)?ISDIGIT((num)):ishexstring((num)))\ + +/** MLan Event application version string */ +#define MLAN_EVENT_VERSION "MlanEvent 2.0" + +/** Failure */ +#define MLAN_EVENT_FAILURE -1 + +#ifdef __GNUC__ +/** Structure packing begins */ +#define PACK_START +/** Structure packeing end */ +#define PACK_END __attribute__ ((packed)) +#else +/** Structure packing begins */ +#define PACK_START __packed +/** Structure packeing end */ +#define PACK_END +#endif + +#ifndef ETH_ALEN +/** MAC address length */ +#define ETH_ALEN 6 +#endif + +/** Netlink protocol number */ +#define NETLINK_NXP (MAX_LINKS - 1) +/** Netlink maximum payload size */ +#define NL_MAX_PAYLOAD (3 * 1024) +/** Netlink multicast group number */ +#define NL_MULTICAST_GROUP 1 +/** Default wait time in seconds for events */ +#define UAP_RECV_WAIT_DEFAULT 10 +/** Maximum number of devices */ +#define MAX_NO_OF_DEVICES 6 + +#ifndef NLMSG_HDRLEN +/** NL message header length */ +#define NLMSG_HDRLEN ((int) NLMSG_ALIGN(sizeof(struct nlmsghdr))) +#endif + +/** 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) + +/** Invitation Flag mask */ +#define INVITATION_FLAG_MASK 0x01 + +/* Event buffer */ +typedef PACK_START struct _evt_buf { + /** Flag to check if event data is present in the buffer or not */ + int flag; + /** Event length */ + int length; + /** Event data */ + t_u8 buffer[NL_MAX_PAYLOAD]; +} PACK_END evt_buf; + +/** Event header */ +typedef PACK_START struct _event_header { + /** Event ID */ + t_u32 event_id; + /** Event data */ + t_u8 event_data[]; +} PACK_END event_header; + +/** Event ID length */ +#define EVENT_ID_LEN 4 + +/** Event ID : WMM status change */ +#define MICRO_AP_EV_WMM_STATUS_CHANGE 0x00000017 + +/** Event ID: STA deauth */ +#define MICRO_AP_EV_ID_STA_DEAUTH 0x0000002c + +/** Event ID: STA associated */ +#define MICRO_AP_EV_ID_STA_ASSOC 0x0000002d + +/** Event ID: BSS started */ +#define MICRO_AP_EV_ID_BSS_START 0x0000002e + +/** Event ID: Debug event */ +#define MICRO_AP_EV_ID_DEBUG 0x00000036 + +/** Event ID: BSS idle event */ +#define MICRO_AP_EV_BSS_IDLE 0x00000043 + +/** Event ID: BSS active event */ +#define MICRO_AP_EV_BSS_ACTIVE 0x00000044 + +/** Event ID: WEP ICV error */ +#define EVENT_WEP_ICV_ERROR 0x00000046 + +#ifdef WIFI_DIRECT_SUPPORT +/** Event ID: UAP,STA wifidirect generic event */ +#define EVENT_WIFIDIRECT_GENERIC 0x00000049 + +/** Event ID: UAP,STA wifidirect service discovery event */ +#define EVENT_WIFIDIRECT_SERVICE_DISCOVERY 0x0000004a +#endif + +/** Event ID: MIC Countermeasures event */ +#define MICRO_AP_EV_ID_MIC_COUNTERMEASURES 0x0000004c + +/** Event ID: RSN Connect event */ +#define MICRO_AP_EV_RSN_CONNECT 0x00000051 + +/** Event ID: Radar Detected */ +#define EVENT_RADAR_DETECTED 0x00000053 +/** Event ID: Channel Report Ready */ +#define EVENT_CHANNEL_REPORT_RDY 0x00000054 + +/** 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 AWAKE event id in legacy PS*/ +#define UAP_EVENT_HOST_SLEEP_AWAKE 0x00000012 + +/** HS WAKE UP event id */ +#define UAP_EVENT_ID_DRV_MGMT_FRAME 0x80000005 + +/** SCAN REPORT Event id */ +#define EVENT_ID_DRV_SCAN_REPORT 0x80000009 + +/** WPA IE Tag */ +#define IEEE_WPA_IE 221 +/** RSN IE Tag */ +#define IEEE_RSN_IE 48 + +/** TLV ID : WAPI Information */ +#define MRVL_WAPI_INFO_TLV_ID 0x0167 + +/** TLV ID : Management Frame */ +#define MRVL_MGMT_FRAME_TLV_ID 0x0168 + +/** TLV Id : Channel Config */ +#define MRVL_CHANNELCONFIG_TLV_ID 0x012a + +/** Assoc Request */ +#define SUBTYPE_ASSOC_REQUEST 0 +/** Assoc Response */ +#define SUBTYPE_ASSOC_RESPONSE 1 +/** ReAssoc Request */ +#define SUBTYPE_REASSOC_REQUEST 2 +/** ReAssoc Response */ +#define SUBTYPE_REASSOC_RESPONSE 3 +/** WEP key user input length */ +#define WEP_KEY_USER_INPUT 13 + +/** TLV buffer header*/ +typedef PACK_START struct _tlvbuf_header { + /** Header type */ + t_u16 type; + /** Header length */ + t_u16 len; +} PACK_END tlvbuf_header; + +/** Event body : STA deauth */ +typedef PACK_START struct _eventbuf_sta_deauth { + /** Deauthentication reason */ + t_u16 reason_code; + /** MAC address of deauthenticated STA */ + t_u8 sta_mac_address[ETH_ALEN]; +} PACK_END eventbuf_sta_deauth; + +/** Event body : WEP ICV error */ +typedef PACK_START struct _eventbuf_wep_icv_error { + /** Deauthentication reason */ + t_u16 reason_code; + /** MAC address of deauthenticated STA */ + t_u8 sta_mac_address[ETH_ALEN]; + /** WEP key index */ + t_u8 wep_key_index; + /** WEP key length */ + t_u8 wep_key_length; + /** WEP key */ + t_u8 wep_key[WEP_KEY_USER_INPUT]; +} PACK_END eventbuf_wep_icv_error; + +/** Event body : STA associated */ +typedef PACK_START struct _eventbuf_sta_assoc { + /** Reserved */ + t_u8 reserved[2]; + /** MAC address of associated STA */ + t_u8 sta_mac_address[ETH_ALEN]; + /** Assoc request/response buffer */ + t_u8 assoc_payload[]; +} PACK_END eventbuf_sta_assoc; + +/** Event body : RSN Connect */ +typedef PACK_START struct _eventbuf_rsn_connect { + /** Reserved */ + t_u8 reserved[2]; + /** MAC address of Station */ + t_u8 sta_mac_address[ETH_ALEN]; + /** WPA/WPA2 TLV IEs */ + t_u8 tlv_list[]; +} PACK_END eventbuf_rsn_connect; + +/** Event body : BSS started */ +typedef PACK_START struct _eventbuf_bss_start { + /** Reserved */ + t_u8 reserved[2]; + /** MAC address of BSS */ + t_u8 ap_mac_address[ETH_ALEN]; +} PACK_END eventbuf_bss_start; + +/** Event body : MIC Countermeasures */ +typedef PACK_START struct _eventbuf_mic_countermeasures { + /** Status */ + t_u16 status; +} PACK_END eventbuf_mic_countermeasures; + +/** + * IEEE 802.11 MAC Message Data Structures + * + * Each IEEE 802.11 MAC message includes a MAC header, a frame body (which + * can be empty), and a frame check sequence field. This section gives the + * structures that used for the MAC message headers and frame bodies that + * can exist in the three types of MAC messages - 1) Control messages, + * 2) Data messages, and 3) Management messages. + */ +typedef 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; +} PACK_END IEEEtypes_FrameCtl_t; + +/** IEEEtypes_AssocRqst_t */ +typedef PACK_START struct _IEEEtypes_AssocRqst_t { + /** Capability Info */ + t_u16 cap_info; + /** Listen Interval */ + t_u16 listen_interval; + /** IE Buffer */ + t_u8 ie_buffer[]; +} PACK_END IEEEtypes_AssocRqst_t; + +/** IEEEtypes_AssocRsp_t */ +typedef PACK_START struct _IEEEtypes_AssocRsp_t { + /** Capability Info */ + t_u16 cap_info; + /** Status Code */ + t_u16 status_code; + /** AID */ + t_u16 aid; +} PACK_END IEEEtypes_AssocRsp_t; + +/** IEEEtypes_ReAssocRqst_t */ +typedef 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[ETH_ALEN]; + /** IE Buffer */ + t_u8 ie_buffer[]; +} PACK_END IEEEtypes_ReAssocRqst_t; + +/** channel band */ +enum { + BAND_2GHZ = 0, + BAND_5GHZ = 1, + BAND_4GHZ = 2, +}; + +/** channel offset */ +enum { + SEC_CHAN_NONE = 0, + SEC_CHAN_ABOVE = 1, + SEC_CHAN_5MHZ = 2, + SEC_CHAN_BELOW = 3 +}; + +/** channel bandwidth */ +enum { + CHAN_BW_20MHZ = 0, + CHAN_BW_10MHZ, + CHAN_BW_40MHZ, + CHAN_BW_80MHZ, + +}; + +/** scan mode */ +enum { + SCAN_MODE_MANUAL = 0, + SCAN_MODE_ACS, + SCAN_MODE_USER, +}; + +/** Band_Config_t */ +typedef PACK_START struct _Band_Config_t { +#ifdef BIG_ENDIAN_SUPPORT + /** Channel Selection Mode - (00)=manual, (01)=ACS, (02)=user*/ + t_u8 scanMode:2; + /** Secondary Channel Offset - (00)=None, (01)=Above, (11)=Below */ + t_u8 chan2Offset:2; + /** Channel Width - (00)=20MHz, (10)=40MHz, (11)=80MHz */ + t_u8 chanWidth:2; + /** Band Info - (00)=2.4GHz, (01)=5GHz */ + t_u8 chanBand:2; +#else + /** Band Info - (00)=2.4GHz, (01)=5GHz */ + t_u8 chanBand:2; + /** Channel Width - (00)=20MHz, (10)=40MHz, (11)=80MHz */ + t_u8 chanWidth:2; + /** Secondary Channel Offset - (00)=None, (01)=Above, (11)=Below */ + t_u8 chan2Offset:2; + /** Channel Selection Mode - (00)=manual, (01)=ACS, (02)=Adoption mode*/ + t_u8 scanMode:2; +#endif +} PACK_END Band_Config_t; + +/** TLV buffer : Channel Config */ +typedef PACK_START struct _tlvbuf_channel_config { + /** Type */ + t_u16 type; + /** Length */ + t_u16 len; + /** Band Configuration */ + Band_Config_t bandcfg; + /** Channel number */ + t_u8 chan_number; +} PACK_END tlvbuf_channel_config; + +/** MrvlIEtypes_WapiInfoSet_t */ +typedef PACK_START struct _MrvlIEtypes_WapiInfoSet_t { + /** Type */ + t_u16 type; + /** Length */ + t_u16 len; + /** Multicast PN */ + t_u8 multicast_PN[16]; +} PACK_END MrvlIEtypes_WapiInfoSet_t; + +/** MrvlIETypes_MgmtFrameSet_t */ +typedef PACK_START struct _MrvlIETypes_MgmtFrameSet_t { + /** Type */ + t_u16 type; + /** Length */ + t_u16 len; + /** Frame Control */ + IEEEtypes_FrameCtl_t frame_control; + /** Frame Contents */ + t_u8 frame_contents[]; +} PACK_END MrvlIETypes_MgmtFrameSet_t; + +/** Debug Type : Event */ +#define DEBUG_TYPE_EVENT 0 +/** Debug Type : Info */ +#define DEBUG_TYPE_INFO 1 + +/** Major debug id: Authenticator */ +#define DEBUG_ID_MAJ_AUTHENTICATOR 1 +/** Minor debug id: PWK1 */ +#define DEBUG_MAJ_AUTH_MIN_PWK1 0 +/** Minor debug id: PWK2 */ +#define DEBUG_MAJ_AUTH_MIN_PWK2 1 +/** Minor debug id: PWK3 */ +#define DEBUG_MAJ_AUTH_MIN_PWK3 2 +/** Minor debug id: PWK4 */ +#define DEBUG_MAJ_AUTH_MIN_PWK4 3 +/** Minor debug id: GWK1 */ +#define DEBUG_MAJ_AUTH_MIN_GWK1 4 +/** Minor debug id: GWK2 */ +#define DEBUG_MAJ_AUTH_MIN_GWK2 5 +/** Minor debug id: station reject */ +#define DEBUG_MAJ_AUTH_MIN_STA_REJ 6 +/** Minor debug id: EAPOL_TR */ +#define DEBUG_MAJ_AUTH_MIN_EAPOL_TR 7 + +/** Major debug id: Assoicate agent */ +#define DEBUG_ID_MAJ_ASSOC_AGENT 2 +/** Minor debug id: WPA IE*/ +#define DEBUG_ID_MAJ_ASSOC_MIN_WPA_IE 0 +/** Minor debug id: station reject */ +#define DEBUG_ID_MAJ_ASSOC_MIN_STA_REJ 1 + +/** ether_hdr */ +typedef PACK_START struct { + /** Dest address */ + t_u8 da[ETH_ALEN]; + /** Src address */ + t_u8 sa[ETH_ALEN]; + /** Header type */ + t_u16 type; +} PACK_END ether_hdr_t; + +/** 8021x header */ +typedef PACK_START struct { + /** Protocol version*/ + t_u8 protocol_ver; + /** Packet type*/ + t_u8 pckt_type; + /** Packet len */ + t_u8 pckt_body_len; +} PACK_END hdr_8021x_t; + +/** Nonce size */ +#define NONCE_SIZE 32 +/** Max WPA IE len */ +#define MAX_WPA_IE_LEN 64 +/** EAPOL mic size */ +#define EAPOL_MIC_SIZE 16 + +/** EAPOL key message */ +typedef PACK_START struct { + /** Ether header */ + ether_hdr_t ether_hdr; + /** 8021x header */ + hdr_8021x_t hdr_8021x; + /** desc_type */ + t_u8 desc_type; + /** Key info */ + t_u16 k; + /** Key length */ + t_u16 key_length; + /** Replay count */ + t_u32 replay_cnt[2]; + /** Key nonce */ + t_u8 key_nonce[NONCE_SIZE]; + /** Key IV */ + t_u8 eapol_key_iv[16]; + /** Key RSC */ + t_u8 key_rsc[8]; + /** Key ID */ + t_u8 key_id[8]; + /** Key MIC */ + t_u8 key_mic[EAPOL_MIC_SIZE]; + /** Key len */ + t_u16 key_material_len; + /** Key data */ + t_u8 key_data[MAX_WPA_IE_LEN]; +} PACK_END eapol_keymsg_debug_t; + +/** Failure after receive EAPOL MSG2 PMK */ +#define REJECT_STATE_FAIL_EAPOL_2 1 +/** Failure after receive EAPOL MSG4 PMK*/ +#define REJECT_STATE_FAIL_EAPOL_4 2 +/** Failure after receive EAPOL Group MSG2 GWK */ +#define REJECT_STATE_FAIL_EAPOL_GROUP_2 3 + +/** Fail reason: Invalid ie */ +#define IEEEtypes_REASON_INVALID_IE 13 +/** Fail reason: Mic failure */ +#define IEEEtypes_REASON_MIC_FAILURE 14 + +/** Station reject */ +typedef PACK_START struct { + /** Reject state */ + t_u8 reject_state; + /** Reject reason */ + t_u16 reject_reason; + /** Station mac address */ + t_u8 sta_mac_addr[ETH_ALEN]; +} PACK_END sta_reject_t; + +/** wpa_ie */ +typedef PACK_START struct { + /** Station mac address */ + t_u8 sta_mac_addr[ETH_ALEN]; + /** WPA IE */ + t_u8 wpa_ie[MAX_WPA_IE_LEN]; +} PACK_END wpaie_t; + +/** Initial state of the state machine */ +#define EAPOL_START 1 +/** Sent eapol msg1, wait for msg2 from the client */ +#define EAPOL_WAIT_PWK2 2 +/** Sent eapol msg3, wait for msg4 from the client */ +#define EAPOL_WAIT_PWK4 3 +/** Sent eapol group key msg1, wait for group msg2 from the client */ +#define EAPOL_WAIT_GTK2 4 +/** Eapol handshake complete */ +#define EAPOL_END 5 + +#ifdef WIFI_DIRECT_SUPPORT +/** TLV : WifiDirect status */ +#define TLV_TYPE_WIFIDIRECT_STATUS 0x0000 +/** TLV : WifiDirect param capability */ +#define TLV_TYPE_WIFIDIRECT_CAPABILITY 0x0002 +/** TLV : WifiDirect param device Id */ +#define TLV_TYPE_WIFIDIRECT_DEVICE_ID 0x0003 +/** TLV : WifiDirect param group owner intent */ +#define TLV_TYPE_WIFIDIRECT_GROUPOWNER_INTENT 0x0004 +/** TLV : WifiDirect param config timeout */ +#define TLV_TYPE_WIFIDIRECT_CONFIG_TIMEOUT 0x0005 +/** TLV : WifiDirect param channel */ +#define TLV_TYPE_WIFIDIRECT_CHANNEL 0x0006 +/** TLV : WifiDirect param group bssId */ +#define TLV_TYPE_WIFIDIRECT_GROUP_BSS_ID 0x0007 +/** TLV : WifiDirect param extended listen time */ +#define TLV_TYPE_WIFIDIRECT_EXTENDED_LISTEN_TIME 0x0008 +/** TLV : WifiDirect param intended address */ +#define TLV_TYPE_WIFIDIRECT_INTENDED_ADDRESS 0x0009 +/** TLV : WifiDirect param manageability */ +#define TLV_TYPE_WIFIDIRECT_MANAGEABILITY 0x000a +/** TLV : WifiDirect param channel list */ +#define TLV_TYPE_WIFIDIRECT_CHANNEL_LIST 0x000b +/** TLV : WifiDirect Notice of Absence */ +#define TLV_TYPE_WIFIDIRECT_NOTICE_OF_ABSENCE 0x000c +/** TLV : WifiDirect param device Info */ +#define TLV_TYPE_WIFIDIRECT_DEVICE_INFO 0x000d +/** TLV : WifiDirect param Group Info */ +#define TLV_TYPE_WIFIDIRECT_GROUP_INFO 0x000e +/** TLV : WifiDirect param group Id */ +#define TLV_TYPE_WIFIDIRECT_GROUP_ID 0x000f +/** TLV : WifiDirect param interface */ +#define TLV_TYPE_WIFIDIRECT_INTERFACE 0x0010 +/** TLV : WifiDirect param operating channel */ +#define TLV_TYPE_WIFIDIRECT_OPCHANNEL 0x0011 +/** TLV : WifiDirect param invitation flag */ +#define TLV_TYPE_WIFIDIRECT_INVITATION_FLAG 0x0012 + +/** WPS Device Info OUI+Type+SubType Length */ +#define WPS_DEVICE_TYPE_LEN 8 + +/** IE header len */ +#define IE_HEADER_LEN 2 + +/** WIFIDIRECT IE header len */ +#define WIFIDIRECT_IE_HEADER_LEN 3 + +/** OUI Type WIFIDIRECT */ +#define WIFIDIRECT_OUI_TYPE 9 +/** OUI Type WPS */ +#define WIFI_WPS_OUI_TYPE 4 + +/* + * To handle overlapping WIFIDIRECT IEs + */ +/** IE next byte type */ +#define WIFIDIRECT_OVERLAP_TYPE 1 +/** IE next byte length */ +#define WIFIDIRECT_OVERLAP_LEN 2 +/** IE next byte data */ +#define WIFIDIRECT_OVERLAP_DATA 3 + +/** Max payload for IE buffer */ +#define WIFI_IE_MAX_PAYLOAD 256 + +/** Fixed length fields in bonjour payload query data */ +#define WIFIDIRECT_DISCOVERY_BONJOUR_FIXED_LEN 5 + +/** Fixed length fields in uPnP payload query data */ +#define WIFIDIRECT_DISCOVERY_UPNP_FIXED_LEN 3 + +/** Action field for discovery request */ +#define WIFIDIRECT_DISCOVERY_REQUEST_ACTION 10 + +/** Action field for discovery response */ +#define WIFIDIRECT_DISCOVERY_RESPONSE_ACTION 11 + +/** TLV buffer : WifiDirect Status */ +typedef PACK_START struct _tlvbuf_wifidirect_status { + /** TLV Header tag */ + t_u8 tag; + /** TLV Header length */ + t_u16 length; + /** WIFIDIRECT status code */ + t_u8 status_code; +} PACK_END tlvbuf_wifidirect_status; + +/** TLV buffer : wifidirect IE device Id */ +typedef PACK_START struct _tlvbuf_wifidirect_device_id { + /** TLV Header tag */ + t_u8 tag; + /** TLV Header length */ + t_u16 length; + /** WIFIDIRECT device MAC address */ + t_u8 dev_mac_address[ETH_ALEN]; +} PACK_END tlvbuf_wifidirect_device_id; + +/** TLV buffer : wifidirect IE capability */ +typedef PACK_START struct _tlvbuf_wifidirect_capability { + /** TLV Header tag */ + t_u8 tag; + /** TLV Header length */ + t_u16 length; + /** WIFIDIRECT device capability */ + t_u8 dev_capability; + /** WIFIDIRECT group capability */ + t_u8 group_capability; +} PACK_END tlvbuf_wifidirect_capability; + +/** TLV buffer : wifidirect IE Group owner intent */ +typedef PACK_START struct _tlvbuf_wifidirect_group_owner_intent { + /** TLV Header tag */ + t_u8 tag; + /** TLV Header length */ + t_u16 length; + /** WIFIDIRECT device group owner intent */ + t_u8 dev_intent; +} PACK_END tlvbuf_wifidirect_group_owner_intent; + +/** TLV buffer : WifiDirect IE Manageability */ +typedef PACK_START struct _tlvbuf_wifidirect_manageability { + /** TLV Header tag */ + t_u8 tag; + /** TLV Header length */ + t_u16 length; + /** WIFIDIRECT Manageability */ + t_u8 manageability; +} PACK_END tlvbuf_wifidirect_manageability; + +/** TLV buffer : WifiDirect IE Invitation Flag */ +typedef PACK_START struct _tlvbuf_wifidirect_invitation_flag { + /** TLV Header tag */ + t_u8 tag; + /** TLV Header length */ + t_u16 length; + /** WIFIDIRECT Manageability */ + t_u8 invitation_flag; +} PACK_END tlvbuf_wifidirect_invitation_flag; + +/** TLV buffer : wifidirect IE capability */ +typedef PACK_START struct _tlvbuf_wifidirect_channel { + /** TLV Header tag */ + t_u8 tag; + /** TLV Header length */ + t_u16 length; + /** WIFIDIRECT country string */ + t_u8 country_string[3]; + /** WIFIDIRECT regulatory class */ + t_u8 regulatory_class; + /** WIFIDIRECT channel number */ + t_u8 channel_number; +} PACK_END tlvbuf_wifidirect_channel; + +/** Channel Entry */ +typedef PACK_START struct _chan_entry { + /** WIFIDIRECT regulatory class */ + t_u8 regulatory_class; + /** WIFIDIRECT no of channels */ + t_u8 num_of_channels; + /** WIFIDIRECT channel number */ + t_u8 chan_list[]; +} PACK_END chan_entry; + +/** TLV buffer : wifidirect IE channel list */ +typedef PACK_START struct _tlvbuf_wifidirect_channel_list { + /** TLV Header tag */ + t_u8 tag; + /** TLV Header length */ + t_u16 length; + /** WIFIDIRECT country string */ + t_u8 country_string[3]; + /** WIFIDIRECT channel entries */ + chan_entry wifidirect_chan_entry_list[]; +} PACK_END tlvbuf_wifidirect_channel_list; + +/** NoA Descriptor */ +typedef PACK_START struct _noa_descriptor { + /** WIFIDIRECT count OR type */ + t_u8 count_type; + /** WIFIDIRECT duration */ + t_u32 duration; + /** WIFIDIRECT interval */ + t_u32 interval; + /** WIFIDIRECT start time */ + t_u32 start_time; +} PACK_END noa_descriptor; + +/** TLV buffer : WifiDirect IE Notice of Absence */ +typedef PACK_START struct _tlvbuf_wifidirect_notice_of_absence { + /** TLV Header tag */ + t_u8 tag; + /** TLV Header length */ + t_u16 length; + /** WIFIDIRECT NoA Index */ + t_u8 noa_index; + /** WIFIDIRECT CTWindow and OppPS parameters */ + t_u8 ctwindow_opp_ps; + /** WIFIDIRECT NoA Descriptor list */ + noa_descriptor wifidirect_noa_descriptor_list[]; +} PACK_END tlvbuf_wifidirect_notice_of_absence; + +/** TLV buffer : wifidirect IE device Info */ +typedef PACK_START struct _tlvbuf_wifidirect_device_info { + /** TLV Header tag */ + t_u8 tag; + /** TLV Header length */ + t_u16 length; + /** WIFIDIRECT device address */ + t_u8 dev_address[ETH_ALEN]; + /** WPS config methods */ + t_u16 config_methods; + /** Primary device type : category */ + t_u16 primary_category; + /** Primary device type : OUI */ + t_u8 primary_oui[4]; + /** Primary device type : sub-category */ + t_u16 primary_subcategory; + /** Secondary Device Count */ + t_u8 secondary_dev_count; + /** Secondary Device Info */ + t_u8 secondary_dev_info[0]; + /** WPS Device Name Tag */ + t_u16 device_name_type; + /** WPS Device Name Length */ + t_u16 device_name_len; + /** Device name */ + t_u8 device_name[]; +} PACK_END tlvbuf_wifidirect_device_info; + +typedef PACK_START struct _wifidirect_client_dev_info { + /** Length of each device */ + t_u8 dev_length; + /** WIFIDIRECT device address */ + t_u8 wifidirect_dev_address[ETH_ALEN]; + /** WIFIDIRECT Interface address */ + t_u8 wifidirect_intf_address[ETH_ALEN]; + /** WIFIDIRECT Device capability*/ + t_u8 wifidirect_dev_capability; + /** WPS config methods */ + t_u16 config_methods; + /** Primary device type : category */ + t_u16 primary_category; + /** Primary device type : OUI */ + t_u8 primary_oui[4]; + /** Primary device type : sub-category */ + t_u16 primary_subcategory; + /** Secondary Device Count */ + t_u8 wifidirect_secondary_dev_count; + /** Secondary Device Info */ + t_u8 wifidirect_secondary_dev_info[0]; + /** WPS WIFIDIRECT Device Name Tag */ + t_u16 wifidirect_device_name_type; + /** WPS WIFIDIRECT Device Name Length */ + t_u16 wifidirect_device_name_len; + /** WIFIDIRECT Device name */ + t_u8 wifidirect_device_name[]; +} PACK_END wifidirect_client_dev_info; + +typedef PACK_START struct _tlvbuf_wifidirect_group_info { + /** TLV Header tag */ + t_u8 tag; + /** TLV Header length */ + t_u16 length; + /** Secondary Device Info */ + t_u8 wifidirect_client_dev_list[]; +} PACK_END tlvbuf_wifidirect_group_info; + +/** TLV buffer : wifidirect IE group Id */ +typedef PACK_START struct _tlvbuf_wifidirect_group_id { + /** TLV Header tag */ + t_u8 tag; + /** TLV Header length */ + t_u16 length; + /** WIFIDIRECT group MAC address */ + t_u8 group_address[ETH_ALEN]; + /** WIFIDIRECT group SSID */ + t_u8 group_ssid[]; +} PACK_END tlvbuf_wifidirect_group_id; + +/** TLV buffer : wifidirect IE group BSS Id */ +typedef PACK_START struct _tlvbuf_wifidirect_group_bss_id { + /** TLV Header tag */ + t_u8 tag; + /** TLV Header length */ + t_u16 length; + /** WIFIDIRECT group Bss Id */ + t_u8 group_bssid[ETH_ALEN]; +} PACK_END tlvbuf_wifidirect_group_bss_id; + +/** TLV buffer : wifidirect IE Interface */ +typedef PACK_START struct _tlvbuf_wifidirect_interface { + /** TLV Header tag */ + t_u8 tag; + /** TLV Header length */ + t_u16 length; + /** WIFIDIRECT interface Id */ + t_u8 interface_id[ETH_ALEN]; + /** WIFIDIRECT interface count */ + t_u8 interface_count; + /** WIFIDIRECT interface addresslist */ + t_u8 interface_idlist[]; +} PACK_END tlvbuf_wifidirect_interface; + +/** TLV buffer : WifiDirect configuration timeout */ +typedef PACK_START struct _tlvbuf_wifidirect_config_timeout { + /** TLV Header tag */ + t_u8 tag; + /** TLV Header length */ + t_u16 length; + /** Group configuration timeout */ + t_u8 group_config_timeout; + /** Device configuration timeout */ + t_u8 device_config_timeout; +} PACK_END tlvbuf_wifidirect_config_timeout; + +/** TLV buffer : WifiDirect extended listen time */ +typedef PACK_START struct _tlvbuf_wifidirect_ext_listen_time { + /** TLV Header tag */ + t_u8 tag; + /** TLV Header length */ + t_u16 length; + /** Availability period */ + t_u16 availability_period; + /** Availability interval */ + t_u16 availability_interval; +} PACK_END tlvbuf_wifidirect_ext_listen_time; + +/** TLV buffer : WifiDirect Intended Interface Address */ +typedef PACK_START struct _tlvbuf_wifidirect_intended_addr { + /** TLV Header tag */ + t_u8 tag; + /** TLV Header length */ + t_u16 length; + /** WIFIDIRECT Group interface address */ + t_u8 group_address[ETH_ALEN]; +} PACK_END tlvbuf_wifidirect_intended_addr; + +/** TLV buffer : Wifi WPS IE */ +typedef PACK_START struct _tlvbuf_wifi_wps_ie { + /** TLV Header tag */ + t_u16 tag; + /** TLV Header length */ + t_u16 length; + /** WIFI WPS IE data */ + t_u8 data[]; +} PACK_END tlvbuf_wps_ie; + +/** WifiDirect IE Header */ +typedef PACK_START struct _wifidirect_ie_header { + /** Element ID */ + t_u8 element_id; + /** IE Length */ + t_u8 ie_length; + /** OUI */ + t_u8 oui[3]; + /** OUI type */ + t_u8 oui_type; + /** IE List of TLV */ + t_u8 ie_list[]; +} PACK_END wifidirect_ie_header; + +/** Event : WifiDirect Generic event */ +typedef PACK_START struct _apeventbuf_wifidirect_generic { + /** Event Length */ + t_u16 event_length; + /** Event Type */ + t_u16 event_type; + /** Event SubType */ + t_u16 event_sub_type; + /** Peer mac address */ + t_u8 peer_mac_addr[ETH_ALEN]; + /** IE List of TLV */ + t_u8 entire_ie_list[]; +} PACK_END apeventbuf_wifidirect_generic; + +/** Internal WIFIDIRECT structure for Query Data */ +typedef PACK_START struct wifidirect_query_data { + union { + PACK_START struct upnp_specific_query { + /** version field */ + t_u8 version; + /** value */ + t_u8 value[]; + } PACK_END upnp; + + PACK_START struct bonjour_specific_query { + /** DNS name */ + t_u8 dns[0]; + /** DNS type */ + t_u8 dns_type; + /** version field */ + t_u8 version; + } PACK_END bonjour; + } u; +} PACK_END wifidirect_query_data; + +/** Internal WIFIDIRECT structure for Response Data */ +typedef PACK_START struct wifidirect_Response_data { + union { + PACK_START struct upnp_specific_response { + /** version field */ + t_u8 version; + /** value */ + t_u8 value[]; + } PACK_END upnp; + + PACK_START struct bonjour_specific_response { + /** DNS name */ + t_u8 dns[0]; + /** DNS type */ + t_u8 dns_type; + /** version field */ + t_u8 version; + /** DNS name */ + t_u8 record[]; + } PACK_END bonjour; + } u; +} PACK_END wifidirect_response_data; + +/** Event : Service Discovery request */ +typedef PACK_START struct _apeventbuf_wifidirect_discovery_request { + /** Peer mac address */ + t_u8 peer_mac_addr[ETH_ALEN]; + /** Category */ + t_u8 category; + /** Action */ + t_u8 action; + /** Dialog taken */ + t_u8 dialog_taken; + /** Advertize protocol IE */ + t_u8 advertize_protocol_ie[4]; + /** Query request Length */ + t_u16 query_len; + /** Information identifier */ + t_u8 info_id[2]; + /** Request Length */ + t_u16 request_len; + /** OUI */ + t_u8 oui[3]; + /** OUI sub type */ + t_u8 oui_sub_type; + /** Service update indicator */ + t_u16 service_update_indicator; + /** Vendor Length */ + t_u16 vendor_len; + /** Service protocol */ + t_u8 service_protocol; + /** Service transaction Id */ + t_u8 service_transaction_id; + /** Query Data */ + wifidirect_query_data disc_query; +} PACK_END apeventbuf_wifidirect_discovery_request; + +/** HostCmd_CMD_WIFIDIRECT_SERVICE_DISCOVERY response */ +typedef PACK_START struct _apeventbuf_wifidirect_discovery_response { + /** Peer mac address */ + t_u8 peer_mac_addr[ETH_ALEN]; + /** Category */ + t_u8 category; + /** Action */ + t_u8 action; + /** Dialog taken */ + t_u8 dialog_taken; + /** Status code */ + t_u8 status_code; + /** GAS comback reply */ + t_u16 gas_reply; + /** Advertize protocol IE */ + t_u8 advertize_protocol_ie[4]; + /** Query response Length */ + t_u16 query_len; + /** Information identifier */ + t_u8 info_id[2]; + /** Response Length */ + t_u16 response_len; + /** OUI */ + t_u8 oui[3]; + /** OUI sub type */ + t_u8 oui_sub_type; + /** Service update indicator */ + t_u16 service_update_indicator; + /** Vendor Length */ + t_u16 vendor_len; + /** Service protocol */ + t_u8 service_protocol; + /** Service transaction Id */ + t_u8 service_transaction_id; + /** Discovery status code */ + t_u8 disc_status_code; + /** Response Data */ + wifidirect_response_data disc_resp; +} PACK_END apeventbuf_wifidirect_discovery_response; + +/** enum : WPS attribute type */ +typedef enum { + SC_AP_Channel = 0x1001, + SC_Association_State = 0x1002, + SC_Authentication_Type = 0x1003, + SC_Authentication_Type_Flags = 0x1004, + SC_Authenticator = 0x1005, + SC_Config_Methods = 0x1008, + SC_Configuration_Error = 0x1009, + SC_Confirmation_URL4 = 0x100A, + SC_Confirmation_URL6 = 0x100B, + SC_Connection_Type = 0x100C, + SC_Connection_Type_Flags = 0x100D, + SC_Credential = 0x100E, + SC_Device_Name = 0x1011, + SC_Device_Password_ID = 0x1012, + SC_E_Hash1 = 0x1014, + SC_E_Hash2 = 0x1015, + SC_E_SNonce1 = 0x1016, + SC_E_SNonce2 = 0x1017, + SC_Encrypted_Settings = 0x1018, + SC_Encryption_Type = 0X100F, + SC_Encryption_Type_Flags = 0x1010, + SC_Enrollee_Nonce = 0x101A, + SC_Feature_ID = 0x101B, + SC_Identity = 0X101C, + SC_Identity_Proof = 0X101D, + SC_Key_Wrap_Authenticator = 0X101E, + SC_Key_Identifier = 0X101F, + SC_MAC_Address = 0x1020, + SC_Manufacturer = 0x1021, + SC_Message_Type = 0x1022, + SC_Model_Name = 0x1023, + SC_Model_Number = 0x1024, + SC_Network_Index = 0x1026, + SC_Network_Key = 0x1027, + SC_Network_Key_Index = 0x1028, + SC_New_Device_Name = 0x1029, + SC_New_Password = 0x102A, + SC_OOB_Device_Password = 0X102C, + SC_OS_Version = 0X102D, + SC_Power_Level = 0X102F, + SC_PSK_Current = 0x1030, + SC_PSK_Max = 0x1031, + SC_Public_Key = 0x1032, + SC_Radio_Enabled = 0x1033, + SC_Reboot = 0x1034, + SC_Registrar_Current = 0x1035, + SC_Registrar_Established = 0x1036, + SC_Registrar_List = 0x1037, + SC_Registrar_Max = 0x1038, + SC_Registrar_Nonce = 0x1039, + SC_Request_Type = 0x103A, + SC_Response_Type = 0x103B, + SC_RF_Band = 0X103C, + SC_R_Hash1 = 0X103D, + SC_R_Hash2 = 0X103E, + SC_R_SNonce1 = 0X103F, + SC_R_SNonce2 = 0x1040, + SC_Selected_Registrar = 0x1041, + SC_Serial_Number = 0x1042, + SC_Simple_Config_State = 0x1044, + SC_SSID = 0x1045, + SC_Total_Networks = 0x1046, + SC_UUID_E = 0x1047, + SC_UUID_R = 0x1048, + SC_Vendor_Extension = 0x1049, + SC_Version = 0x104A, + SC_X_509_Certificate_Request = 0x104B, + SC_X_509_Certificate = 0x104C, + SC_EAP_Identity = 0x104D, + SC_Message_Counter = 0x104E, + SC_Public_Key_Hash = 0x104F, + SC_Rekey_Key = 0x1050, + SC_Key_Lifetime = 0x1051, + SC_Permitted_Config_Methods = 0x1052, + SC_SelectedRegistrarConfigMethods = 0x1053, + SC_Primary_Device_Type = 0x1054, + SC_Secondary_Device_Type_List = 0x1055, + SC_Portable_Device = 0x1056, + SC_AP_Setup_Locked = 0x1057, + SC_Application_List = 0x1058, + SC_EAP_Type = 0x1059, + SC_Initialization_Vector = 0x1060, + SC_Key_Provided_Auto = 0x1061, + SC_8021x_Enabled = 0x1062, + SC_App_Session_key = 0x1063, + SC_WEP_Transmit_Key = 0x1064, +} wps_simple_config_attribute; +#endif + +/** Eapol state */ +typedef PACK_START struct { + /** Eapol state*/ + t_u8 eapol_state; + /** Station address*/ + t_u8 sta_mac_addr[ETH_ALEN]; +} PACK_END eapol_state_t; + +/** Debug Info */ +typedef PACK_START union { + /** Eapol key message */ + eapol_keymsg_debug_t eapol_pwkmsg; + /** Station reject*/ + sta_reject_t sta_reject; + /** WPA IE */ + wpaie_t wpaie; + /** Eapol state */ + eapol_state_t eapol_state; +} PACK_END d_info; + +/** Event body : Debug */ +typedef PACK_START struct _eventbuf_debug { + /** Debug type */ + t_u8 debug_type; + /** Major debug id */ + t_u32 debug_id_major; + /** Minor debug id */ + t_u32 debug_id_minor; + /** Debug Info */ + d_info info; +} PACK_END eventbuf_debug; + +int ishexstring(void *hex); +unsigned int a2hex(char *s); +/** + * @brief isdigit for String. + * + * @param x Char string + * @return MLAN_EVENT_FAILURE for non-digit. + * 0 for digit + */ +static inline int +ISDIGIT(char *x) +{ + unsigned int i; + for (i = 0; i < strlen(x); i++) + if (isdigit(x[i]) == 0) + return MLAN_EVENT_FAILURE; + return 0; +} + +#endif /* _MLAN_EVENT_H */ diff --git a/mxm_wifiex/wlan_src/mapp/mlanutl/Makefile b/mxm_wifiex/wlan_src/mapp/mlanutl/Makefile new file mode 100644 index 0000000..e2f9b24 --- /dev/null +++ b/mxm_wifiex/wlan_src/mapp/mlanutl/Makefile @@ -0,0 +1,55 @@ +# File : mlanutl/Makefile +# +# Copyright 2014-2020 NXP + +# Path to the top directory of the wlan distribution +PATH_TO_TOP = ../.. + +# Determine how we should copy things to the install directory +ABSPATH := $(filter /%, $(INSTALLDIR)) +RELPATH := $(filter-out /%, $(INSTALLDIR)) +INSTALLPATH := $(ABSPATH) +ifeq ($(strip $(INSTALLPATH)),) +INSTALLPATH := $(PATH_TO_TOP)/$(RELPATH) +endif + +# Override CFLAGS for application sources, remove __ kernel namespace defines +CFLAGS := $(filter-out -D__%, $(ccflags-y)) +# remove KERNEL include dir +CFLAGS := $(filter-out -I$(KERNELDIR)%, $(CFLAGS)) + + +#CFLAGS += -DAP22 -fshort-enums +CFLAGS += -Wall +#ECHO = @ +LIBS = -lrt + +.PHONY: default tags all + +OBJECTS = mlanutl.o +HEADERS = mlanutl.h + + + + +exectarget=mlanutl +TARGET := $(exectarget) + +build default: $(TARGET) + @cp -f $(TARGET) $(INSTALLPATH) + +all : tags default + +$(TARGET): $(OBJECTS) $(HEADERS) + $(ECHO)$(CC) $(LIBS) -o $@ $(OBJECTS) + +%.o: %.c $(HEADERS) + $(ECHO)$(CC) $(CFLAGS) -c -o $@ $< + +tags: + ctags -R -f tags.txt + +distclean clean: + $(ECHO)$(RM) $(OBJECTS) $(TARGET) + $(ECHO)$(RM) tags.txt + diff --git a/mxm_wifiex/wlan_src/mapp/mlanutl/mlanhostcmd.c b/mxm_wifiex/wlan_src/mapp/mlanutl/mlanhostcmd.c new file mode 100644 index 0000000..3d2797d --- /dev/null +++ b/mxm_wifiex/wlan_src/mapp/mlanutl/mlanhostcmd.c @@ -0,0 +1,900 @@ +/** @file mlanhostcmd.c + * + * @brief This file contains mlanutl helper functions + * + * + * Copyright 2014-2020 NXP + * + * NXP CONFIDENTIAL + * The source code contained or described herein and all documents related to + * the source code (Materials) are owned by NXP, its + * suppliers and/or its licensors. Title to the Materials remains with NXP, + * its suppliers and/or its licensors. The Materials contain + * trade secrets and proprietary and confidential information of NXP, its + * suppliers and/or its licensors. The Materials are protected by worldwide copyright + * and trade secret laws and treaty provisions. No part of the Materials may be + * used, copied, reproduced, modified, published, uploaded, posted, + * transmitted, distributed, or disclosed in any way without NXP's prior + * express written permission. + * + * No license under any patent, copyright, trade secret or other intellectual + * property right is granted to or conferred upon you by disclosure or delivery + * of the Materials, either expressly, by implication, inducement, estoppel or + * otherwise. Any license under such intellectual property rights must be + * express and approved by NXP in writing. + * + */ +/************************************************************************ +Change log: + 11/26/2008: initial version +************************************************************************/ + +#include "mlanhostcmd.h" + +#ifndef MIN +/** Find minimum value */ +#define MIN(a, b) ((a) < (b) ? (a) : (b)) +#endif /* MIN */ + +/******************************************************** + Local Variables +********************************************************/ + +/******************************************************** + Global Variables +********************************************************/ + +/******************************************************** + Local Functions +********************************************************/ +/** + * @brief get hostcmd data + * + * @param ln A pointer to line number + * @param buf A pointer to hostcmd data + * @param size A pointer to the return size of hostcmd buffer + * @return MLAN_STATUS_SUCCESS + */ +static int +mlan_get_hostcmd_data(FILE * fp, int *ln, t_u8 *buf, t_u16 *size) +{ + t_s32 errors = 0, i; + t_s8 line[512], *pos, *pos1, *pos2, *pos3; + t_u16 len; + + while ((pos = mlan_config_get_line(fp, line, sizeof(line), ln))) { + (*ln)++; + if (strcmp(pos, "}") == 0) { + break; + } + + pos1 = strchr(pos, ':'); + if (pos1 == NULL) { + printf("Line %d: Invalid hostcmd line '%s'\n", *ln, + pos); + errors++; + continue; + } + *pos1++ = '\0'; + + pos2 = strchr(pos1, '='); + if (pos2 == NULL) { + printf("Line %d: Invalid hostcmd line '%s'\n", *ln, + pos); + errors++; + continue; + } + *pos2++ = '\0'; + + len = a2hex_or_atoi(pos1); + if (len < 1 || len > MRVDRV_SIZE_OF_CMD_BUFFER) { + printf("Line %d: Invalid hostcmd line '%s'\n", *ln, + pos); + errors++; + continue; + } + + *size += len; + + if (*pos2 == '"') { + pos2++; + pos3 = strchr(pos2, '"'); + if (pos3 == NULL) { + printf("Line %d: invalid quotation '%s'\n", *ln, + pos); + errors++; + continue; + } + *pos3 = '\0'; + memset(buf, 0, len); + memmove(buf, pos2, MIN(strlen(pos2), len)); + buf += len; + } else if (*pos2 == '\'') { + pos2++; + pos3 = strchr(pos2, '\''); + if (pos3 == NULL) { + printf("Line %d: invalid quotation '%s'\n", *ln, + pos); + errors++; + continue; + } + *pos3 = ','; + for (i = 0; i < len; i++) { + pos3 = strchr(pos2, ','); + if (pos3 != NULL) { + *pos3 = '\0'; + *buf++ = (t_u8)a2hex_or_atoi(pos2); + pos2 = pos3 + 1; + } else + *buf++ = 0; + } + } else if (*pos2 == '{') { + t_u16 tlvlen = 0, tmp_tlvlen; + mlan_get_hostcmd_data(fp, ln, buf + len, &tlvlen); + tmp_tlvlen = tlvlen; + while (len--) { + *buf++ = (t_u8)(tmp_tlvlen & 0xff); + tmp_tlvlen >>= 8; + } + *size += tlvlen; + buf += tlvlen; + } else { + t_u32 value = a2hex_or_atoi(pos2); + while (len--) { + *buf++ = (t_u8)(value & 0xff); + value >>= 8; + } + } + } + return MLAN_STATUS_SUCCESS; +} + +/******************************************************** + Global Functions +********************************************************/ +/** + * @brief convert char to hex integer + * + * @param chr char to convert + * @return hex integer or 0 + */ +int +hexval(t_s32 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 Hump hex data + * + * @param prompt A pointer prompt buffer + * @param p A pointer to data buffer + * @param len the len of data buffer + * @param delim delim char + * @return hex integer + */ +t_void +hexdump(t_s8 *prompt, t_void *p, t_s32 len, t_s8 delim) +{ + t_s32 i; + t_u8 *s = p; + + if (prompt) { + printf("%s: len=%d\n", prompt, (int)len); + } + for (i = 0; i < len; i++) { + if (i != len - 1) + printf("%02x%c", *s++, delim); + else + printf("%02x\n", *s); + if ((i + 1) % 16 == 0) + printf("\n"); + } + printf("\n"); +} + +/** + * @brief convert char to hex integer + * + * @param chr char + * @return hex integer + */ +t_u8 +hexc2bin(t_s8 chr) +{ + if (chr >= '0' && chr <= '9') + chr -= '0'; + else if (chr >= 'A' && chr <= 'F') + chr -= ('A' - 10); + else if (chr >= 'a' && chr <= 'f') + chr -= ('a' - 10); + + return chr; +} + +/** + * @brief convert string to hex integer + * + * @param s A pointer string buffer + * @return hex integer + */ +t_u32 +a2hex(t_s8 *s) +{ + t_u32 val = 0; + + if (!strncasecmp("0x", s, 2)) { + s += 2; + } + + while (*s && isxdigit(*s)) { + val = (val << 4) + hexc2bin(*s++); + } + + return val; +} + +/* + * @brief convert String to integer + * + * @param value A pointer to string + * @return integer + */ +t_u32 +a2hex_or_atoi(t_s8 *value) +{ + if (value[0] == '0' && (value[1] == 'X' || value[1] == 'x')) { + return a2hex(value + 2); + } else if (isdigit(*value)) { + return atoi(value); + } else { + return *value; + } +} + +/** + * @brief convert string to hex + * + * @param ptr A pointer to data buffer + * @param chr A pointer to return integer + * @return A pointer to next data field + */ +t_s8 * +convert2hex(t_s8 *ptr, t_u8 *chr) +{ + t_u8 val; + + for (val = 0; *ptr && isxdigit(*ptr); ptr++) { + val = (val * 16) + hexval(*ptr); + } + + *chr = val; + + return ptr; +} + +/** + * @brief Check the Hex String + * @param s A pointer to the string + * @return MLAN_STATUS_SUCCESS --HexString, MLAN_STATUS_FAILURE --not HexString + */ +int +ishexstring(t_s8 *s) +{ + int ret = MLAN_STATUS_FAILURE; + t_s32 tmp; + + if (!strncasecmp("0x", s, 2)) { + s += 2; + } + while (*s) { + tmp = toupper(*s); + if (((tmp >= 'A') && (tmp <= 'F')) || + ((tmp >= '0') && (tmp <= '9'))) { + ret = MLAN_STATUS_SUCCESS; + } else { + ret = MLAN_STATUS_FAILURE; + break; + } + s++; + } + + return ret; +} + +/** + * @brief Convert String to Integer + * @param buf A pointer to the string + * @return Integer + */ +int +atoval(t_s8 *buf) +{ + if (!strncasecmp(buf, "0x", 2)) + return a2hex(buf + 2); + else if (!ishexstring(buf)) + return a2hex(buf); + else + return atoi(buf); +} + +/** + * @brief Prepare host-command buffer + * @param fp File handler + * @param cmd_name Command name + * @param buf A pointer to comand buffer + * @return MLAN_STATUS_SUCCESS--success, otherwise--fail + */ +int +prepare_host_cmd_buffer(FILE * fp, char *cmd_name, t_u8 *buf) +{ + t_s8 line[256], cmdname[256], *pos, cmdcode[10]; + HostCmd_DS_GEN *hostcmd; + int ln = 0; + int cmdname_found = 0, cmdcode_found = 0; + + memset(buf, 0, MRVDRV_SIZE_OF_CMD_BUFFER); + hostcmd = (HostCmd_DS_GEN *)buf; + hostcmd->command = 0xffff; + + snprintf(cmdname, sizeof(cmdname), "%s={", cmd_name); + cmdname_found = 0; + while ((pos = mlan_config_get_line(fp, line, sizeof(line), &ln))) { + if (strcmp(pos, cmdname) == 0) { + t_u16 len = 0; + cmdname_found = 1; + snprintf(cmdcode, sizeof(cmdcode), "CmdCode="); + cmdcode_found = 0; + while ((pos = + mlan_config_get_line(fp, line, sizeof(line), + &ln))) { + if (strncmp(pos, cmdcode, strlen(cmdcode)) == 0) { + cmdcode_found = 1; + hostcmd->command = + a2hex_or_atoi(pos + + strlen(cmdcode)); + hostcmd->size = S_DS_GEN; + mlan_get_hostcmd_data(fp, &ln, + buf + + hostcmd->size, + &len); + hostcmd->size += len; + break; + } + } + if (!cmdcode_found) { + fprintf(stderr, + "mlanutl: CmdCode not found in conf file\n"); + return MLAN_STATUS_FAILURE; + } + break; + } + } + + if (!cmdname_found) { + fprintf(stderr, + "mlanutl: cmdname '%s' is not found in conf file\n", + cmd_name); + return MLAN_STATUS_FAILURE; + } + + hostcmd->seq_num = 0; + hostcmd->result = 0; + hostcmd->command = cpu_to_le16(hostcmd->command); + hostcmd->size = cpu_to_le16(hostcmd->size); + return MLAN_STATUS_SUCCESS; +} + +/** Config data header length */ +#define CFG_DATA_HEADER_LEN 6 + +/** + * @brief Prepare cfg-data buffer + * @param argc number of arguments + * @param argv A pointer to arguments array + * @param fp File handler + * @param buf A pointer to comand buffer + * @return MLAN_STATUS_SUCCESS--success, otherwise--fail + */ +int +prepare_cfg_data_buffer(int argc, char *argv[], FILE * fp, t_u8 *buf) +{ + int ln = 0, type; + HostCmd_DS_GEN *hostcmd; + HostCmd_DS_802_11_CFG_DATA *pcfg_data; + + memset(buf, 0, MRVDRV_SIZE_OF_CMD_BUFFER); + hostcmd = (HostCmd_DS_GEN *)buf; + hostcmd->command = cpu_to_le16(HostCmd_CMD_CFG_DATA); + pcfg_data = (HostCmd_DS_802_11_CFG_DATA *)(buf + S_DS_GEN); + pcfg_data->action = + (argc == 4) ? HostCmd_ACT_GEN_GET : HostCmd_ACT_GEN_SET; + type = atoi(argv[3]); + if ((type < 1) || (type > 2)) { + fprintf(stderr, "mlanutl: Invalid register type\n"); + return MLAN_STATUS_FAILURE; + } else { + pcfg_data->type = type; + } + if (argc == 5) { + ln = fparse_for_hex(fp, pcfg_data->data); + } + pcfg_data->data_len = ln; + hostcmd->size = + cpu_to_le16(pcfg_data->data_len + S_DS_GEN + + CFG_DATA_HEADER_LEN); + pcfg_data->data_len = cpu_to_le16(pcfg_data->data_len); + pcfg_data->type = cpu_to_le16(pcfg_data->type); + pcfg_data->action = cpu_to_le16(pcfg_data->action); + + hostcmd->seq_num = 0; + hostcmd->result = 0; + return MLAN_STATUS_SUCCESS; +} + +/** + * @brief Process host_cmd response + * @param buf A pointer to the response buffer + * @return MLAN_STATUS_SUCCESS--success, otherwise--fail + */ +int +process_host_cmd_resp(t_u8 *buf) +{ + HostCmd_DS_GEN *hostcmd = (HostCmd_DS_GEN *)buf; + int ret = MLAN_STATUS_SUCCESS; + + hostcmd->command = le16_to_cpu(hostcmd->command); + hostcmd->size = le16_to_cpu(hostcmd->size); + hostcmd->seq_num = le16_to_cpu(hostcmd->seq_num); + hostcmd->result = le16_to_cpu(hostcmd->result); + + hostcmd->command &= ~HostCmd_RET_BIT; + if (!hostcmd->result) { + switch (hostcmd->command) { + case HostCmd_CMD_CFG_DATA: + { + HostCmd_DS_802_11_CFG_DATA *pstcfgData = + (HostCmd_DS_802_11_CFG_DATA *)(buf + + S_DS_GEN); + pstcfgData->data_len = + le16_to_cpu(pstcfgData->data_len); + pstcfgData->action = + le16_to_cpu(pstcfgData->action); + + if (pstcfgData->action == HostCmd_ACT_GEN_GET) { + hexdump("cfgdata", pstcfgData->data, + pstcfgData->data_len, ' '); + } + break; + } + case HostCmd_CMD_802_11_TPC_ADAPT_REQ: + { + mlan_ioctl_11h_tpc_resp *tpcIoctlResp = + (mlan_ioctl_11h_tpc_resp *)(buf + + S_DS_GEN); + if (tpcIoctlResp->status_code == 0) { + printf("tpcrequest: txPower(%d), linkMargin(%d), rssi(%d)\n", tpcIoctlResp->tx_power, tpcIoctlResp->link_margin, tpcIoctlResp->rssi); + } else { + printf("tpcrequest: failure, status = %d\n", tpcIoctlResp->status_code); + } + break; + } + case HostCmd_CMD_802_11_CRYPTO: + { + t_u16 alg = + le16_to_cpu((t_u16) + *(buf + S_DS_GEN + + sizeof(t_u16))); + if (alg != CIPHER_TEST_AES_CCM && + alg != CIPHER_TEST_GCMP) { + HostCmd_DS_802_11_CRYPTO *cmd = + (HostCmd_DS_802_11_CRYPTO *)(buf + + + S_DS_GEN); + cmd->encdec = le16_to_cpu(cmd->encdec); + cmd->algorithm = + le16_to_cpu(cmd->algorithm); + cmd->key_IV_length = + le16_to_cpu(cmd->key_IV_length); + cmd->key_length = + le16_to_cpu(cmd->key_length); + cmd->data.header.type = + le16_to_cpu(cmd->data.header. + type); + cmd->data.header.len = + le16_to_cpu(cmd->data.header. + len); + + printf("crypto_result: encdec=%d algorithm=%d,KeyIVLen=%d," " KeyLen=%d,dataLen=%d\n", cmd->encdec, cmd->algorithm, cmd->key_IV_length, cmd->key_length, cmd->data.header.len); + hexdump("KeyIV", cmd->keyIV, + cmd->key_IV_length, ' '); + hexdump("Key", cmd->key, + cmd->key_length, ' '); + hexdump("Data", cmd->data.data, + cmd->data.header.len, ' '); + } else { + HostCmd_DS_802_11_CRYPTO_AES_CCM + *cmd_aes_ccm = + (HostCmd_DS_802_11_CRYPTO_AES_CCM + *)(buf + S_DS_GEN); + + cmd_aes_ccm->encdec + = + le16_to_cpu(cmd_aes_ccm-> + encdec); + cmd_aes_ccm->algorithm = + le16_to_cpu(cmd_aes_ccm-> + algorithm); + cmd_aes_ccm->key_length = + le16_to_cpu(cmd_aes_ccm-> + key_length); + cmd_aes_ccm->nonce_length = + le16_to_cpu(cmd_aes_ccm-> + nonce_length); + cmd_aes_ccm->AAD_length = + le16_to_cpu(cmd_aes_ccm-> + AAD_length); + cmd_aes_ccm->data.header.type = + le16_to_cpu(cmd_aes_ccm->data. + header.type); + cmd_aes_ccm->data.header.len = + le16_to_cpu(cmd_aes_ccm->data. + header.len); + + printf("crypto_result: encdec=%d algorithm=%d, KeyLen=%d," " NonceLen=%d,AADLen=%d,dataLen=%d\n", cmd_aes_ccm->encdec, cmd_aes_ccm->algorithm, cmd_aes_ccm->key_length, cmd_aes_ccm->nonce_length, cmd_aes_ccm->AAD_length, cmd_aes_ccm->data.header.len); + + hexdump("Key", cmd_aes_ccm->key, + cmd_aes_ccm->key_length, ' '); + hexdump("Nonce", cmd_aes_ccm->nonce, + cmd_aes_ccm->nonce_length, ' '); + hexdump("AAD", cmd_aes_ccm->AAD, + cmd_aes_ccm->AAD_length, ' '); + hexdump("Data", cmd_aes_ccm->data.data, + cmd_aes_ccm->data.header.len, + ' '); + } + break; + } + case HostCmd_CMD_802_11_AUTO_TX: + { + HostCmd_DS_802_11_AUTO_TX *at = + (HostCmd_DS_802_11_AUTO_TX *)(buf + + S_DS_GEN); + + if (le16_to_cpu(at->action) == + HostCmd_ACT_GEN_GET) { + if (S_DS_GEN + sizeof(at->action) == + hostcmd->size) { + printf("auto_tx not configured\n"); + + } else { + MrvlIEtypesHeader_t *header = + &at->auto_tx.header; + + header->type = + le16_to_cpu(header-> + type); + header->len = + le16_to_cpu(header-> + len); + + if ((S_DS_GEN + + sizeof(at->action) + + + sizeof(MrvlIEtypesHeader_t) + + header->len == + hostcmd->size) && + (header->type == + TLV_TYPE_AUTO_TX)) { + + AutoTx_MacFrame_t *atmf + = + &at->auto_tx. + auto_tx_mac_frame; + + printf("Interval: %d second(s)\n", le16_to_cpu(atmf->interval)); + printf("Priority: %#x\n", atmf->priority); + printf("Frame Length: %d\n", le16_to_cpu(atmf->frame_len)); + printf("Dest Mac Address: " "%02x:%02x:%02x:%02x:%02x:%02x\n", atmf->dest_mac_addr[0], atmf->dest_mac_addr[1], atmf->dest_mac_addr[2], atmf->dest_mac_addr[3], atmf->dest_mac_addr[4], atmf->dest_mac_addr[5]); + printf("Src Mac Address: " "%02x:%02x:%02x:%02x:%02x:%02x\n", atmf->src_mac_addr[0], atmf->src_mac_addr[1], atmf->src_mac_addr[2], atmf->src_mac_addr[3], atmf->src_mac_addr[4], atmf->src_mac_addr[5]); + + hexdump("Frame Payload", + atmf->payload, + le16_to_cpu + (atmf-> + frame_len) + - + MLAN_MAC_ADDR_LENGTH + * 2, ' '); + } else { + printf("incorrect auto_tx command response\n"); + } + } + } + break; + } + case HostCmd_CMD_802_11_SUBSCRIBE_EVENT: + { + HostCmd_DS_802_11_SUBSCRIBE_EVENT *se = + (HostCmd_DS_802_11_SUBSCRIBE_EVENT + *)(buf + S_DS_GEN); + if (le16_to_cpu(se->action) == + HostCmd_ACT_GEN_GET) { + int len = + S_DS_GEN + + sizeof + (HostCmd_DS_802_11_SUBSCRIBE_EVENT); + printf("\nEvent\t\tValue\tFreq\tsubscribed\n\n"); + while (len < hostcmd->size) { + MrvlIEtypesHeader_t *header = + (MrvlIEtypesHeader_t + *)(buf + len); + switch (le16_to_cpu + (header->type)) { + case TLV_TYPE_RSSI_LOW: + { + MrvlIEtypes_RssiThreshold_t + *low_rssi + = + (MrvlIEtypes_RssiThreshold_t + *)(buf + + + len); + printf("Beacon Low RSSI\t%d\t%d\t%s\n", low_rssi->RSSI_value, low_rssi->RSSI_freq, (le16_to_cpu(se->events) & 0x0001) ? "yes" : "no"); + break; + } + case TLV_TYPE_SNR_LOW: + { + MrvlIEtypes_SnrThreshold_t + *low_snr + = + (MrvlIEtypes_SnrThreshold_t + *)(buf + + + len); + printf("Beacon Low SNR\t%d\t%d\t%s\n", low_snr->SNR_value, low_snr->SNR_freq, (le16_to_cpu(se->events) & 0x0002) ? "yes" : "no"); + break; + } + case TLV_TYPE_FAILCOUNT: + { + MrvlIEtypes_FailureCount_t + *failure_count + = + (MrvlIEtypes_FailureCount_t + *)(buf + + + len); + printf("Failure Count\t%d\t%d\t%s\n", failure_count->fail_value, failure_count->fail_freq, (le16_to_cpu(se->events) & 0x0004) ? "yes" : "no"); + break; + } + case TLV_TYPE_BCNMISS: + { + MrvlIEtypes_BeaconsMissed_t + *bcn_missed + = + (MrvlIEtypes_BeaconsMissed_t + *)(buf + + + len); + printf("Beacon Missed\t%d\tN/A\t%s\n", bcn_missed->beacon_missed, (le16_to_cpu(se->events) & 0x0008) ? "yes" : "no"); + break; + } + case TLV_TYPE_RSSI_HIGH: + { + MrvlIEtypes_RssiThreshold_t + *high_rssi + = + (MrvlIEtypes_RssiThreshold_t + *)(buf + + + len); + printf("Bcn High RSSI\t%d\t%d\t%s\n", high_rssi->RSSI_value, high_rssi->RSSI_freq, (le16_to_cpu(se->events) & 0x0010) ? "yes" : "no"); + break; + } + + case TLV_TYPE_SNR_HIGH: + { + MrvlIEtypes_SnrThreshold_t + *high_snr + = + (MrvlIEtypes_SnrThreshold_t + *)(buf + + + len); + printf("Beacon High SNR\t%d\t%d\t%s\n", high_snr->SNR_value, high_snr->SNR_freq, (le16_to_cpu(se->events) & 0x0020) ? "yes" : "no"); + break; + } + case TLV_TYPE_RSSI_LOW_DATA: + { + MrvlIEtypes_RssiThreshold_t + *low_rssi + = + (MrvlIEtypes_RssiThreshold_t + *)(buf + + + len); + printf("Data Low RSSI\t%d\t%d\t%s\n", low_rssi->RSSI_value, low_rssi->RSSI_freq, (le16_to_cpu(se->events) & 0x0040) ? "yes" : "no"); + break; + } + case TLV_TYPE_SNR_LOW_DATA: + { + MrvlIEtypes_SnrThreshold_t + *low_snr + = + (MrvlIEtypes_SnrThreshold_t + *)(buf + + + len); + printf("Data Low SNR\t%d\t%d\t%s\n", low_snr->SNR_value, low_snr->SNR_freq, (le16_to_cpu(se->events) & 0x0080) ? "yes" : "no"); + break; + } + case TLV_TYPE_RSSI_HIGH_DATA: + { + MrvlIEtypes_RssiThreshold_t + *high_rssi + = + (MrvlIEtypes_RssiThreshold_t + *)(buf + + + len); + printf("Data High RSSI\t%d\t%d\t%s\n", high_rssi->RSSI_value, high_rssi->RSSI_freq, (le16_to_cpu(se->events) & 0x0100) ? "yes" : "no"); + break; + } + case TLV_TYPE_SNR_HIGH_DATA: + { + MrvlIEtypes_SnrThreshold_t + *high_snr + = + (MrvlIEtypes_SnrThreshold_t + *)(buf + + + len); + printf("Data High SNR\t%d\t%d\t%s\n", high_snr->SNR_value, high_snr->SNR_freq, (le16_to_cpu(se->events) & 0x0200) ? "yes" : "no"); + break; + } + case TLV_TYPE_LINK_QUALITY: + { + MrvlIEtypes_LinkQuality_t + *link_qual + = + (MrvlIEtypes_LinkQuality_t + *)(buf + + + len); + printf("Link Quality Parameters:\n"); + printf("------------------------\n"); + printf("Link Quality Event Subscribed\t%s\n", (le16_to_cpu(se->events) & 0x0400) ? "yes" : "no"); + printf("Link SNR Threshold = %d\n", le16_to_cpu(link_qual->link_SNR_thrs)); + printf("Link SNR Frequency = %d\n", le16_to_cpu(link_qual->link_SNR_freq)); + printf("Min Rate Value = %d\n", le16_to_cpu(link_qual->min_rate_val)); + printf("Min Rate Frequency = %d\n", le16_to_cpu(link_qual->min_rate_freq)); + printf("Tx Latency Value = %d\n", le32_to_cpu(link_qual->tx_latency_val)); + printf("Tx Latency Threshold = %d\n", le32_to_cpu(link_qual->tx_latency_thrs)); + + break; + } + case TLV_TYPE_PRE_BEACON_LOST: + { + MrvlIEtypes_PreBeaconLost_t + *pre_bcn_lost + = + (MrvlIEtypes_PreBeaconLost_t + *)(buf + + + len); + printf("------------------------\n"); + printf("Pre-Beacon Lost Event Subscribed\t%s\n", (le16_to_cpu(se->events) & 0x0800) ? "yes" : "no"); + printf("Pre-Beacon Lost: %d\n", pre_bcn_lost->pre_beacon_lost); + break; + } + default: + printf("Unknown subscribed event TLV Type=%#x," " Len=%d\n", le16_to_cpu(header->type), le16_to_cpu(header->len)); + break; + } + + len += (sizeof + (MrvlIEtypesHeader_t) + + + le16_to_cpu(header-> + len)); + } + } + 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: + { + HostCmd_DS_REG *preg = + (HostCmd_DS_REG *)(buf + S_DS_GEN); + preg->action = le16_to_cpu(preg->action); + if (preg->action == HostCmd_ACT_GEN_GET) { + preg->value = le32_to_cpu(preg->value); + printf("value = 0x%08x\n", preg->value); + } + break; + } + case HostCmd_CMD_MEM_ACCESS: + { + HostCmd_DS_MEM *pmem = + (HostCmd_DS_MEM *)(buf + S_DS_GEN); + pmem->action = le16_to_cpu(pmem->action); + if (pmem->action == HostCmd_ACT_GEN_GET) { + pmem->value = le32_to_cpu(pmem->value); + printf("value = 0x%08x\n", pmem->value); + } + break; + } + default: + printf("HOSTCMD_RESP: CmdCode=%#04x, Size=%#04x," + " SeqNum=%#04x, Result=%#04x\n", + hostcmd->command, hostcmd->size, + hostcmd->seq_num, hostcmd->result); + hexdump("payload", + (t_void *)(buf + S_DS_GEN), + hostcmd->size - S_DS_GEN, ' '); + break; + } + } else { + printf("HOSTCMD failed: CmdCode=%#04x, Size=%#04x," + " SeqNum=%#04x, Result=%#04x\n", + hostcmd->command, hostcmd->size, + hostcmd->seq_num, hostcmd->result); + } + return ret; +} + +/** + * @brief Prepare the hostcmd for register access + * @param type Register type + * @param offset Register offset + * @param value Pointer to value (NULL for read) + * @param buf Pointer to hostcmd buffer + * @return MLAN_STATUS_SUCCESS--success, otherwise--fail + */ +int +prepare_hostcmd_regrdwr(t_u32 type, t_u32 offset, t_u32 *value, t_u8 *buf) +{ + HostCmd_DS_GEN *hostcmd; + HostCmd_DS_REG *preg; + + hostcmd = (HostCmd_DS_GEN *)buf; + switch (type) { + case 1: + hostcmd->command = cpu_to_le16(HostCmd_CMD_MAC_REG_ACCESS); + break; + case 2: + hostcmd->command = cpu_to_le16(HostCmd_CMD_BBP_REG_ACCESS); + break; + case 3: + hostcmd->command = cpu_to_le16(HostCmd_CMD_RF_REG_ACCESS); + break; + case 5: + hostcmd->command = cpu_to_le16(HostCmd_CMD_CAU_REG_ACCESS); + break; + default: + printf("Invalid register set specified\n"); + return -EINVAL; + } + preg = (HostCmd_DS_REG *)(buf + S_DS_GEN); + preg->action = (value) ? HostCmd_ACT_GEN_SET : HostCmd_ACT_GEN_GET; + preg->action = cpu_to_le16(preg->action); + preg->offset = cpu_to_le16((t_u16)offset); + if (value) + preg->value = cpu_to_le32(*value); + else + preg->value = 0; + hostcmd->size = cpu_to_le16(S_DS_GEN + sizeof(HostCmd_DS_REG)); + hostcmd->seq_num = 0; + hostcmd->result = 0; + + return MLAN_STATUS_SUCCESS; +} diff --git a/mxm_wifiex/wlan_src/mapp/mlanutl/mlanhostcmd.h b/mxm_wifiex/wlan_src/mapp/mlanutl/mlanhostcmd.h new file mode 100644 index 0000000..b4485a0 --- /dev/null +++ b/mxm_wifiex/wlan_src/mapp/mlanutl/mlanhostcmd.h @@ -0,0 +1,139 @@ +/** @file mlanhostcmd.h + * + * @brief This file contains command structures for mlanutl application + * + * + * Copyright 2014-2020 NXP + * + * NXP CONFIDENTIAL + * The source code contained or described herein and all documents related to + * the source code (Materials) are owned by NXP, its + * suppliers and/or its licensors. Title to the Materials remains with NXP, + * its suppliers and/or its licensors. The Materials contain + * trade secrets and proprietary and confidential information of NXP, its + * suppliers and/or its licensors. The Materials are protected by worldwide copyright + * and trade secret laws and treaty provisions. No part of the Materials may be + * used, copied, reproduced, modified, published, uploaded, posted, + * transmitted, distributed, or disclosed in any way without NXP's prior + * express written permission. + * + * No license under any patent, copyright, trade secret or other intellectual + * property right is granted to or conferred upon you by disclosure or delivery + * of the Materials, either expressly, by implication, inducement, estoppel or + * otherwise. Any license under such intellectual property rights must be + * express and approved by NXP in writing. + * + */ +/************************************************************************ +Change log: + 11/26/2008: initial version +************************************************************************/ +#ifndef _MLANHOSTCMD_H_ +#define _MLANHOSTCMD_H_ + +/** Find number of elements */ +#define NELEMENTS(x) (sizeof(x)/sizeof(x[0])) + +/** Size of command buffer */ +#define MRVDRV_SIZE_OF_CMD_BUFFER (3 * 1024) + +/** Host Command ID : Memory access */ +#define HostCmd_CMD_MEM_ACCESS 0x0086 + +/** Pre-Authenticate - 11r only */ +#define HostCmd_CMD_802_11_AUTHENTICATE 0x0011 + +/** Read/Write Mac register */ +#define HostCmd_CMD_MAC_REG_ACCESS 0x0019 +/** Read/Write BBP register */ +#define HostCmd_CMD_BBP_REG_ACCESS 0x001a +/** Read/Write RF register */ +#define HostCmd_CMD_RF_REG_ACCESS 0x001b +/** Get TX Power data */ +#define HostCmd_CMD_802_11_RF_TX_POWER 0x001e +/** Host Command ID : CAU register access */ +#define HostCmd_CMD_CAU_REG_ACCESS 0x00ed + +/** Host Command ID : 802.11 BG scan configuration */ +#define HostCmd_CMD_802_11_BG_SCAN_CONFIG 0x006b +/** Host Command ID : Configuration data */ +#define HostCmd_CMD_CFG_DATA 0x008f +/** Host Command ID : 802.11 TPC adapt req */ +#define HostCmd_CMD_802_11_TPC_ADAPT_REQ 0x0060 +/** Host Command ID : 802.11 crypto */ +#define HostCmd_CMD_802_11_CRYPTO 0x0078 +/** Host Command ID : 802.11 auto Tx */ +#define HostCmd_CMD_802_11_AUTO_TX 0x0082 + +/** Host Command ID : 802.11 subscribe event */ +#define HostCmd_CMD_802_11_SUBSCRIBE_EVENT 0x0075 + +#ifdef OPCHAN +/** Host Command ID : Operating channel config */ +#define HostCmd_CMD_OPCHAN_CONFIG 0x00f8 +/** Host Command ID : Opchan channel group config */ +#define HostCmd_CMD_OPCHAN_CHANGROUP_CONFIG 0x00f9 +#endif + +/** Host Command ID : Channel TRPC config */ +#define HostCmd_CMD_CHAN_TRPC_CONFIG 0x00fb + +/** TLV type ID definition */ +#define PROPRIETARY_TLV_BASE_ID 0x0100 +/** 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 : 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 : Auto Tx */ +#define TLV_TYPE_AUTO_TX (PROPRIETARY_TLV_BASE_ID + 0x18) /* 0x0118 */ +/** 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: Pre-Beacon Lost */ +#define TLV_TYPE_PRE_BEACON_LOST (PROPRIETARY_TLV_BASE_ID + 0x49) /* 0x0149 */ + +#ifdef OPCHAN +/** TLV type : Operating channel control description */ +#define TLV_TYPE_OPCHAN_CONTROL_DESC (PROPRIETARY_TLV_BASE_ID + 0x79) /* 0x0179 */ +/** TLV type : Operating channel group control */ +#define TLV_TYPE_OPCHAN_CHANGRP_CTRL (PROPRIETARY_TLV_BASE_ID + 0x7a) /* 0x017a */ +#endif + +/** TLV type : Channel TRPC */ +#define TLV_TYPE_CHAN_TRPC (PROPRIETARY_TLV_BASE_ID + 0x89) /* 0x0189 */ + +/** mlan_ioctl_11h_tpc_resp */ +typedef struct { + int status_code; + /**< Firmware command result status code */ + int tx_power;/**< Reported TX Power from the TPC Report */ + int link_margin; + /**< Reported Link margin from the TPC Report */ + int rssi; /**< RSSI of the received TPC Report frame */ +} __ATTRIB_PACK__ mlan_ioctl_11h_tpc_resp; + +/* Define general hostcmd data structure */ + +/** Convert String to integer */ +t_u32 a2hex_or_atoi(char *value); +char *mlan_config_get_line(FILE * fp, char *str, t_s32 size, int *lineno); + +int prepare_host_cmd_buffer(FILE * fp, char *cmd_name, t_u8 *buf); +int prepare_hostcmd_regrdwr(t_u32 type, t_u32 offset, t_u32 *value, t_u8 *buf); + +#endif /* _MLANHOSTCMD_H_ */ diff --git a/mxm_wifiex/wlan_src/mapp/mlanutl/mlanoffload.c b/mxm_wifiex/wlan_src/mapp/mlanutl/mlanoffload.c new file mode 100644 index 0000000..5679c54 --- /dev/null +++ b/mxm_wifiex/wlan_src/mapp/mlanutl/mlanoffload.c @@ -0,0 +1,3056 @@ +/** @file mlanoffload.c + * + * @brief This files contains mlanutl offload command handling. + * + * + * Copyright 2014-2020 NXP + * + * NXP CONFIDENTIAL + * The source code contained or described herein and all documents related to + * the source code (Materials) are owned by NXP, its + * suppliers and/or its licensors. Title to the Materials remains with NXP, + * its suppliers and/or its licensors. The Materials contain + * trade secrets and proprietary and confidential information of NXP, its + * suppliers and/or its licensors. The Materials are protected by worldwide copyright + * and trade secret laws and treaty provisions. No part of the Materials may be + * used, copied, reproduced, modified, published, uploaded, posted, + * transmitted, distributed, or disclosed in any way without NXP's prior + * express written permission. + * + * No license under any patent, copyright, trade secret or other intellectual + * property right is granted to or conferred upon you by disclosure or delivery + * of the Materials, either expressly, by implication, inducement, estoppel or + * otherwise. Any license under such intellectual property rights must be + * express and approved by NXP in writing. + * + */ +/************************************************************************ +Change log: + 08/11/2009: initial version +************************************************************************/ + +#include "mlanutl.h" +#include "mlanhostcmd.h" +#include "mlanoffload.h" + +/******************************************************** + Local Variables +********************************************************/ + +t_void hexdump(char *prompt, t_void *p, t_s32 len, t_s8 delim); + +/******************************************************** + Global Variables +********************************************************/ + +/******************************************************** + Local Functions +********************************************************/ + +/** + * @brief Remove unwanted spaces, tabs from a line + * + * @param data A pointer to the starting of the line + * @return NA + */ +static void +profile_param_polish(char *data) +{ + t_u8 i, j, len = 0; + char *ptr; + ptr = strrchr(data, '\r'); + if (ptr == NULL) { + ptr = strrchr(data, '\n'); + if (ptr == NULL) { + return; + } + } + len = ptr - data; + for (i = 0; i < len; i++) { + if ((*(data + i) == ' ') || (*(data + i) == '\t')) { + for (j = i; j < len; j++) { + data[j] = data[j + 1]; + } + i--; + len--; + } + } +} + +static int +ascii_value(char letter) +{ + if (letter >= '0' && letter <= '9') + return letter - '0'; + if (letter >= 'a' && letter <= 'f') + return letter - 'a' + 10; + if (letter >= 'A' && letter <= 'F') + return letter - 'A' + 10; + return -1; +} + +static int +twodigit_ascii(const char *nibble) +{ + int a, b; + a = ascii_value(*nibble++); + if (a < 0) + return -1; + b = ascii_value(*nibble++); + if (b < 0) + return -1; + return (a << 4) | b; +} + +/** + * @brief Read a network block from the profile configuration file + * + * @param fp file pointer of the configuration file + * @param p_head profile head + * @return MLAN_STATUS_SUCCESS + */ +static int +profile_read_block(FILE * fp, profile_entry_t *p_head) +{ + char line[0x100]; + char *ptr, *eptr; + t_u8 key_cnt = 0; + t_u8 i, wep_len; + int byte; + int tmpIdx; + unsigned int mac[ETH_ALEN]; + + while (fgets(line, sizeof(line), fp)) { + /* call function to remove spaces, tabs */ + profile_param_polish(line); + + if (strstr(line, "}") != NULL) { + ptr = strstr(line, "}"); + /* end of network */ + break; + + } else if (line[0] == '#') { + /* comments go ahead */ + continue; + + } else if (strstr(line, "bssid=") != NULL) { + ptr = strstr(line, "bssid="); + ptr = ptr + strlen("bssid="); + sscanf(ptr, "%2x:%2x:%2x:%2x:%2x:%2x", + mac + 0, mac + 1, mac + 2, mac + 3, mac + 4, + mac + 5); + for (tmpIdx = 0; (unsigned int)tmpIdx < NELEMENTS(mac); + tmpIdx++) { + p_head->bssid[tmpIdx] = (t_u8)mac[tmpIdx]; + } + + } else if (strstr(line, "ssid=") != NULL) { + + ptr = strstr(line, "ssid="); + ptr = ptr + strlen("ssid="); + eptr = strrchr(ptr + 1, '"'); + + if ((*ptr != '"') || (strrchr(ptr + 1, '"') == NULL)) { + + fprintf(stderr, "ssid not within quotes\n"); + break; + } + + p_head->ssid_len = + MIN(IW_ESSID_MAX_SIZE, eptr - ptr - 1); + strncpy((char *)p_head->ssid, ptr + 1, + p_head->ssid_len); + p_head->ssid[p_head->ssid_len] = '\0'; + + } else if (strstr(line, "psk=") != NULL) { + ptr = strstr(line, "psk="); + ptr = ptr + strlen("psk="); + if (*ptr != '"') { + p_head->psk_config = 1; + strncpy((char *)p_head->psk, ptr, KEY_LEN); + } else { + eptr = strrchr(ptr + 1, '"'); + if (eptr == NULL) { + fprintf(stderr, + "passphrase not within quotes.\n"); + break; + } + p_head->passphrase_len = + MIN(PHRASE_LEN, eptr - ptr - 1); + strncpy((char *)p_head->passphrase, ptr + 1, + p_head->passphrase_len); + } + } else if (strstr(line, "wep_key") != NULL) { + ptr = strstr(line, "wep_key"); + ptr = ptr + strlen("wep_key"); + key_cnt = atoi(ptr); + ptr++; + if (*ptr != '=') { + fprintf(stderr, + "invalid wep_key, missing =.\n"); + break; + } + eptr = strrchr(ptr + 1, '\r'); + if (eptr == NULL) { + eptr = strrchr(ptr + 1, '\n'); + if (eptr == NULL) { + fprintf(stderr, + "missing EOL from the wep_key config\n"); + break; + } + } + ptr++; + if (*ptr == '"') { + eptr = strrchr(ptr + 1, '"'); + if (eptr == NULL) { + fprintf(stderr, + "wep key does not end with quote.\n"); + break; + } + *eptr = '\0'; + p_head->wep_key_len[key_cnt] = eptr - ptr - 1; + strncpy((char *)p_head->wep_key[key_cnt], + ptr + 1, p_head->wep_key_len[key_cnt]); + } else { + while (*eptr == '\r' || *eptr == '\n') + eptr--; + *(eptr + 1) = '\0'; + wep_len = strlen(ptr); + if (wep_len & 0x01) { + fprintf(stderr, + "incorrect wep key %s.\n", ptr); + break; + } + p_head->wep_key_len[key_cnt] = wep_len / 2; + for (i = 0; i < wep_len / 2; i++) { + byte = twodigit_ascii(ptr); + if (byte == -1) { + fprintf(stderr, + "incorrect wep key %s.\n", + ptr); + break; + } + *(p_head->wep_key[key_cnt] + i) = + (t_u8)byte; + ptr += 2; + } + } + } else if (strstr(line, "key_mgmt=") != NULL) { + ptr = strstr(line, "key_mgmt="); + ptr = ptr + strlen("key_mgmt="); + eptr = strstr(ptr, "WPA-EAP"); + if (eptr != NULL) { + p_head->key_mgmt |= + PROFILE_DB_KEY_MGMT_IEEE8021X; + } + eptr = strstr(ptr, "WPA-PSK"); + if (eptr != NULL) { + p_head->key_mgmt |= PROFILE_DB_KEY_MGMT_PSK; + } + eptr = strstr(ptr, "FT-EAP"); + if (eptr != NULL) { + p_head->key_mgmt |= + PROFILE_DB_KEY_MGMT_FT_IEEE8021X; + } + eptr = strstr(ptr, "FT-PSK"); + if (eptr != NULL) { + p_head->key_mgmt |= PROFILE_DB_KEY_MGMT_FT_PSK; + } + eptr = strstr(ptr, "WPA-EAP-SHA256"); + if (eptr != NULL) { + p_head->key_mgmt |= + PROFILE_DB_KEY_MGMT_SHA256_IEEE8021X; + } + eptr = strstr(ptr, "WPA-PSK-SHA256"); + if (eptr != NULL) { + p_head->key_mgmt |= + PROFILE_DB_KEY_MGMT_SHA256_PSK; + } + eptr = strstr(ptr, "CCKM"); + if (eptr != NULL) { + p_head->key_mgmt |= PROFILE_DB_KEY_MGMT_CCKM; + } + eptr = strstr(ptr, "NONE"); + if (eptr != NULL) { + p_head->key_mgmt |= PROFILE_DB_KEY_MGMT_NONE; + } + } else if (strstr(line, "proto=") != NULL) { + ptr = strstr(line, "proto="); + ptr = ptr + strlen("proto="); + eptr = strstr(ptr, "WPA"); + if (eptr != NULL) { + p_head->protocol |= PROFILE_DB_PROTO_WPA; + } + + eptr = strstr(ptr, "RSN"); + if (eptr != NULL) { + p_head->protocol |= PROFILE_DB_PROTO_WPA2; + + } + } else if (strstr(line, "pairwise=") != NULL) { + ptr = strstr(line, "pairwise="); + ptr = ptr + strlen("pairwise="); + eptr = strstr(ptr, "CCMP"); + if (eptr != NULL) { + p_head->pairwise_cipher |= + PROFILE_DB_CIPHER_CCMP; + } + eptr = strstr(ptr, "TKIP"); + if (eptr != NULL) { + p_head->pairwise_cipher |= + PROFILE_DB_CIPHER_TKIP; + } + } else if (strstr(line, "groupwise=") != NULL) { + ptr = strstr(line, "groupwise="); + ptr = ptr + strlen("groupwise="); + eptr = strstr(ptr, "CCMP"); + if (eptr != NULL) { + p_head->groupwise_cipher |= + PROFILE_DB_CIPHER_CCMP; + } + eptr = strstr(ptr, "TKIP"); + if (eptr != NULL) { + p_head->groupwise_cipher |= + PROFILE_DB_CIPHER_TKIP; + } + } else if (strstr(line, "wep_tx_keyidx=") != NULL) { + ptr = strstr(line, "wep_tx_keyidx="); + ptr = ptr + strlen("wep_tx_keyidx="); + p_head->wep_key_idx = atoi(ptr); + } else if (strstr(line, "roaming=") != NULL) { + ptr = strstr(line, "roaming="); + ptr = ptr + strlen("roaming="); + p_head->roaming = atoi(ptr); + } else if (strstr(line, "ccx=") != NULL) { + ptr = strstr(line, "ccx="); + ptr = ptr + strlen("ccx="); + p_head->ccx = atoi(ptr); + } else if (strstr(line, "mode=") != NULL) { + ptr = strstr(line, "mode="); + ptr = ptr + strlen("mode="); + p_head->mode = atoi(ptr); + } + } + return MLAN_STATUS_SUCCESS; +} + +/** + * @brief Issue profile command to add new profile to FW + * + * @param filename Name of profile file + * + * @return MLAN_STATUS_SUCCESS--success, otherwise--fail + */ +static int +profile_read_download(char *filename) +{ + int ret = MLAN_STATUS_SUCCESS; + struct ifreq ifr; + t_u8 *buffer = NULL, *pos = NULL; + int i = 0; + t_u16 temp, tempc; + t_u32 cmd_len = 0, cmd_header_len; + struct eth_priv_cmd *cmd = NULL; + HostCmd_DS_GEN *hostcmd = NULL; + profile_entry_t *p_head = NULL; + FILE *fp; + char line[0x100]; + + fp = fopen(filename, "r"); + if (fp == NULL) { + perror("fopen"); + fprintf(stderr, "Cannot open file %s\n", filename); + ret = MLAN_STATUS_FAILURE; + goto done; + } + + cmd_header_len = strlen(CMD_NXP) + strlen(HOSTCMD); + + buffer = (t_u8 *)malloc(BUFFER_LENGTH); + if (buffer == NULL) { + fprintf(stderr, "Cannot alloc memory\n"); + ret = ENOMEM; + goto done; + } + memset(buffer, 0, BUFFER_LENGTH); + + cmd = (struct eth_priv_cmd *)malloc(sizeof(struct eth_priv_cmd)); + if (!cmd) { + printf("ERR:Cannot allocate buffer for command!\n"); + free(buffer); + ret = ENOMEM; + goto done; + } + + /* Fill up buffer */ +#ifdef USERSPACE_32BIT_OVER_KERNEL_64BIT + memset(cmd, 0, sizeof(struct eth_priv_cmd)); + memcpy(&cmd->buf, &buffer, sizeof(buffer)); +#else + cmd->buf = buffer; +#endif + cmd->used_len = 0; + cmd->total_len = BUFFER_LENGTH; + + /* buffer = MRVL_CMD */ + strncpy((char *)buffer, CMD_NXP, strlen(CMD_NXP)); + strncpy((char *)buffer + strlen(CMD_NXP), HOSTCMD, strlen(HOSTCMD)); + + /* buffer = MRVL_CMD */ + hostcmd = (HostCmd_DS_GEN *)(buffer + cmd_header_len + sizeof(t_u32)); + + pos = (t_u8 *)hostcmd; + while (fgets(line, sizeof(line), fp)) { + /* call function to remove spaces, tabs */ + profile_param_polish(line); + if ((strstr(line, "network={") == NULL) || (line[0] == '#')) { + continue; + } + /* + * Memory allocation of every network block + */ + p_head = (profile_entry_t *)malloc(sizeof(profile_entry_t)); + if (p_head == NULL) { + fprintf(stderr, "Memory error.\n"); + ret = MLAN_STATUS_FAILURE; + goto done; + } + memset(p_head, 0x00, sizeof(profile_entry_t)); + + ret = profile_read_block(fp, p_head); + if (ret || p_head->ssid_len == 0) { + free(p_head); + continue; + } + + /* + * Put all the ssid parameters in the buffer + */ + memset(pos, 0, + (BUFFER_LENGTH - cmd_header_len - sizeof(t_u32))); + + /* Cmd Header : Command */ + hostcmd->command = cpu_to_le16(HostCmd_CMD_PROFILE_DB); + cmd_len = sizeof(HostCmd_DS_GEN); + + /* set action as set */ + tempc = cpu_to_le16(HostCmd_ACT_GEN_SET); + memcpy((pos + cmd_len), &tempc, sizeof(t_u16)); + cmd_len += 2; + + /* ssid */ + tempc = cpu_to_le16(TLV_TYPE_SSID); + memcpy((pos + cmd_len), &tempc, sizeof(t_u16)); + cmd_len += 2; + temp = strlen((char *)p_head->ssid); + tempc = cpu_to_le16(temp); + memcpy((pos + cmd_len), &tempc, sizeof(t_u16)); + cmd_len += 2; + memcpy((void *)(pos + cmd_len), p_head->ssid, temp); + cmd_len += temp; + + if (memcmp(p_head->bssid, "\x00\x00\x00\x00\x00\x00", ETH_ALEN)) { + /* bssid */ + tempc = cpu_to_le16(TLV_TYPE_BSSID); + memcpy((pos + cmd_len), &tempc, sizeof(t_u16)); + cmd_len += 2; + temp = ETH_ALEN; + tempc = cpu_to_le16(temp); + memcpy((pos + cmd_len), &tempc, sizeof(t_u16)); + cmd_len += 2; + memcpy((void *)(pos + cmd_len), p_head->bssid, temp); + cmd_len += temp; + } + + /* proto */ + if (p_head->protocol == 0) { + p_head->protocol = 0xFFFF; + } + + tempc = cpu_to_le16(TLV_TYPE_PROTO); + memcpy((pos + cmd_len), &tempc, sizeof(t_u16)); + cmd_len += 2; + temp = 2; + tempc = cpu_to_le16(temp); + memcpy((pos + cmd_len), &tempc, sizeof(t_u16)); + cmd_len += 2; + memcpy((pos + cmd_len), &(p_head->protocol), temp); + cmd_len += temp; + + /* key_mgmt */ + if (p_head->key_mgmt == 0) { + p_head->key_mgmt = 0xFFFF; + } + + tempc = cpu_to_le16(TLV_TYPE_AKMP); + memcpy((pos + cmd_len), &tempc, sizeof(t_u16)); + cmd_len += 2; + temp = 2; + tempc = cpu_to_le16(temp); + memcpy((pos + cmd_len), &tempc, sizeof(t_u16)); + cmd_len += 2; + memcpy((pos + cmd_len), &(p_head->key_mgmt), temp); + cmd_len += temp; + + /* pairwise */ + if (p_head->pairwise_cipher == 0) { + p_head->pairwise_cipher = 0xFF; + } + + /* groupwise */ + if (p_head->groupwise_cipher == 0) { + p_head->groupwise_cipher = 0xFF; + } + + tempc = cpu_to_le16(TLV_TYPE_CIPHER); + memcpy((pos + cmd_len), &tempc, sizeof(t_u16)); + cmd_len += 2; + temp = 2; + tempc = cpu_to_le16(temp); + memcpy((pos + cmd_len), &tempc, sizeof(t_u16)); + cmd_len += 2; + pos[cmd_len] = p_head->pairwise_cipher; + cmd_len += 1; + pos[cmd_len] = p_head->groupwise_cipher; + cmd_len += 1; + + if (p_head->passphrase_len) { + /* passphrase */ + tempc = cpu_to_le16(TLV_TYPE_PASSPHRASE); + memcpy((pos + cmd_len), &tempc, sizeof(t_u16)); + cmd_len += 2; + temp = p_head->passphrase_len; + tempc = cpu_to_le16(temp); + memcpy((pos + cmd_len), &tempc, sizeof(t_u16)); + cmd_len += 2; + memcpy((void *)(pos + cmd_len), p_head->passphrase, + temp); + cmd_len += temp; + } + + if (p_head->psk_config) { + /* psk method */ + tempc = cpu_to_le16(TLV_TYPE_PMK); + memcpy((pos + cmd_len), &tempc, sizeof(t_u16)); + cmd_len += 2; + temp = 32; + tempc = cpu_to_le16(temp); + memcpy((pos + cmd_len), &tempc, sizeof(t_u16)); + cmd_len += 2; + memcpy((void *)(pos + cmd_len), p_head->psk, temp); + cmd_len += temp; + } + + for (i = 0; i < WEP_KEY_CNT; i++) { + if (p_head->wep_key_len[i]) { + /* TAG_WEP_KEY */ + tempc = cpu_to_le16(TLV_TYPE_WEP_KEY); + memcpy((pos + cmd_len), &tempc, sizeof(t_u16)); + cmd_len += 2; + /* wep_key_len + sizeof(keyIndex) + sizeof(IsDefault) */ + tempc = cpu_to_le16(p_head->wep_key_len[i] + 1 + + 1); + memcpy((pos + cmd_len), &tempc, sizeof(t_u16)); + cmd_len += 2; + *(pos + cmd_len) = i; + cmd_len += 1; + *(pos + cmd_len) = (i == p_head->wep_key_idx); + cmd_len += 1; + temp = p_head->wep_key_len[i]; + memcpy((void *)(pos + cmd_len), + p_head->wep_key[i], temp); + cmd_len += temp; + } + } + + if (p_head->roaming | p_head->ccx) { + tempc = cpu_to_le16(TLV_TYPE_OFFLOAD_ENABLE); + memcpy((pos + cmd_len), &tempc, sizeof(t_u16)); + cmd_len += 2; + temp = 2; + tempc = cpu_to_le16(temp); + memcpy((pos + cmd_len), &tempc, sizeof(t_u16)); + cmd_len += 2; + tempc = 0; + if (p_head->roaming) + tempc |= PROFILE_DB_FEATURE_ROAMING; + if (p_head->ccx) + tempc |= PROFILE_DB_FEATURE_CCX; + tempc = cpu_to_le16(tempc); + memcpy((pos + cmd_len), &tempc, sizeof(t_u16)); + cmd_len += temp; + } + + /* Put buffer length */ + memcpy(buffer + cmd_header_len, &cmd_len, sizeof(t_u32)); + hostcmd->size = cpu_to_le16(cmd_len); + + fprintf(stdout, "Downloading profile: %s ... ", p_head->ssid); + fflush(stdout); + + /* Initialize the ifr structure */ + memset(&ifr, 0, sizeof(ifr)); + strncpy(ifr.ifr_ifrn.ifrn_name, dev_name, strlen(dev_name)); + ifr.ifr_ifru.ifru_data = (void *)cmd; + /* Perform ioctl */ + if (ioctl(sockfd, MLAN_ETH_PRIV, &ifr)) { + perror("ioctl[profiledb ioctl]"); + printf("ERR:Command sending failed!\n"); + ret = -EFAULT; + goto done; + } else { + hostcmd->result = le16_to_cpu(hostcmd->result); + if (hostcmd->result != 0) { + printf("hostcmd : profiledb ioctl failure, code %d\n", hostcmd->result); + ret = -EFAULT; + goto done; + } + } + + fprintf(stdout, "done.\n"); + + if (p_head) + free(p_head); + } + +done: + if (buffer) + free(buffer); + if (cmd) + free(cmd); + if (fp) + fclose(fp); + return ret; +} + +/******************************************************** + Global Functions +********************************************************/ + +/** + * @brief Process sub command + * + * @param sub_cmd Sub command + * @param num_sub_cmds Number of subcommands + * @param argc Number of arguments + * @param argv A pointer to arguments array + * + * @return MLAN_STATUS_SUCCESS--success, otherwise--fail + */ +int +process_sub_cmd(sub_cmd_exec_t *sub_cmd, int num_sub_cmds, + int argc, char *argv[]) +{ + int idx; + boolean invalid_cmd = TRUE; + int ret = MLAN_STATUS_FAILURE; + + if (argv[3]) { + for (idx = 0; idx < num_sub_cmds; idx++) { + if (strncmp(argv[3], + sub_cmd[idx].str, + sub_cmd[idx].match_len) == 0) { + invalid_cmd = FALSE; + ret = sub_cmd[idx].callback(argc - 4, argv + 4); + break; + } + } + } + + if (invalid_cmd) { + printf("\nUnknown %s command. Valid subcmds:\n", argv[2]); + for (idx = 0; idx < num_sub_cmds; idx++) { + if (sub_cmd[idx].display) { + printf(" - %s\n", sub_cmd[idx].str); + } + } + printf("\n"); + } + + return ret; +} + +/** + * @brief select the table's regclass + * + * @param table_str Reg channel table type + * @param pTable Pointer to the Reg channel table + * + * @return TRUE if success otherwise FALSE + */ +boolean +reg_class_table_select(char *table_str, reg_chan_table_e *pTable) +{ + boolean retval = TRUE; + + if (strcmp(table_str, "user") == 0) { + *pTable = REGTABLE_USER; + } else if ((strcmp(table_str, "md") == 0) || + (strncmp(table_str, "multidomain", 5) == 0)) { + *pTable = REGTABLE_MULTIDOMAIN; + } else if (strcmp(table_str, "ess") == 0) { + *pTable = REGTABLE_ESS; + } else if (strcmp(table_str, "default") == 0) { + *pTable = REGTABLE_DEFAULT; + } else { /* If no option/wrong option set to default */ + *pTable = REGTABLE_DEFAULT; + } + + return retval; +} + +/** + * @brief Issue a measurement timing command + * + * @param argc number of arguments + * @param argv A pointer to arguments array + * + * @return MLAN_STATUS_SUCCESS--success, otherwise--fail + */ +int +process_measurement(int argc, char *argv[]) +{ + int ret = 0; + struct ifreq ifr; + t_u8 *buffer = NULL, *pos = NULL; + t_u32 cmd_len = 0, cmd_header_len; + struct eth_priv_cmd *cmd = NULL; + HostCmd_DS_GEN *hostcmd = NULL; + HostCmd_DS_MEASUREMENT_Timing *timing_cmd = NULL; + MrvlIETypes_MeasTiming_t *timing_tlv = NULL; + int idx, rsp_len; + t_u8 sel = 0; + t_u16 tlv_len = 0; + timing_sel_t sel_str[] = { {"disconnected", 1}, + {"adhoc", 1}, + {"fullpower", 1}, + {"ieeeps", 1}, + {"periodic", 1} + }; + + if ((argc < 4) || strncmp(argv[3], "timing", + MAX(strlen("timing"), strlen(argv[3])))) { + printf("\nUnknown %s command. Valid subcmd: timing \n", + argv[2]); + return MLAN_STATUS_FAILURE; + } + + cmd_header_len = strlen(CMD_NXP) + strlen(HOSTCMD); + cmd_len = S_DS_GEN + sizeof(t_u16); + + buffer = (t_u8 *)malloc(BUFFER_LENGTH); + if (buffer == NULL) { + fprintf(stderr, "Cannot alloc memory\n"); + return -ENOMEM; + } + memset(buffer, 0, BUFFER_LENGTH); + + cmd = (struct eth_priv_cmd *)malloc(sizeof(struct eth_priv_cmd)); + if (!cmd) { + printf("ERR:Cannot allocate buffer for command!\n"); + free(buffer); + return -ENOMEM; + } + + /* Fill up buffer */ +#ifdef USERSPACE_32BIT_OVER_KERNEL_64BIT + memset(cmd, 0, sizeof(struct eth_priv_cmd)); + memcpy(&cmd->buf, &buffer, sizeof(buffer)); +#else + cmd->buf = buffer; +#endif + cmd->used_len = 0; + cmd->total_len = BUFFER_LENGTH; + + /* buffer = MRVL_CMD */ + strncpy((char *)buffer, CMD_NXP, strlen(CMD_NXP)); + strncpy((char *)buffer + strlen(CMD_NXP), HOSTCMD, strlen(HOSTCMD)); + + /* buffer = MRVL_CMD */ + hostcmd = (HostCmd_DS_GEN *)(buffer + cmd_header_len + sizeof(t_u32)); + hostcmd->command = cpu_to_le16(HostCmd_CMD_MEASUREMENT_TIMING_CONFIG); + hostcmd->size = cmd_len; + hostcmd->seq_num = 0; + hostcmd->result = 0; + + /* Point after host command header */ + pos = (t_u8 *)hostcmd + S_DS_GEN; + + timing_cmd = (HostCmd_DS_MEASUREMENT_Timing *)pos; + timing_cmd->action = cpu_to_le16(HostCmd_ACT_GEN_GET); + timing_tlv = (MrvlIETypes_MeasTiming_t *)timing_cmd->tlv_buffer; + + if (argc == 7) { + timing_cmd->action = cpu_to_le16(HostCmd_ACT_GEN_SET); + timing_tlv->header.type = + cpu_to_le16(TLV_TYPE_MEASUREMENT_TIMING); + timing_tlv->header.len = + cpu_to_le16(sizeof(MrvlIETypes_MeasTiming_t) + - sizeof(timing_tlv->header)); + + for (idx = 1; (unsigned int)idx < NELEMENTS(sel_str); idx++) { + if (strncmp + (argv[4], sel_str[idx].str, + sel_str[idx].match_len) == 0) { + sel = idx + 1; + break; + } + } + + if (idx == NELEMENTS(sel_str)) { + printf("Wrong argument for mode selected \"%s\"\n", + argv[4]); + ret = -EINVAL; + goto done; + } + + timing_tlv->mode = cpu_to_le32(sel); + timing_tlv->max_off_channel = cpu_to_le32(atoi(argv[5])); + timing_tlv->max_on_channel = cpu_to_le32(atoi(argv[6])); + cmd_len += sizeof(MrvlIETypes_MeasTiming_t); + } + + /* Put buffer length */ + memcpy(buffer + cmd_header_len, &cmd_len, sizeof(t_u32)); + hostcmd->size = cpu_to_le16(cmd_len); + + /* Initialize the ifr structure */ + memset(&ifr, 0, sizeof(ifr)); + strncpy(ifr.ifr_ifrn.ifrn_name, dev_name, strlen(dev_name)); + ifr.ifr_ifru.ifru_data = (void *)cmd; + + /* Perform ioctl */ + if (ioctl(sockfd, MLAN_ETH_PRIV, &ifr)) { + perror("ioctl[measurement timing ioctl]"); + printf("ERR:Command sending failed!\n"); + ret = -EFAULT; + goto done; + } + + printf("--------------------------------------------------\n"); + printf("%44s\n", "Measurement Timing Profiles (in ms)"); + printf("--------------------------------------------------\n"); + printf(" Profile | MaxOffChannel | MaxOnChannel\n"); + printf("--------------------------------------------------\n"); + + /* Changed to TLV parsing */ + rsp_len = le16_to_cpu(hostcmd->size); + rsp_len -= (S_DS_GEN + sizeof(t_u16)); + pos = (t_u8 *)hostcmd + S_DS_GEN + sizeof(t_u16); + while ((unsigned int)rsp_len > sizeof(MrvlIEtypesHeader_t)) { + switch (le16_to_cpu(*(t_u16 *)(pos))) { + case TLV_TYPE_MEASUREMENT_TIMING: + timing_tlv = (MrvlIETypes_MeasTiming_t *)pos; + tlv_len = le16_to_cpu(timing_tlv->header.len); + printf("%15s | %14d | %13d\n", + sel_str[le32_to_cpu(timing_tlv->mode) - 1].str, + (int)le32_to_cpu(timing_tlv->max_off_channel), + (int)le32_to_cpu(timing_tlv->max_on_channel)); + break; + } + pos += tlv_len + sizeof(MrvlIEtypesHeader_t); + rsp_len -= tlv_len + sizeof(MrvlIEtypesHeader_t); + rsp_len = (rsp_len > 0) ? rsp_len : 0; + } + printf("\n"); + +done: + if (buffer) + free(buffer); + if (cmd) + free(cmd); + return ret; +} + +/** + * @brief Issue a profile command + * + * @param argc number of arguments + * @param argv A pointer to arguments array + * + * @return MLAN_STATUS_SUCCESS--success, otherwise--fail + */ +int +process_profile_entry(int argc, char *argv[]) +{ + int ret = MLAN_STATUS_SUCCESS; + struct ifreq ifr; + unsigned int mac[ETH_ALEN] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; + int idx; + t_u16 temp, tempc; + char *ssid = NULL; + t_u8 *buffer = NULL, *pos = NULL; + t_u32 cmd_len = 0, cmd_header_len; + struct eth_priv_cmd *cmd = NULL; + HostCmd_DS_GEN *hostcmd = NULL; + + cmd_header_len = strlen(CMD_NXP) + strlen(HOSTCMD); + + if (argc < 4) { + fprintf(stderr, "Invalid number of argument!\n"); + ret = MLAN_STATUS_FAILURE; + goto done; + } + + if (!strncmp(argv[3], "delete", sizeof("delete"))) { + if (argc > 4) { + if (strncmp(argv[4], "bssid=", strlen("bssid=")) == 0) { + /* "bssid" token string handler */ + sscanf(argv[4] + strlen("bssid="), + "%2x:%2x:%2x:%2x:%2x:%2x", mac + 0, + mac + 1, mac + 2, mac + 3, mac + 4, + mac + 5); + } else if (strncmp(argv[4], "ssid=", strlen("ssid=")) == + 0) { + /* "ssid" token string handler */ + ssid = argv[4] + strlen("ssid="); + } else { + printf("Error: missing required option for command (ssid, bssid)\n"); + ret = -ENOMEM; + goto done; + } + printf("Driver profile delete request\n"); + } else { + printf("Error: missing required option for command (ssid, bssid)\n"); + ret = -ENOMEM; + goto done; + } + } else if (!strncmp(argv[3], "flush", sizeof("flush"))) { + printf("Driver profile flush request\n"); + } else { + ret = profile_read_download(argv[3]); + goto done; + } + + buffer = (t_u8 *)malloc(BUFFER_LENGTH); + if (buffer == NULL) { + fprintf(stderr, "Cannot alloc memory\n"); + ret = -ENOMEM; + goto done; + } + memset(buffer, 0, BUFFER_LENGTH); + + cmd = (struct eth_priv_cmd *)malloc(sizeof(struct eth_priv_cmd)); + if (!cmd) { + printf("ERR:Cannot allocate buffer for command!\n"); + ret = -ENOMEM; + goto done; + } + + /* Fill up buffer */ +#ifdef USERSPACE_32BIT_OVER_KERNEL_64BIT + memset(cmd, 0, sizeof(struct eth_priv_cmd)); + memcpy(&cmd->buf, &buffer, sizeof(buffer)); +#else + cmd->buf = buffer; +#endif + cmd->used_len = 0; + cmd->total_len = BUFFER_LENGTH; + + /* buffer = MRVL_CMD */ + strncpy((char *)buffer, CMD_NXP, strlen(CMD_NXP)); + strncpy((char *)buffer + strlen(CMD_NXP), HOSTCMD, strlen(HOSTCMD)); + + /* buffer = MRVL_CMD */ + hostcmd = (HostCmd_DS_GEN *)(buffer + cmd_header_len + sizeof(t_u32)); + hostcmd->command = cpu_to_le16(HostCmd_CMD_PROFILE_DB); + hostcmd->size = 0; + hostcmd->seq_num = 0; + hostcmd->result = 0; + + /* Point after host command header */ + pos = (t_u8 *)hostcmd; + cmd_len = S_DS_GEN; + + /* set action as del */ + tempc = cpu_to_le16(HostCmd_ACT_GEN_REMOVE); + memcpy((pos + cmd_len), &tempc, sizeof(t_u16)); + cmd_len += 2; + + /* ssid */ + if (ssid) { + printf("For ssid %s\n", ssid); + tempc = cpu_to_le16(TLV_TYPE_SSID); + memcpy((pos + cmd_len), &tempc, sizeof(t_u16)); + cmd_len += 2; + temp = strlen((char *)ssid); + tempc = cpu_to_le16(temp); + memcpy((pos + cmd_len), &tempc, sizeof(t_u16)); + cmd_len += 2; + memcpy((void *)(pos + cmd_len), ssid, temp); + cmd_len += temp; + } else { + /* bssid */ + if (mac[0] != 0xFF) { + printf("For bssid %02x:%02x:%02x:%02x:%02x:%02x\n", + mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); + } + tempc = cpu_to_le16(TLV_TYPE_BSSID); + memcpy((pos + cmd_len), &tempc, sizeof(t_u16)); + cmd_len += 2; + temp = ETH_ALEN; + tempc = cpu_to_le16(temp); + memcpy((pos + cmd_len), &tempc, sizeof(t_u16)); + cmd_len += 2; + for (idx = 0; (unsigned int)idx < NELEMENTS(mac); idx++) { + pos[cmd_len + idx] = (t_u8)mac[idx]; + } + cmd_len += temp; + } + + /* Put buffer length */ + memcpy(buffer + cmd_header_len, &cmd_len, sizeof(t_u32)); + hostcmd->size = cpu_to_le16(cmd_len); + + /* Initialize the ifr structure */ + memset(&ifr, 0, sizeof(ifr)); + strncpy(ifr.ifr_ifrn.ifrn_name, dev_name, strlen(dev_name)); + ifr.ifr_ifru.ifru_data = (void *)cmd; + /* Perform ioctl */ + if (ioctl(sockfd, MLAN_ETH_PRIV, &ifr)) { + perror("ioctl[profiledb ioctl]"); + printf("ERR:Command sending failed!\n"); + ret = -EFAULT; + goto done; + } else { + hostcmd->result = le16_to_cpu(hostcmd->result); + if (hostcmd->result != 0) { + printf("hostcmd : profiledb ioctl failure, code %d\n", + hostcmd->result); + ret = -EFAULT; + goto done; + } + } + +done: + if (buffer) + free(buffer); + if (cmd) + free(cmd); + return ret; +} + +/** + * @brief Issue a chan report command + * + * @param argc number of arguments + * @param argv A pointer to arguments array + * + * @return MLAN_STATUS_SUCCESS--success, otherwise--fail + */ +int +process_chanrpt(int argc, char *argv[]) +{ + int ret = MLAN_STATUS_SUCCESS; + int respLen; + struct ifreq ifr; + t_u8 *buffer = NULL, *pos = NULL; + t_u32 cmd_len = 0, cmd_header_len; + struct eth_priv_cmd *cmd = NULL; + t_u8 *pByte; + t_u8 numBins; + t_u8 idx; + MrvlIEtypes_Data_t *pTlvHdr; + HostCmd_DS_GEN *hostcmd; + HostCmd_DS_CHAN_RPT_RSP *pChanRptRsp; + HostCmd_DS_CHAN_RPT_REQ *pChanRptReq; + + MrvlIEtypes_ChanRptBcn_t *pBcnRpt; + MrvlIEtypes_ChanRptChanLoad_t *pLoadRpt; + MrvlIEtypes_ChanRptNoiseHist_t *pNoiseRpt; + MrvlIEtypes_ChanRpt11hBasic_t *pBasicRpt; + MrvlIEtypes_ChanRptFrame_t *pFrameRpt; + + cmd_header_len = strlen(CMD_NXP) + strlen(HOSTCMD); + + buffer = (t_u8 *)malloc(BUFFER_LENGTH); + if (buffer == NULL) { + fprintf(stderr, "Cannot alloc memory\n"); + ret = ENOMEM; + goto done; + } + memset(buffer, 0, BUFFER_LENGTH); + + cmd = (struct eth_priv_cmd *)malloc(sizeof(struct eth_priv_cmd)); + if (!cmd) { + printf("ERR:Cannot allocate buffer for command!\n"); + ret = ENOMEM; + goto done; + } + + /* Fill up buffer */ +#ifdef USERSPACE_32BIT_OVER_KERNEL_64BIT + memset(cmd, 0, sizeof(struct eth_priv_cmd)); + memcpy(&cmd->buf, &buffer, sizeof(buffer)); +#else + cmd->buf = buffer; +#endif + cmd->used_len = 0; + cmd->total_len = BUFFER_LENGTH; + + /* buffer = MRVL_CMD */ + strncpy((char *)buffer, CMD_NXP, strlen(CMD_NXP)); + strncpy((char *)buffer + strlen(CMD_NXP), HOSTCMD, strlen(HOSTCMD)); + + /* buffer = MRVL_CMD */ + hostcmd = (HostCmd_DS_GEN *)(buffer + cmd_header_len + sizeof(t_u32)); + + /* Point after host command header */ + pos = (t_u8 *)hostcmd + S_DS_GEN; + + cmd_len = S_DS_GEN + sizeof(HostCmd_DS_CHAN_RPT_REQ); + + hostcmd->command = cpu_to_le16(HostCmd_CMD_CHAN_REPORT_REQUEST); + hostcmd->size = cpu_to_le16(cmd_len); + hostcmd->seq_num = 0; + hostcmd->result = 0; + + pChanRptReq = (HostCmd_DS_CHAN_RPT_REQ *)pos; + pChanRptRsp = (HostCmd_DS_CHAN_RPT_RSP *)pos; + + memset((void *)pChanRptReq, 0x00, sizeof(HostCmd_DS_CHAN_RPT_REQ)); + + if ((argc != 5) && (argc != 6)) { + printf("\nchanrpt syntax: chanrpt [sFreq]\n\n"); + ret = MLAN_STATUS_FAILURE; + goto done; + } + + pChanRptReq->chanDesc.chanNum = atoi(argv[3]); + pChanRptReq->millisecDwellTime = cpu_to_le32(atoi(argv[4])); + + if (argc == 6) { + pChanRptReq->chanDesc.startFreq = cpu_to_le16(atoi(argv[5])); + } + + /* Put buffer length */ + memcpy(buffer + cmd_header_len, &cmd_len, sizeof(t_u32)); + + /* Initialize the ifr structure */ + memset(&ifr, 0, sizeof(ifr)); + strncpy(ifr.ifr_ifrn.ifrn_name, dev_name, strlen(dev_name)); + ifr.ifr_ifru.ifru_data = (void *)cmd; + /* Perform ioctl */ + if (ioctl(sockfd, MLAN_ETH_PRIV, &ifr)) { + perror("ioctl[chanrpt hostcmd]"); + printf("ERR:Command sending failed!\n"); + ret = -EFAULT; + goto done; + } + + /* TSF is a t_u64, some formatted printing libs have + * trouble printing long longs, so cast and dump as bytes + */ + pByte = (t_u8 *)&pChanRptRsp->startTsf; + + printf("\n"); + printf("[%03d] TSF: 0x%02x%02x%02x%02x%02x%02x%02x%02x\n", + atoi(argv[3]), + pByte[7], pByte[6], pByte[5], pByte[4], + pByte[3], pByte[2], pByte[1], pByte[0]); + printf("[%03d] Dwell: %u us\n", + atoi(argv[3]), (unsigned int)le32_to_cpu(pChanRptRsp->duration)); + + pByte = pChanRptRsp->tlvBuffer; + + respLen = le16_to_cpu(hostcmd->size) - sizeof(HostCmd_DS_GEN); + + respLen -= sizeof(pChanRptRsp->commandResult); + respLen -= sizeof(pChanRptRsp->startTsf); + respLen -= sizeof(pChanRptRsp->duration); + + pByte = pChanRptRsp->tlvBuffer; + + while ((unsigned int)respLen >= sizeof(pTlvHdr->header)) { + pTlvHdr = (MrvlIEtypes_Data_t *)pByte; + pTlvHdr->header.len = le16_to_cpu(pTlvHdr->header.len); + + switch (le16_to_cpu(pTlvHdr->header.type)) { + case TLV_TYPE_CHANRPT_BCN: + pBcnRpt = (MrvlIEtypes_ChanRptBcn_t *)pTlvHdr; + printf("[%03d] Beacon: scanReqId = %d\n", + atoi(argv[3]), pBcnRpt->scanReqId); + + break; + + case TLV_TYPE_CHANRPT_CHAN_LOAD: + pLoadRpt = (MrvlIEtypes_ChanRptChanLoad_t *)pTlvHdr; + printf("[%03d] ChanLoad: %d%%\n", + atoi(argv[3]), + (pLoadRpt->ccaBusyFraction * 100) / 255); + break; + + case TLV_TYPE_CHANRPT_NOISE_HIST: + pNoiseRpt = (MrvlIEtypes_ChanRptNoiseHist_t *)pTlvHdr; + numBins = + pNoiseRpt->header.len - sizeof(pNoiseRpt->anpi); + printf("[%03d] ANPI: %d dB\n", atoi(argv[3]), + le16_to_cpu(pNoiseRpt->anpi)); + printf("[%03d] NoiseHst:", atoi(argv[3])); + for (idx = 0; idx < numBins; idx++) { + printf(" %03d", pNoiseRpt->rpiDensities[idx]); + } + printf("\n"); + break; + + case TLV_TYPE_CHANRPT_11H_BASIC: + pBasicRpt = (MrvlIEtypes_ChanRpt11hBasic_t *)pTlvHdr; + printf("[%03d] 11hBasic: BSS(%d), OFDM(%d), UnId(%d), Radar(%d): " "[0x%02x]\n", atoi(argv[3]), pBasicRpt->map.BSS, pBasicRpt->map.OFDM_Preamble, pBasicRpt->map.Unidentified, pBasicRpt->map.Radar, *(t_u8 *)&pBasicRpt->map); + break; + + case TLV_TYPE_CHANRPT_FRAME: + pFrameRpt = (MrvlIEtypes_ChanRptFrame_t *)pTlvHdr; + printf("[%03d] Frame: %02x:%02x:%02x:%02x:%02x:%02x " "%02x:%02x:%02x:%02x:%02x:%02x %3d %02d\n", atoi(argv[3]), pFrameRpt->sourceAddr[0], pFrameRpt->sourceAddr[1], pFrameRpt->sourceAddr[2], pFrameRpt->sourceAddr[3], pFrameRpt->sourceAddr[4], pFrameRpt->sourceAddr[5], pFrameRpt->bssid[0], pFrameRpt->bssid[1], pFrameRpt->bssid[2], pFrameRpt->bssid[3], pFrameRpt->bssid[4], pFrameRpt->bssid[5], pFrameRpt->rssi, pFrameRpt->frameCnt); + break; + + default: + printf("[%03d] Other: Id=0x%x, Size = %d\n", + atoi(argv[3]), + pTlvHdr->header.type, pTlvHdr->header.len); + + break; + } + + pByte += (pTlvHdr->header.len + sizeof(pTlvHdr->header)); + respLen -= (pTlvHdr->header.len + sizeof(pTlvHdr->header)); + respLen = (respLen > 0) ? respLen : 0; + } + + printf("\n"); + +done: + if (buffer) + free(buffer); + if (cmd) + free(cmd); + return ret; +} + +/** + * @brief Issue a assoc timing command + * + * @param argc number of arguments + * @param argv A pointer to arguments array + * + * @return MLAN_STATUS_SUCCESS--success, otherwise--fail + */ +int +process_assoc_timing(int argc, char *argv[]) +{ + int ret = MLAN_STATUS_SUCCESS; + struct ifreq ifr; + t_u8 *buffer = NULL, *pos = NULL; + t_u32 cmd_len = 0, cmd_header_len; + struct eth_priv_cmd *cmd = NULL; + HostCmd_DS_GEN *hostcmd; + HostCmd_DS_AssociationTiming_t *assoctiming; + + cmd_header_len = strlen(CMD_NXP) + strlen(HOSTCMD); + + buffer = (t_u8 *)malloc(BUFFER_LENGTH); + if (buffer == NULL) { + fprintf(stderr, "Cannot alloc memory\n"); + ret = ENOMEM; + goto done; + } + memset(buffer, 0, BUFFER_LENGTH); + + cmd = (struct eth_priv_cmd *)malloc(sizeof(struct eth_priv_cmd)); + if (!cmd) { + printf("ERR:Cannot allocate buffer for command!\n"); + ret = ENOMEM; + goto done; + } + + /* Fill up buffer */ +#ifdef USERSPACE_32BIT_OVER_KERNEL_64BIT + memset(cmd, 0, sizeof(struct eth_priv_cmd)); + memcpy(&cmd->buf, &buffer, sizeof(buffer)); +#else + cmd->buf = buffer; +#endif + cmd->used_len = 0; + cmd->total_len = BUFFER_LENGTH; + + /* buffer = MRVL_CMD */ + strncpy((char *)buffer, CMD_NXP, strlen(CMD_NXP)); + strncpy((char *)buffer + strlen(CMD_NXP), HOSTCMD, strlen(HOSTCMD)); + + /* buffer = MRVL_CMD */ + hostcmd = (HostCmd_DS_GEN *)(buffer + cmd_header_len + sizeof(t_u32)); + + /* Point after host command header */ + pos = (t_u8 *)hostcmd + S_DS_GEN; + + cmd_len = S_DS_GEN + sizeof(HostCmd_DS_AssociationTiming_t); + + hostcmd->command = cpu_to_le16(HostCmd_CMD_ASSOCIATION_TIMING); + hostcmd->size = cpu_to_le16(cmd_len); + hostcmd->seq_num = 0; + hostcmd->result = 0; + + assoctiming = (HostCmd_DS_AssociationTiming_t *)pos; + assoctiming->Action = cpu_to_le16(HostCmd_ACT_GEN_GET); + + /* Put buffer length */ + memcpy(buffer + cmd_header_len, &cmd_len, sizeof(t_u32)); + + /* Initialize the ifr structure */ + memset(&ifr, 0, sizeof(ifr)); + strncpy(ifr.ifr_ifrn.ifrn_name, dev_name, strlen(dev_name)); + ifr.ifr_ifru.ifru_data = (void *)cmd; + /* Perform ioctl */ + if (ioctl(sockfd, MLAN_ETH_PRIV, &ifr)) { + perror("ioctl[hostcmd]"); + printf("ERR:Command sending failed!\n"); + ret = -EFAULT; + goto done; + } + + if (argc > 3) { + assoctiming->Action = cpu_to_le16(HostCmd_ACT_GEN_SET); + switch (argc) { + case 9: + assoctiming->ReassocDiscMax = + cpu_to_le16(atoi(argv[8])); + /* No break, do everything below as well */ + case 8: + assoctiming->PriorApDeauthDelay = + cpu_to_le16(atoi(argv[7])); + /* No break, do everything below as well */ + case 7: + assoctiming->FrameExchangeTimeout = + cpu_to_le16(atoi(argv[6])); + /* No break, do everything below as well */ + case 6: + assoctiming->HandShakeTimeout = + cpu_to_le16(atoi(argv[5])); + /* No break, do everything below as well */ + case 5: + assoctiming->ReassocTimeout = + cpu_to_le16(atoi(argv[4])); + /* No break, do everything below as well */ + case 4: + assoctiming->AssocTimeout = cpu_to_le16(atoi(argv[3])); + break; + } + } + + /* Put buffer length */ + memcpy(buffer + cmd_header_len, &cmd_len, sizeof(t_u32)); + + /* Initialize the ifr structure */ + memset(&ifr, 0, sizeof(ifr)); + strncpy(ifr.ifr_ifrn.ifrn_name, dev_name, strlen(dev_name)); + ifr.ifr_ifru.ifru_data = (void *)cmd; + /* Perform ioctl */ + if (ioctl(sockfd, MLAN_ETH_PRIV, &ifr)) { + perror("ioctl[hostcmd]"); + printf("ERR:Command sending failed!\n"); + ret = -EFAULT; + goto done; + } + + puts(""); + printf("------------------------------------------------\n"); + printf(" Association Timing Parameters\n"); + printf("------------------------------------------------\n"); + + printf("Association Timeout %5u ms\n" + "Reassociation Timeout %5u ms\n" + "Handshake Timeout %5u ms\n" + "Frame Exchange Timeout %5u ms\n" + "Prior AP Deauth Delay %5u ms\n" + "Reassoc Disconnect Max %5u ms\n", + le16_to_cpu(assoctiming->AssocTimeout), + le16_to_cpu(assoctiming->ReassocTimeout), + le16_to_cpu(assoctiming->HandShakeTimeout), + le16_to_cpu(assoctiming->FrameExchangeTimeout), + le16_to_cpu(assoctiming->PriorApDeauthDelay), + le16_to_cpu(assoctiming->ReassocDiscMax)); + puts(""); + +done: + if (buffer) + free(buffer); + if (cmd) + free(cmd); + return ret; +} + +/** + * @brief Retrieve the association response from the driver + * + * Retrieve the buffered (re)association management frame from the driver. + * The response is identical to the one received from the AP and conforms + * to the IEEE specification. + * + * @return MLAN_STATUS_SUCCESS or ioctl error code + */ +int +process_get_assocrsp(int argc, char *argv[]) +{ + int ret = 0; + t_u8 *buffer = NULL; + struct eth_priv_cmd *cmd = NULL; + struct ifreq ifr; + IEEEtypes_AssocRsp_t *pAssocRsp = NULL; + + /* Initialize buffer */ + buffer = (t_u8 *)malloc(BUFFER_LENGTH); + if (!buffer) { + printf("ERR:Cannot allocate buffer for command!\n"); + return MLAN_STATUS_FAILURE; + } + + pAssocRsp = (IEEEtypes_AssocRsp_t *)buffer; + + /* buffer = MRVL_CMD */ + strncpy((char *)buffer, CMD_NXP, strlen(CMD_NXP)); + strncpy((char *)buffer + strlen(CMD_NXP), argv[2], strlen(argv[2])); + + cmd = (struct eth_priv_cmd *)malloc(sizeof(struct eth_priv_cmd)); + if (!cmd) { + printf("ERR:Cannot allocate buffer for command!\n"); + free(buffer); + return MLAN_STATUS_FAILURE; + } + + /* Fill up buffer */ +#ifdef USERSPACE_32BIT_OVER_KERNEL_64BIT + memset(cmd, 0, sizeof(struct eth_priv_cmd)); + memcpy(&cmd->buf, &buffer, sizeof(buffer)); +#else + cmd->buf = buffer; +#endif + cmd->used_len = 0; + cmd->total_len = BUFFER_LENGTH; + + /* Perform IOCTL */ + memset(&ifr, 0, sizeof(struct ifreq)); + strncpy(ifr.ifr_ifrn.ifrn_name, dev_name, strlen(dev_name)); + ifr.ifr_ifru.ifru_data = (void *)cmd; + + if (ioctl(sockfd, MLAN_ETH_PRIV, &ifr)) { + perror("mlanutl"); + fprintf(stderr, "mlanutl: version fail\n"); + ret = MLAN_STATUS_FAILURE; + goto done; + } + + if (cmd->used_len) { + printf("getassocrsp: Status[%d], Cap[0x%04x]:\n", + pAssocRsp->StatusCode, + le16_to_cpu(*(t_u16 *)&pAssocRsp->Capability)); + hexdump(NULL, buffer, cmd->used_len, ' '); + } else { + printf("getassocrsp: \n"); + } + +done: + if (buffer) + free(buffer); + if (cmd) + free(cmd); + + return ret; +} + +#ifdef OPCHAN +static void +dumpCc(MrvlIEtypes_ChanControlDesc_t *pCcTlv) +{ + printf(" %d.%-3d\t0x%04x\t\t%2d\t%2d\t%2d\t%2d\n", + le16_to_cpu(pCcTlv->chanDesc.startFreq), + pCcTlv->chanDesc.chanNum, + le16_to_cpu(pCcTlv->controlFlags), + pCcTlv->actPower, + pCcTlv->mdMinPower, pCcTlv->mdMaxPower, pCcTlv->mdPower); +} + +static void +dumpCg(MrvlIEtypes_ChanGroupControl_t *pCgTlv) +{ + int idx; + t_u16 lastFreq; + char buf[100]; + + lastFreq = 0; + *buf = 0; + + if (pCgTlv->numChan) { + for (idx = 0; idx < pCgTlv->numChan; idx++) { + if (lastFreq != + le16_to_cpu(pCgTlv->chanDesc[idx].startFreq)) { + lastFreq = + le16_to_cpu(pCgTlv->chanDesc[idx]. + startFreq); + + if (strlen(buf)) { + puts(buf); + *buf = 0; + } + + sprintf(buf, " 0x%08x 0x%02x %04d:%d", + (unsigned int)le32_to_cpu(pCgTlv-> + chanGroupBitmap), + *(t_u8 *)&pCgTlv->scanMode, + le16_to_cpu(pCgTlv->chanDesc[idx]. + startFreq), + pCgTlv->chanDesc[idx].chanNum); + } else { + sprintf(buf + strlen(buf), ",%d", + pCgTlv->chanDesc[idx].chanNum); + } + + if (strlen(buf) > 76) { + /* Cut the display off */ + lastFreq = 0; + puts(buf); + *buf = 0; + } + } + } + + if (strlen(buf)) { + puts(buf); + } +} + +static void +dumpCgBuf(t_u8 *tlv_buffer, int tlv_size) +{ + int tlvOffset = 0; + MrvlIEtypes_ChanGroupControl_t *pCgcTlv; + + while (tlvOffset < tlv_size) { + pCgcTlv = + (MrvlIEtypes_ChanGroupControl_t *)(tlv_buffer + + tlvOffset); + + dumpCg(pCgcTlv); + + tlvOffset += sizeof(pCgcTlv->header); + tlvOffset += le16_to_cpu(pCgcTlv->header.len); + } +} + +static void +execChanGroupCmd(struct eth_priv_cmd *cmd, int tlv_size, t_u8 displayResult) +{ + struct ifreq ifr; + t_u8 *buffer = NULL, *pos = NULL; + t_u32 cmd_len = 0, cmd_header_len; + struct eth_priv_cmd; + HostCmd_DS_OPCHAN_CHANGROUP_CONFIG *pChanGroup; + HostCmd_DS_GEN *hostcmd; + + cmd_header_len = strlen(CMD_NXP) + strlen(HOSTCMD); + +#ifdef USERSPACE_32BIT_OVER_KERNEL_64BIT + memcpy(&buffer, &cmd->buf, sizeof(buffer)); +#else + buffer = cmd->buf; +#endif + + /* buffer = MRVL_CMD */ + hostcmd = (HostCmd_DS_GEN *)(buffer + cmd_header_len + sizeof(t_u32)); + /* Point after host command header */ + pos = (t_u8 *)hostcmd + S_DS_GEN; + pChanGroup = (HostCmd_DS_OPCHAN_CHANGROUP_CONFIG *)pos; + cmd_len = S_DS_GEN + sizeof(pChanGroup->action) + tlv_size; + + hostcmd->command = cpu_to_le16(HostCmd_CMD_OPCHAN_CHANGROUP_CONFIG); + hostcmd->seq_num = 0; + hostcmd->result = 0; + hostcmd->size = cpu_to_le16(cmd_len); + + /* Put buffer length */ + memcpy(buffer + cmd_header_len, &cmd_len, sizeof(t_u32)); + + /* Initialize the ifr structure */ + memset(&ifr, 0, sizeof(ifr)); + strncpy(ifr.ifr_ifrn.ifrn_name, dev_name, strlen(dev_name)); + ifr.ifr_ifru.ifru_data = (void *)cmd; + /* Perform ioctl */ + if (ioctl(sockfd, MLAN_ETH_PRIV, &ifr)) { + perror("ioctl[changroup hostcmd]"); + printf("ERR:Command sending failed!\n"); + return; + } + + if (displayResult) { + dumpCgBuf(pChanGroup->tlv_buffer, (le16_to_cpu(hostcmd->size) + - sizeof(HostCmd_DS_GEN) + - + sizeof(pChanGroup->action))); + } +} + +/** + * @brief Issue a opchan command + * + * @param argc number of arguments + * @param argv A pointer to arguments array + * + * @return MLAN_STATUS_SUCCESS--success, otherwise--fail + */ +int +process_opchan(int argc, char *argv[]) +{ + char line[100]; + char section[80]; + int ln = 0; + t_u8 sectionFound = 0; + int totalTlvBytes = 0; + FILE *fp = NULL; + + int ret = MLAN_STATUS_SUCCESS; + struct ifreq ifr; + t_u8 *buffer = NULL, *pos = NULL; + t_u32 cmd_len = 0, cmd_header_len; + struct eth_priv_cmd *cmd = NULL; + HostCmd_DS_GEN *hostcmd; + HostCmd_DS_OPCHAN_CONFIG *pOpChanConfig; + MrvlIEtypes_ChanControlDesc_t *pCcTlv; + + if ((argc < 3) || (argc > 5)) { + /* 3 arguments for a get, 4 for clear, 5 arguments for a set */ + printf("Invalid number of arguments\n"); + ret = -EOPNOTSUPP; + goto done; + } + + cmd_header_len = strlen(CMD_NXP) + strlen(HOSTCMD); + + buffer = (t_u8 *)malloc(BUFFER_LENGTH); + if (buffer == NULL) { + fprintf(stderr, "Cannot alloc memory\n"); + ret = ENOMEM; + goto done; + } + memset(buffer, 0, BUFFER_LENGTH); + + cmd = (struct eth_priv_cmd *)malloc(sizeof(struct eth_priv_cmd)); + if (!cmd) { + printf("ERR:Cannot allocate buffer for command!\n"); + ret = ENOMEM; + goto done; + } + + /* Fill up buffer */ +#ifdef USERSPACE_32BIT_OVER_KERNEL_64BIT + memset(cmd, 0, sizeof(struct eth_priv_cmd)); + memcpy(&cmd->buf, &buffer, sizeof(buffer)); +#else + cmd->buf = buffer; +#endif + cmd->used_len = 0; + cmd->total_len = BUFFER_LENGTH; + + /* buffer = MRVL_CMD */ + strncpy((char *)buffer, CMD_NXP, strlen(CMD_NXP)); + strncpy((char *)buffer + strlen(CMD_NXP), HOSTCMD, strlen(HOSTCMD)); + + /* buffer = MRVL_CMD */ + hostcmd = (HostCmd_DS_GEN *)(buffer + cmd_header_len + sizeof(t_u32)); + + /* Point after host command header */ + pos = (t_u8 *)hostcmd + S_DS_GEN; + + cmd_len = S_DS_GEN + 2000; + + pOpChanConfig = (HostCmd_DS_OPCHAN_CONFIG *)pos; + + if ((argc == 4) && (strcmp(argv[3], "clear") != 0)) { + /* With 4 arguments cmd must be: mlanutl mlan0 opchan clear */ + printf("Invalid command arguments.\n"); + ret = -EOPNOTSUPP; + goto done; + } else if (argc == 5) { + pOpChanConfig->action = cpu_to_le16(HostCmd_ACT_GEN_SET); + + fp = fopen(argv[3], "r"); + if (fp == NULL) { + fprintf(stderr, "Cannot open file %s\n", argv[3]); + ret = MLAN_STATUS_FAILURE; + goto done; + } + + sprintf(section, "[%s]", argv[4]); + + while (!sectionFound + && mlan_config_get_line(fp, line, sizeof(line), &ln)) { + if (strncmp(line, section, strlen(section)) == 0) { + sectionFound = 1; + break; + } + } + } + + while (sectionFound + && mlan_config_get_line(fp, line, sizeof(line), &ln)) { + + MrvlIEtypes_ChanControlDesc_t ccTlv; + int startFreq; + int chanNum; + int controlFlags; + int actPower; + int mdMinPower; + int mdMaxPower; + int mdPower; + + if (line[0] == '#') { + continue; + } + + if (line[0] == '[') { + break; + } + + sscanf(line, "%d.%d 0x%x %d %d %d %d", + &startFreq, &chanNum, + &controlFlags, + &actPower, &mdMinPower, &mdMaxPower, &mdPower); + + ccTlv.chanDesc.startFreq = cpu_to_le16(startFreq); + ccTlv.chanDesc.chanNum = chanNum; + ccTlv.controlFlags = cpu_to_le16(controlFlags); + ccTlv.actPower = actPower; + ccTlv.mdMinPower = mdMinPower; + ccTlv.mdMaxPower = mdMaxPower; + ccTlv.mdPower = mdPower; + + ccTlv.header.len = + cpu_to_le16(sizeof(ccTlv) - sizeof(ccTlv.header)); + ccTlv.header.type = cpu_to_le16(TLV_TYPE_OPCHAN_CONTROL_DESC); + + memcpy(pOpChanConfig->tlv_buffer + totalTlvBytes, + &ccTlv, sizeof(ccTlv)); + + totalTlvBytes += sizeof(ccTlv); + } + + if (argc == 3) { + pOpChanConfig->action = cpu_to_le16(HostCmd_ACT_GEN_GET); + } else if (argc == 4) { + /* Clears the multidomain learning table only. Does not change the + ** operating channels + */ + pOpChanConfig->action = cpu_to_le16(HostCmd_ACT_GEN_CLEAR); + } + + else if (!sectionFound) { + printf("Section \"%s\" not found\n", argv[4]); + ret = -EFAULT; + goto done; + } + + hostcmd->command = cpu_to_le16(HostCmd_CMD_OPCHAN_CONFIG); + hostcmd->seq_num = 0; + hostcmd->result = 0; + hostcmd->size = cpu_to_le16(sizeof(HostCmd_DS_GEN) + + sizeof(pOpChanConfig->action) + + totalTlvBytes); + + /* Put buffer length */ + memcpy(buffer + cmd_header_len, &cmd_len, sizeof(t_u32)); + + /* Initialize the ifr structure */ + memset(&ifr, 0, sizeof(ifr)); + strncpy(ifr.ifr_ifrn.ifrn_name, dev_name, strlen(dev_name)); + ifr.ifr_ifru.ifru_data = (void *)cmd; + /* Perform ioctl */ + if (ioctl(sockfd, MLAN_ETH_PRIV, &ifr)) { + perror("ioctl[changroup hostcmd]"); + printf("ERR:Command sending failed!\n"); + ret = -EFAULT; + goto done; + } + + totalTlvBytes = (le16_to_cpu(hostcmd->size) + - sizeof(HostCmd_DS_GEN) + - sizeof(pOpChanConfig->action)); + + pCcTlv = (MrvlIEtypes_ChanControlDesc_t *)pOpChanConfig->tlv_buffer; + + while (totalTlvBytes) { + /* Switch to TLV parsing */ + dumpCc(pCcTlv); + pCcTlv++; + totalTlvBytes -= sizeof(MrvlIEtypes_ChanControlDesc_t); + } + +done: + if (fp) + fclose(fp); + if (buffer) + free(buffer); + if (cmd) + free(cmd); + return ret; +} + +/** + * @brief Issue a changroup command + * + * @param argc number of arguments + * @param argv A pointer to arguments array + * + * @return MLAN_STATUS_SUCCESS--success, otherwise--fail + */ +int +process_changroup(int argc, char *argv[]) +{ + int ret = MLAN_STATUS_SUCCESS; + t_u8 *buffer = NULL, *pos = NULL; + t_u32 cmd_header_len; + struct eth_priv_cmd *cmd = NULL; + char line[100]; + char section[80]; + int ln = 0; + t_u8 sectionFound = 0; + int totalTlvBytes = 0; + FILE *fp = NULL; + + HostCmd_DS_OPCHAN_CHANGROUP_CONFIG *pChanGroup; + MrvlIEtypes_ChanGroupControl_t cgTlv; + + puts(""); + + if ((argc != 3) && (argc != 5)) { + /* 3 arguments for a get, 5 arguments for a set */ + ret = -EOPNOTSUPP; + goto done; + } + + cmd_header_len = strlen(CMD_NXP) + strlen(HOSTCMD); + + buffer = (t_u8 *)malloc(BUFFER_LENGTH); + if (buffer == NULL) { + fprintf(stderr, "Cannot alloc memory\n"); + ret = ENOMEM; + goto done; + } + memset(buffer, 0, BUFFER_LENGTH); + + cmd = (struct eth_priv_cmd *)malloc(sizeof(struct eth_priv_cmd)); + if (!cmd) { + printf("ERR:Cannot allocate buffer for command!\n"); + ret = ENOMEM; + goto done; + } + + /* Fill up buffer */ +#ifdef USERSPACE_32BIT_OVER_KERNEL_64BIT + memset(cmd, 0, sizeof(struct eth_priv_cmd)); + memcpy(&cmd->buf, &buffer, sizeof(buffer)); +#else + cmd->buf = buffer; +#endif + cmd->used_len = 0; + cmd->total_len = BUFFER_LENGTH; + + /* buffer = MRVL_CMD */ + strncpy((char *)buffer, CMD_NXP, strlen(CMD_NXP)); + strncpy((char *)buffer + strlen(CMD_NXP), HOSTCMD, strlen(HOSTCMD)); + + pos = (t_u8 *)buffer + cmd_header_len + sizeof(t_u32) + S_DS_GEN; + pChanGroup = (HostCmd_DS_OPCHAN_CHANGROUP_CONFIG *)pos; + + if (argc == 5) { + pChanGroup->action = cpu_to_le16(HostCmd_ACT_GEN_SET); + + fp = fopen(argv[3], "r"); + if (fp == NULL) { + fprintf(stderr, "Cannot open file %s\n", argv[3]); + ret = MLAN_STATUS_FAILURE; + goto done; + } + + sprintf(section, "[%s]", argv[4]); + + while (!sectionFound + && mlan_config_get_line(fp, line, sizeof(line), &ln)) { + if (strncmp(line, section, strlen(section)) == 0) { + sectionFound = 1; + break; + } + } + + while (sectionFound + && mlan_config_get_line(fp, line, sizeof(line), &ln)) { + + int startFreq; + int chanNum; + int chanCount; + int chanGroupBitmap; + int scanMode; + int tlvBytes; + char *ptr; + char *ret; + + memset(&cgTlv, 0x00, sizeof(cgTlv)); + + if (line[0] == '#') { + continue; + } + + if (line[0] == '[') { + break; + } + + sscanf(strstr(line, "0"), + "0x%x 0x%x %d:", + &chanGroupBitmap, &scanMode, &startFreq); + + ptr = strtok_r(line, ":", &ret); + + if (ptr == NULL) { + break; + } + + chanCount = 0; + tlvBytes = sizeof(cgTlv.chanGroupBitmap); + tlvBytes += sizeof(cgTlv.scanMode); + tlvBytes += sizeof(cgTlv.numChan); + + while ((ptr = strtok_r(NULL, ",", &ret)) != NULL) { + sscanf(ptr, "%d", &chanNum); + + cgTlv.chanDesc[chanCount].startFreq = + cpu_to_le16(startFreq); + cgTlv.chanDesc[chanCount].chanNum = chanNum; + tlvBytes += sizeof(MrvlChannelDesc_t); + chanCount++; + } + + memcpy(&cgTlv.scanMode, &scanMode, + sizeof(cgTlv.scanMode)); + cgTlv.chanGroupBitmap = cpu_to_le32(chanGroupBitmap); + cgTlv.numChan = chanCount; + cgTlv.header.len = cpu_to_le16(tlvBytes); + cgTlv.header.type = + cpu_to_le16(TLV_TYPE_OPCHAN_CHANGRP_CTRL); + tlvBytes += sizeof(cgTlv.header); + + memcpy(pChanGroup->tlv_buffer + totalTlvBytes, + &cgTlv, sizeof(cgTlv.header) + tlvBytes); + + totalTlvBytes += tlvBytes; + } + + if (!sectionFound) { + printf("Section \"%s\" not found\n", argv[4]); + ret = MLAN_STATUS_FAILURE; + goto done; + } + + execChanGroupCmd(cmd, totalTlvBytes, FALSE); + } + + if (argc == 3 || sectionFound) { + t_u8 loop; + + totalTlvBytes = sizeof(cgTlv.header); + totalTlvBytes += sizeof(cgTlv.chanGroupBitmap); + totalTlvBytes += sizeof(cgTlv.scanMode); + totalTlvBytes += sizeof(cgTlv.numChan); + + pChanGroup->action = cpu_to_le16(HostCmd_ACT_GEN_GET); + + memset(&cgTlv, 0x00, sizeof(cgTlv)); + cgTlv.header.len = cpu_to_le16(totalTlvBytes); + cgTlv.header.type = cpu_to_le16(TLV_TYPE_OPCHAN_CHANGRP_CTRL); + + for (loop = 0; loop < 4; loop++) { + /* Retrieve 8 channel groups at a time */ + cgTlv.chanGroupBitmap = cpu_to_le32(0xFF << 8 * loop); + + memcpy(pChanGroup->tlv_buffer, + &cgTlv, sizeof(cgTlv.header) + totalTlvBytes); + + execChanGroupCmd(cmd, totalTlvBytes, TRUE); + } + } + + puts(""); + +done: + if (fp) + fclose(fp); + if (buffer) + free(buffer); + if (cmd) + free(cmd); + return ret; +} +#endif + +/* +** Process mlanutl fcontrol command: +** +** mlanutl mlanX fcontrol %d [0xAA 0xBB... ] +** +** Sets and/or retrieves the feature control settings for a specific +** control set (argv[3] decimal argument). +** +*/ +int +process_fcontrol(int argc, char *argv[]) +{ + int ret = MLAN_STATUS_SUCCESS; + struct ifreq ifr; + t_u8 *buffer = NULL, *pos = NULL; + t_u32 cmd_len = 0, cmd_header_len; + struct eth_priv_cmd *cmd = NULL; + t_u8 idx; + HostCmd_DS_GEN *hostcmd; + HostCmd_DS_OFFLOAD_FEATURE_CONTROL *pFcontrol; + + cmd_header_len = strlen(CMD_NXP) + strlen(HOSTCMD); + + buffer = (t_u8 *)malloc(BUFFER_LENGTH); + if (buffer == NULL) { + fprintf(stderr, "Cannot alloc memory\n"); + ret = ENOMEM; + goto done; + } + memset(buffer, 0, BUFFER_LENGTH); + + cmd = (struct eth_priv_cmd *)malloc(sizeof(struct eth_priv_cmd)); + if (!cmd) { + printf("ERR:Cannot allocate buffer for command!\n"); + ret = ENOMEM; + goto done; + } + + /* Fill up buffer */ +#ifdef USERSPACE_32BIT_OVER_KERNEL_64BIT + memset(cmd, 0, sizeof(struct eth_priv_cmd)); + memcpy(&cmd->buf, &buffer, sizeof(buffer)); +#else + cmd->buf = buffer; +#endif + cmd->used_len = 0; + cmd->total_len = BUFFER_LENGTH; + + /* buffer = MRVL_CMD */ + strncpy((char *)buffer, CMD_NXP, strlen(CMD_NXP)); + strncpy((char *)buffer + strlen(CMD_NXP), HOSTCMD, strlen(HOSTCMD)); + + /* buffer = MRVL_CMD */ + hostcmd = (HostCmd_DS_GEN *)(buffer + cmd_header_len + sizeof(t_u32)); + + /* Point after host command header */ + pos = (t_u8 *)hostcmd + S_DS_GEN; + + pFcontrol = (HostCmd_DS_OFFLOAD_FEATURE_CONTROL *)pos; + + if (argc < 4) { + printf("Wrong number of arguments\n"); + ret = -EINVAL; + goto done; + } + + pFcontrol->controlSelect = atoi(argv[3]); + cmd_len = S_DS_GEN + sizeof(pFcontrol->controlSelect); + + for (idx = 4; idx < argc; idx++) { + pFcontrol->controlBitmap[idx - 4] = a2hex_or_atoi(argv[idx]); + cmd_len++; + } + + hostcmd->command = cpu_to_le16(HostCmd_CMD_OFFLOAD_FEATURE_CONTROL); + hostcmd->size = cpu_to_le16(cmd_len); + hostcmd->seq_num = 0; + hostcmd->result = 0; + + /* Put buffer length */ + memcpy(buffer + cmd_header_len, &cmd_len, sizeof(t_u32)); + + /* Initialize the ifr structure */ + memset(&ifr, 0, sizeof(ifr)); + strncpy(ifr.ifr_ifrn.ifrn_name, dev_name, strlen(dev_name)); + ifr.ifr_ifru.ifru_data = (void *)cmd; + /* Perform ioctl */ + if (ioctl(sockfd, MLAN_ETH_PRIV, &ifr)) { + perror("ioctl[fcontrol hostcmd]"); + printf("ERR:Command sending failed!\n"); + ret = -EFAULT; + goto done; + } + + cmd_len = (le16_to_cpu(hostcmd->size) - sizeof(HostCmd_DS_GEN)); + + printf("Control[%d]", pFcontrol->controlSelect); + cmd_len--; + + for (idx = 0; idx < cmd_len; idx++) { + printf("\t0x%02x", pFcontrol->controlBitmap[idx]); + } + + printf("\n"); + +done: + if (buffer) + free(buffer); + if (cmd) + free(cmd); + return ret; +} + +/* +** Process mlanutl iapp command: +** +** mlanutl mlanX iapp 0xAA 0xBB [0x... 0x.. ] +** +** 0xAA = IAPP type +** 0xBB = IAPP subtype +** 0x.. = Remaning bytes are iapp data +** +*/ +int +process_iapp(int argc, char *argv[]) +{ + int ret = MLAN_STATUS_SUCCESS; + struct ifreq ifr; + t_u8 *buffer = NULL, *pos = NULL; + t_u32 cmd_len = 0, cmd_header_len; + struct eth_priv_cmd *cmd = NULL; + t_u8 idx; + t_u8 fixlen; + HostCmd_DS_GEN *hostcmd; + HostCmd_DS_IAPP_PROXY *pIappProxy; + + cmd_header_len = strlen(CMD_NXP) + strlen(HOSTCMD); + + buffer = (t_u8 *)malloc(BUFFER_LENGTH); + if (buffer == NULL) { + fprintf(stderr, "Cannot alloc memory\n"); + ret = ENOMEM; + goto done; + } + memset(buffer, 0, BUFFER_LENGTH); + + cmd = (struct eth_priv_cmd *)malloc(sizeof(struct eth_priv_cmd)); + if (!cmd) { + printf("ERR:Cannot allocate buffer for command!\n"); + ret = ENOMEM; + goto done; + } + + /* Fill up buffer */ +#ifdef USERSPACE_32BIT_OVER_KERNEL_64BIT + memset(cmd, 0, sizeof(struct eth_priv_cmd)); + memcpy(&cmd->buf, &buffer, sizeof(buffer)); +#else + cmd->buf = buffer; +#endif + cmd->used_len = 0; + cmd->total_len = BUFFER_LENGTH; + + /* buffer = MRVL_CMD */ + strncpy((char *)buffer, CMD_NXP, strlen(CMD_NXP)); + strncpy((char *)buffer + strlen(CMD_NXP), HOSTCMD, strlen(HOSTCMD)); + + /* buffer = MRVL_CMD */ + hostcmd = (HostCmd_DS_GEN *)(buffer + cmd_header_len + sizeof(t_u32)); + + /* Point after host command header */ + pos = (t_u8 *)hostcmd + S_DS_GEN; + + cmd_len = S_DS_GEN + sizeof(HostCmd_DS_IAPP_PROXY); + + pIappProxy = (HostCmd_DS_IAPP_PROXY *)pos; + + if (argc < 6) { + printf("Wrong number of arguments\n"); + ret = -EINVAL; + } + + memset(pIappProxy, 0x00, sizeof(HostCmd_DS_IAPP_PROXY)); + + pIappProxy->iappType = a2hex_or_atoi(argv[4]); + pIappProxy->iappSubType = a2hex_or_atoi(argv[5]); + + /* Fixed len portions of command */ + fixlen = (S_DS_GEN + sizeof(HostCmd_DS_IAPP_PROXY) + - sizeof(pIappProxy->iappData)); + + pIappProxy->timeout_ms = cpu_to_le32(a2hex_or_atoi(argv[3])); + + for (idx = 6; idx < argc; idx++) { + pIappProxy->iappData[idx - 6] = a2hex_or_atoi(argv[idx]); + pIappProxy->iappDataLen++; + } + + hostcmd->command = cpu_to_le16(HostCmd_CMD_IAPP_PROXY); + hostcmd->size = cpu_to_le16(fixlen + pIappProxy->iappDataLen); + hostcmd->seq_num = 0; + hostcmd->result = 0; + + pIappProxy->iappDataLen = cpu_to_le32(pIappProxy->iappDataLen); + /* Put buffer length */ + memcpy(buffer + cmd_header_len, &cmd_len, sizeof(t_u32)); + + /* Initialize the ifr structure */ + memset(&ifr, 0, sizeof(ifr)); + strncpy(ifr.ifr_ifrn.ifrn_name, dev_name, strlen(dev_name)); + ifr.ifr_ifru.ifru_data = (void *)cmd; + /* Perform ioctl */ + if (ioctl(sockfd, MLAN_ETH_PRIV, &ifr)) { + perror("ioctl[iapp hostcmd]"); + printf("ERR:Command sending failed!\n"); + ret = -EFAULT; + goto done; + } + + printf("\nResult: %d\n", le32_to_cpu(pIappProxy->commandResult)); + printf("Type: 0x%02x\n", pIappProxy->iappType); + printf("SubType: 0x%02x\n", pIappProxy->iappSubType); + + printf("IappData: "); + hexdump(NULL, pIappProxy->iappData, + le32_to_cpu(pIappProxy->iappDataLen), ' '); + printf("\n\n"); + +done: + if (buffer) + free(buffer); + if (cmd) + free(cmd); + return ret; +} + +/** + * @brief Issue a rf tx power command + * + * @param argc number of arguments + * @param argv A pointer to arguments array + * + * @return MLAN_STATUS_SUCCESS--success, otherwise--fail + */ +int +process_rf_tx_power(int argc, char *argv[]) +{ + int ret = MLAN_STATUS_SUCCESS; + struct ifreq ifr; + t_u8 *buffer = NULL, *pos = NULL; + t_u32 cmd_len = 0, cmd_header_len; + struct eth_priv_cmd *cmd = NULL; + HostCmd_DS_GEN *hostcmd; + HostCmd_DS_802_11_RF_TX_POWER *pRfTxPower; + + cmd_header_len = strlen(CMD_NXP) + strlen(HOSTCMD); + + buffer = (t_u8 *)malloc(BUFFER_LENGTH); + if (buffer == NULL) { + fprintf(stderr, "Cannot alloc memory\n"); + ret = ENOMEM; + goto done; + } + memset(buffer, 0, BUFFER_LENGTH); + + cmd = (struct eth_priv_cmd *)malloc(sizeof(struct eth_priv_cmd)); + if (!cmd) { + printf("ERR:Cannot allocate buffer for command!\n"); + ret = ENOMEM; + goto done; + } + + /* Fill up buffer */ +#ifdef USERSPACE_32BIT_OVER_KERNEL_64BIT + memset(cmd, 0, sizeof(struct eth_priv_cmd)); + memcpy(&cmd->buf, &buffer, sizeof(buffer)); +#else + cmd->buf = buffer; +#endif + cmd->used_len = 0; + cmd->total_len = BUFFER_LENGTH; + + /* buffer = MRVL_CMD */ + strncpy((char *)buffer, CMD_NXP, strlen(CMD_NXP)); + strncpy((char *)buffer + strlen(CMD_NXP), HOSTCMD, strlen(HOSTCMD)); + + /* buffer = MRVL_CMD */ + hostcmd = (HostCmd_DS_GEN *)(buffer + cmd_header_len + sizeof(t_u32)); + + /* Point after host command header */ + pos = (t_u8 *)hostcmd + S_DS_GEN; + + cmd_len = S_DS_GEN + sizeof(HostCmd_DS_802_11_RF_TX_POWER); + + pRfTxPower = (HostCmd_DS_802_11_RF_TX_POWER *)pos; + + memset(pRfTxPower, 0x00, sizeof(HostCmd_DS_802_11_RF_TX_POWER)); + + hostcmd->command = cpu_to_le16(HostCmd_CMD_802_11_RF_TX_POWER); + hostcmd->size = cpu_to_le16(cmd_len); + hostcmd->seq_num = 0; + hostcmd->result = 0; + + /* Put buffer length */ + memcpy(buffer + cmd_header_len, &cmd_len, sizeof(t_u32)); + + /* Initialize the ifr structure */ + memset(&ifr, 0, sizeof(ifr)); + strncpy(ifr.ifr_ifrn.ifrn_name, dev_name, strlen(dev_name)); + ifr.ifr_ifru.ifru_data = (void *)cmd; + /* Perform ioctl */ + if (ioctl(sockfd, MLAN_ETH_PRIV, &ifr)) { + perror("ioctl[hostcmd]"); + printf("ERR:Command sending failed!\n"); + ret = -EFAULT; + goto done; + } + + printf("\n"); + printf(" MinPower: %2d\n", pRfTxPower->min_power); + printf(" MaxPower: %2d\n", pRfTxPower->max_power); + printf(" Current: %2d\n", le16_to_cpu(pRfTxPower->current_level)); + printf("\n"); + +done: + if (buffer) + free(buffer); + if (cmd) + free(cmd); + return ret; +} + +/** + * @brief Issue a authenticate command + * + * @param argc number of arguments + * @param argv A pointer to arguments array + * + * @return MLAN_STATUS_SUCCESS--success, otherwise--fail + */ +int +process_authenticate(int argc, char *argv[]) +{ + int ret = MLAN_STATUS_SUCCESS; + struct ifreq ifr; + t_u8 *buffer = NULL, *pos = NULL; + t_u32 cmd_len = 0, cmd_header_len; + struct eth_priv_cmd *cmd = NULL; + HostCmd_DS_GEN *hostcmd; + HostCmd_DS_802_11_AUTHENTICATE *pAuth; + unsigned int mac[ETH_ALEN]; + int tmpIdx; + + if (argc != 4) { + printf("Wrong number of arguments\n"); + ret = -EINVAL; + goto done; + } + + cmd_header_len = strlen(CMD_NXP) + strlen(HOSTCMD); + + buffer = (t_u8 *)malloc(BUFFER_LENGTH); + if (buffer == NULL) { + fprintf(stderr, "Cannot alloc memory\n"); + ret = ENOMEM; + goto done; + } + memset(buffer, 0, BUFFER_LENGTH); + + cmd = (struct eth_priv_cmd *)malloc(sizeof(struct eth_priv_cmd)); + if (!cmd) { + printf("ERR:Cannot allocate buffer for command!\n"); + ret = ENOMEM; + goto done; + } + + /* Fill up buffer */ +#ifdef USERSPACE_32BIT_OVER_KERNEL_64BIT + memset(cmd, 0, sizeof(struct eth_priv_cmd)); + memcpy(&cmd->buf, &buffer, sizeof(buffer)); +#else + cmd->buf = buffer; +#endif + cmd->used_len = 0; + cmd->total_len = BUFFER_LENGTH; + + /* buffer = MRVL_CMD */ + strncpy((char *)buffer, CMD_NXP, strlen(CMD_NXP)); + strncpy((char *)buffer + strlen(CMD_NXP), HOSTCMD, strlen(HOSTCMD)); + + /* buffer = MRVL_CMD */ + hostcmd = (HostCmd_DS_GEN *)(buffer + cmd_header_len + sizeof(t_u32)); + + /* Point after host command header */ + pos = (t_u8 *)hostcmd + S_DS_GEN; + + cmd_len = S_DS_GEN + sizeof(HostCmd_DS_802_11_AUTHENTICATE); + + pAuth = (HostCmd_DS_802_11_AUTHENTICATE *)pos; + + memset(pAuth, 0x00, sizeof(HostCmd_DS_802_11_AUTHENTICATE)); + + sscanf(argv[3], + "%2x:%2x:%2x:%2x:%2x:%2x", + mac + 0, mac + 1, mac + 2, mac + 3, mac + 4, mac + 5); + + for (tmpIdx = 0; (unsigned int)tmpIdx < NELEMENTS(mac); tmpIdx++) { + pAuth->MacAddr[tmpIdx] = (t_u8)mac[tmpIdx]; + } + + hostcmd->command = cpu_to_le16(HostCmd_CMD_802_11_AUTHENTICATE); + hostcmd->size = cpu_to_le16(cmd_len); + hostcmd->seq_num = 0; + hostcmd->result = 0; + + /* Put buffer length */ + memcpy(buffer + cmd_header_len, &cmd_len, sizeof(t_u32)); + + /* Initialize the ifr structure */ + memset(&ifr, 0, sizeof(ifr)); + strncpy(ifr.ifr_ifrn.ifrn_name, dev_name, strlen(dev_name)); + ifr.ifr_ifru.ifru_data = (void *)cmd; + /* Perform ioctl */ + if (ioctl(sockfd, MLAN_ETH_PRIV, &ifr)) { + perror("ioctl[hostcmd]"); + printf("ERR:Command sending failed!\n"); + ret = -EFAULT; + goto done; + } + +done: + if (buffer) + free(buffer); + if (cmd) + free(cmd); + return ret; +} + +static void +display_channel(void) +{ + FILE *tmpfile; + char result[200]; + char cmdStr[50]; + int ghz, mhz, chan; + + puts("\n"); + + sprintf(cmdStr, "iwlist %s chan", dev_name); + + tmpfile = popen(cmdStr, "r"); + + if (tmpfile == NULL) { + perror("mlanutl: iwlist failed to get current channel"); + } else { + while (fgets(result, sizeof(result), tmpfile)) { + if ((sscanf + (result, " Current Frequency=%d.%d ", &ghz, + &mhz) == 2) || + (sscanf + (result, " Current Frequency:%d.%d ", &ghz, + &mhz) == 2)) { + if (mhz < 10) { + mhz *= 100; + } else if (mhz < 100) { + mhz *= 10; + } + + chan = ghz * 1000 + mhz; + if (chan > 5000) { + chan -= 5000; + chan /= 5; + } else if (chan == 2484) { + chan = 14; + } else { + chan -= 2407; + chan /= 5; + } + printf(" Channel: %3d [%d.%d GHz]\n", chan, + ghz, mhz); + } + } + pclose(tmpfile); + } +} + +static char * +get_ratestr(int txRate) +{ + char *pStr; + + switch (txRate) { + case 0: + pStr = "1"; + break; + case 1: + pStr = "2"; + break; + case 2: + pStr = "5.5"; + break; + case 3: + pStr = "11"; + break; + case 4: + pStr = "6"; + break; + case 5: + pStr = "9"; + break; + case 6: + pStr = "12"; + break; + case 7: + pStr = "18"; + break; + case 8: + pStr = "24"; + break; + case 9: + pStr = "36"; + break; + case 10: + pStr = "48"; + break; + case 11: + pStr = "54"; + break; + case 12: + pStr = "MCS0"; + break; + case 13: + pStr = "MCS1"; + break; + case 14: + pStr = "MCS2"; + break; + case 15: + pStr = "MCS3"; + break; + case 16: + pStr = "MCS4"; + break; + case 17: + pStr = "MCS5"; + break; + case 18: + pStr = "MCS6"; + break; + case 19: + pStr = "MCS7"; + break; + + case 140: + pStr = "MCS0"; + break; + case 141: + pStr = "MCS1"; + break; + case 142: + pStr = "MCS2"; + break; + case 143: + pStr = "MCS3"; + break; + case 144: + pStr = "MCS4"; + break; + case 145: + pStr = "MCS5"; + break; + case 146: + pStr = "MCS6"; + break; + case 147: + pStr = "MCS7"; + break; + + default: + pStr = "Unkn"; + break; + } + + return pStr; +} + +typedef struct { + int rate; + int min; + int max; + +} RatePower_t; + +static int +get_txpwrcfg(RatePower_t ratePower[]) +{ + FILE *tmpfile; + char result[300]; + char cmdStr[50]; + int counter = 0; + char *pBuf; + int r1 = 0, r2 = 0, min = 0, max = 0, rate = 0; + int rateIdx = 0; + + sprintf(cmdStr, "iwpriv %s txpowercfg", dev_name); + + tmpfile = popen(cmdStr, "r"); + + if (tmpfile == NULL) { + perror("mlanutl: iwpriv failed to get txpowercfg"); + } else { + while (fgets(result, sizeof(result), tmpfile)) { + pBuf = strtok(result, ": "); + + while (pBuf != NULL) { + switch (counter % 5) { + case 0: + r1 = atoi(pBuf); + break; + + case 1: + r2 = atoi(pBuf); + break; + + case 2: + min = atoi(pBuf); + break; + + case 3: + max = atoi(pBuf); + break; + + case 4: + for (rate = r1; rate <= r2; rate++) { + ratePower[rateIdx].rate = rate; + ratePower[rateIdx].min = min; + ratePower[rateIdx].max = max; + rateIdx++; + } + break; + } + + if (isdigit(*pBuf)) { + counter++; + } + pBuf = strtok(NULL, ": "); + } + } + pclose(tmpfile); + } + + return rateIdx; +} + +static void +rateSort(RatePower_t rateList[], int numRates) +{ + int inc, i, j; + RatePower_t tmp; + + inc = 3; + + while (inc > 0) { + for (i = 0; i < numRates; i++) { + j = i; + memcpy(&tmp, &rateList[i], sizeof(RatePower_t)); + + while ((j >= inc) && + (rateList[j - inc].rate > tmp.rate)) { + memcpy(&rateList[j], &rateList[j - inc], + sizeof(RatePower_t)); + j -= inc; + } + + memcpy(&rateList[j], &tmp, sizeof(RatePower_t)); + } + + if (inc >> 1) { + inc >>= 1; + } else if (inc == 1) { + inc = 0; + } else { + inc = 1; + } + } +} + +typedef struct { + int rate; + int modGroup; + +} RateModPair_t; + +/* +** +** ModulationGroups +** 0: CCK (1,2,5.5,11 Mbps) +** 1: OFDM (6,9,12,18 Mbps) +** 2: OFDM (24,36 Mbps) +** 3: OFDM (48,54 Mbps) +** 4: HT20 (0,1,2) +** 5: HT20 (3,4) +** 6: HT20 (5,6,7) +** 7: HT40 (0,1,2) +** 8: HT40 (3,4) +** 9: HT40 (5,6,7) +*/ + +static RateModPair_t rateModPairs[] = { + {0, 0}, /* 1 */ + {1, 0}, /* 2 */ + {2, 0}, /* 5.5 */ + {3, 0}, /* 11 */ + {4, 1}, /* 6 */ + {5, 1}, /* 9 */ + {6, 1}, /* 12 */ + {7, 1}, /* 18 */ + {8, 2}, /* 24 */ + {9, 2}, /* 36 */ + {10, 3}, /* 48 */ + {11, 3}, /* 54 */ + {12, 4}, /* MCS0 */ + {13, 4}, /* MCS1 */ + {14, 4}, /* MCS2 */ + {15, 5}, /* MCS3 */ + {16, 5}, /* MCS4 */ + {17, 6}, /* MCS5 */ + {18, 6}, /* MCS6 */ + {19, 6}, /* MCS7 */ + + {140, 7}, /* MCS0 */ + {141, 7}, /* MCS1 */ + {142, 7}, /* MCS2 */ + {143, 8}, /* MCS3 */ + {144, 8}, /* MCS4 */ + {145, 9}, /* MCS5 */ + {146, 9}, /* MCS6 */ + {147, 9}, /* MCS7 */ +}; + +int +process_chantrpcdisp(int startRate, int endRate) +{ + int ret = MLAN_STATUS_SUCCESS; + struct ifreq ifr; + t_u8 *buffer = NULL, *pos = NULL; + t_u32 cmd_len = 0, cmd_header_len; + struct eth_priv_cmd *cmd = NULL; + HostCmd_DS_GEN *hostcmd; + HostCmd_DS_CHAN_TRPC_CONFIG *pChanTrpc; + MrvlIEtypes_ChanTrpcCfg_t *pChanTrpcTlv; + int totalTlvBytes = 0; + + cmd_header_len = strlen(CMD_NXP) + strlen(HOSTCMD); + + buffer = (t_u8 *)malloc(BUFFER_LENGTH); + if (buffer == NULL) { + fprintf(stderr, "Cannot alloc memory\n"); + ret = ENOMEM; + goto done; + } + memset(buffer, 0, BUFFER_LENGTH); + + cmd = (struct eth_priv_cmd *)malloc(sizeof(struct eth_priv_cmd)); + if (!cmd) { + printf("ERR:Cannot allocate buffer for command!\n"); + ret = ENOMEM; + goto done; + } + + /* Fill up buffer */ +#ifdef USERSPACE_32BIT_OVER_KERNEL_64BIT + memset(cmd, 0, sizeof(struct eth_priv_cmd)); + memcpy(&cmd->buf, &buffer, sizeof(buffer)); +#else + cmd->buf = buffer; +#endif + cmd->used_len = 0; + cmd->total_len = BUFFER_LENGTH; + + /* buffer = MRVL_CMD */ + strncpy((char *)buffer, CMD_NXP, strlen(CMD_NXP)); + strncpy((char *)buffer + strlen(CMD_NXP), HOSTCMD, strlen(HOSTCMD)); + + /* buffer = MRVL_CMD */ + hostcmd = (HostCmd_DS_GEN *)(buffer + cmd_header_len + sizeof(t_u32)); + + /* Point after host command header */ + pos = (t_u8 *)hostcmd + S_DS_GEN; + + pChanTrpc = (HostCmd_DS_CHAN_TRPC_CONFIG *)pos; + pChanTrpc->action = cpu_to_le16(HostCmd_ACT_GEN_GET); + + cmd_len = S_DS_GEN + sizeof(pChanTrpc->action); + hostcmd->command = cpu_to_le16(HostCmd_CMD_CHAN_TRPC_CONFIG); + hostcmd->size = cpu_to_le16(cmd_len); + hostcmd->seq_num = 0; + hostcmd->result = 0; + + /* Put buffer length */ + memcpy(buffer + cmd_header_len, &cmd_len, sizeof(t_u32)); + + /* Initialize the ifr structure */ + memset(&ifr, 0, sizeof(ifr)); + strncpy(ifr.ifr_ifrn.ifrn_name, dev_name, strlen(dev_name)); + ifr.ifr_ifru.ifru_data = (void *)cmd; + /* Perform ioctl */ + if (ioctl(sockfd, MLAN_ETH_PRIV, &ifr)) { + perror("ioctl[chantrpc hostcmd]"); + printf("ERR:Command sending failed!\n"); + ret = -EFAULT; + goto done; + } + + totalTlvBytes = (le16_to_cpu(hostcmd->size) + - sizeof(HostCmd_DS_GEN) + - sizeof(pChanTrpc->action) + - sizeof(pChanTrpc->reserved)); + + pChanTrpcTlv = (MrvlIEtypes_ChanTrpcCfg_t *)pChanTrpc->tlv_buffer; + + while (totalTlvBytes) { + int tlvSize, numModGroups, idx, modIdx, numOut; + + /* Switch to TLV parsing */ + printf("%4d.%-3d ", + le16_to_cpu(pChanTrpcTlv->chanDesc.startFreq), + pChanTrpcTlv->chanDesc.chanNum); + + numOut = 0; + + tlvSize = (le16_to_cpu(pChanTrpcTlv->header.len) + + sizeof(pChanTrpcTlv->header)); + + numModGroups = (le16_to_cpu(pChanTrpcTlv->header.len) + - sizeof(pChanTrpcTlv->chanDesc)); + numModGroups /= sizeof(pChanTrpcTlv->chanTrpcEntry[0]); + + for (idx = 0; idx < NELEMENTS(rateModPairs); idx++) { + if ((rateModPairs[idx].rate >= startRate) && + (rateModPairs[idx].rate <= endRate)) { + for (modIdx = 0; modIdx < numModGroups; + modIdx++) { + if (rateModPairs[idx].modGroup == + pChanTrpcTlv->chanTrpcEntry[modIdx]. + modGroup) { + printf("%*d", + (numOut == 0) ? 3 : 6, + pChanTrpcTlv-> + chanTrpcEntry[modIdx]. + txPower); + numOut++; + } + } + + if (numOut == 0) { + printf(" -- "); + } + } + } + + puts(""); + + pChanTrpcTlv = + (MrvlIEtypes_ChanTrpcCfg_t *)((t_u8 *)pChanTrpcTlv + + tlvSize); + totalTlvBytes -= tlvSize; + } + +done: + if (buffer) + free(buffer); + if (cmd) + free(cmd); + return ret; +} + +/** + * @brief Issue a tx power display command + * + * @param argc number of arguments + * @param argv A pointer to arguments array + * + * @return MLAN_STATUS_SUCCESS--success, otherwise--fail + */ +int +process_txpowdisp(int argc, char *argv[]) +{ + int ret = MLAN_STATUS_SUCCESS; + int rateIdx, rates; + int connected; + struct ifreq ifr; + t_u8 *buffer = NULL, *pos = NULL; + t_u32 cmd_len = 0, cmd_header_len; + struct eth_priv_cmd *cmd = NULL; + HostCmd_DS_GEN *hostcmd; + HostCmd_DS_802_11_RF_TX_POWER *pRfTxPower; + RatePower_t ratePower[50]; + + cmd_header_len = strlen(CMD_NXP) + strlen(HOSTCMD); + + buffer = (t_u8 *)malloc(BUFFER_LENGTH); + if (buffer == NULL) { + fprintf(stderr, "Cannot alloc memory\n"); + ret = ENOMEM; + goto done; + } + memset(buffer, 0, BUFFER_LENGTH); + + cmd = (struct eth_priv_cmd *)malloc(sizeof(struct eth_priv_cmd)); + if (!cmd) { + printf("ERR:Cannot allocate buffer for command!\n"); + ret = ENOMEM; + goto done; + } + + /* Fill up buffer */ +#ifdef USERSPACE_32BIT_OVER_KERNEL_64BIT + memset(cmd, 0, sizeof(struct eth_priv_cmd)); + memcpy(&cmd->buf, &buffer, sizeof(buffer)); +#else + cmd->buf = buffer; +#endif + cmd->used_len = 0; + cmd->total_len = BUFFER_LENGTH; + + /* buffer = MRVL_CMD */ + strncpy((char *)buffer, CMD_NXP, strlen(CMD_NXP)); + strncpy((char *)buffer + strlen(CMD_NXP), HOSTCMD, strlen(HOSTCMD)); + + /* buffer = MRVL_CMD */ + hostcmd = (HostCmd_DS_GEN *)(buffer + cmd_header_len + sizeof(t_u32)); + + /* Point after host command header */ + pos = (t_u8 *)hostcmd + S_DS_GEN; + + cmd_len = S_DS_GEN + sizeof(HostCmd_DS_802_11_RF_TX_POWER); + + pRfTxPower = (HostCmd_DS_802_11_RF_TX_POWER *)pos; + + memset(pRfTxPower, 0x00, sizeof(HostCmd_DS_802_11_RF_TX_POWER)); + + hostcmd->command = cpu_to_le16(HostCmd_CMD_802_11_RF_TX_POWER); + hostcmd->size = cpu_to_le16(cmd_len); + hostcmd->seq_num = 0; + hostcmd->result = 0; + + /* Put buffer length */ + memcpy(buffer + cmd_header_len, &cmd_len, sizeof(t_u32)); + + /* Initialize the ifr structure */ + memset(&ifr, 0, sizeof(ifr)); + strncpy(ifr.ifr_ifrn.ifrn_name, dev_name, strlen(dev_name)); + ifr.ifr_ifru.ifru_data = (void *)cmd; + /* Perform ioctl */ + if (ioctl(sockfd, MLAN_ETH_PRIV, &ifr)) { + perror("ioctl[hostcmd]"); + printf("ERR:Command sending failed!\n"); + ret = -EFAULT; + goto done; + } + + connected = le16_to_cpu(pRfTxPower->current_level) ? TRUE : FALSE; + + if (connected) { + display_channel(); + + printf("\n"); + printf(" MinPower: %2d\n", pRfTxPower->min_power); + printf(" MaxPower: %2d\n", pRfTxPower->max_power); + printf(" Current: %2d\n", + le16_to_cpu(pRfTxPower->current_level)); + printf("\n"); + } + + rates = get_txpwrcfg(ratePower); + + puts(""); + + rateSort(ratePower, rates); + + printf("20MHz:"); + + for (rateIdx = 0; rateIdx < 12; rateIdx++) { + printf("%6s", get_ratestr(ratePower[rateIdx].rate)); + } + + printf("\n---------------------------------------" + "----------------------------------------\n%s", + connected ? "Active" : "Max "); + + for (rateIdx = 0; rateIdx < 12; rateIdx++) { + printf("%6d", ratePower[rateIdx].max); + } + + if (!connected) { + printf("\n---------------------------------------" + "----------------------------------------\n"); + + process_chantrpcdisp(ratePower[0].rate, ratePower[12 - 1].rate); + } + + puts("\n"); + + /* + ** MCS0 -> MCS7 + */ + + printf("20MHz:"); + + for (rateIdx = 12; rateIdx < 20; rateIdx++) { + printf("%6s", get_ratestr(ratePower[rateIdx].rate)); + } + + printf("\n---------------------------------------" + "----------------------------------------\n%s", + connected ? "Active" : "Max "); + + for (rateIdx = 12; rateIdx < 20; rateIdx++) { + printf("%6d", ratePower[rateIdx].max); + } + + if (!connected) { + printf("\n---------------------------------------" + "----------------------------------------\n"); + + process_chantrpcdisp(ratePower[12].rate, + ratePower[20 - 1].rate); + } + + puts("\n"); + + /* + ** MCS0 -> MCS7 @ 40MHz + */ + + printf("40MHz:"); + + for (rateIdx = 20; rateIdx < rates; rateIdx++) { + printf("%6s", get_ratestr(ratePower[rateIdx].rate)); + } + + printf("\n---------------------------------------" + "----------------------------------------\n%s", + connected ? "Active" : "Max "); + + for (rateIdx = 20; rateIdx < rates; rateIdx++) { + printf("%6d", ratePower[rateIdx].max); + } + + if (!connected) { + printf("\n---------------------------------------" + "----------------------------------------\n"); + + process_chantrpcdisp(ratePower[20].rate, + ratePower[rates - 1].rate); + } + + puts("\n"); + +done: + if (buffer) + free(buffer); + if (cmd) + free(cmd); + return ret; +} diff --git a/mxm_wifiex/wlan_src/mapp/mlanutl/mlanoffload.h b/mxm_wifiex/wlan_src/mapp/mlanutl/mlanoffload.h new file mode 100644 index 0000000..8444bbc --- /dev/null +++ b/mxm_wifiex/wlan_src/mapp/mlanutl/mlanoffload.h @@ -0,0 +1,519 @@ +/** @file mlanoffload.h + * + * @brief This files contains mlanutl offload command handling. + * + * + * Copyright 2014-2020 NXP + * + * NXP CONFIDENTIAL + * The source code contained or described herein and all documents related to + * the source code (Materials) are owned by NXP, its + * suppliers and/or its licensors. Title to the Materials remains with NXP, + * its suppliers and/or its licensors. The Materials contain + * trade secrets and proprietary and confidential information of NXP, its + * suppliers and/or its licensors. The Materials are protected by worldwide copyright + * and trade secret laws and treaty provisions. No part of the Materials may be + * used, copied, reproduced, modified, published, uploaded, posted, + * transmitted, distributed, or disclosed in any way without NXP's prior + * express written permission. + * + * No license under any patent, copyright, trade secret or other intellectual + * property right is granted to or conferred upon you by disclosure or delivery + * of the Materials, either expressly, by implication, inducement, estoppel or + * otherwise. Any license under such intellectual property rights must be + * express and approved by NXP in writing. + * + */ +/************************************************************************ +Change log: + 08/11/2009: initial version +************************************************************************/ + +#ifndef _MLANOFFLOAD_H_ +#define _MLANOFFLOAD_H_ + +#ifndef MAX +/** Find maximum value */ +#define MAX(a, b) ((a) > (b) ? (a) : (b)) +#endif /* MAX */ + +/** Key length */ +#define KEY_LEN 32 +/** Phrase length */ +#define PHRASE_LEN 32 +/** WEP Key count */ +#define WEP_KEY_CNT 4 + +/* Bitmap for OFFLoad Enable - Feature*/ +#ifdef BIG_ENDIAN_SUPPORT +/** Roaming Feature */ +#define PROFILE_DB_FEATURE_ROAMING 0x8000 +/** CCX Feature */ +#define PROFILE_DB_FEATURE_CCX 0x4000 +/** UNUSED Feature */ +#define PROFILE_DB_FEATURE_UNUSED 0x2000 +/** adhoc/infra mode */ +#define PROFILE_DB_FEATURE_MODE 0x1000 +#else +/** Roaming Feature */ +#define PROFILE_DB_FEATURE_ROAMING 0x0001 +/** CCX Feature */ +#define PROFILE_DB_FEATURE_CCX 0x0002 +/** UNUSED Feature */ +#define PROFILE_DB_FEATURE_UNUSED 0x0004 +/** adhoc/infra mode */ +#define PROFILE_DB_FEATURE_MODE 0x0008 +#endif + +/* Bitmap for profile AKMP Support */ +#ifdef BIG_ENDIAN_SUPPORT +/** Key Management EAP */ +#define PROFILE_DB_KEY_MGMT_IEEE8021X 0x8000 +/** Key Management PSK */ +#define PROFILE_DB_KEY_MGMT_PSK 0x4000 +/** Key Management NONE */ +#define PROFILE_DB_KEY_MGMT_NONE 0x2000 +/** Key Management CCKM */ +#define PROFILE_DB_KEY_MGMT_CCKM 0x1000 +/** Key Management UNUSED */ +#define PROFILE_DB_KEY_MGMT_UNUSED 0x0800 +/** Key Management FT 802.1x */ +#define PROFILE_DB_KEY_MGMT_FT_IEEE8021X 0x0400 +/** Key Management FT PSK */ +#define PROFILE_DB_KEY_MGMT_FT_PSK 0x0200 +/** Key Management SHA256 802.1x */ +#define PROFILE_DB_KEY_MGMT_SHA256_IEEE8021X 0x0100 +/** Key Management SHA256 PSK*/ +#define PROFILE_DB_KEY_MGMT_SHA256_PSK 0x0080 +#else +/** Key Management EAP */ +#define PROFILE_DB_KEY_MGMT_IEEE8021X 0x0001 +/** Key Management PSK */ +#define PROFILE_DB_KEY_MGMT_PSK 0x0002 +/** Key Management NONE */ +#define PROFILE_DB_KEY_MGMT_NONE 0x0004 +/** Key Management CCKM */ +#define PROFILE_DB_KEY_MGMT_CCKM 0x0008 +/** Key Management UNUSED */ +#define PROFILE_DB_KEY_MGMT_UNUSED 0x0010 +/** Key Management FT 802.1x */ +#define PROFILE_DB_KEY_MGMT_FT_IEEE8021X 0x0020 +/** Key Management FT PSK */ +#define PROFILE_DB_KEY_MGMT_FT_PSK 0x0040 +/** Key Management SHA256 802.1x */ +#define PROFILE_DB_KEY_MGMT_SHA256_IEEE8021X 0x0080 +/** Key Management SHA256 PSK*/ +#define PROFILE_DB_KEY_MGMT_SHA256_PSK 0x0100 +#endif + +/* Bitmap for profile Encryption protocol support */ +#ifdef BIG_ENDIAN_SUPPORT +/** Encryption protocol noRsn */ +#define PROFILE_DB_PROTO_NO_RSN 0x8000 +/** Encryption protocol static wep */ +#define PROFILE_DB_PROTO_WEP_STATIC 0x4000 +/** Encryption protocol dynamic wep */ +#define PROFILE_DB_PROTO_WEP_DYNAMIC 0x2000 +/** Encryption protocol WPA */ +#define PROFILE_DB_PROTO_WPA 0x1000 +/** Encryption protocol WPA-none + * Ad-hoc Networks */ +#define PROFILE_DB_PROTO_WPA_NONE 0x0800 +/** Encryption protocol WPA2 */ +#define PROFILE_DB_PROTO_WPA2 0x0400 +/** Encryption protocol CCKM */ +#define PROFILE_DB_PROTO_CCKM 0x0200 +#else +/** Encryption protocol noRsn */ +#define PROFILE_DB_PROTO_NO_RSN 0x0001 +/** Encryption protocol static wep */ +#define PROFILE_DB_PROTO_WEP_STATIC 0x0002 +/** Encryption protocol dynamic wep */ +#define PROFILE_DB_PROTO_WEP_DYNAMIC 0x0004 +/** Encryption protocol WPA */ +#define PROFILE_DB_PROTO_WPA 0x0008 +/** Encryption protocol WPA-none + * Ad-hoc Networks */ +#define PROFILE_DB_PROTO_WPA_NONE 0x0010 +/** Encryption protocol WPA2 */ +#define PROFILE_DB_PROTO_WPA2 0x0020 +/** Encryption protocol CCKM */ +#define PROFILE_DB_PROTO_CCKM 0x0040 +#endif + +#ifdef BIG_ENDIAN_SUPPORT +/** Cipher wep40 */ +#define PROFILE_DB_CIPHER_WEP40 0x80 +/** Cipher wep104 */ +#define PROFILE_DB_CIPHER_WEP104 0x40 +/** Cipher tkip */ +#define PROFILE_DB_CIPHER_TKIP 0x20 +/** Cipher ccmp */ +#define PROFILE_DB_CIPHER_CCMP 0x10 +#else +/** Cipher wep40 */ +#define PROFILE_DB_CIPHER_WEP40 0x01 +/** Cipher wep104 */ +#define PROFILE_DB_CIPHER_WEP104 0x02 +/** Cipher tkip */ +#define PROFILE_DB_CIPHER_TKIP 0x04 +/** Cipher ccmp */ +#define PROFILE_DB_CIPHER_CCMP 0x08 +#endif + +typedef struct { + /** Header */ + MrvlIEtypesHeader_t header; + + t_u32 mode; /**< Mode */ + t_u32 max_off_channel; + /**< Maximum off-channel measurement duration (ms) */ + t_u32 max_on_channel; + /**< Maximum on-channel measurement duration (ms) */ + +} __ATTRIB_PACK__ MrvlIETypes_MeasTiming_t; + +typedef struct { + /** Action Set or get */ + t_u16 action; + + /** TLV buffer starts here */ + t_u8 tlv_buffer[1]; + + /* + * MrvlIETypes_MeasTiming_t + */ +} __ATTRIB_PACK__ HostCmd_DS_MEASUREMENT_Timing; + +/** helper structure for profile parsing */ +typedef struct { + /** SSID name string */ + t_u8 ssid[IW_ESSID_MAX_SIZE + 1]; + /** SSID len */ + t_u32 ssid_len; + /** BSSID network name */ + t_u8 bssid[ETH_ALEN]; + /** passphrase configured */ + t_s8 passphrase[PHRASE_LEN]; + /** passphrase length */ + t_u32 passphrase_len; + /** Pre-shared key config flag */ + int psk_config; + /** Pre-shared key */ + t_u8 psk[KEY_LEN]; + /** wep keys */ + t_u8 wep_key[WEP_KEY_CNT][KEY_LEN]; + /** wep keys lengths */ + t_u8 wep_key_len[WEP_KEY_CNT]; + /** wep key index */ + int wep_key_idx; + /** protocol fields */ + t_u16 protocol; + /** pairwise Cipher values */ + t_u8 pairwise_cipher; + /** Group Cipher values */ + t_u8 groupwise_cipher; + /** key management */ + t_u16 key_mgmt; + /** offload specific parameter(roaming) */ + t_u16 roaming; + /** offload specific parameter */ + t_u16 reserved; + /** offload specific parameter--ccx */ + t_u16 ccx; + /** offload specific parameter--mode */ + t_u16 mode; +} profile_entry_t; + +typedef struct { +#ifdef BIG_ENDIAN_SUPPORT + /** Reserved */ + t_u8 Reserved:3; + /** Channel not measured */ + t_u8 Unmeasured:1; + /** Radar detected */ + t_u8 Radar:1; + /** Unidentified signal received */ + t_u8 Unidentified:1; + /** OFDM Preamble received */ + t_u8 OFDM_Preamble:1; + /** BSS found */ + t_u8 BSS:1; +#else + /** BSS found */ + t_u8 BSS:1; + /** OFDM Preamble received */ + t_u8 OFDM_Preamble:1; + /** Unidentified signal received */ + t_u8 Unidentified:1; + /** Radar detected */ + t_u8 Radar:1; + /** Channel not measured */ + t_u8 Unmeasured:1; + /** Reserved */ + t_u8 Reserved:3; +#endif +} __ATTRIB_PACK__ IEEEtypes_DFS_Map_t; + +typedef struct { + MrvlIEtypesHeader_t Header; /**< Header */ + + t_u8 scanReqId; /**< Scan request id assigned in table */ +} __ATTRIB_PACK__ MrvlIEtypes_ChanRptBcn_t; + +typedef struct { + MrvlIEtypesHeader_t Header; /**< Header */ + + IEEEtypes_DFS_Map_t map; /**< IEEE 802.11h basic meas report */ +} __ATTRIB_PACK__ MrvlIEtypes_ChanRpt11hBasic_t; + +typedef struct { + MrvlIEtypesHeader_t Header; /**< Header */ + + t_u8 sourceAddr[ETH_ALEN]; /**< Source MAC */ + t_u8 bssid[ETH_ALEN]; /**< BSSID MAC */ + t_s16 rssi; /**< Avg RSSI of frames */ + t_u16 frameCnt; /**< # of frames */ +} __ATTRIB_PACK__ MrvlIEtypes_ChanRptFrame_t; + +#ifdef OPCHAN +typedef struct { + MrvlIEtypesHeader_t header; + /**< Header */ + + MrvlChannelDesc_t chanDesc; + + t_u16 controlFlags; + t_u16 reserved; + + t_u8 actPower; + t_u8 mdMinPower; + t_u8 mdMaxPower; + t_u8 mdPower; + +} __ATTRIB_PACK__ MrvlIEtypes_ChanControlDesc_t; + +typedef struct { +#ifdef BIG_ENDIAN + /** Reserved */ + t_u8 reserved_4_7:4; + /** Disble channel filtering flag */ + t_u8 disable_chan_filt:1; + /** Channel scan mode passive flag */ + t_u8 passive_scan:1; + /** Multidomain scan mode */ + t_u8 multidomain_scan:1; + /** Enable probe response timeout */ + t_u8 rsp_timeout_en:1; +#else + /** Enable probe response timeout */ + t_u8 rsp_timeout_en:1; + /** Multidomain scan mode */ + t_u8 multidomain_scan:1; + /** Channel scan mode passive flag */ + t_u8 passive_scan:1; + /** Disble channel filtering flag */ + t_u8 disable_chan_filt:1; + /** Reserved */ + t_u8 reserved_4_7:4; +#endif +} __ATTRIB_PACK__ ChanScanMode_t; + +typedef struct { + MrvlIEtypesHeader_t header; + /**< Header */ + + t_u32 chanGroupBitmap; + ChanScanMode_t scanMode; + t_u8 numChan; + + MrvlChannelDesc_t chanDesc[50]; + +} __ATTRIB_PACK__ MrvlIEtypes_ChanGroupControl_t; + +typedef struct { + t_u16 action; + /**< CMD Action Get/Set*/ + + t_u8 tlv_buffer[1]; + +} __ATTRIB_PACK__ HostCmd_DS_OPCHAN_CONFIG; + +typedef struct { + t_u16 action; + /**< CMD Action Get/Set*/ + + t_u8 tlv_buffer[1]; + +} __ATTRIB_PACK__ HostCmd_DS_OPCHAN_CHANGROUP_CONFIG; +#endif + +typedef struct { + t_u8 modGroup; + t_u8 txPower; + +} __ATTRIB_PACK__ MrvlChanTrpcEntry_t; + +typedef struct { + MrvlIEtypesHeader_t header; + /**< Header */ + + MrvlChannelDesc_t chanDesc; + MrvlChanTrpcEntry_t chanTrpcEntry[1]; + +} __ATTRIB_PACK__ MrvlIEtypes_ChanTrpcCfg_t; + +typedef struct { + t_u16 action; + /**< CMD Action Get/Set*/ + t_u16 reserved; + + t_u8 tlv_buffer[1];/** MrvlIEtypes_ChanTrpcCfg_t TLVs */ + +} __ATTRIB_PACK__ HostCmd_DS_CHAN_TRPC_CONFIG; + +typedef struct { + t_u8 controlSelect; + + t_u8 controlBitmap[1]; /* Variable length # of byte bitmaps */ + +} __ATTRIB_PACK__ HostCmd_DS_OFFLOAD_FEATURE_CONTROL; + +#define IAPP_DATA_MAX 1000 + +/** + * @brief Enumeration for the command result from an IAPP Proxy command + */ +typedef enum { + IAPP_PROXY_RESULT_SUCCESS = 0, + IAPP_PROXY_RESULT_EXEC_FAILURE = 1, + IAPP_PROXY_RESULT_TIMEOUT = 2, + IAPP_PROXY_RESULT_DATA_INVALID = 3, +} __ATTRIB_PACK__ mlan_iapp_proxy_result_e; + +typedef struct { + mlan_iapp_proxy_result_e commandResult; + /**< Firmware execution result */ + + t_u32 timeout_ms; /**< Timeout value in milliseconds */ + + t_u8 iappType; + t_u8 iappSubType; + + t_u32 iappDataLen; + t_u8 iappData[IAPP_DATA_MAX]; + +} __ATTRIB_PACK__ HostCmd_DS_IAPP_PROXY; + +typedef struct { + /** Action: GET/SET */ + t_u16 Action; + /** Reserved */ + t_u16 Reserved; + /** Association timeout */ + t_u32 AssocTimeout; + /** Reassociation timeout */ + t_u32 ReassocTimeout; + /** Hand shake timeout */ + t_u32 HandShakeTimeout; + /** Frame exchange timeout */ + t_u32 FrameExchangeTimeout; + /** Deauth of old AP in millisec; 0 to disable */ + t_u32 PriorApDeauthDelay; + /** Maximum time after a disconnect where a reassoc frame will be sent */ + t_u32 ReassocDiscMax; +} __ATTRIB_PACK__ HostCmd_DS_AssociationTiming_t; + +/** 16 bit unsigned integer */ +typedef t_u16 IEEEtypes_AId_t; +/** 16 bit unsigned integer */ +typedef t_u16 IEEEtypes_StatusCode_t; + +typedef struct { + /** Capability information */ + IEEEtypes_CapInfo_t Capability; + /** Association response status code */ + IEEEtypes_StatusCode_t StatusCode; + /** Association ID */ + IEEEtypes_AId_t AId; + /** IE data buffer */ + t_u8 IEBuffer[1]; +} __ATTRIB_PACK__ IEEEtypes_AssocRsp_t; + +/** Maximum number of AC QOS queues available in the driver/firmware */ +#define MAX_AC_QUEUES 4 + +/** timing select structure */ +typedef struct { + char *str; /**< Timing mode string */ + int match_len; /**< match length */ + t_u8 sel; /**< flag */ + +} timing_sel_t; + +/** ENUM definition: reg_chan_table */ +typedef enum { + REGTABLE_DEFAULT = 0, + REGTABLE_ESS = 1, + REGTABLE_USER = 2, + REGTABLE_MULTIDOMAIN = 3, + + REGTABLE_MAX = 0xFFFF, +} reg_chan_table_e; + +/** Sub-command callback */ +typedef int (*sub_cmd_callback_t) (int argc, char *argv[]); + +/** Sub-command execution data */ +typedef struct { + char *str; + /**< Command string */ + int match_len; + /**< Length */ + int display; + /**< display as valid cmd */ + sub_cmd_callback_t callback; + /**< Sub-command callback */ + +} sub_cmd_exec_t; + +/** HostCmd_CMD_802_11_RF_TX_POWER */ +typedef struct { + t_u16 action; + t_s16 current_level; + t_s8 max_power; + t_s8 min_power; + +} __ATTRIB_PACK__ HostCmd_DS_802_11_RF_TX_POWER; + +/** HostCmd_CMD_802_11_AUTHENTICATE */ +typedef struct { + /** MAC address */ + t_u8 MacAddr[ETH_ALEN]; + /** Authentication type */ + t_u8 AuthType; +} __ATTRIB_PACK__ HostCmd_DS_802_11_AUTHENTICATE; + +boolean reg_class_table_select(char *tableStr, reg_chan_table_e *pTable); +int process_sub_cmd(sub_cmd_exec_t *sub_cmd, int num_sub_cmds, + int argc, char *argv[]); +int process_regclass(int argc, char *argv[]); +int process_scanagent(int argc, char *argv[]); +int process_measurement(int argc, char *argv[]); +int process_profile_entry(int argc, char *argv[]); +int process_get_ra_config(int argc, char *argv[]); +int process_set_ra_config(int argc, char *argv[]); +int process_chanrpt(int argc, char *argv[]); +int process_assoc_timing(int argc, char *argv[]); +int process_get_assocrsp(int argc, char *argv[]); +int process_link_stats(int argc, char *argv[]); + +int process_opchan(int argc, char *argv[]); +int process_changroup(int argc, char *argv[]); +int process_fcontrol(int argc, char *argv[]); +int process_iapp(int argc, char *argv[]); +int process_rf_tx_power(int argc, char *argv[]); +int process_authenticate(int argc, char *argv[]); +int process_txpowdisp(int argc, char *argv[]); + +#endif /* _MLANOFFLOAD_H_ */ diff --git a/mxm_wifiex/wlan_src/mapp/mlanutl/mlanregclass.c b/mxm_wifiex/wlan_src/mapp/mlanutl/mlanregclass.c new file mode 100644 index 0000000..72fb607 --- /dev/null +++ b/mxm_wifiex/wlan_src/mapp/mlanutl/mlanregclass.c @@ -0,0 +1,545 @@ +/** @file mlanregclass.c + * + * @brief This files contains mlanutl regclass command handling. + * + * + * Copyright 2014-2020 NXP + * + * NXP CONFIDENTIAL + * The source code contained or described herein and all documents related to + * the source code (Materials) are owned by NXP, its + * suppliers and/or its licensors. Title to the Materials remains with NXP, + * its suppliers and/or its licensors. The Materials contain + * trade secrets and proprietary and confidential information of NXP, its + * suppliers and/or its licensors. The Materials are protected by worldwide copyright + * and trade secret laws and treaty provisions. No part of the Materials may be + * used, copied, reproduced, modified, published, uploaded, posted, + * transmitted, distributed, or disclosed in any way without NXP's prior + * express written permission. + * + * No license under any patent, copyright, trade secret or other intellectual + * property right is granted to or conferred upon you by disclosure or delivery + * of the Materials, either expressly, by implication, inducement, estoppel or + * otherwise. Any license under such intellectual property rights must be + * express and approved by NXP in writing. + * + */ +/************************************************************************ +Change log: + 08/11/2009: initial version +************************************************************************/ + +#include "mlanutl.h" +#include "mlanhostcmd.h" +#include "mlanoffload.h" +#include "mlanregclass.h" + +/******************************************************** + Local Variables +********************************************************/ + +/******************************************************** + Global Variables +********************************************************/ + +/******************************************************** + Local Functions +********************************************************/ + +/** + * @brief Convert reg domain number to string + * + * @param reg_domain Reg Domain + * + * @return Reg Domain type + */ +static char * +reg_domain_to_str(reg_domain_e reg_domain) +{ + switch (reg_domain) { + case REGDOMAIN_FCC: + return "FCC"; + + case REGDOMAIN_ETSI: + return "ETSI"; + + case REGDOMAIN_MIC: + return "MIC"; + + case REGDOMAIN_OTHER: + return "MULTI"; + + default: + break; + } + + return "UNKN"; +} + +/** + * @brief Convert reg channel table number to string + * + * @param table_select Reg channel table + * + * @return Reg channel table type + */ +static char * +table_num_to_str(reg_chan_table_e table_select) +{ + switch (table_select) { + case REGTABLE_USER: + return "User"; + + case REGTABLE_MULTIDOMAIN: + return "MultiDomain"; + + case REGTABLE_ESS: + return "ESS"; + + case REGTABLE_DEFAULT: + return "Default"; + + default: + break; + } + + return "UNKN"; +} + +/** + * @brief Regclass dump channel table + * + * @param argc Number of arguments + * @param argv A pointer to arguments array + * + * @return MLAN_STATUS_SUCCESS--success, otherwise--fail + */ +static int +reg_class_dump_chan_table(int argc, char *argv[]) +{ + int ret = MLAN_STATUS_SUCCESS; + struct ifreq ifr; + t_u8 *buffer = NULL, *pos = NULL; + t_u32 cmd_len = 0, cmd_header_len; + struct eth_priv_cmd *cmd = NULL; + HostCmd_DS_GEN *hostcmd; + HostCmd_DS_REGCLASS_GET_CHAN_TABLE *get_table; + int idx; + t_u16 regLimits; + boolean invalid_cmd = FALSE; + + printf("ERR:Cannot allocate buffer for command!\n"); + if (argv[0] == NULL) { + invalid_cmd = TRUE; + } else { + + cmd_header_len = strlen(CMD_NXP) + strlen(HOSTCMD); + + buffer = (t_u8 *)malloc(BUFFER_LENGTH); + if (buffer == NULL) { + fprintf(stderr, "Cannot alloc memory\n"); + ret = ENOMEM; + goto done; + } + memset(buffer, 0, BUFFER_LENGTH); + + cmd = (struct eth_priv_cmd *) + malloc(sizeof(struct eth_priv_cmd)); + if (!cmd) { + printf("ERR:Cannot allocate buffer for command!\n"); + ret = ENOMEM; + goto done; + } + + /* Fill up buffer */ +#ifdef USERSPACE_32BIT_OVER_KERNEL_64BIT + memset(cmd, 0, sizeof(struct eth_priv_cmd)); + memcpy(&cmd->buf, &buffer, sizeof(buffer)); +#else + cmd->buf = buffer; +#endif + cmd->used_len = 0; + cmd->total_len = BUFFER_LENGTH; + + /* buffer = MRVL_CMD */ + strncpy((char *)buffer, CMD_NXP, strlen(CMD_NXP)); + strncpy((char *)buffer + strlen(CMD_NXP), HOSTCMD, + strlen(HOSTCMD)); + + /* buffer = MRVL_CMD */ + hostcmd = + (HostCmd_DS_GEN *)(buffer + cmd_header_len + + sizeof(t_u32)); + + /* Point after host command header */ + pos = (t_u8 *)hostcmd + S_DS_GEN; + + cmd_len = S_DS_GEN + sizeof(HostCmd_DS_REGCLASS_GET_CHAN_TABLE); + hostcmd->command = cpu_to_le16(HostCmd_CMD_REGCLASS_CHAN_TABLE); + hostcmd->size = cpu_to_le16(cmd_len); + hostcmd->seq_num = 0; + hostcmd->result = 0; + + get_table = (HostCmd_DS_REGCLASS_GET_CHAN_TABLE *)pos; + get_table->action = cpu_to_le16(HostCmd_ACT_GEN_GET); + + if (reg_class_table_select(argv[0], (reg_chan_table_e *) + &get_table->table_select) == FALSE) { + invalid_cmd = TRUE; + } + } + + if (invalid_cmd) { + printf("\nValid tables table; valid [user, md, ess, default]\n\n"); + ret = MLAN_STATUS_FAILURE; + goto done; + } + + get_table->table_select = cpu_to_le16((t_u16)(get_table->table_select)); + + /* Put buffer length */ + memcpy(buffer + cmd_header_len, &cmd_len, sizeof(t_u32)); + + /* Initialize the ifr structure */ + memset(&ifr, 0, sizeof(ifr)); + strncpy(ifr.ifr_ifrn.ifrn_name, dev_name, strlen(dev_name)); + ifr.ifr_ifru.ifru_data = (void *)cmd; + /* Perform ioctl */ + if (ioctl(sockfd, MLAN_ETH_PRIV, &ifr)) { + perror("ioctl[regClassIoctl]"); + printf("ERR:Command sending failed!\n"); + ret = -EFAULT; + goto done; + } + + if (!le16_to_cpu(hostcmd->result)) { + printf("HOSTCMD_RESP: ReturnCode=%#04x, Result=%#04x\n", + le16_to_cpu(hostcmd->command), + le16_to_cpu(hostcmd->result)); + } else { + printf("HOSTCMD failed: ReturnCode=%#04x, Result=%#04x\n", + le16_to_cpu(hostcmd->command), + le16_to_cpu(hostcmd->result)); + } + + get_table->table_select = le16_to_cpu(get_table->table_select); + get_table->chan = le32_to_cpu(get_table->chan); + + printf("---------------------------------------"); + printf("---------------------------------------\n"); + printf("%35s: %s [%d]\n", "Channel Table", + table_num_to_str(get_table->table_select), (int)get_table->chan); + printf("---------------------------------------"); + printf("---------------------------------------\n"); + printf(" chn | freq | sfrq | sp | class | maxP | behavior limits\n"); + printf("---------------------------------------"); + printf("---------------------------------------\n"); + + for (idx = 0; (unsigned int)idx < get_table->chan; idx++) { + char regDisp[8]; + + sprintf(regDisp, "%4s-%02u", + reg_domain_to_str(get_table->chan_entry[idx]. + reg_domain), + get_table->chan_entry[idx].regulatory_class); + + printf(" %03u | %04u | %04u | %02u | %-8s | %02u |", + get_table->chan_entry[idx].chan_num, + (get_table->chan_entry[idx].start_freq + + (get_table->chan_entry[idx].chan_num * 5)), + le16_to_cpu(get_table->chan_entry[idx].start_freq), + le16_to_cpu(get_table->chan_entry[idx].chan_spacing), + regDisp, get_table->chan_entry[idx].max_tx_power); + + regLimits = le16_to_cpu(get_table->chan_entry[idx].reg_limits); + + if (regLimits & BLIMIT_NOMADIC) + printf(" nomadic"); + if (regLimits & BLIMIT_INDOOR_ONLY) + printf(" indoor"); + if (regLimits & BLIMIT_TPC) + printf(" tpc"); + if (regLimits & BLIMIT_DFS) + printf(" dfs"); + if (regLimits & BLIMIT_IBSS_PROHIBIT) + printf(" no_ibss"); + if (regLimits & BLIMIT_FOUR_MS_CS) + printf(" 4ms_cs"); + if (regLimits & BLIMIT_LIC_BASE_STA) + printf(" base_sta"); + if (regLimits & BLIMIT_MOBILE_STA) + printf(" mobile"); + if (regLimits & BLIMIT_PUBLIC_SAFETY) + printf(" safety"); + if (regLimits & BLIMIT_ISM_BANDS) + printf(" ism"); + + printf("\n"); + } + printf("---------------------------------------"); + printf("---------------------------------------\n"); + printf("\n"); + +done: + if (buffer) + free(buffer); + if (cmd) + free(cmd); + return ret; +} + +/** + * @brief Regclass configure user table + * + * @param argc Number of arguments + * @param argv A pointer to arguments array + * + * @return MLAN_STATUS_SUCCESS--success, otherwise--fail + */ +static int +reg_class_config_user_table(int argc, char *argv[]) +{ + int ret = MLAN_STATUS_SUCCESS; + struct ifreq ifr; + t_u8 *buffer = NULL, *pos = NULL; + t_u32 cmd_len = 0, cmd_header_len; + struct eth_priv_cmd *cmd = NULL; + HostCmd_DS_GEN *hostcmd; + HostCmd_DS_REGCLASS_CONFIG_USER_TABLE *cfg_user_table; + + if (argv[0] == NULL) { + printf("\nCountry string not specified\n"); + ret = MLAN_STATUS_FAILURE; + goto done; + } + + cmd_header_len = strlen(CMD_NXP) + strlen(HOSTCMD); + + buffer = (t_u8 *)malloc(BUFFER_LENGTH); + if (buffer == NULL) { + fprintf(stderr, "Cannot alloc memory\n"); + ret = ENOMEM; + goto done; + } + memset(buffer, 0, BUFFER_LENGTH); + + cmd = (struct eth_priv_cmd *)malloc(sizeof(struct eth_priv_cmd)); + if (!cmd) { + printf("ERR:Cannot allocate buffer for command!\n"); + ret = ENOMEM; + goto done; + } + + /* Fill up buffer */ +#ifdef USERSPACE_32BIT_OVER_KERNEL_64BIT + memset(cmd, 0, sizeof(struct eth_priv_cmd)); + memcpy(&cmd->buf, &buffer, sizeof(buffer)); +#else + cmd->buf = buffer; +#endif + cmd->used_len = 0; + cmd->total_len = BUFFER_LENGTH; + + /* buffer = MRVL_CMD */ + strncpy((char *)buffer, CMD_NXP, strlen(CMD_NXP)); + strncpy((char *)buffer + strlen(CMD_NXP), HOSTCMD, strlen(HOSTCMD)); + + /* buffer = MRVL_CMD */ + hostcmd = (HostCmd_DS_GEN *)(buffer + cmd_header_len + sizeof(t_u32)); + + /* Point after host command header */ + pos = (t_u8 *)hostcmd + S_DS_GEN; + + cmd_len = S_DS_GEN + sizeof(HostCmd_DS_REGCLASS_CONFIG_USER_TABLE); + hostcmd->command = cpu_to_le16(HostCmd_CMD_REGCLASS_CONFIG_USER_TABLE); + hostcmd->size = cpu_to_le16(cmd_len); + hostcmd->seq_num = 0; + hostcmd->result = 0; + + cfg_user_table = (HostCmd_DS_REGCLASS_CONFIG_USER_TABLE *)pos; + cfg_user_table->action = cpu_to_le16(HostCmd_ACT_GEN_SET); + memcpy(cfg_user_table->regulatory_str, + argv[0], + MIN(strlen(argv[0]), sizeof(cfg_user_table->regulatory_str))); + + /* Put buffer length */ + memcpy(buffer + cmd_header_len, &cmd_len, sizeof(t_u32)); + + /* Initialize the ifr structure */ + memset(&ifr, 0, sizeof(ifr)); + strncpy(ifr.ifr_ifrn.ifrn_name, dev_name, strlen(dev_name)); + ifr.ifr_ifru.ifru_data = (void *)cmd; + /* Perform ioctl */ + if (ioctl(sockfd, MLAN_ETH_PRIV, &ifr)) { + perror("ioctl[regClassIoctl]"); + printf("ERR:Command sending failed!\n"); + ret = -EFAULT; + goto done; + } + + if (!le16_to_cpu(hostcmd->result)) { + printf("HOSTCMD_RESP: ReturnCode=%#04x, Result=%#04x\n", + le16_to_cpu(hostcmd->command), + le16_to_cpu(hostcmd->result)); + } else { + printf("HOSTCMD failed: ReturnCode=%#04x, Result=%#04x\n", + le16_to_cpu(hostcmd->command), + le16_to_cpu(hostcmd->result)); + } + +done: + if (buffer) + free(buffer); + if (cmd) + free(cmd); + return ret; +} + +/** + * @brief Issue regclass multi-domain command + * + * @param argc number of arguments + * @param argv A pointer to arguments array + * + * @return MLAN_STATUS_SUCCESS--success, otherwise--fail + */ +static int +reg_class_multidomain(int argc, char *argv[]) +{ + int ret = MLAN_STATUS_SUCCESS; + struct ifreq ifr; + t_u8 *buffer = NULL, *pos = NULL; + t_u32 cmd_len = 0, cmd_header_len; + struct eth_priv_cmd *cmd = NULL; + HostCmd_DS_GEN *hostcmd; + HostCmd_DS_REGCLASS_MULTIDOMAIN_CONTROL *multidomain_ctrl; + boolean invalid_cmd = FALSE; + + if (argv[0] == NULL) { + invalid_cmd = TRUE; + } else { + cmd_header_len = strlen(CMD_NXP) + strlen(HOSTCMD); + + buffer = (t_u8 *)malloc(BUFFER_LENGTH); + if (buffer == NULL) { + fprintf(stderr, "Cannot alloc memory\n"); + ret = ENOMEM; + goto done; + } + memset(buffer, 0, BUFFER_LENGTH); + + cmd = (struct eth_priv_cmd *) + malloc(sizeof(struct eth_priv_cmd)); + if (!cmd) { + printf("ERR:Cannot allocate buffer for command!\n"); + ret = ENOMEM; + goto done; + } + + /* Fill up buffer */ +#ifdef USERSPACE_32BIT_OVER_KERNEL_64BIT + memset(cmd, 0, sizeof(struct eth_priv_cmd)); + memcpy(&cmd->buf, &buffer, sizeof(buffer)); +#else + cmd->buf = buffer; +#endif + cmd->used_len = 0; + cmd->total_len = BUFFER_LENGTH; + + /* buffer = MRVL_CMD */ + strncpy((char *)buffer, CMD_NXP, strlen(CMD_NXP)); + strncpy((char *)buffer + strlen(CMD_NXP), HOSTCMD, + strlen(HOSTCMD)); + + /* buffer = MRVL_CMD */ + hostcmd = + (HostCmd_DS_GEN *)(buffer + cmd_header_len + + sizeof(t_u32)); + + /* Point after host command header */ + pos = (t_u8 *)hostcmd + S_DS_GEN; + + cmd_len = + S_DS_GEN + + sizeof(HostCmd_DS_REGCLASS_MULTIDOMAIN_CONTROL); + hostcmd->command = + cpu_to_le16(HostCmd_CMD_REGCLASS_MULTIDOMAIN_CONTROL); + hostcmd->size = cpu_to_le16(cmd_len); + hostcmd->seq_num = 0; + hostcmd->result = 0; + + multidomain_ctrl = + (HostCmd_DS_REGCLASS_MULTIDOMAIN_CONTROL *)pos; + if (strcmp(argv[0], "on") == 0) { + multidomain_ctrl->multidomain_enable = 1; + } else if (strcmp(argv[0], "off") == 0) { + multidomain_ctrl->multidomain_enable = 0; + } else { + invalid_cmd = TRUE; + } + } + + if (invalid_cmd) { + printf("\nUnknown multiDomain command; valid [on, off]\n\n"); + ret = MLAN_STATUS_FAILURE; + goto done; + } + + multidomain_ctrl->multidomain_enable = + cpu_to_le32(multidomain_ctrl->multidomain_enable); + + /* Put buffer length */ + memcpy(buffer + cmd_header_len, &cmd_len, sizeof(t_u32)); + + /* Initialize the ifr structure */ + memset(&ifr, 0, sizeof(ifr)); + strncpy(ifr.ifr_ifrn.ifrn_name, dev_name, strlen(dev_name)); + ifr.ifr_ifru.ifru_data = (void *)cmd; + /* Perform ioctl */ + if (ioctl(sockfd, MLAN_ETH_PRIV, &ifr)) { + perror("ioctl[regClass]"); + printf("ERR:Command sending failed!\n"); + ret = -EFAULT; + goto done; + } else { + printf("\nMultiDomain: %s\n", + le32_to_cpu(multidomain_ctrl->multidomain_enable) ? + "Enabled" : "Disabled"); + } + + if (!le16_to_cpu(hostcmd->result)) { + printf("HOSTCMD_RESP: ReturnCode=%#04x, Result=%#04x\n", + le16_to_cpu(hostcmd->command), + le16_to_cpu(hostcmd->result)); + } else { + printf("HOSTCMD failed: ReturnCode=%#04x, Result=%#04x\n", + le16_to_cpu(hostcmd->command), + le16_to_cpu(hostcmd->result)); + } + +done: + if (buffer) + free(buffer); + if (cmd) + free(cmd); + return ret; +} + +/** + * @brief Issue a regclass command + * + * @param argc number of arguments + * @param argv A pointer to arguments array + * + * @return MLAN_STATUS_SUCCESS--success, otherwise--fail + */ +int +process_regclass(int argc, char *argv[]) +{ + sub_cmd_exec_t sub_cmd[] = { {"table", 1, 1, reg_class_dump_chan_table}, + {"multidomain", 1, 1, reg_class_multidomain}, + {"country", 1, 1, reg_class_config_user_table} + }; + + return process_sub_cmd(sub_cmd, NELEMENTS(sub_cmd), argc, argv); +} diff --git a/mxm_wifiex/wlan_src/mapp/mlanutl/mlanregclass.h b/mxm_wifiex/wlan_src/mapp/mlanutl/mlanregclass.h new file mode 100644 index 0000000..1e18329 --- /dev/null +++ b/mxm_wifiex/wlan_src/mapp/mlanutl/mlanregclass.h @@ -0,0 +1,105 @@ +/** @file mlanregclass.h + * + * @brief This files contains mlanutl regclass command handling. + * + * + * Copyright 2014-2020 NXP + * + * NXP CONFIDENTIAL + * The source code contained or described herein and all documents related to + * the source code (Materials) are owned by NXP, its + * suppliers and/or its licensors. Title to the Materials remains with NXP, + * its suppliers and/or its licensors. The Materials contain + * trade secrets and proprietary and confidential information of NXP, its + * suppliers and/or its licensors. The Materials are protected by worldwide copyright + * and trade secret laws and treaty provisions. No part of the Materials may be + * used, copied, reproduced, modified, published, uploaded, posted, + * transmitted, distributed, or disclosed in any way without NXP's prior + * express written permission. + * + * No license under any patent, copyright, trade secret or other intellectual + * property right is granted to or conferred upon you by disclosure or delivery + * of the Materials, either expressly, by implication, inducement, estoppel or + * otherwise. Any license under such intellectual property rights must be + * express and approved by NXP in writing. + * + */ +/************************************************************************ +Change log: + 08/11/2009: initial version +************************************************************************/ + +#ifndef _MLANREGCLASS_H +#define _MLANREGCLASS_H + +/** Nomadic */ +#define BLIMIT_NOMADIC (1 << 0) +/** Indoor */ +#define BLIMIT_INDOOR_ONLY (1 << 1) +/** Tpc */ +#define BLIMIT_TPC (1 << 2) +/** Dfs */ +#define BLIMIT_DFS (1 << 3) +/** IBSS Prohibit */ +#define BLIMIT_IBSS_PROHIBIT (1 << 4) +/** Four MS CS */ +#define BLIMIT_FOUR_MS_CS (1 << 5) +/** LIC Base STA */ +#define BLIMIT_LIC_BASE_STA (1 << 6) +/** Mobile STA */ +#define BLIMIT_MOBILE_STA (1 << 7) +/** Public Safety */ +#define BLIMIT_PUBLIC_SAFETY (1 << 8) +/** ISM Bands */ +#define BLIMIT_ISM_BANDS (1 << 9) + +/** Enum Definitions: reg_domain */ +typedef enum { + REGDOMAIN_NULL = 0x00, + + REGDOMAIN_FCC = 0x01, + REGDOMAIN_ETSI = 0x02, + REGDOMAIN_MIC = 0x03, + + REGDOMAIN_OTHER = 0xFF, + +} reg_domain_e; + +typedef struct { + t_u8 reg_domain; /**< Domain */ + t_u8 regulatory_class; + /**< Regulatory class */ + t_u8 chan_num; /**< Channel Number */ + t_u8 reserved1; /**< Reserved */ + t_u16 start_freq; /**< Start frequency */ + t_u16 chan_spacing; /**< channel spacing */ + t_u8 max_tx_power; /**< Max. tx power */ + t_u8 coverage_class;/**< Coverage class */ + t_u16 reg_limits; /**< Limits */ +} __ATTRIB_PACK__ chan_entry_t; + +typedef struct { + /** Action: GET/SET */ + t_u16 action; + /** Reg channel table */ + t_u16 table_select; + /** Channel number */ + t_u32 chan; + /** Channel entry */ + chan_entry_t chan_entry[75]; +} __ATTRIB_PACK__ HostCmd_DS_REGCLASS_GET_CHAN_TABLE; + +typedef struct { + t_u16 action; + /**< Action: GET/SET */ + t_u16 reserved; + /**< Reserved */ + char regulatory_str[3];/**< Regulatory String */ +} __ATTRIB_PACK__ HostCmd_DS_REGCLASS_CONFIG_USER_TABLE; + +typedef struct { + t_u32 multidomain_enable; + /**< Multi domain enable */ +} __ATTRIB_PACK__ HostCmd_DS_REGCLASS_MULTIDOMAIN_CONTROL; + +#endif /* _MLANREGCLASS_H */ diff --git a/mxm_wifiex/wlan_src/mapp/mlanutl/mlanroamagent.c b/mxm_wifiex/wlan_src/mapp/mlanutl/mlanroamagent.c new file mode 100644 index 0000000..4f3ba5d --- /dev/null +++ b/mxm_wifiex/wlan_src/mapp/mlanutl/mlanroamagent.c @@ -0,0 +1,3675 @@ +/** @file mlanroamagent.c + * + * @brief This files contains mlanutl roamagent command handling. + * + * + * Copyright 2014-2020 NXP + * + * NXP CONFIDENTIAL + * The source code contained or described herein and all documents related to + * the source code (Materials) are owned by NXP, its + * suppliers and/or its licensors. Title to the Materials remains with NXP, + * its suppliers and/or its licensors. The Materials contain + * trade secrets and proprietary and confidential information of NXP, its + * suppliers and/or its licensors. The Materials are protected by worldwide copyright + * and trade secret laws and treaty provisions. No part of the Materials may be + * used, copied, reproduced, modified, published, uploaded, posted, + * transmitted, distributed, or disclosed in any way without NXP's prior + * express written permission. + * + * No license under any patent, copyright, trade secret or other intellectual + * property right is granted to or conferred upon you by disclosure or delivery + * of the Materials, either expressly, by implication, inducement, estoppel or + * otherwise. Any license under such intellectual property rights must be + * express and approved by NXP in writing. + * + */ +/************************************************************************ +Change log: + 08/11/2009: initial version +************************************************************************/ + +#include "mlanutl.h" +#include "mlanhostcmd.h" +#include "mlanoffload.h" +#include "mlanroamagent.h" + +/******************************************************** + Local Variables +********************************************************/ + +/******************************************************** + Global Variables +********************************************************/ + +/******************************************************** + Local Functions +********************************************************/ + +/** + * @brief Issue getra failcnt command + * + * @param argc number of arguments + * @param argv A pointer to arguments array + * + * @return MLAN_STATUS_SUCCESS--success, otherwise--fail + */ +static int +roamGetFailureCount(int argc, char *argv[]) +{ + int ret = MLAN_STATUS_SUCCESS; + int failCount, failTimeThresh, state, i; + struct ifreq ifr; + t_u8 *buffer = NULL, *pos = NULL; + t_u32 cmd_len = 0, cmd_header_len; + struct eth_priv_cmd *cmd = NULL; + HostCmd_DS_GEN *hostcmd; + HostCmd_DS_CMD_ROAMAGENT_STATISTICS_THRESHOLD *statsthreshold; + MrvlIEtypes_FailureCount_t *pFailureCount; + MrvlIEtypesHeader_t *pTlvHdr; + t_u8 *tlvptr; + const char *states[] = + { "Stable", "Degrading", "Unacceptable", "Hardroam" }; + + cmd_header_len = strlen(CMD_NXP) + strlen(HOSTCMD); + + buffer = (t_u8 *)malloc(BUFFER_LENGTH); + if (buffer == NULL) { + fprintf(stderr, "Cannot alloc memory\n"); + ret = ENOMEM; + goto done; + } + memset(buffer, 0, BUFFER_LENGTH); + + cmd = (struct eth_priv_cmd *)malloc(sizeof(struct eth_priv_cmd)); + if (!cmd) { + printf("ERR:Cannot allocate buffer for command!\n"); + free(buffer); + ret = ENOMEM; + goto done; + } + + /* Fill up buffer */ +#ifdef USERSPACE_32BIT_OVER_KERNEL_64BIT + memset(cmd, 0, sizeof(struct eth_priv_cmd)); + memcpy(&cmd->buf, &buffer, sizeof(buffer)); +#else + cmd->buf = buffer; +#endif + cmd->used_len = 0; + cmd->total_len = BUFFER_LENGTH; + + /* buffer = MRVL_CMD */ + strncpy((char *)buffer, CMD_NXP, strlen(CMD_NXP)); + strncpy((char *)buffer + strlen(CMD_NXP), HOSTCMD, strlen(HOSTCMD)); + + /* buffer = MRVL_CMD */ + hostcmd = (HostCmd_DS_GEN *)(buffer + cmd_header_len + sizeof(t_u32)); + + /* Point after host command header */ + pos = (t_u8 *)hostcmd + S_DS_GEN; + + statsthreshold = (HostCmd_DS_CMD_ROAMAGENT_STATISTICS_THRESHOLD *)pos; + cmd_len = + (S_DS_GEN + + sizeof(HostCmd_DS_CMD_ROAMAGENT_STATISTICS_THRESHOLD) + - sizeof(statsthreshold->TlvBuffer)); + + /* Can be extended to all states later */ + for (state = STATE_HARDROAM - 1; state < STATE_HARDROAM; state++) { + statsthreshold->State = state + 1; + hostcmd->command = + cpu_to_le16(HostCmd_CMD_ROAMAGENT_STATISTICS_THRESHOLD); + hostcmd->size = cpu_to_le16(cmd_len); + hostcmd->seq_num = 0; + hostcmd->result = 0; + statsthreshold->action = cpu_to_le16(HostCmd_ACT_GEN_GET); + + /* Put buffer length */ + memcpy(buffer + cmd_header_len, &cmd_len, sizeof(t_u32)); + + /* Initialize the ifr structure */ + memset(&ifr, 0, sizeof(ifr)); + strncpy(ifr.ifr_ifrn.ifrn_name, dev_name, strlen(dev_name)); + ifr.ifr_ifru.ifru_data = (void *)cmd; + /* Perform ioctl */ + if (ioctl(sockfd, MLAN_ETH_PRIV, &ifr)) { + perror("ioctl[roamstatistics]"); + printf("ERR:Command sending failed!\n"); + ret = -EFAULT; + goto done; + } + + i = le16_to_cpu(hostcmd->size); + i -= cmd_len; + tlvptr = statsthreshold->TlvBuffer; + + while (i > 2) { + pTlvHdr = (MrvlIEtypesHeader_t *)tlvptr; + + switch (le16_to_cpu(pTlvHdr->type)) { + case TLV_TYPE_FAILCOUNT: + pFailureCount = + (MrvlIEtypes_FailureCount_t *)pTlvHdr; + failCount = pFailureCount->fail_value; + failTimeThresh = + le16_to_cpu(pFailureCount-> + fail_min_thresh_time_millisecs); + break; + } + + tlvptr += (le16_to_cpu(pTlvHdr->len) + + sizeof(MrvlIEtypesHeader_t)); + i -= (le16_to_cpu(pTlvHdr->len) + + sizeof(MrvlIEtypesHeader_t)); + } + + printf("State: %-8s. FailCount = %d, FailTimeThresh(ms) = %d\n", + states[state], failCount, failTimeThresh); + } + +done: + if (buffer) + free(buffer); + if (cmd) + free(cmd); + return ret; +} + +/** + * @brief Issue getra bcnmiss command + * + * @param argc number of arguments + * @param argv A pointer to arguments array + * + * @return MLAN_STATUS_SUCCESS--success, otherwise--fail + */ +static int +roamGetPreBeaconMiss(int argc, char *argv[]) +{ + int ret = MLAN_STATUS_SUCCESS; + int bcnmiss, state = STATE_HARDROAM, i; + struct ifreq ifr; + t_u8 *buffer = NULL, *pos = NULL; + t_u32 cmd_len = 0, cmd_header_len; + struct eth_priv_cmd *cmd = NULL; + HostCmd_DS_GEN *hostcmd; + HostCmd_DS_CMD_ROAMAGENT_STATISTICS_THRESHOLD *statsthreshold; + MrvlIEtypes_BeaconsMissed_t *pBeaconMissed; + MrvlIEtypesHeader_t *pTlvHdr; + t_u8 *tlvptr; + const char *states[] = + { "Stable", "Degrading", "Unacceptable", "Hardroam" }; + + cmd_header_len = strlen(CMD_NXP) + strlen(HOSTCMD); + + buffer = (t_u8 *)malloc(BUFFER_LENGTH); + if (buffer == NULL) { + fprintf(stderr, "Cannot alloc memory\n"); + ret = ENOMEM; + goto done; + } + memset(buffer, 0, BUFFER_LENGTH); + + cmd = (struct eth_priv_cmd *)malloc(sizeof(struct eth_priv_cmd)); + if (!cmd) { + printf("ERR:Cannot allocate buffer for command!\n"); + free(buffer); + ret = ENOMEM; + goto done; + } + + /* Fill up buffer */ +#ifdef USERSPACE_32BIT_OVER_KERNEL_64BIT + memset(cmd, 0, sizeof(struct eth_priv_cmd)); + memcpy(&cmd->buf, &buffer, sizeof(buffer)); +#else + cmd->buf = buffer; +#endif + cmd->used_len = 0; + cmd->total_len = BUFFER_LENGTH; + + /* buffer = MRVL_CMD */ + strncpy((char *)buffer, CMD_NXP, strlen(CMD_NXP)); + strncpy((char *)buffer + strlen(CMD_NXP), HOSTCMD, strlen(HOSTCMD)); + + /* buffer = MRVL_CMD */ + hostcmd = (HostCmd_DS_GEN *)(buffer + cmd_header_len + sizeof(t_u32)); + + /* Point after host command header */ + pos = (t_u8 *)hostcmd + S_DS_GEN; + + statsthreshold = (HostCmd_DS_CMD_ROAMAGENT_STATISTICS_THRESHOLD *)pos; + cmd_len = + (S_DS_GEN + + sizeof(HostCmd_DS_CMD_ROAMAGENT_STATISTICS_THRESHOLD) + - sizeof(statsthreshold->TlvBuffer)); + + /* Can be extended to all states later */ + for (state = STATE_HARDROAM - 1; state < STATE_HARDROAM; state++) { + statsthreshold->State = state + 1; + hostcmd->command = + cpu_to_le16(HostCmd_CMD_ROAMAGENT_STATISTICS_THRESHOLD); + hostcmd->size = cpu_to_le16(cmd_len); + hostcmd->seq_num = 0; + hostcmd->result = 0; + statsthreshold->action = cpu_to_le16(HostCmd_ACT_GEN_GET); + + /* Put buffer length */ + memcpy(buffer + cmd_header_len, &cmd_len, sizeof(t_u32)); + + /* Initialize the ifr structure */ + memset(&ifr, 0, sizeof(ifr)); + strncpy(ifr.ifr_ifrn.ifrn_name, dev_name, strlen(dev_name)); + ifr.ifr_ifru.ifru_data = (void *)cmd; + /* Perform ioctl */ + if (ioctl(sockfd, MLAN_ETH_PRIV, &ifr)) { + perror("ioctl[beacon miss]"); + printf("ERR:Command sending failed!\n"); + ret = -EFAULT; + goto done; + } + + i = le16_to_cpu(hostcmd->size); + i -= cmd_len; + tlvptr = statsthreshold->TlvBuffer; + + while (i > 2) { + pTlvHdr = (MrvlIEtypesHeader_t *)tlvptr; + + switch (le16_to_cpu(pTlvHdr->type)) { + + case TLV_TYPE_PRE_BEACON_LOST: + pBeaconMissed = + (MrvlIEtypes_BeaconsMissed_t *)pTlvHdr; + bcnmiss = pBeaconMissed->beacon_missed; + } + + tlvptr += (le16_to_cpu(pTlvHdr->len) + + sizeof(MrvlIEtypesHeader_t)); + i -= (le16_to_cpu(pTlvHdr->len) + + sizeof(MrvlIEtypesHeader_t)); + } + + printf("State: %-8s. Pre Beacon missed threshold %d\n", + states[state], bcnmiss); + } + +done: + if (buffer) + free(buffer); + if (cmd) + free(cmd); + return ret; +} + +/** + * @brief Issue getra rssi/snr command + * + * @param argc number of arguments + * @param argv A pointer to arguments array + * @param type RSSI/SNR threshold type + * + * @return MLAN_STATUS_SUCCESS--success, otherwise--fail + */ +static int +roamGetStatsThreshold(int argc, char *argv[], int type) +{ + int ret = MLAN_STATUS_SUCCESS; + int state = 0, i = 0, profile = 1; + struct ifreq ifr; + t_u8 *buffer = NULL, *pos = NULL; + t_u32 cmd_len = 0, cmd_header_len; + struct eth_priv_cmd *cmd = NULL; + HostCmd_DS_GEN *hostcmd; + HostCmd_DS_CMD_ROAMAGENT_STATISTICS_THRESHOLD *statsthreshold; + MrvlIEtypes_BeaconHighRssiThreshold_t *pHighRssiThreshold; + MrvlIEtypes_BeaconLowRssiThreshold_t *pLowRssiThreshold; + MrvlIEtypes_BeaconHighSnrThreshold_t *pHighSnrThreshold; + MrvlIEtypes_BeaconLowSnrThreshold_t *pLowSnrThreshold; + t_s8 high, low; + t_u8 *tlvptr; + t_u16 tlv; + const char *states[] = { "Stable", "Degrading", "Unacceptable" }; + + if (argc) { + if (strncmp(argv[0], "configured", strlen("config")) == 0) { + profile = 0; + } else if (strncmp(argv[0], "active", strlen("active"))) { + printf("\nIncorrect parameter %s for getra command\n\n", + argv[0]); + ret = MLAN_STATUS_FAILURE; + goto done; + } + } + + cmd_header_len = strlen(CMD_NXP) + strlen(HOSTCMD); + + buffer = (t_u8 *)malloc(BUFFER_LENGTH); + if (buffer == NULL) { + fprintf(stderr, "Cannot alloc memory\n"); + ret = ENOMEM; + goto done; + } + memset(buffer, 0, BUFFER_LENGTH); + + cmd = (struct eth_priv_cmd *)malloc(sizeof(struct eth_priv_cmd)); + if (!cmd) { + printf("ERR:Cannot allocate buffer for command!\n"); + free(buffer); + ret = ENOMEM; + goto done; + } + + /* Fill up buffer */ +#ifdef USERSPACE_32BIT_OVER_KERNEL_64BIT + memset(cmd, 0, sizeof(struct eth_priv_cmd)); + memcpy(&cmd->buf, &buffer, sizeof(buffer)); +#else + cmd->buf = buffer; +#endif + cmd->used_len = 0; + cmd->total_len = BUFFER_LENGTH; + + /* buffer = MRVL_CMD */ + strncpy((char *)buffer, CMD_NXP, strlen(CMD_NXP)); + strncpy((char *)buffer + strlen(CMD_NXP), HOSTCMD, strlen(HOSTCMD)); + + /* buffer = MRVL_CMD */ + hostcmd = (HostCmd_DS_GEN *)(buffer + cmd_header_len + sizeof(t_u32)); + + /* Point after host command header */ + pos = (t_u8 *)hostcmd + S_DS_GEN; + + statsthreshold = (HostCmd_DS_CMD_ROAMAGENT_STATISTICS_THRESHOLD *)pos; + cmd_len = + (S_DS_GEN + + sizeof(HostCmd_DS_CMD_ROAMAGENT_STATISTICS_THRESHOLD) + - sizeof(statsthreshold->TlvBuffer)); + + printf("---------------------------------------------\n"); + if (type == RSSI_THRESHOLD) { + printf(" RSSI Thresholds\n"); + } else { + printf(" SNR Thresholds\n"); + } + printf("---------------------------------------------\n"); + + for (state = STATE_STABLE - 1; state < STATE_UNACCEPTABLE; state++) { + statsthreshold->State = state + 1; + statsthreshold->Profile = profile; + hostcmd->command = + cpu_to_le16(HostCmd_CMD_ROAMAGENT_STATISTICS_THRESHOLD); + hostcmd->size = cpu_to_le16(cmd_len); + hostcmd->seq_num = 0; + hostcmd->result = 0; + statsthreshold->action = cpu_to_le16(HostCmd_ACT_GEN_GET); + + /* Put buffer length */ + memcpy(buffer + cmd_header_len, &cmd_len, sizeof(t_u32)); + + /* Initialize the ifr structure */ + memset(&ifr, 0, sizeof(ifr)); + strncpy(ifr.ifr_ifrn.ifrn_name, dev_name, strlen(dev_name)); + ifr.ifr_ifru.ifru_data = (void *)cmd; + /* Perform ioctl */ + if (ioctl(sockfd, MLAN_ETH_PRIV, &ifr)) { + perror("ioctl[roamstatistics]"); + printf("ERR:Command sending failed!\n"); + ret = -EFAULT; + goto done; + } + + if (le16_to_cpu(hostcmd->result)) { + printf("\nHostCmd Error: ReturnCode=%#04x, Result=%#04x\n\n", le16_to_cpu(hostcmd->command), le16_to_cpu(hostcmd->result)); + ret = MLAN_STATUS_FAILURE; + goto done; + } + + i = le16_to_cpu(hostcmd->size); + i -= cmd_len; + tlvptr = statsthreshold->TlvBuffer; + while (i > 2) { + /* + * ENDIANNESS for Response + */ + tlv = le16_to_cpu(*((t_u16 *)(tlvptr))); + + switch (tlv) { + case TLV_TYPE_RSSI_HIGH: + high = *(t_s8 *)(tlvptr + sizeof(t_u16) + + sizeof(t_u16)); + pHighRssiThreshold = + (MrvlIEtypes_BeaconHighRssiThreshold_t + *)(tlvptr); + tlvptr += + (le16_to_cpu + (pHighRssiThreshold->Header.len) + + sizeof(MrvlIEtypesHeader_t)); + i -= (le16_to_cpu + (pHighRssiThreshold->Header.len) + + sizeof(MrvlIEtypesHeader_t)); + break; + + case TLV_TYPE_RSSI_LOW: + low = *(t_s8 *)(tlvptr + sizeof(t_u16) + + sizeof(t_u16)); + pLowRssiThreshold = + (MrvlIEtypes_BeaconLowRssiThreshold_t + *)(tlvptr); + tlvptr += + (le16_to_cpu + (pLowRssiThreshold->Header.len) + + sizeof(MrvlIEtypesHeader_t)); + i -= (le16_to_cpu(pLowRssiThreshold->Header.len) + + sizeof(MrvlIEtypesHeader_t)); + break; + + case TLV_TYPE_SNR_HIGH: + high = *(t_s8 *)(tlvptr + sizeof(t_u16) + + sizeof(t_u16)); + pHighSnrThreshold = + (MrvlIEtypes_BeaconHighSnrThreshold_t + *)(tlvptr); + tlvptr += + (le16_to_cpu + (pHighSnrThreshold->Header.len) + + sizeof(MrvlIEtypesHeader_t)); + i -= (le16_to_cpu(pHighSnrThreshold->Header.len) + + sizeof(MrvlIEtypesHeader_t)); + break; + + case TLV_TYPE_SNR_LOW: + low = *(t_s8 *)(tlvptr + sizeof(t_u16) + + sizeof(t_u16)); + pLowSnrThreshold = + (MrvlIEtypes_BeaconLowSnrThreshold_t + *)(tlvptr); + tlvptr += + (le16_to_cpu + (pLowSnrThreshold->Header.len) + + sizeof(MrvlIEtypesHeader_t)); + i -= (le16_to_cpu(pLowSnrThreshold->Header.len) + + sizeof(MrvlIEtypesHeader_t)); + break; + } + } + + printf("%-13s| High = %4d | Low = %4d |\n", + states[state], high, low); + } + puts(""); + +done: + if (buffer) + free(buffer); + if (cmd) + free(cmd); + return ret; +} + +/** + * @brief Issue getra rssi/snr command + * + * @param argc number of arguments + * @param argv A pointer to arguments array + * + * @return MLAN_STATUS_SUCCESS--success, otherwise--fail + */ +static int +roamGetRssiStatsThreshold(int argc, char *argv[]) +{ + return roamGetStatsThreshold(argc, argv, RSSI_THRESHOLD); +} + +/** + * @brief Coverts ms to exactTime + * + * @param ms number of milliseconds + * @param t converted into this structure + * + * @return none + */ +static void +ms2exactTime(t_u32 ms, ExactTime_t *t) +{ + memset(t, 0, sizeof(ExactTime_t)); + + t->msecs = ms % 1000; + if (ms >= 1000) { + ms = (ms - t->msecs) / 1000; + t->secs = ms % 60; + if (ms >= 60) { + ms = (ms - t->secs) / 60; + t->mins = ms % 60; + if (ms >= 60) { + ms = (ms - t->mins) / 60; + t->hrs = ms; + } + } + } + return; +} + +/** + * @brief Issue getra neighbor assessment command + * + * @pNborAssessment neighbour assessment struct + * + * @return MLAN_STATUS_SUCCESS--success, otherwise--fail + */ +static int +getNborAssessment(HostCmd_DS_CMD_ROAMAGENT_NEIGHBOR_ASSESSMENT + *pNborAssessmentParam) +{ + int ret = MLAN_STATUS_SUCCESS; + struct ifreq ifr; + t_u8 *buffer = NULL, *pos = NULL; + t_u32 cmd_len = 0, cmd_header_len; + struct eth_priv_cmd *cmd = NULL; + HostCmd_DS_GEN *hostcmd; + HostCmd_DS_CMD_ROAMAGENT_NEIGHBOR_ASSESSMENT *pNborAssessment; + + /* + * NEIGHBOR_ASSESSMENT + */ + cmd_header_len = strlen(CMD_NXP) + strlen(HOSTCMD); + + buffer = (t_u8 *)malloc(BUFFER_LENGTH); + if (buffer == NULL) { + fprintf(stderr, "Cannot alloc memory\n"); + ret = ENOMEM; + goto done; + } + memset(buffer, 0, BUFFER_LENGTH); + + cmd = (struct eth_priv_cmd *)malloc(sizeof(struct eth_priv_cmd)); + if (!cmd) { + printf("ERR:Cannot allocate buffer for command!\n"); + free(buffer); + ret = ENOMEM; + goto done; + } + + /* Fill up buffer */ +#ifdef USERSPACE_32BIT_OVER_KERNEL_64BIT + memset(cmd, 0, sizeof(struct eth_priv_cmd)); + memcpy(&cmd->buf, &buffer, sizeof(buffer)); +#else + cmd->buf = buffer; +#endif + cmd->used_len = 0; + cmd->total_len = BUFFER_LENGTH; + + /* buffer = MRVL_CMD */ + strncpy((char *)buffer, CMD_NXP, strlen(CMD_NXP)); + strncpy((char *)buffer + strlen(CMD_NXP), HOSTCMD, strlen(HOSTCMD)); + + /* buffer = MRVL_CMD */ + hostcmd = (HostCmd_DS_GEN *)(buffer + cmd_header_len + sizeof(t_u32)); + + /* Point after host command header */ + pos = (t_u8 *)hostcmd + S_DS_GEN; + + pNborAssessment = (HostCmd_DS_CMD_ROAMAGENT_NEIGHBOR_ASSESSMENT *)pos; + cmd_len = S_DS_GEN + sizeof(pNborAssessment->action); + pNborAssessment->action = cpu_to_le16(HostCmd_ACT_GEN_GET); + hostcmd->command = + cpu_to_le16(HostCmd_CMD_ROAMAGENT_NEIGHBOR_ASSESSMENT); + hostcmd->size = cpu_to_le16(cmd_len); + hostcmd->seq_num = 0; + hostcmd->result = 0; + + /* Put buffer length */ + memcpy(buffer + cmd_header_len, &cmd_len, sizeof(t_u32)); + + /* Initialize the ifr structure */ + memset(&ifr, 0, sizeof(ifr)); + strncpy(ifr.ifr_ifrn.ifrn_name, dev_name, strlen(dev_name)); + ifr.ifr_ifru.ifru_data = (void *)cmd; + /* Perform ioctl */ + if (ioctl(sockfd, MLAN_ETH_PRIV, &ifr)) { + perror("ioctl[GetNeibhorAssesinfo]"); + printf("ERR:Command sending failed!\n"); + ret = -EFAULT; + goto done; + } + /* + * ENDIANNESS for Response + */ + pNborAssessment->QualifyingNumNeighbor = + le16_to_cpu(pNborAssessment->QualifyingNumNeighbor); + pNborAssessment->ShortBlacklistPeriod = + le32_to_cpu(pNborAssessment->ShortBlacklistPeriod); + pNborAssessment->LongBlacklistPeriod = + le32_to_cpu(pNborAssessment->LongBlacklistPeriod); + pNborAssessment->StaleCount = le16_to_cpu(pNborAssessment->StaleCount); + pNborAssessment->StalePeriod = + le32_to_cpu(pNborAssessment->StalePeriod); + + memcpy((void *)pNborAssessmentParam, (void *)pNborAssessment, + sizeof(HostCmd_DS_CMD_ROAMAGENT_NEIGHBOR_ASSESSMENT)); + +done: + if (buffer) + free(buffer); + if (cmd) + free(cmd); + return ret; +} + +/** + * @brief Display exactTime structure elements + * + * @param t ExactTime_t struct + * + * @return None + */ +static void +printExactTime2stdout(ExactTime_t *t) +{ + int flag = 0; + if (t->hrs) { + printf("%dh ", t->hrs); + flag = 1; + } + if (t->mins) { + printf("%dm ", t->mins); + flag = 1; + } + if (t->secs) { + printf("%ds ", t->secs); + flag = 1; + } + if (t->msecs) { + printf("%dms", t->msecs); + flag = 1; + } + if (!flag) { + printf(" 0"); + } +} + +static int +printNeighborAssessmentConfig(void) +{ + HostCmd_DS_CMD_ROAMAGENT_NEIGHBOR_ASSESSMENT nborAssessment; + int idx; + int threshDisp = FALSE; + + if (getNborAssessment(&nborAssessment) != MLAN_STATUS_SUCCESS) { + return MLAN_STATUS_FAILURE; + } + + printf("----------------------------------------------------------\n"); + printf(" Neighbor Threshold Parameters\n"); + printf("----------------------------------------------------------\n"); + printf(" Neighbors needed for tracking mode = %d\n", + nborAssessment.QualifyingNumNeighbor); + printf(" Config RSSI qualification offset = %d dB\n", + nborAssessment.ConfQualSignalStrength); + printf(" Active RSSI qualification offset = %d dB\n", + nborAssessment.ActiveQualSignalStrength); + printf(" Short black list period = %d ms\n", + (int)nborAssessment.ShortBlacklistPeriod); + printf(" Long black list period = %d ms\n", + (int)nborAssessment.LongBlacklistPeriod); + printf(" Stale count = %d\n", + (int)nborAssessment.StaleCount); + printf(" Stale period = %d ms\n", + (int)nborAssessment.StalePeriod); + printf(" Proactive Roaming Thresholds ="); + for (idx = 0; idx < NELEMENTS(nborAssessment.RoamThresh); idx++) { + if (nborAssessment.RoamThresh[idx].RssiNborDiff) { + if (threshDisp) { + printf(" "); + } + + threshDisp = TRUE; + printf("%3d to %4d [%d]\n", + nborAssessment.RoamThresh[idx].RssiHighLevel, + nborAssessment.RoamThresh[idx].RssiLowLevel, + nborAssessment.RoamThresh[idx].RssiNborDiff); + } + } + + if (!threshDisp) { + puts(" < None >"); + } + puts(""); + + return MLAN_STATUS_SUCCESS; +} + +/** + * @brief Issue getra neighbors command + * + * @param argc number of arguments + * @param argv A pointer to arguments array + * + * @return MLAN_STATUS_SUCCESS--success, otherwise--fail + */ +static int +roamGetNborList(int argc, char *argv[]) +{ + int ret = MLAN_STATUS_SUCCESS; + int cmdresplen, i; + struct ifreq ifr; + char neighflag[6]; + ExactTime_t t; + t_u16 tlv; + t_u8 *buffer = NULL, *pos = NULL, *tlvptr = NULL; + t_u32 cmd_len = 0, cmd_header_len; + struct eth_priv_cmd *cmd = NULL; + HostCmd_DS_GEN *hostcmd; + HostCmd_DS_CMD_ROAMAGENT_NEIGHBORLIST *pNborList; + MrvlIEtypes_NeighborEntry_t *pNeighbor; + + /* + * NEIGHBOR_LIST + */ + cmd_header_len = strlen(CMD_NXP) + strlen(HOSTCMD); + + buffer = (t_u8 *)malloc(BUFFER_LENGTH); + if (buffer == NULL) { + fprintf(stderr, "Cannot alloc memory\n"); + ret = ENOMEM; + goto done; + } + memset(buffer, 0, BUFFER_LENGTH); + + cmd = (struct eth_priv_cmd *)malloc(sizeof(struct eth_priv_cmd)); + if (!cmd) { + printf("ERR:Cannot allocate buffer for command!\n"); + free(buffer); + ret = ENOMEM; + goto done; + } + + /* Fill up buffer */ +#ifdef USERSPACE_32BIT_OVER_KERNEL_64BIT + memset(cmd, 0, sizeof(struct eth_priv_cmd)); + memcpy(&cmd->buf, &buffer, sizeof(buffer)); +#else + cmd->buf = buffer; +#endif + cmd->used_len = 0; + cmd->total_len = BUFFER_LENGTH; + + /* buffer = MRVL_CMD */ + strncpy((char *)buffer, CMD_NXP, strlen(CMD_NXP)); + strncpy((char *)buffer + strlen(CMD_NXP), HOSTCMD, strlen(HOSTCMD)); + + /* buffer = MRVL_CMD */ + hostcmd = (HostCmd_DS_GEN *)(buffer + cmd_header_len + sizeof(t_u32)); + + /* Point after host command header */ + pos = (t_u8 *)hostcmd + S_DS_GEN; + + pNborList = (HostCmd_DS_CMD_ROAMAGENT_NEIGHBORLIST *)pos; + cmd_len = S_DS_GEN + sizeof(pNborList->action); + pNborList->action = cpu_to_le16(HostCmd_ACT_GEN_GET); + hostcmd->command = cpu_to_le16(HostCmd_CMD_ROAMAGENT_NEIGHBORLIST); + hostcmd->size = cpu_to_le16(cmd_len); + hostcmd->seq_num = 0; + hostcmd->result = 0; + + /* Put buffer length */ + memcpy(buffer + cmd_header_len, &cmd_len, sizeof(t_u32)); + + /* Initialize the ifr structure */ + memset(&ifr, 0, sizeof(ifr)); + strncpy(ifr.ifr_ifrn.ifrn_name, dev_name, strlen(dev_name)); + ifr.ifr_ifru.ifru_data = (void *)cmd; + /* Perform ioctl */ + if (ioctl(sockfd, MLAN_ETH_PRIV, &ifr)) { + perror("ioctl[roamneighborlist]"); + printf("ERR:Command sending failed!\n"); + ret = -EFAULT; + goto done; + } + + cmdresplen = le16_to_cpu(hostcmd->size); + cmdresplen -= cmd_len + sizeof(pNborList->Reserved); + tlvptr = pNborList->TlvBuffer; + + printf("----------------------------------------------------" + "--------------\n"); + printf(" BSSID | RSSI | Age | Qualified |" + " Blacklist Duration\n"); + printf("----------------------------------------------------" + "--------------\n"); + + i = 0; + + while (cmdresplen > 2) { + i++; + /* + * ENDIANNESS for Response + */ + tlv = le16_to_cpu(*((t_u16 *)(tlvptr))); + switch (tlv) { + case TLV_TYPE_NEIGHBOR_ENTRY: + pNeighbor = (MrvlIEtypes_NeighborEntry_t *)(tlvptr); + pNeighbor->SignalStrength = + le16_to_cpu(pNeighbor->SignalStrength); + pNeighbor->Age = le16_to_cpu(pNeighbor->Age); + pNeighbor->QualifiedNeighborBitmap = + le32_to_cpu(pNeighbor->QualifiedNeighborBitmap); + + pNeighbor->BlackListDuration = + le32_to_cpu(pNeighbor->BlackListDuration); + ms2exactTime(pNeighbor->BlackListDuration, &t); + neighflag[0] = '\0'; + + if ((pNeighbor->QualifiedNeighborBitmap + & (BIT_NEIGHFLAG_RSSI + | BIT_NEIGHFLAG_AGE + | BIT_NEIGHFLAG_BLACKLIST + | BIT_NEIGHFLAG_ADMISSION_CAP + | BIT_NEIGHFLAG_UPLINK_RSSI)) + == (BIT_NEIGHFLAG_RSSI + | BIT_NEIGHFLAG_AGE + | BIT_NEIGHFLAG_BLACKLIST + | BIT_NEIGHFLAG_ADMISSION_CAP + | BIT_NEIGHFLAG_UPLINK_RSSI)) { + strcat(neighflag, "Yes"); + } else { + strcat(neighflag, "No: "); + if (! + (pNeighbor-> + QualifiedNeighborBitmap & + BIT_NEIGHFLAG_RSSI)) { + strcat(neighflag, "R"); + } + if (! + (pNeighbor-> + QualifiedNeighborBitmap & + BIT_NEIGHFLAG_AGE)) { + strcat(neighflag, "S"); + } + if (!(pNeighbor->QualifiedNeighborBitmap + & BIT_NEIGHFLAG_BLACKLIST)) { + strcat(neighflag, "B"); + } + if (!(pNeighbor->QualifiedNeighborBitmap + & BIT_NEIGHFLAG_ADMISSION_CAP)) { + strcat(neighflag, "A"); + } + if (!(pNeighbor->QualifiedNeighborBitmap + & BIT_NEIGHFLAG_UPLINK_RSSI)) { + strcat(neighflag, "U"); + } + } + printf(" %02x:%02x:%02x:%02x:%02x:%02x | %3d | %5d | %9s | ", pNeighbor->Bssid[0], pNeighbor->Bssid[1], pNeighbor->Bssid[2], pNeighbor->Bssid[3], pNeighbor->Bssid[4], pNeighbor->Bssid[5], pNeighbor->SignalStrength, pNeighbor->Age, neighflag); + + if (pNeighbor->BlackListDuration) { + printExactTime2stdout(&t); + } else { + printf("Not Blacklisted"); + } + printf("\n"); + + tlvptr += (le16_to_cpu(pNeighbor->Header.len) + + sizeof(MrvlIEtypesHeader_t)); + cmdresplen -= (le16_to_cpu(pNeighbor->Header.len) + + sizeof(MrvlIEtypesHeader_t)); + break; + + default: + printf("\nIncorrect response.\n\n"); + break; + } + } + + if (i == 0) { + printf("< Empty >\n"); + } + + printf("\n"); + +done: + if (buffer) + free(buffer); + if (cmd) + free(cmd); + return ret; +} + +/** + * @brief Issue getra neighbor params command + * + * @param argc number of arguments + * @param argv A pointer to arguments array + * + * @return MLAN_STATUS_SUCCESS--success, otherwise--fail + */ +static int +roamGetNborParams(int argc, char *argv[]) +{ + printNeighborAssessmentConfig(); + + return MLAN_STATUS_SUCCESS; +} + +/** + * @brief Issue getra metrics command + * + * @param argc number of arguments + * @param argv A pointer to arguments array + * + * @return MLAN_STATUS_SUCCESS--success, otherwise--fail + */ +static int +roamGetMetrics(int argc, char *argv[]) +{ + int ret = MLAN_STATUS_SUCCESS; + int i; + t_u16 Metrics = 0; + struct ifreq ifr; + t_u8 *buffer = NULL, *pos = NULL; + t_u32 cmd_len = 0, cmd_header_len; + struct eth_priv_cmd *cmd = NULL; + HostCmd_DS_GEN *hostcmd; + HostCmd_DS_CMD_ROAMAGENT_ADV_METRIC_THRESHOLD *metricscmd; + + const char *metricslist[] = { "beacon", "data", "per", "fer" }; + + if (argc != 0) { + puts("\nIncorrect number of arguments.\n"); + ret = MLAN_STATUS_FAILURE; + goto done; + } + + cmd_header_len = strlen(CMD_NXP) + strlen(HOSTCMD); + + buffer = (t_u8 *)malloc(BUFFER_LENGTH); + if (buffer == NULL) { + fprintf(stderr, "Cannot alloc memory\n"); + ret = ENOMEM; + goto done; + } + memset(buffer, 0, BUFFER_LENGTH); + + cmd = (struct eth_priv_cmd *)malloc(sizeof(struct eth_priv_cmd)); + if (!cmd) { + printf("ERR:Cannot allocate buffer for command!\n"); + free(buffer); + ret = ENOMEM; + goto done; + } + + /* Fill up buffer */ +#ifdef USERSPACE_32BIT_OVER_KERNEL_64BIT + memset(cmd, 0, sizeof(struct eth_priv_cmd)); + memcpy(&cmd->buf, &buffer, sizeof(buffer)); +#else + cmd->buf = buffer; +#endif + cmd->used_len = 0; + cmd->total_len = BUFFER_LENGTH; + + /* buffer = MRVL_CMD */ + strncpy((char *)buffer, CMD_NXP, strlen(CMD_NXP)); + strncpy((char *)buffer + strlen(CMD_NXP), HOSTCMD, strlen(HOSTCMD)); + + /* buffer = MRVL_CMD */ + hostcmd = (HostCmd_DS_GEN *)(buffer + cmd_header_len + sizeof(t_u32)); + + /* Point after host command header */ + pos = (t_u8 *)hostcmd + S_DS_GEN; + + metricscmd = (HostCmd_DS_CMD_ROAMAGENT_ADV_METRIC_THRESHOLD *)pos; + cmd_len = S_DS_GEN + sizeof(metricscmd->action); + metricscmd->action = cpu_to_le16(HostCmd_ACT_GEN_GET); + hostcmd->command = + cpu_to_le16(HostCmd_CMD_ROAMAGENT_ADV_METRIC_THRESHOLD); + hostcmd->size = cpu_to_le16(cmd_len); + hostcmd->seq_num = 0; + hostcmd->result = 0; + + /* Put buffer length */ + memcpy(buffer + cmd_header_len, &cmd_len, sizeof(t_u32)); + + /* Initialize the ifr structure */ + memset(&ifr, 0, sizeof(ifr)); + strncpy(ifr.ifr_ifrn.ifrn_name, dev_name, strlen(dev_name)); + ifr.ifr_ifru.ifru_data = (void *)cmd; + /* Perform ioctl */ + if (ioctl(sockfd, MLAN_ETH_PRIV, &ifr)) { + perror("ioctl[roam set matrics]"); + printf("ERR:Command sending failed!\n"); + ret = -EFAULT; + goto done; + } + + Metrics = le16_to_cpu(metricscmd->Metrics); + + if (le16_to_cpu(hostcmd->result) == MLAN_STATUS_SUCCESS) { + printf("\n Metrics Activated: "); + for (i = 0; (unsigned int)i < NELEMENTS(metricslist); i++) { + if (Metrics & BIT(i)) { + printf(" %s ", metricslist[i]); + } + } + printf("\n"); + + if (Metrics & BIT(3)) { + printf("FER Threshold : %u %% \n", + metricscmd->UcFerThresholdValue); + printf("FER Packet Threshold: %d \n", + le32_to_cpu(metricscmd->UiFerPktThreshold)); + printf("FER period. Stable : %d ms, Degrading : %d ms, " + "Unacceptable : %d ms\n", + le32_to_cpu(metricscmd->StableFERPeriod_ms), + le32_to_cpu(metricscmd->DegradingFERPeriod_ms), + le32_to_cpu(metricscmd-> + UnacceptableFERPeriod_ms)); + } + + if (Metrics & BIT(2)) { + printf("PER Threshold : %u %% \n", + metricscmd->UcPerThresholdValue); + printf("PER Packet Threshold: %d \n", + le32_to_cpu(metricscmd->UiPerPktThreshold)); + printf("PER period. Stable : %d ms, Degrading : %d ms, " + "Unacceptable : %d ms\n", + le32_to_cpu(metricscmd->StablePERPeriod_ms), + le32_to_cpu(metricscmd->DegradingPERPeriod_ms), + le32_to_cpu(metricscmd-> + UnacceptablePERPeriod_ms)); + } + + if (Metrics & BIT(1)) { + printf("Data Packet Threshold: %d \n", + le32_to_cpu(metricscmd->UiRxPktThreshold)); + } + + if ((Metrics & BIT(1)) || (Metrics & BIT(2)) || + (Metrics & BIT(3))) { + + printf("Inactivity Period: %d ms \n", + le32_to_cpu(metricscmd-> + InactivityPeriodThreshold_ms)); + } + } else { + printf("command response failure %d.\n", + le16_to_cpu(hostcmd->result)); + } + +done: + if (buffer) + free(buffer); + if (cmd) + free(cmd); + return ret; +} + +/** + * @brief Issue getra scanperiod command + * + * @param argc number of arguments + * @param argv A pointer to arguments array + * + * @return MLAN_STATUS_SUCCESS--success, otherwise--fail + */ +static int +roamGetScanPeriod(int argc, char *argv[]) +{ + int ret = MLAN_STATUS_SUCCESS; + int state = 0, scanmode = 0, cmdresplen; + struct ifreq ifr; + t_u8 *buffer = NULL, *pos = NULL, *tlvptr = NULL; + t_u16 tlv; + t_u32 cmd_len = 0, cmd_header_len; + struct eth_priv_cmd *cmd = NULL; + HostCmd_DS_GEN *hostcmd; + HostCmd_DS_CMD_ROAMAGENT_NEIGHBOR_SCANPERIOD_RSP *scanPeriodInfo; + MrvlIEtypes_NeighborScanPeriod_t *pscanperiod; + const char *states[] = { "Stable", "Degrading", "Unacceptable" }; + const char *scanmodes[] = { "Discovery", "Tracking" }; + /* scanperiodValues[state][scanmode] */ + t_u32 values[3][2]; + + /* + * NEIGHBOR_SCANPERIOD + */ + cmd_header_len = strlen(CMD_NXP) + strlen(HOSTCMD); + + buffer = (t_u8 *)malloc(BUFFER_LENGTH); + if (buffer == NULL) { + fprintf(stderr, "Cannot alloc memory\n"); + ret = ENOMEM; + goto done; + } + memset(buffer, 0, BUFFER_LENGTH); + + cmd = (struct eth_priv_cmd *)malloc(sizeof(struct eth_priv_cmd)); + if (!cmd) { + printf("ERR:Cannot allocate buffer for command!\n"); + free(buffer); + ret = ENOMEM; + goto done; + } + + /* Fill up buffer */ +#ifdef USERSPACE_32BIT_OVER_KERNEL_64BIT + memset(cmd, 0, sizeof(struct eth_priv_cmd)); + memcpy(&cmd->buf, &buffer, sizeof(buffer)); +#else + cmd->buf = buffer; +#endif + cmd->used_len = 0; + cmd->total_len = BUFFER_LENGTH; + + /* buffer = MRVL_CMD */ + strncpy((char *)buffer, CMD_NXP, strlen(CMD_NXP)); + strncpy((char *)buffer + strlen(CMD_NXP), HOSTCMD, strlen(HOSTCMD)); + + /* buffer = MRVL_CMD */ + hostcmd = (HostCmd_DS_GEN *)(buffer + cmd_header_len + sizeof(t_u32)); + + /* Point after host command header */ + pos = (t_u8 *)hostcmd + S_DS_GEN; + + scanPeriodInfo = + (HostCmd_DS_CMD_ROAMAGENT_NEIGHBOR_SCANPERIOD_RSP *)pos; + cmd_len = S_DS_GEN + sizeof(scanPeriodInfo->action); + scanPeriodInfo->action = cpu_to_le16(HostCmd_ACT_GEN_GET); + hostcmd->command = + cpu_to_le16(HostCmd_CMD_ROAMAGENT_NEIGHBOR_SCAN_PERIOD); + hostcmd->size = cpu_to_le16(cmd_len); + hostcmd->seq_num = 0; + hostcmd->result = 0; + + /* Put buffer length */ + memcpy(buffer + cmd_header_len, &cmd_len, sizeof(t_u32)); + + /* Initialize the ifr structure */ + memset(&ifr, 0, sizeof(ifr)); + strncpy(ifr.ifr_ifrn.ifrn_name, dev_name, strlen(dev_name)); + ifr.ifr_ifru.ifru_data = (void *)cmd; + /* Perform ioctl */ + if (ioctl(sockfd, MLAN_ETH_PRIV, &ifr)) { + perror("ioctl[roamscanperiod]"); + printf("ERR:Command sending failed!\n"); + ret = -EFAULT; + goto done; + } + + cmdresplen = le16_to_cpu(hostcmd->size); + cmdresplen -= cmd_len + sizeof(scanPeriodInfo->Reserved); + tlvptr = scanPeriodInfo->TlvBuffer; + while (cmdresplen > 2) { + /* + * ENDIANNESS for Response + */ + tlv = le16_to_cpu(*((t_u16 *)(tlvptr))); + switch (tlv) { + case TLV_TYPE_NEIGHBOR_SCANPERIOD: + pscanperiod = + (MrvlIEtypes_NeighborScanPeriod_t *)(tlvptr); + pscanperiod->SearchMode = + le16_to_cpu(pscanperiod->SearchMode); + pscanperiod->State = le16_to_cpu(pscanperiod->State); + pscanperiod->ScanPeriod = + le32_to_cpu(pscanperiod->ScanPeriod); + state = pscanperiod->State; + scanmode = pscanperiod->SearchMode; + if ((state < STATE_STABLE) || + (state > STATE_UNACCEPTABLE)) { + puts("\nIncorrect state in response.\n"); + } + if ((scanmode < DISCOVERY_MODE) || + (scanmode > TRACKING_MODE)) { + puts("\nIncorrect scanmode in response.\n"); + } + values[state - 1][scanmode - 1] = + pscanperiod->ScanPeriod; + tlvptr += + (le16_to_cpu(pscanperiod->Header.len) + + sizeof(MrvlIEtypesHeader_t)); + cmdresplen -= + (le16_to_cpu(pscanperiod->Header.len) + + sizeof(MrvlIEtypesHeader_t)); + break; + + default: + puts("\nIncorrect response.\n"); + break; + } + } + + for (state = STATE_STABLE - 1; state < STATE_UNACCEPTABLE; state++) { + printf("\nState: %-14s ", states[state]); + for (scanmode = DISCOVERY_MODE - 1; + scanmode < TRACKING_MODE; scanmode++) { + printf("%s = %6d ms\t", + scanmodes[scanmode], + (int)values[state][scanmode]); + } + } + printf("\n"); +done: + if (buffer) + free(buffer); + if (cmd) + free(cmd); + return ret; +} + +/** + * @brief Issue getra command + * + * @param pcontrol control struct to return + * + * @return MLAN_STATUS_SUCCESS--success, otherwise--fail + */ +static int +getControl(HostCmd_DS_CMD_ROAMAGENT_CONTROL *pcontrol) +{ + int ret = MLAN_STATUS_SUCCESS; + struct ifreq ifr; + t_u8 *buffer = NULL, *pos = NULL; + t_u32 cmd_len = 0, cmd_header_len; + struct eth_priv_cmd *cmd = NULL; + HostCmd_DS_GEN *hostcmd; + HostCmd_DS_CMD_ROAMAGENT_CONTROL *roamcontrolcmd = NULL; + + cmd_header_len = strlen(CMD_NXP) + strlen(HOSTCMD); + + buffer = (t_u8 *)malloc(BUFFER_LENGTH); + if (buffer == NULL) { + fprintf(stderr, "Cannot alloc memory\n"); + ret = ENOMEM; + goto done; + } + memset(buffer, 0, BUFFER_LENGTH); + + cmd = (struct eth_priv_cmd *)malloc(sizeof(struct eth_priv_cmd)); + if (!cmd) { + printf("ERR:Cannot allocate buffer for command!\n"); + free(buffer); + ret = ENOMEM; + goto done; + } + + /* Fill up buffer */ +#ifdef USERSPACE_32BIT_OVER_KERNEL_64BIT + memset(cmd, 0, sizeof(struct eth_priv_cmd)); + memcpy(&cmd->buf, &buffer, sizeof(buffer)); +#else + cmd->buf = buffer; +#endif + cmd->used_len = 0; + cmd->total_len = BUFFER_LENGTH; + + /* buffer = MRVL_CMD */ + strncpy((char *)buffer, CMD_NXP, strlen(CMD_NXP)); + strncpy((char *)buffer + strlen(CMD_NXP), HOSTCMD, strlen(HOSTCMD)); + + /* buffer = MRVL_CMD */ + hostcmd = (HostCmd_DS_GEN *)(buffer + cmd_header_len + sizeof(t_u32)); + cmd_len = S_DS_GEN + sizeof(roamcontrolcmd->action); + hostcmd->command = cpu_to_le16(HostCmd_CMD_ROAMAGENT_CONTROL); + hostcmd->size = cpu_to_le16(cmd_len); + hostcmd->seq_num = 0; + hostcmd->result = 0; + + /* Point after host command header */ + pos = (t_u8 *)hostcmd + S_DS_GEN; + + roamcontrolcmd = (HostCmd_DS_CMD_ROAMAGENT_CONTROL *)pos; + + roamcontrolcmd->action = cpu_to_le16(HostCmd_ACT_GEN_GET); + + /* Put buffer length */ + memcpy(buffer + cmd_header_len, &cmd_len, sizeof(t_u32)); + + /* Initialize the ifr structure */ + memset(&ifr, 0, sizeof(ifr)); + strncpy(ifr.ifr_ifrn.ifrn_name, dev_name, strlen(dev_name)); + ifr.ifr_ifru.ifru_data = (void *)cmd; + /* Perform ioctl */ + if (ioctl(sockfd, MLAN_ETH_PRIV, &ifr)) { + perror("ioctl[roamcontrol]"); + printf("ERR:Command sending failed!\n"); + ret = -EFAULT; + goto done; + } + + memcpy((void *)pcontrol, + (void *)roamcontrolcmd, + sizeof(HostCmd_DS_CMD_ROAMAGENT_CONTROL)); + +done: + if (buffer) + free(buffer); + if (cmd) + free(cmd); + return ret; +} + +/** + * @brief Issue getra command + * + * @param argc number of arguments + * @param argv A pointer to arguments array + * @param control roma control indicator value + * + * @return MLAN_STATUS_SUCCESS--success, otherwise--fail + */ +static int +roamGetEventBitmap(int argc, char *argv[]) +{ + t_u8 hostevent; + HostCmd_DS_CMD_ROAMAGENT_CONTROL roamcontrolcmd; + + if (getControl(&roamcontrolcmd) != MLAN_STATUS_SUCCESS) { + return MLAN_STATUS_FAILURE; + } + + hostevent = roamcontrolcmd.HostEvent; + if (!(hostevent | 0)) { + puts("\nHost events are disabled.\n"); + return MLAN_STATUS_SUCCESS; + } + printf("\nHost events enabled: "); + if (hostevent & HOST_EVENT_NBOR_ENABLE) + printf("neighbor "); + + if (hostevent & HOST_EVENT_ROAM_ENABLE) + printf("roam "); + + if (hostevent & HOST_EVENT_STATE_ENABLE) + printf("state"); + + printf("\n"); + return MLAN_STATUS_SUCCESS; +} + +/** + * @brief Issue getra command + * + * @param argc number of arguments + * @param argv A pointer to arguments array + * @param control roma control indicator value + * + * @return MLAN_STATUS_SUCCESS--success, otherwise--fail + */ +static int +roamGetControl(int argc, char *argv[]) +{ + t_u8 control; + HostCmd_DS_CMD_ROAMAGENT_CONTROL roamcontrolcmd; + + if (getControl(&roamcontrolcmd) != MLAN_STATUS_SUCCESS) { + return MLAN_STATUS_FAILURE; + } + + control = roamcontrolcmd.Control; + printf("\nGlobal roaming agent state: "); + if (control & ROAM_CONTROL_ENABLE) { + printf("enabled, "); + if (control & ROAM_CONTROL_SUSPEND) + printf("suspend.\n"); + else + printf("resume.\n"); + } else + printf("disabled.\n"); + + printf("Crossband: "); + if (control & CROSSBAND_ENABLE) + printf("enabled.\n"); + else + printf("disabled.\n"); + + return MLAN_STATUS_SUCCESS; +} + +/** + * @brief Internal funtion to issue getra backoff + * + * @param roambackoffcmd Backoff command structure + * @return MLAN_STATUS_SUCCESS--success, otherwise--fail + */ +static int +getBackOff(HostCmd_DS_CMD_ROAMAGENT_BACKOFF *roambackoffcmdParam) +{ + int ret = MLAN_STATUS_SUCCESS; + struct ifreq ifr; + t_u8 *buffer = NULL, *pos = NULL; + t_u32 cmd_len = 0, cmd_header_len; + struct eth_priv_cmd *cmd = NULL; + HostCmd_DS_GEN *hostcmd; + HostCmd_DS_CMD_ROAMAGENT_BACKOFF *roambackoffcmd; + + cmd_header_len = strlen(CMD_NXP) + strlen(HOSTCMD); + + buffer = (t_u8 *)malloc(BUFFER_LENGTH); + if (buffer == NULL) { + fprintf(stderr, "Cannot alloc memory\n"); + ret = ENOMEM; + goto done; + } + memset(buffer, 0, BUFFER_LENGTH); + + cmd = (struct eth_priv_cmd *)malloc(sizeof(struct eth_priv_cmd)); + if (!cmd) { + printf("ERR:Cannot allocate buffer for command!\n"); + free(buffer); + ret = ENOMEM; + goto done; + } + + /* Fill up buffer */ +#ifdef USERSPACE_32BIT_OVER_KERNEL_64BIT + memset(cmd, 0, sizeof(struct eth_priv_cmd)); + memcpy(&cmd->buf, &buffer, sizeof(buffer)); +#else + cmd->buf = buffer; +#endif + cmd->used_len = 0; + cmd->total_len = BUFFER_LENGTH; + + /* buffer = MRVL_CMD */ + strncpy((char *)buffer, CMD_NXP, strlen(CMD_NXP)); + strncpy((char *)buffer + strlen(CMD_NXP), HOSTCMD, strlen(HOSTCMD)); + + /* buffer = MRVL_CMD */ + hostcmd = (HostCmd_DS_GEN *)(buffer + cmd_header_len + sizeof(t_u32)); + + /* Point after host command header */ + pos = (t_u8 *)hostcmd + S_DS_GEN; + + roambackoffcmd = (HostCmd_DS_CMD_ROAMAGENT_BACKOFF *)pos; + cmd_len = S_DS_GEN + sizeof(roambackoffcmd->action); + roambackoffcmd->action = cpu_to_le16(HostCmd_ACT_GEN_GET); + hostcmd->command = cpu_to_le16(HostCmd_CMD_ROAMAGENT_BACKOFF); + hostcmd->size = cpu_to_le16(cmd_len); + hostcmd->seq_num = 0; + hostcmd->result = 0; + + /* Put buffer length */ + memcpy(buffer + cmd_header_len, &cmd_len, sizeof(t_u32)); + + /* Initialize the ifr structure */ + memset(&ifr, 0, sizeof(ifr)); + strncpy(ifr.ifr_ifrn.ifrn_name, dev_name, strlen(dev_name)); + ifr.ifr_ifru.ifru_data = (void *)cmd; + /* Perform ioctl */ + if (ioctl(sockfd, MLAN_ETH_PRIV, &ifr)) { + perror("ioctl[roambackoff]"); + printf("ERR:Command sending failed!\n"); + ret = -EFAULT; + goto done; + } + + /* + * ENDIANNESS for Response + */ + roambackoffcmd->Scans = le16_to_cpu(roambackoffcmd->Scans); + roambackoffcmd->Period = le32_to_cpu(roambackoffcmd->Period); + + memcpy((void *)roambackoffcmdParam, (void *)roambackoffcmd, + sizeof(HostCmd_DS_CMD_ROAMAGENT_BACKOFF)); + +done: + if (buffer) + free(buffer); + if (cmd) + free(cmd); + return ret; +} + +/** + * @brief Issue getra backoff command + * + * @param argc number of arguments + * @param argv A pointer to arguments array + * @param control roma control indicator value + * + * @return MLAN_STATUS_SUCCESS--success, otherwise--fail + */ +static int +roamGetBackOff(int argc, char *argv[]) +{ + HostCmd_DS_CMD_ROAMAGENT_BACKOFF backoffcmd; + + if (getBackOff(&backoffcmd) != MLAN_STATUS_SUCCESS) { + return MLAN_STATUS_FAILURE; + } + + puts(""); + printf("----------------------------------------------------\n"); + printf(" Scanning Backoff Parameters \n"); + printf("----------------------------------------------------\n"); + printf(" Backoff period (max time in tracking) = %d ms\n", + backoffcmd.Period); + printf(" # of discovery scans before backoff = %d\n", + backoffcmd.Scans); + puts(""); + + if (backoffcmd.Scans) { + printf(" - Discovery backoff mode is enabled.\n" + " After %d discovery scans without a change in the number\n" + " of neighbors, the RA will only track the existing\n" + " neighbors until the backoff period expires.\n", + backoffcmd.Scans); + } else { + printf(" - Discovery backoff mode is disabled.\n" + " The RA will only move to tracking mode if a minimum\n" + " number of good neighbors have been found. See the\n" + " getra neighbor command for the current min setting.\n"); + } + puts(""); + + return MLAN_STATUS_SUCCESS; +} + +static int +printGetNeighborDeprecation(int argc, char *argv[]) +{ + printf("\nInfo: getra neighbor replaced with:\n" + " - getra nlist (display neighbor list)\n" + " - getra nparams (display neighbor assessment params)\n\n"); + + return MLAN_STATUS_SUCCESS; +} + +/** + * @brief Get the Roaming agent configuration parameters from FW. + * + * @param argc number of arguments + * @param argv A pointer to arguments array + * + * @return MLAN_STATUS_SUCCESS--success, otherwise--fail + */ +int +process_get_ra_config(int argc, char *argv[]) +{ + if (argc == 3) { + return roamGetControl(argc, argv); + } + + sub_cmd_exec_t subCmds[] = { + {"rssi", 1, 1, roamGetRssiStatsThreshold}, + {"prebcnmiss", 1, 1, roamGetPreBeaconMiss}, + {"failcnt", 1, 1, roamGetFailureCount}, + {"backoff", 1, 1, roamGetBackOff}, + {"neighbor", 2, 0, printGetNeighborDeprecation}, + {"nlist", 2, 1, roamGetNborList}, + {"nparams", 2, 1, roamGetNborParams}, + {"scanperiod", 1, 1, roamGetScanPeriod}, + {"metrics", 1, 1, roamGetMetrics}, + {"event", 1, 1, roamGetEventBitmap} + }; + + return process_sub_cmd(subCmds, NELEMENTS(subCmds), argc, argv); +} + +/** + * @brief Issue setra bcnmiss command + * + * @param argc number of arguments + * @param argv A pointer to arguments array + * + * @return MLAN_STATUS_SUCCESS--success, otherwise--fail + */ +static int +roamSetPreBeaconLoss(int argc, char *argv[]) +{ + int ret = MLAN_STATUS_SUCCESS; + int bcnmiss; + struct ifreq ifr; + t_u8 *buffer = NULL, *pos = NULL; + t_u32 cmd_len = 0, cmd_header_len; + struct eth_priv_cmd *cmd = NULL; + HostCmd_DS_GEN *hostcmd; + HostCmd_DS_CMD_ROAMAGENT_STATISTICS_THRESHOLD *statsthreshold; + MrvlIEtypes_BeaconsMissed_t *beaconmiss; + + if (argc != 1) { + puts("\nIncorrect number of arguments.\n"); + ret = MLAN_STATUS_FAILURE; + goto done; + } + + bcnmiss = atoi(argv[0]); + + cmd_header_len = strlen(CMD_NXP) + strlen(HOSTCMD); + + buffer = (t_u8 *)malloc(BUFFER_LENGTH); + if (buffer == NULL) { + fprintf(stderr, "Cannot alloc memory\n"); + ret = ENOMEM; + goto done; + } + memset(buffer, 0, BUFFER_LENGTH); + + cmd = (struct eth_priv_cmd *)malloc(sizeof(struct eth_priv_cmd)); + if (!cmd) { + printf("ERR:Cannot allocate buffer for command!\n"); + ret = ENOMEM; + goto done; + } + + /* Fill up buffer */ +#ifdef USERSPACE_32BIT_OVER_KERNEL_64BIT + memset(cmd, 0, sizeof(struct eth_priv_cmd)); + memcpy(&cmd->buf, &buffer, sizeof(buffer)); +#else + cmd->buf = buffer; +#endif + cmd->used_len = 0; + cmd->total_len = BUFFER_LENGTH; + + /* buffer = MRVL_CMD */ + strncpy((char *)buffer, CMD_NXP, strlen(CMD_NXP)); + strncpy((char *)buffer + strlen(CMD_NXP), HOSTCMD, strlen(HOSTCMD)); + + /* buffer = MRVL_CMD */ + hostcmd = (HostCmd_DS_GEN *)(buffer + cmd_header_len + sizeof(t_u32)); + + /* Point after host command header */ + pos = (t_u8 *)hostcmd + S_DS_GEN; + + statsthreshold = (HostCmd_DS_CMD_ROAMAGENT_STATISTICS_THRESHOLD *)pos; + cmd_len = sizeof(HostCmd_DS_GEN) + sizeof(statsthreshold->action) + + sizeof(statsthreshold->State) + + sizeof(statsthreshold->Profile) + + sizeof(MrvlIEtypes_BeaconsMissed_t); + + hostcmd->command = + cpu_to_le16(HostCmd_CMD_ROAMAGENT_STATISTICS_THRESHOLD); + hostcmd->size = cpu_to_le16(cmd_len); + hostcmd->seq_num = 0; + hostcmd->result = 0; + + statsthreshold = (HostCmd_DS_CMD_ROAMAGENT_STATISTICS_THRESHOLD *)pos; + statsthreshold->action = cpu_to_le16(HostCmd_ACT_GEN_SET); + statsthreshold->State = STATE_HARDROAM; + + beaconmiss = (MrvlIEtypes_BeaconsMissed_t *)&statsthreshold->TlvBuffer; + beaconmiss->beacon_missed = bcnmiss; + beaconmiss->header.type = cpu_to_le16(TLV_TYPE_PRE_BEACON_LOST); + beaconmiss->header.len = + cpu_to_le16(sizeof(MrvlIEtypes_BeaconsMissed_t) - + sizeof(MrvlIEtypesHeader_t)); + + /* Put buffer length */ + memcpy(buffer + cmd_header_len, &cmd_len, sizeof(t_u32)); + + /* Initialize the ifr structure */ + memset(&ifr, 0, sizeof(ifr)); + strncpy(ifr.ifr_ifrn.ifrn_name, dev_name, strlen(dev_name)); + ifr.ifr_ifru.ifru_data = (void *)cmd; + /* Perform ioctl */ + if (ioctl(sockfd, MLAN_ETH_PRIV, &ifr)) { + perror("ioctl[setra]"); + printf("ERR:Command sending failed!\n"); + ret = -EFAULT; + goto done; + } + + if (le16_to_cpu(hostcmd->result)) { + printf("\nHostCmd Error: ReturnCode=%#04x, Result=%#04x\n\n", + le16_to_cpu(hostcmd->command), + le16_to_cpu(hostcmd->result)); + } else { + roamGetPreBeaconMiss(argc, argv); + } + +done: + if (buffer) + free(buffer); + if (cmd) + free(cmd); + return ret; +} + +/** + * @brief Issue setra failurecnt command + * + * @param argc number of arguments + * @param argv A pointer to arguments array + * + * @return MLAN_STATUS_SUCCESS--success, otherwise--fail + */ +static int +roamSetFailureCount(int argc, char *argv[]) +{ + int ret = MLAN_STATUS_SUCCESS; + int failCount, failTimeThresh; + struct ifreq ifr; + t_u8 *buffer = NULL, *pos = NULL; + t_u32 cmd_len = 0, cmd_header_len; + struct eth_priv_cmd *cmd = NULL; + HostCmd_DS_GEN *hostcmd; + HostCmd_DS_CMD_ROAMAGENT_STATISTICS_THRESHOLD *statsthreshold; + MrvlIEtypes_FailureCount_t *failcnt; + + if (argc != 2) { + puts("\n2 arguments required: FailCnt, FailTimeThresh(ms)\n"); + ret = MLAN_STATUS_FAILURE; + goto done; + } + + failCount = atoi(argv[0]); + failTimeThresh = atoi(argv[1]); + + cmd_header_len = strlen(CMD_NXP) + strlen(HOSTCMD); + + buffer = (t_u8 *)malloc(BUFFER_LENGTH); + if (buffer == NULL) { + fprintf(stderr, "Cannot alloc memory\n"); + ret = ENOMEM; + goto done; + } + memset(buffer, 0, BUFFER_LENGTH); + + cmd = (struct eth_priv_cmd *)malloc(sizeof(struct eth_priv_cmd)); + if (!cmd) { + printf("ERR:Cannot allocate buffer for command!\n"); + ret = ENOMEM; + goto done; + } + + /* Fill up buffer */ +#ifdef USERSPACE_32BIT_OVER_KERNEL_64BIT + memset(cmd, 0, sizeof(struct eth_priv_cmd)); + memcpy(&cmd->buf, &buffer, sizeof(buffer)); +#else + cmd->buf = buffer; +#endif + cmd->used_len = 0; + cmd->total_len = BUFFER_LENGTH; + + /* buffer = MRVL_CMD */ + strncpy((char *)buffer, CMD_NXP, strlen(CMD_NXP)); + strncpy((char *)buffer + strlen(CMD_NXP), HOSTCMD, strlen(HOSTCMD)); + + /* buffer = MRVL_CMD */ + hostcmd = (HostCmd_DS_GEN *)(buffer + cmd_header_len + sizeof(t_u32)); + + /* Point after host command header */ + pos = (t_u8 *)hostcmd + S_DS_GEN; + + statsthreshold = (HostCmd_DS_CMD_ROAMAGENT_STATISTICS_THRESHOLD *)pos; + + cmd_len = (S_DS_GEN + + sizeof(statsthreshold->action) + + sizeof(statsthreshold->State) + + sizeof(statsthreshold->Profile) + + sizeof(MrvlIEtypes_FailureCount_t)); + + hostcmd->command = + cpu_to_le16(HostCmd_CMD_ROAMAGENT_STATISTICS_THRESHOLD); + hostcmd->size = cpu_to_le16(cmd_len); + hostcmd->seq_num = 0; + hostcmd->result = 0; + statsthreshold->action = cpu_to_le16(HostCmd_ACT_GEN_SET); + statsthreshold->State = STATE_HARDROAM; + + failcnt = (MrvlIEtypes_FailureCount_t *)&statsthreshold->TlvBuffer; + failcnt->fail_value = failCount; + failcnt->fail_min_thresh_time_millisecs = cpu_to_le16(failTimeThresh); + failcnt->header.type = cpu_to_le16(TLV_TYPE_FAILCOUNT); + failcnt->header.len = cpu_to_le16(sizeof(MrvlIEtypes_FailureCount_t) + - sizeof(MrvlIEtypesHeader_t)); + + /* Put buffer length */ + memcpy(buffer + cmd_header_len, &cmd_len, sizeof(t_u32)); + + /* Initialize the ifr structure */ + memset(&ifr, 0, sizeof(ifr)); + strncpy(ifr.ifr_ifrn.ifrn_name, dev_name, strlen(dev_name)); + ifr.ifr_ifru.ifru_data = (void *)cmd; + /* Perform ioctl */ + if (ioctl(sockfd, MLAN_ETH_PRIV, &ifr)) { + perror("ioctl[setra]"); + printf("ERR:Command sending failed!\n"); + ret = -EFAULT; + goto done; + } + + if (le16_to_cpu(hostcmd->result)) { + printf("\nHostCmd Error: ReturnCode=%#04x, Result=%#04x\n\n", + le16_to_cpu(hostcmd->command), + le16_to_cpu(hostcmd->result)); + } else { + roamGetFailureCount(argc, argv); + } + +done: + if (buffer) + free(buffer); + if (cmd) + free(cmd); + return ret; +} + +/** + * @brief Issue setra rssi/snr command + * + * @param argc number of arguments + * @param argv A pointer to arguments array + * @param type RSSI/SNR threshold type + * + * @return MLAN_STATUS_SUCCESS--success, otherwise--fail + */ +static int +roamSetStatsThreshold(int argc, char *argv[], int type) +{ + int ret = MLAN_STATUS_SUCCESS; + int i, state = 0, low = 0, high = 0, lowval, highval; + struct ifreq ifr; + t_u8 *buffer = NULL, *pos = NULL; + t_u32 cmd_len = 0, cmd_header_len; + struct eth_priv_cmd *cmd = NULL; + HostCmd_DS_GEN *hostcmd; + HostCmd_DS_CMD_ROAMAGENT_STATISTICS_THRESHOLD *statsthreshold; + MrvlIEtypes_BeaconHighRssiThreshold_t *bcnhighrssi; + MrvlIEtypes_BeaconLowRssiThreshold_t *bcnlowrssi; + MrvlIEtypes_BeaconHighSnrThreshold_t *bcnhighsnr; + MrvlIEtypes_BeaconLowSnrThreshold_t *bcnlowsnr; + + if (argv[0] == NULL) { + puts("\nInsufficient arguments.. \n"); + ret = MLAN_STATUS_FAILURE; + goto done; + } + + if (argv[0] && strncmp(argv[0], "stable", strlen("stable")) == 0) { + state = STATE_STABLE; + /* degrad[ing] */ + } else if (argv[0] && strncmp(argv[0], "degrad", strlen("degrad")) == 0) { + state = STATE_DEGRADING; + /* unaccep[table] */ + } else if (argv[0] + && strncmp(argv[0], "unaccep", strlen("unaccep")) == 0) { + state = STATE_UNACCEPTABLE; + } else { + puts("\nUnknown state. Use stable/degrading/unacceptable\n"); + ret = MLAN_STATUS_FAILURE; + goto done; + } + if (argc != 3 && argc != 5) { + puts("\nIncorrect number of arguments.\n"); + ret = MLAN_STATUS_FAILURE; + goto done; + } + if (argv[1] && strncmp(argv[1], "low", strlen("low")) == 0) { + low = 1; + lowval = atoi(argv[2]); + /* TODO validation check on lowval */ + } + if (argv[1 + (2 * low)] + && strncmp(argv[1 + (2 * low)], "high", strlen("high")) == 0) { + high = 1; + highval = atoi(argv[2 + (2 * low)]); + /* TODO validation check on highval */ + } + /* check if low is specified after high */ + if ((low == 0) && (argc == 5)) { + if (argv[1 + (2 * high)] + && strncmp(argv[1 + (2 * high)], "low", strlen("low")) == 0) { + low = 1; + lowval = atoi(argv[2 + 2 * (high)]); + /* TODO validation check on lowval */ + } + } + + if (!low && !high) { + puts("\nIncorrect argument. Use low /high \n"); + ret = MLAN_STATUS_FAILURE; + goto done; + } + + cmd_header_len = strlen(CMD_NXP) + strlen(HOSTCMD); + + buffer = (t_u8 *)malloc(BUFFER_LENGTH); + if (buffer == NULL) { + fprintf(stderr, "Cannot alloc memory\n"); + ret = ENOMEM; + goto done; + } + memset(buffer, 0, BUFFER_LENGTH); + + cmd = (struct eth_priv_cmd *)malloc(sizeof(struct eth_priv_cmd)); + if (!cmd) { + printf("ERR:Cannot allocate buffer for command!\n"); + ret = ENOMEM; + goto done; + } + + /* Fill up buffer */ +#ifdef USERSPACE_32BIT_OVER_KERNEL_64BIT + memset(cmd, 0, sizeof(struct eth_priv_cmd)); + memcpy(&cmd->buf, &buffer, sizeof(buffer)); +#else + cmd->buf = buffer; +#endif + cmd->used_len = 0; + cmd->total_len = BUFFER_LENGTH; + + /* buffer = MRVL_CMD */ + strncpy((char *)buffer, CMD_NXP, strlen(CMD_NXP)); + strncpy((char *)buffer + strlen(CMD_NXP), HOSTCMD, strlen(HOSTCMD)); + + /* buffer = MRVL_CMD */ + hostcmd = (HostCmd_DS_GEN *)(buffer + cmd_header_len + sizeof(t_u32)); + + /* Point after host command header */ + pos = (t_u8 *)hostcmd + S_DS_GEN; + + statsthreshold = (HostCmd_DS_CMD_ROAMAGENT_STATISTICS_THRESHOLD *)pos; + cmd_len = + (S_DS_GEN + + sizeof(HostCmd_DS_CMD_ROAMAGENT_STATISTICS_THRESHOLD) + - sizeof(statsthreshold->TlvBuffer)); + if (type == RSSI_THRESHOLD) { + if (high) { + cmd_len += + sizeof(MrvlIEtypes_BeaconHighRssiThreshold_t); + } + if (low) { + cmd_len += sizeof(MrvlIEtypes_BeaconLowRssiThreshold_t); + } + } else { + if (high) { + cmd_len += sizeof(MrvlIEtypes_BeaconHighSnrThreshold_t); + } + if (low) { + cmd_len += sizeof(MrvlIEtypes_BeaconLowSnrThreshold_t); + } + } + + hostcmd->command = + cpu_to_le16(HostCmd_CMD_ROAMAGENT_STATISTICS_THRESHOLD); + hostcmd->size = cpu_to_le16(cmd_len); + hostcmd->seq_num = 0; + hostcmd->result = 0; + + statsthreshold->action = cpu_to_le16(HostCmd_ACT_GEN_SET); + statsthreshold->State = state; + + /* + * TLV buffer start pointer initialization + */ + i = 0; + if (type == RSSI_THRESHOLD) { + if (high) { + bcnhighrssi = (MrvlIEtypes_BeaconHighRssiThreshold_t *) + (((t_u8 *)&statsthreshold->TlvBuffer) + i); + bcnhighrssi->Header.type = TLV_TYPE_RSSI_HIGH; + bcnhighrssi->Header.len = + (sizeof(MrvlIEtypes_BeaconHighRssiThreshold_t) + - sizeof(MrvlIEtypesHeader_t)); + bcnhighrssi->Value = highval; + i += sizeof(MrvlIEtypes_BeaconHighRssiThreshold_t); + /* + * ENDIANNESS + */ + bcnhighrssi->Header.type = + cpu_to_le16(bcnhighrssi->Header.type); + bcnhighrssi->Header.len = + cpu_to_le16(bcnhighrssi->Header.len); + } + + if (low) { + bcnlowrssi = (MrvlIEtypes_BeaconLowRssiThreshold_t *) + (((t_u8 *)&statsthreshold->TlvBuffer) + i); + bcnlowrssi->Header.type = TLV_TYPE_RSSI_LOW; + bcnlowrssi->Header.len = + (sizeof(MrvlIEtypes_BeaconLowRssiThreshold_t) + - sizeof(MrvlIEtypesHeader_t)); + bcnlowrssi->Value = lowval; + i += sizeof(MrvlIEtypes_BeaconLowRssiThreshold_t); + /* + * ENDIANNESS + */ + bcnlowrssi->Header.type = + cpu_to_le16(bcnlowrssi->Header.type); + bcnlowrssi->Header.len = + cpu_to_le16(bcnlowrssi->Header.len); + } + } else { + if (high) { + bcnhighsnr = (MrvlIEtypes_BeaconHighSnrThreshold_t *) + (((t_u8 *)&statsthreshold->TlvBuffer) + i); + bcnhighsnr->Header.type = TLV_TYPE_SNR_HIGH; + bcnhighsnr->Header.len = + (sizeof(MrvlIEtypes_BeaconHighSnrThreshold_t) + - sizeof(MrvlIEtypesHeader_t)); + bcnhighsnr->Value = highval; + i += sizeof(MrvlIEtypes_BeaconHighSnrThreshold_t); + /* + * ENDIANNESS + */ + bcnhighsnr->Header.type = + cpu_to_le16(bcnhighsnr->Header.type); + bcnhighsnr->Header.len = + cpu_to_le16(bcnhighsnr->Header.len); + } + if (low) { + bcnlowsnr = (MrvlIEtypes_BeaconLowSnrThreshold_t *) + (((t_u8 *)&statsthreshold->TlvBuffer) + i); + bcnlowsnr->Header.type = TLV_TYPE_SNR_LOW; + bcnlowsnr->Header.len = + (sizeof(MrvlIEtypes_BeaconLowSnrThreshold_t) + - sizeof(MrvlIEtypesHeader_t)); + bcnlowsnr->Value = lowval; + i += sizeof(MrvlIEtypes_BeaconLowSnrThreshold_t); + /* + * ENDIANNESS + */ + bcnlowsnr->Header.type = + cpu_to_le16(bcnlowsnr->Header.type); + bcnlowsnr->Header.len = + cpu_to_le16(bcnlowsnr->Header.len); + } + } + + /* Put buffer length */ + memcpy(buffer + cmd_header_len, &cmd_len, sizeof(t_u32)); + + /* Initialize the ifr structure */ + memset(&ifr, 0, sizeof(ifr)); + strncpy(ifr.ifr_ifrn.ifrn_name, dev_name, strlen(dev_name)); + ifr.ifr_ifru.ifru_data = (void *)cmd; + /* Perform ioctl */ + if (ioctl(sockfd, MLAN_ETH_PRIV, &ifr)) { + perror("ioctl[setra]"); + printf("ERR:Command sending failed!\n"); + ret = -EFAULT; + goto done; + } + + if (le16_to_cpu(hostcmd->result)) { + printf("\nHostCmd Error: ReturnCode=%#04x, Result=%#04x\n\n", + le16_to_cpu(hostcmd->command), + le16_to_cpu(hostcmd->result)); + } else { + printf("\nHostCmd Success: ReturnCode=%#04x, Result=%#04x\n\n", + le16_to_cpu(hostcmd->command), + le16_to_cpu(hostcmd->result)); + } + +done: + if (buffer) + free(buffer); + if (cmd) + free(cmd); + return ret; +} + +/** + * @brief Issue setra rssi command + * + * @param argc number of arguments + * @param argv A pointer to arguments array + * + * @return MLAN_STATUS_SUCCESS--success, otherwise--fail + */ +static int +roamSetRssiStatsThreshold(int argc, char *argv[]) +{ + if (roamSetStatsThreshold(argc, argv, RSSI_THRESHOLD) + == MLAN_STATUS_SUCCESS) { + roamGetStatsThreshold(0, argv, RSSI_THRESHOLD); + } + + return MLAN_STATUS_SUCCESS; +} + +/** + * @brief Issue setra scanperiod command + * + * @param argc number of arguments + * @param argv A pointer to arguments array + * + * @return MLAN_STATUS_SUCCESS--success, otherwise--fail + */ +static int +roamSetScanPeriod(int argc, char *argv[]) +{ + int ret = MLAN_STATUS_SUCCESS; + int scanmode = 0, period = 0, state = 0; + struct ifreq ifr; + t_u8 *buffer = NULL, *pos = NULL; + t_u32 cmd_len = 0, cmd_header_len; + struct eth_priv_cmd *cmd = NULL; + HostCmd_DS_GEN *hostcmd; + HostCmd_DS_CMD_ROAMAGENT_NEIGHBOR_SCANPERIOD *scanPeriodInfo; + + if (argv[0] == NULL) { + puts("\nInsufficient arguments.. \n"); + ret = MLAN_STATUS_FAILURE; + goto done; + } + + /* scanperiod */ + if (argc != 3) { + puts("\nIncorrect number of arguments.\n"); + ret = MLAN_STATUS_FAILURE; + goto done; + } + + if (argv[0] && strncmp(argv[0], "stable", strlen("stable")) == 0) { + state = STATE_STABLE; + /* degrad[ing] */ + } else if (argv[0] && strncmp(argv[0], "degrad", strlen("degrad")) == 0) { + state = STATE_DEGRADING; + /* unaccep[table] */ + } else if (argv[0] + && strncmp(argv[0], "unaccep", strlen("unaccep")) == 0) { + state = STATE_UNACCEPTABLE; + } else { + puts("\nUnknown state. Use stable/degrading/unacceptable\n"); + ret = MLAN_STATUS_FAILURE; + goto done; + } + + if (argv[1] && strncmp(argv[1], "disc", strlen("disc")) == 0) { + scanmode = DISCOVERY_MODE; + /* track[ing] */ + } else if (argv[1] && strncmp(argv[1], "track", strlen("track")) == 0) { + scanmode = TRACKING_MODE; + } else { + puts("\nUnknown scamode. Use discovery/ tracking\n"); + ret = MLAN_STATUS_FAILURE; + goto done; + } + period = atoi(argv[2]); + /* TODO validation check on period */ + + cmd_header_len = strlen(CMD_NXP) + strlen(HOSTCMD); + + buffer = (t_u8 *)malloc(BUFFER_LENGTH); + if (buffer == NULL) { + fprintf(stderr, "Cannot alloc memory\n"); + ret = ENOMEM; + goto done; + } + memset(buffer, 0, BUFFER_LENGTH); + + cmd = (struct eth_priv_cmd *)malloc(sizeof(struct eth_priv_cmd)); + if (!cmd) { + printf("ERR:Cannot allocate buffer for command!\n"); + ret = ENOMEM; + goto done; + } + + /* Fill up buffer */ +#ifdef USERSPACE_32BIT_OVER_KERNEL_64BIT + memset(cmd, 0, sizeof(struct eth_priv_cmd)); + memcpy(&cmd->buf, &buffer, sizeof(buffer)); +#else + cmd->buf = buffer; +#endif + cmd->used_len = 0; + cmd->total_len = BUFFER_LENGTH; + + /* buffer = MRVL_CMD */ + strncpy((char *)buffer, CMD_NXP, strlen(CMD_NXP)); + strncpy((char *)buffer + strlen(CMD_NXP), HOSTCMD, strlen(HOSTCMD)); + + /* buffer = MRVL_CMD */ + hostcmd = (HostCmd_DS_GEN *)(buffer + cmd_header_len + sizeof(t_u32)); + + /* Point after host command header */ + pos = (t_u8 *)hostcmd + S_DS_GEN; + + scanPeriodInfo = (HostCmd_DS_CMD_ROAMAGENT_NEIGHBOR_SCANPERIOD *)pos; + cmd_len = + S_DS_GEN + sizeof(HostCmd_DS_CMD_ROAMAGENT_NEIGHBOR_SCANPERIOD); + hostcmd->command = + cpu_to_le16(HostCmd_CMD_ROAMAGENT_NEIGHBOR_SCAN_PERIOD); + hostcmd->size = cpu_to_le16(cmd_len); + hostcmd->seq_num = 0; + hostcmd->result = 0; + scanPeriodInfo->action = HostCmd_ACT_GEN_SET; + scanPeriodInfo->scanPeriod.Header.type = TLV_TYPE_NEIGHBOR_SCANPERIOD; + scanPeriodInfo->scanPeriod.Header.len = + sizeof(MrvlIEtypes_NeighborScanPeriod_t) - + sizeof(MrvlIEtypesHeader_t); + scanPeriodInfo->scanPeriod.SearchMode = scanmode; + scanPeriodInfo->scanPeriod.State = state; + scanPeriodInfo->scanPeriod.ScanPeriod = period; + + /* + * ENDIANNESS + */ + scanPeriodInfo->action = cpu_to_le16(scanPeriodInfo->action); + scanPeriodInfo->scanPeriod.Header.type = cpu_to_le16 + (scanPeriodInfo->scanPeriod.Header.type); + scanPeriodInfo->scanPeriod.Header.len = cpu_to_le16 + (scanPeriodInfo->scanPeriod.Header.len); + scanPeriodInfo->scanPeriod.SearchMode = cpu_to_le16 + (scanPeriodInfo->scanPeriod.SearchMode); + scanPeriodInfo->scanPeriod.State = cpu_to_le16 + (scanPeriodInfo->scanPeriod.State); + scanPeriodInfo->scanPeriod.ScanPeriod = cpu_to_le32 + (scanPeriodInfo->scanPeriod.ScanPeriod); + + /* Put buffer length */ + memcpy(buffer + cmd_header_len, &cmd_len, sizeof(t_u32)); + + /* Initialize the ifr structure */ + memset(&ifr, 0, sizeof(ifr)); + strncpy(ifr.ifr_ifrn.ifrn_name, dev_name, strlen(dev_name)); + ifr.ifr_ifru.ifru_data = (void *)cmd; + /* Perform ioctl */ + if (ioctl(sockfd, MLAN_ETH_PRIV, &ifr)) { + perror("ioctl[neighborlist maintain]"); + printf("ERR:Command sending failed!\n"); + ret = -EFAULT; + goto done; + } + + if (le16_to_cpu(hostcmd->result)) { + printf("\nHostCmd Error: ReturnCode=%#04x, Result=%#04x\n\n", + le16_to_cpu(hostcmd->command), + le16_to_cpu(hostcmd->result)); + } else { + printf("\nHostCmd Success: ReturnCode=%#04x, Result=%#04x\n\n", + le16_to_cpu(hostcmd->command), + le16_to_cpu(hostcmd->result)); + } + +done: + if (buffer) + free(buffer); + if (cmd) + free(cmd); + return ret; +} + +/** + * @brief Check it string contains digits + * @param str string to check for digits + * @return same as isdigit(char) + */ +static inline int +isdigitstr(char *str) +{ + unsigned int i = 0; + for (i = 0; i < strlen(str); i++) { + if (!isdigit((str)[i])) + return 0; + } + return 1; +} + +/** + * @brief Process sub command + * + * @param valid_cmds valid commands array + * @param count number of valid commands + * @param argc number of arguments + * @param argv A pointer to arguments array + * @param param argc parameter counter + * @param value values to update back + * + * @return command index--success, otherwise--fail + */ +static int +process_subcmd(char *valid_cmds[], int count, int argc, char *argv[], + int *param, int *value) +{ + int ret = 0; + int j = *param; + int k; + while (1) { + for (k = 0; k < count; k++) + if (argv[j] && + !strncmp(valid_cmds[k], argv[j], + strlen(valid_cmds[k]))) + break; + if (k >= count) { + break; + } else { + /* special case */ + if (!strncmp + (valid_cmds[k], "perperiod", strlen("perperiod")) || + !strncmp(valid_cmds[k], "ferperiod", + strlen("ferperiod"))) { + *param = j; + return ret | 1 << k; + } + if (!argv[j + 1] || !isdigitstr(argv[j + 1])) + return -1; + value[k] = atoi(argv[j + 1]); + j = j + 2; + ret |= (1 << k); + } + + if (j >= argc) { + break; + } + } + + if (*param == j) { + return -1; + } + + *param = j; + return ret; +} + +static int +printSetNeighborDeprecation(int argc, char *argv[]) +{ + printf("\nInfo: setra neighbor replaced with:\n" + " - setra nparams (config neighbor assessment params)\n\n"); + + return MLAN_STATUS_SUCCESS; +} + +/** + * @brief Issue setra neighbor command + * + * @param argc number of arguments + * @param argv A pointer to arguments array + * + * @return MLAN_STATUS_SUCCESS--success, otherwise--fail + */ +static int +roamSetNborParams(int argc, char *argv[]) +{ + int ret = MLAN_STATUS_SUCCESS; + int trackcount = 0, i = 0, j = 0; + int blist[2] = { 0, 0 }; /* blacklist short and long: 0-short 1-long */ + int qualoffset[1] = { 0 }; /* rssi */ + int stalecount = ~0; + int staleperiod = ~0; + signed char temp; + struct ifreq ifr; + t_u8 *buffer = NULL, *pos = NULL; + t_u32 cmd_len = 0, cmd_header_len; + struct eth_priv_cmd *cmd = NULL; + char *valid_cmds[] = { "trackcount", "qualoffset", "blacklistdur", + "stalecount", "staleperiod", "roamthresh" + }; + + /** blacklistdur sub commands */ + char *valid_blcmds[] = { "short", "long" }; + + /** qualoffset sub commands */ + char *valid_bfcmds[] = { "rssi" }; + HostCmd_DS_GEN *hostcmd; + HostCmd_DS_CMD_ROAMAGENT_NEIGHBOR_ASSESSMENT *pNborAssessment; + + if (argv[0] == NULL) { + puts("\nUnknown setra nparams subcmd. Valid subcmds:"); + for (i = 0; i < NELEMENTS(valid_cmds); i++) { + printf(" - %s\n", valid_cmds[i]); + } + printf("\n"); + + ret = MLAN_STATUS_FAILURE; + goto done; + } + + if (argc < 2 || argc > 18) { + puts("\nIncorrect number of arguments.\n"); + ret = MLAN_STATUS_FAILURE; + goto done; + } + + cmd_header_len = strlen(CMD_NXP) + strlen(HOSTCMD); + + buffer = (t_u8 *)malloc(BUFFER_LENGTH); + if (buffer == NULL) { + fprintf(stderr, "Cannot alloc memory\n"); + ret = ENOMEM; + goto done; + } + memset(buffer, 0, BUFFER_LENGTH); + + cmd = (struct eth_priv_cmd *)malloc(sizeof(struct eth_priv_cmd)); + if (!cmd) { + printf("ERR:Cannot allocate buffer for command!\n"); + ret = ENOMEM; + goto done; + } + + /* Fill up buffer */ +#ifdef USERSPACE_32BIT_OVER_KERNEL_64BIT + memset(cmd, 0, sizeof(struct eth_priv_cmd)); + memcpy(&cmd->buf, &buffer, sizeof(buffer)); +#else + cmd->buf = buffer; +#endif + cmd->used_len = 0; + cmd->total_len = BUFFER_LENGTH; + + /* buffer = MRVL_CMD */ + strncpy((char *)buffer, CMD_NXP, strlen(CMD_NXP)); + strncpy((char *)buffer + strlen(CMD_NXP), HOSTCMD, strlen(HOSTCMD)); + + /* buffer = MRVL_CMD */ + hostcmd = (HostCmd_DS_GEN *)(buffer + cmd_header_len + sizeof(t_u32)); + + /* Point after host command header */ + pos = (t_u8 *)hostcmd + S_DS_GEN; + + pNborAssessment = (HostCmd_DS_CMD_ROAMAGENT_NEIGHBOR_ASSESSMENT *)pos; + cmd_len = + S_DS_GEN + sizeof(HostCmd_DS_CMD_ROAMAGENT_NEIGHBOR_ASSESSMENT); + + hostcmd->command = + cpu_to_le16(HostCmd_CMD_ROAMAGENT_NEIGHBOR_ASSESSMENT); + hostcmd->size = cpu_to_le16(cmd_len); + hostcmd->seq_num = 0; + hostcmd->result = 0; + + /* Get parameters unspecified on command line */ + if (getNborAssessment(pNborAssessment) != MLAN_STATUS_SUCCESS) { + ret = MLAN_STATUS_FAILURE; + goto done; + } + + while (argc - j) { + for (i = 0; (unsigned int)i < NELEMENTS(valid_cmds); i++) { + if (!strncmp + (valid_cmds[i], argv[j], strlen(valid_cmds[i]))) + break; + } + + if ((unsigned int)i >= NELEMENTS(valid_cmds)) { + printf("\nInvalid argument to \"%s\"\n\n", argv[0]); + ret = MLAN_STATUS_FAILURE; + goto done; + } + + switch (i) { + + case 0: + /** trackcount */ + trackcount = atoi(argv[j + 1]); + pNborAssessment->QualifyingNumNeighbor = trackcount; + j = j + 2; + break; + + case 1: + /** qualoffset */ + j++; + ret = process_subcmd(valid_bfcmds, + NELEMENTS(valid_bfcmds), argc, + argv, &j, qualoffset); + if (ret == -1) { + printf("\nInvalid argument to \"%s\"\n\n", + argv[j - 1]); + ret = ret; + goto done; + } + pNborAssessment->ConfQualSignalStrength = qualoffset[0]; + break; + + case 2: + /** blacklistdur */ + j++; + ret = process_subcmd(valid_blcmds, + NELEMENTS(valid_blcmds), argc, + argv, &j, blist); + if (ret == -1) { + printf("\nInvalid argument to \"%s\"\n\n", + argv[j - 1]); + ret = ret; + goto done; + } else { + if (ret & 0x01) { + pNborAssessment->ShortBlacklistPeriod = + blist[0]; + } + if (ret & 0x02) { + pNborAssessment->LongBlacklistPeriod = + blist[1]; + } + } + break; + + case 3: + /** stalecount */ + stalecount = atoi(argv[j + 1]); + pNborAssessment->StaleCount = stalecount; + j = j + 2; + break; + + case 4: + /** staleperiod */ + staleperiod = atoi(argv[j + 1]); + pNborAssessment->StalePeriod = staleperiod; + j = j + 2; + break; + + case 5: + /** roamthresh */ + j++; + temp = 0; + for (i = 0; j + i < argc; i++) { + if (isdigit(*argv[j + i]) || + (*argv[j + i] == '-')) { + temp++; + } else { + break; + } + } + + if ((temp % 3 != 0) || (temp > 12)) { + puts(""); + printf("Error: %d numeric arguments detected for roamthresh.\n" " Roam threhold values must be specified in\n" " multiples of 3 (low, high, diff triplets) up\n" " to a maximum of 4 sets (12 numbers max).\n", temp); + puts(""); + + ret = MLAN_STATUS_FAILURE; + goto done; + } + + for (i = 0; (i < 12); i++) { + if ((j >= argc) || + (!isdigit(*argv[j]) && *argv[j] != '-')) { + temp = 0; + } else { + temp = atoi(argv[j]); + j++; + } + + switch (i % 3) { + case 0: + pNborAssessment->RoamThresh[i / + 3]. + RssiHighLevel = temp; + break; + + case 1: + pNborAssessment->RoamThresh[i / + 3]. + RssiLowLevel = temp; + break; + + case 2: + pNborAssessment->RoamThresh[i / + 3]. + RssiNborDiff = temp; + break; + } + } + break; + } + } + + pNborAssessment->action = cpu_to_le16(HostCmd_ACT_GEN_SET); + + /* Both stalecount, staleperiod can not be zero */ + if ((pNborAssessment->StaleCount == 0) && + (pNborAssessment->StalePeriod == 0)) { + + puts("\nstalecount and staleperiod both can not be zero\n"); + ret = (MLAN_STATUS_FAILURE); + goto done; + } + + /* + * ENDIANNESS + */ + pNborAssessment->QualifyingNumNeighbor = + cpu_to_le16(pNborAssessment->QualifyingNumNeighbor); + pNborAssessment->ShortBlacklistPeriod = + cpu_to_le32(pNborAssessment->ShortBlacklistPeriod); + pNborAssessment->LongBlacklistPeriod = + cpu_to_le32(pNborAssessment->LongBlacklistPeriod); + pNborAssessment->StaleCount = cpu_to_le16(pNborAssessment->StaleCount); + pNborAssessment->StalePeriod = + cpu_to_le16(pNborAssessment->StalePeriod); + + /* Put buffer length */ + memcpy(buffer + cmd_header_len, &cmd_len, sizeof(t_u32)); + + /* Initialize the ifr structure */ + memset(&ifr, 0, sizeof(ifr)); + strncpy(ifr.ifr_ifrn.ifrn_name, dev_name, strlen(dev_name)); + ifr.ifr_ifru.ifru_data = (void *)cmd; + /* Perform ioctl */ + if (ioctl(sockfd, MLAN_ETH_PRIV, &ifr)) { + perror("ioctl[roam neighbor assessment]"); + printf("ERR:Command sending failed!\n"); + ret = -EFAULT; + goto done; + } + + if (le16_to_cpu(hostcmd->result)) { + printf("\nHostCmd Error: ReturnCode=%#04x, Result=%#04x\n\n", + le16_to_cpu(hostcmd->command), + le16_to_cpu(hostcmd->result)); + } else { + printNeighborAssessmentConfig(); + } + +done: + if (buffer) + free(buffer); + if (cmd) + free(cmd); + return ret; +} + +/** + * @brief Issue setra metrics command + * + * @param argc number of arguments + * @param argv A pointer to arguments array + * + * @return MLAN_STATUS_SUCCESS--success, otherwise--fail + */ +static int +roamSetMetrics(int argc, char *argv[]) +{ + int ret = MLAN_STATUS_SUCCESS; + struct ifreq ifr; + t_u8 *buffer = NULL, *pos = NULL; + t_u32 cmd_len = 0, cmd_header_len; + struct eth_priv_cmd *cmd = NULL; + HostCmd_DS_GEN *hostcmd; + HostCmd_DS_CMD_ROAMAGENT_ADV_METRIC_THRESHOLD *metricscmd; + + int perlist[3] = { 0, 0, 0 }; /* 0=inactivity, + 1=perthreshold, + 2=packetthreshold */ + int ferlist[3] = { 0, 0, 0 }; /* 0=inactivity, + 1=ferthreshold, + 2=framethreshold */ + int perstate[3] = { 0, 0, 0 }; /* 0=stable, 1=degrading, 2=unacceptable */ + int ferstate[3] = { 0, 0, 0 }; /* 0=stable, 1=degrading, 2=unacceptable */ + int datalist[2] = { 0, 0 }; /* 0=inactivity, 1=datathreshold */ + char *valid_cmds[] = { "Beacon", "Data", "PER", "FER" }; + + /** PER sub commands */ + char *valid_percmds[] = { "inactivity", "perthreshold", + "packetthreshold", "perperiod" + }; + + char *valid_fercmds[] = { "inactivity", "ferthreshold", + "framethreshold", "ferperiod" + }; + + /** PER period states */ + char *per_states[] = { "stable", "degrading", "unacceptable" }; + + /** Data sub commands */ + char *valid_datacmds[] = { "inactivity", "datathreshold" }; + + int i = 0, j = 0; + + if (argv[0] == NULL) { + puts("\nInsufficient arguments.. \n"); + ret = MLAN_STATUS_FAILURE; + goto done; + } + + if (argc < 1 || argc > 38) { + puts("\nIncorrect number of arguments.\n"); + ret = MLAN_STATUS_FAILURE; + goto done; + } + + cmd_header_len = strlen(CMD_NXP) + strlen(HOSTCMD); + + buffer = (t_u8 *)malloc(BUFFER_LENGTH); + if (buffer == NULL) { + fprintf(stderr, "Cannot alloc memory\n"); + ret = ENOMEM; + goto done; + } + memset(buffer, 0, BUFFER_LENGTH); + + cmd = (struct eth_priv_cmd *)malloc(sizeof(struct eth_priv_cmd)); + if (!cmd) { + printf("ERR:Cannot allocate buffer for command!\n"); + ret = ENOMEM; + goto done; + } + + /* Fill up buffer */ +#ifdef USERSPACE_32BIT_OVER_KERNEL_64BIT + memset(cmd, 0, sizeof(struct eth_priv_cmd)); + memcpy(&cmd->buf, &buffer, sizeof(buffer)); +#else + cmd->buf = buffer; +#endif + cmd->used_len = 0; + cmd->total_len = BUFFER_LENGTH; + + /* buffer = MRVL_CMD */ + strncpy((char *)buffer, CMD_NXP, strlen(CMD_NXP)); + strncpy((char *)buffer + strlen(CMD_NXP), HOSTCMD, strlen(HOSTCMD)); + + /* buffer = MRVL_CMD */ + hostcmd = (HostCmd_DS_GEN *)(buffer + cmd_header_len + sizeof(t_u32)); + + /* Point after host command header */ + pos = (t_u8 *)hostcmd + S_DS_GEN; + + cmd_len = + S_DS_GEN + + sizeof(HostCmd_DS_CMD_ROAMAGENT_ADV_METRIC_THRESHOLD); + + hostcmd->command = + cpu_to_le16(HostCmd_CMD_ROAMAGENT_ADV_METRIC_THRESHOLD); + hostcmd->size = cpu_to_le16(cmd_len); + hostcmd->seq_num = 0; + hostcmd->result = 0; + + metricscmd = (HostCmd_DS_CMD_ROAMAGENT_ADV_METRIC_THRESHOLD *)pos; + metricscmd->action = cpu_to_le16(HostCmd_ACT_GEN_SET); + + /* clear [ Beacon/Data/PER ] */ + if (!strncmp("clear", argv[j], strlen("clear"))) { + if (argc == 1) { + puts("\nInvalid number of argument"); + ret = MLAN_STATUS_FAILURE; + goto done; + } + while (1) { + j++; + for (i = 0; (unsigned int)i < NELEMENTS(valid_cmds); + i++) { + if (!strncmp + (valid_cmds[i], argv[j], + strlen(valid_cmds[i]))) + break; + } + if ((unsigned int)i >= NELEMENTS(valid_cmds)) { + printf("\nInvalid argument \"%s\"\n\n", + argv[j]); + ret = MLAN_STATUS_FAILURE; + goto done; + } else { + metricscmd->Metrics |= BIT(i); + } + + if (j >= (argc - 1)) { + break; + } + } + metricscmd->action = HostCmd_ACT_GEN_REMOVE; + } else { /* set [ Beacon/Data/PER ] */ + + while (argc - j) { + for (i = 0; (unsigned int)i < NELEMENTS(valid_cmds); + i++) { + if (!strncmp + (valid_cmds[i], argv[j], + strlen(valid_cmds[i]))) + break; + } + if ((unsigned int)i >= NELEMENTS(valid_cmds)) { + printf("\nInvalid argument to \"%s\"\n\n", + argv[j]); + ret = MLAN_STATUS_FAILURE; + goto done; + } + + switch (i) { + case 0: + /** Beacon */ + j++; + metricscmd->Metrics |= 0x01; + break; + + case 1: + /** Data*/ + j++; + ret = process_subcmd(valid_datacmds, + NELEMENTS(valid_datacmds), + argc, argv, &j, datalist); + if (ret > 0) { + if (ret & 0x01) { + metricscmd-> + InactivityPeriodThreshold_ms + = datalist[0]; + } + if (ret & 0x02) { + metricscmd->UiRxPktThreshold = + datalist[1]; + } + } + metricscmd->Metrics |= 0x02; + break; + + case 2: + /** PER */ + j++; + ret = process_subcmd(valid_percmds, + NELEMENTS(valid_percmds), + argc, argv, &j, perlist); + if (ret > 0) { + if (ret & 0x01) { + metricscmd-> + InactivityPeriodThreshold_ms + = perlist[0]; + } + if (ret & 0x02) { + metricscmd-> + UcPerThresholdValue = + perlist[1]; + } + if (ret & 0x04) { + metricscmd->UiPerPktThreshold = + perlist[2]; + } + if (ret & 0x08) { + j++; + ret = process_subcmd(per_states, + NELEMENTS + (per_states), + argc, argv, + &j, + perstate); + if (ret & 0x01) { + metricscmd-> + StablePERPeriod_ms + = perstate[0]; + } + if (ret & 0x02) { + metricscmd-> + DegradingPERPeriod_ms + = perstate[1]; + } + if (ret & 0x04) { + metricscmd-> + UnacceptablePERPeriod_ms + = perstate[2]; + } + if (j < argc) { + ret = process_subcmd + (valid_percmds, + NELEMENTS + (valid_percmds), + argc, argv, &j, + perlist); + if (ret > 0) { + if (ret & 0x01) { + metricscmd-> + InactivityPeriodThreshold_ms + = + perlist + [0]; + } + if (ret & 0x02) { + metricscmd-> + UcPerThresholdValue + = + perlist + [1]; + } + if (ret & 0x04) { + metricscmd-> + UiPerPktThreshold + = + perlist + [2]; + } + } + } + } + } + metricscmd->Metrics |= 0x04; + break; + + case 3: + /** FER */ + j++; + ret = process_subcmd(valid_fercmds, + NELEMENTS(valid_fercmds), + argc, argv, &j, ferlist); + if (ret > 0) { + if (ret & 0x01) { + metricscmd-> + InactivityPeriodThreshold_ms + = ferlist[0]; + } + if (ret & 0x02) { + metricscmd-> + UcFerThresholdValue = + ferlist[1]; + } + if (ret & 0x04) { + metricscmd->UiFerPktThreshold = + ferlist[2]; + } + if (ret & 0x08) { + j++; + ret = process_subcmd(per_states, + NELEMENTS + (per_states), + argc, argv, + &j, + ferstate); + if (ret & 0x01) { + metricscmd-> + StableFERPeriod_ms + = ferstate[0]; + } + if (ret & 0x02) { + metricscmd-> + DegradingFERPeriod_ms + = ferstate[1]; + } + if (ret & 0x04) { + metricscmd-> + UnacceptableFERPeriod_ms + = ferstate[2]; + } + if (j < argc) { + ret = process_subcmd + (valid_fercmds, + NELEMENTS + (valid_fercmds), + argc, argv, &j, + ferlist); + if (ret > 0) { + if (ret & 0x01) { + metricscmd-> + InactivityPeriodThreshold_ms + = + ferlist + [0]; + } + if (ret & 0x02) { + metricscmd-> + UcFerThresholdValue + = + ferlist + [1]; + } + if (ret & 0x04) { + metricscmd-> + UiFerPktThreshold + = + ferlist + [2]; + } + } + } + } + } + metricscmd->Metrics |= 0x08; + break; + } + metricscmd->action = HostCmd_ACT_GEN_SET; + } + } + + /* + * ENDIANNESS + */ + metricscmd->action = cpu_to_le16(metricscmd->action); + metricscmd->Metrics = cpu_to_le16(metricscmd->Metrics); + metricscmd->UiPerPktThreshold = + cpu_to_le32(metricscmd->UiPerPktThreshold); + metricscmd->StablePERPeriod_ms = + cpu_to_le32(metricscmd->StablePERPeriod_ms); + metricscmd->DegradingPERPeriod_ms = + cpu_to_le32(metricscmd->DegradingPERPeriod_ms); + metricscmd->UnacceptablePERPeriod_ms = + cpu_to_le32(metricscmd->UnacceptablePERPeriod_ms); + metricscmd->InactivityPeriodThreshold_ms = + cpu_to_le32(metricscmd->InactivityPeriodThreshold_ms); + metricscmd->UiRxPktThreshold = + cpu_to_le32(metricscmd->UiRxPktThreshold); + + /* Put buffer length */ + memcpy(buffer + cmd_header_len, &cmd_len, sizeof(t_u32)); + + /* Initialize the ifr structure */ + memset(&ifr, 0, sizeof(ifr)); + strncpy(ifr.ifr_ifrn.ifrn_name, dev_name, strlen(dev_name)); + ifr.ifr_ifru.ifru_data = (void *)cmd; + /* Perform ioctl */ + if (ioctl(sockfd, MLAN_ETH_PRIV, &ifr)) { + perror("ioctl[neighborlist maintain]"); + printf("ERR:Command sending failed!\n"); + ret = -EFAULT; + goto done; + } + + if (le16_to_cpu(hostcmd->result)) { + printf("\nHostCmd Error: ReturnCode=%#04x, Result=%#04x\n\n", + le16_to_cpu(hostcmd->command), + le16_to_cpu(hostcmd->result)); + } else { + printf("\nHostCmd Success: ReturnCode=%#04x, Result=%#04x\n\n", + le16_to_cpu(hostcmd->command), + le16_to_cpu(hostcmd->result)); + } + +done: + if (buffer) + free(buffer); + if (cmd) + free(cmd); + return ret; +} + +/** + * @brief Process maintenance of Neighbor list + * + * @param argc # arguments + * @param argv A pointer to arguments array + * + */ +static int +roamSetNborMaintenance(int argc, char *argv[]) +{ + int ret = MLAN_STATUS_SUCCESS; + struct ifreq ifr; + t_u8 *buffer = NULL, *pos = NULL; + t_u32 cmd_len = 0, cmd_header_len; + struct eth_priv_cmd *cmd = NULL; + char *valid_cmds[] = { "blacklist", "clear" }; + int i = 0, j = 0, k = 0; + unsigned int mac[ETH_ALEN]; + + HostCmd_DS_GEN *hostcmd; + HostCmd_DS_CMD_ROAMAGENT_NEIGHBORLIST_MAINTENANCE *pNborMaintainance; + + if (argv[0] == NULL) { + puts("\nInsufficient arguments.. \n"); + ret = MLAN_STATUS_FAILURE; + goto done; + } + + if (argc != 2) { + puts("\nIncorrect number of arguments.\n"); + ret = MLAN_STATUS_FAILURE; + goto done; + } + for (i = 0; (unsigned int)i < NELEMENTS(valid_cmds); i++) + if (!strncmp(valid_cmds[i], argv[j], strlen(valid_cmds[i]))) + break; + if ((unsigned int)i >= NELEMENTS(valid_cmds)) { + printf("\nInvalid argument \"%s\"\n\n", argv[0]); + ret = MLAN_STATUS_FAILURE; + goto done; + } + switch (i) { + case 0: + /** blacklist */ + j++; + sscanf(argv[j], "%2x:%2x:%2x:%2x:%2x:%2x", + mac, mac + 1, mac + 2, mac + 3, mac + 4, mac + 5); + for (k = 0; k < ETH_ALEN; k++) { + if (*(mac + k) != 0xFF) { + break; + } + } + + if (k == ETH_ALEN) { + puts("\nBlacklisting a Broadcast address is not allowed"); + ret = MLAN_STATUS_FAILURE; + goto done; + } + break; + + case 1: + /** clear */ + j++; + if (!strncmp("all", argv[j], strlen("all"))) { + for (k = 0; k < ETH_ALEN; k++) { + *(mac + k) = 0xFF; + } + } else { + sscanf(argv[j], "%2x:%2x:%2x:%2x:%2x:%2x", + mac, mac + 1, mac + 2, mac + 3, mac + 4, + mac + 5); + } + break; + } + + cmd_header_len = strlen(CMD_NXP) + strlen(HOSTCMD); + + buffer = (t_u8 *)malloc(BUFFER_LENGTH); + if (buffer == NULL) { + fprintf(stderr, "Cannot alloc memory\n"); + ret = ENOMEM; + goto done; + } + memset(buffer, 0, BUFFER_LENGTH); + + cmd = (struct eth_priv_cmd *)malloc(sizeof(struct eth_priv_cmd)); + if (!cmd) { + printf("ERR:Cannot allocate buffer for command!\n"); + ret = ENOMEM; + goto done; + } + + /* Fill up buffer */ +#ifdef USERSPACE_32BIT_OVER_KERNEL_64BIT + memset(cmd, 0, sizeof(struct eth_priv_cmd)); + memcpy(&cmd->buf, &buffer, sizeof(buffer)); +#else + cmd->buf = buffer; +#endif + cmd->used_len = 0; + cmd->total_len = BUFFER_LENGTH; + + /* buffer = MRVL_CMD */ + strncpy((char *)buffer, CMD_NXP, strlen(CMD_NXP)); + strncpy((char *)buffer + strlen(CMD_NXP), HOSTCMD, strlen(HOSTCMD)); + + /* buffer = MRVL_CMD */ + hostcmd = (HostCmd_DS_GEN *)(buffer + cmd_header_len + sizeof(t_u32)); + + /* Point after host command header */ + pos = (t_u8 *)hostcmd + S_DS_GEN; + + pNborMaintainance + = (HostCmd_DS_CMD_ROAMAGENT_NEIGHBORLIST_MAINTENANCE *)pos; + + cmd_len = S_DS_GEN + + sizeof(HostCmd_DS_CMD_ROAMAGENT_NEIGHBORLIST_MAINTENANCE); + + hostcmd->command + = cpu_to_le16(HostCmd_CMD_ROAMAGENT_NEIGHBORLIST_MAINTENANCE); + hostcmd->size = cpu_to_le16(cmd_len); + hostcmd->seq_num = 0; + hostcmd->result = 0; + pNborMaintainance->action = ((i == 0) ? HostCmd_ACT_ADD_TO_BLACKLIST : + HostCmd_ACT_REMOVE_FROM_BLACKLIST); + pNborMaintainance->action = cpu_to_le16(pNborMaintainance->action); + for (k = 0; k < ETH_ALEN; k++) { + pNborMaintainance->BSSID[k] = *(mac + k); + } + + /* Put buffer length */ + memcpy(buffer + cmd_header_len, &cmd_len, sizeof(t_u32)); + + /* Initialize the ifr structure */ + memset(&ifr, 0, sizeof(ifr)); + strncpy(ifr.ifr_ifrn.ifrn_name, dev_name, strlen(dev_name)); + ifr.ifr_ifru.ifru_data = (void *)cmd; + /* Perform ioctl */ + if (ioctl(sockfd, MLAN_ETH_PRIV, &ifr)) { + perror("ioctl[neighborlist maintain]"); + printf("ERR:Command sending failed!\n"); + ret = -EFAULT; + goto done; + } + + if (le16_to_cpu(hostcmd->result)) { + printf("\nHostCmd Error: ReturnCode=%#04x, Result=%#04x\n\n", + le16_to_cpu(hostcmd->command), + le16_to_cpu(hostcmd->result)); + } else { + printf("\nHostCmd Success: ReturnCode=%#04x, Result=%#04x\n\n", + le16_to_cpu(hostcmd->command), + le16_to_cpu(hostcmd->result)); + } + +done: + if (buffer) + free(buffer); + if (cmd) + free(cmd); + return ret; +} + +/** + * @brief Issue setra backoff command + * + * @param argc number of arguments + * @param argv A pointer to arguments array + * + * @return MLAN_STATUS_SUCCESS--success, otherwise--fail + */ +static int +roamSetBackOff(int argc, char *argv[]) +{ + int ret = MLAN_STATUS_SUCCESS; + struct ifreq ifr; + t_u8 *buffer = NULL, *pos = NULL; + t_u32 cmd_len = 0, cmd_header_len; + struct eth_priv_cmd *cmd = NULL; + int spflag[2] = { 0, 0 }; /*scan,priod */ + t_u16 minscan; + t_u32 bperiod; + HostCmd_DS_GEN *hostcmd; + HostCmd_DS_CMD_ROAMAGENT_BACKOFF *roambackoffcmd; + int i; + + if (argv[0] == NULL) { + puts("\nInsufficient arguments.. \n"); + ret = MLAN_STATUS_FAILURE; + goto done; + } + /* BackOff */ + if ((argc != 2) && (argc != 4)) { + puts("\nIncorrect number of arguments.\n"); + ret = MLAN_STATUS_FAILURE; + goto done; + } + + for (i = 0; i < 4; i++) { + if (argv[i + 0] && + strncmp(argv[i + 0], "scans", strlen("scans")) == 0) { + minscan = atoi(argv[i + 1]); + i++; + spflag[0] = 1; + /* TODO validation check on minscan */ + } + if (argv[i + 0] && + strncmp(argv[i + 0], "period", strlen("period")) == 0) { + bperiod = atoi(argv[i + 1]); + i++; + spflag[1] = 1; + /* TODO validation check on bperiod */ + } + } + + cmd_header_len = strlen(CMD_NXP) + strlen(HOSTCMD); + + buffer = (t_u8 *)malloc(BUFFER_LENGTH); + if (buffer == NULL) { + fprintf(stderr, "Cannot alloc memory\n"); + ret = ENOMEM; + goto done; + } + memset(buffer, 0, BUFFER_LENGTH); + + cmd = (struct eth_priv_cmd *)malloc(sizeof(struct eth_priv_cmd)); + if (!cmd) { + printf("ERR:Cannot allocate buffer for command!\n"); + ret = ENOMEM; + goto done; + } + + /* Fill up buffer */ +#ifdef USERSPACE_32BIT_OVER_KERNEL_64BIT + memset(cmd, 0, sizeof(struct eth_priv_cmd)); + memcpy(&cmd->buf, &buffer, sizeof(buffer)); +#else + cmd->buf = buffer; +#endif + cmd->used_len = 0; + cmd->total_len = BUFFER_LENGTH; + + /* buffer = MRVL_CMD */ + strncpy((char *)buffer, CMD_NXP, strlen(CMD_NXP)); + strncpy((char *)buffer + strlen(CMD_NXP), HOSTCMD, strlen(HOSTCMD)); + + /* buffer = MRVL_CMD */ + hostcmd = (HostCmd_DS_GEN *)(buffer + cmd_header_len + sizeof(t_u32)); + + /* Point after host command header */ + pos = (t_u8 *)hostcmd + S_DS_GEN; + + roambackoffcmd = (HostCmd_DS_CMD_ROAMAGENT_BACKOFF *)pos; + cmd_len = S_DS_GEN + sizeof(HostCmd_DS_CMD_ROAMAGENT_BACKOFF); + hostcmd->command = cpu_to_le16(HostCmd_CMD_ROAMAGENT_BACKOFF); + hostcmd->size = cpu_to_le16(cmd_len); + hostcmd->seq_num = 0; + hostcmd->result = 0; + + switch (spflag[0] + spflag[1]) { + case 0: + /* error */ + puts("\nIncorrect arguments for setra backoff command.\n"); + ret = MLAN_STATUS_FAILURE; + goto done; + + case 1: + /* get missing parameter */ + if (getBackOff(roambackoffcmd) != MLAN_STATUS_SUCCESS) { + ret = MLAN_STATUS_FAILURE; + goto done; + } + if (spflag[0] == 0) { + minscan = roambackoffcmd->Scans; + } else { + bperiod = roambackoffcmd->Period; + } + break; + + case 2: + default: + break; + } + + roambackoffcmd->action = cpu_to_le16(HostCmd_ACT_GEN_SET); + roambackoffcmd->Scans = cpu_to_le16(minscan); + roambackoffcmd->Period = cpu_to_le16(bperiod); + + /* Put buffer length */ + memcpy(buffer + cmd_header_len, &cmd_len, sizeof(t_u32)); + + /* Initialize the ifr structure */ + memset(&ifr, 0, sizeof(ifr)); + strncpy(ifr.ifr_ifrn.ifrn_name, dev_name, strlen(dev_name)); + ifr.ifr_ifru.ifru_data = (void *)cmd; + /* Perform ioctl */ + if (ioctl(sockfd, MLAN_ETH_PRIV, &ifr)) { + perror("ioctl[roambackoff]"); + printf("ERR:Command sending failed!\n"); + ret = -EFAULT; + goto done; + } + + if (le16_to_cpu(hostcmd->result)) { + printf("\nHostCmd Error: ReturnCode=%#04x, Result=%#04x\n\n", + le16_to_cpu(hostcmd->command), + le16_to_cpu(hostcmd->result)); + } else { + printf("\nHostCmd Success: ReturnCode=%#04x, Result=%#04x\n\n", + le16_to_cpu(hostcmd->command), + le16_to_cpu(hostcmd->result)); + } + +done: + if (buffer) + free(buffer); + if (cmd) + free(cmd); + return ret; +} + +/** + * @brief Issue setra enable/disable/resume/suspend command + * + * @param argc number of arguments + * @param argv A pointer to arguments array + * @param set/reset set/reset flag + * @param value roam control/ host event bitmap value + * + * @return MLAN_STATUS_SUCCESS--success, otherwise--fail + */ +static int +roamSetControl(int argc, char *argv[], int setreset, t_u8 value) +{ + int ret = MLAN_STATUS_SUCCESS; + struct ifreq ifr; + t_u8 *buffer = NULL, *pos = NULL; + t_u32 cmd_len = 0, cmd_header_len; + struct eth_priv_cmd *cmd = NULL; + HostCmd_DS_GEN *hostcmd; + HostCmd_DS_CMD_ROAMAGENT_CONTROL *roamcontrolcmd; + + cmd_header_len = strlen(CMD_NXP) + strlen(HOSTCMD); + + buffer = (t_u8 *)malloc(BUFFER_LENGTH); + if (buffer == NULL) { + fprintf(stderr, "Cannot alloc memory\n"); + ret = ENOMEM; + goto done; + } + memset(buffer, 0, BUFFER_LENGTH); + + cmd = (struct eth_priv_cmd *)malloc(sizeof(struct eth_priv_cmd)); + if (!cmd) { + printf("ERR:Cannot allocate buffer for command!\n"); + ret = ENOMEM; + goto done; + } + + /* Fill up buffer */ +#ifdef USERSPACE_32BIT_OVER_KERNEL_64BIT + memset(cmd, 0, sizeof(struct eth_priv_cmd)); + memcpy(&cmd->buf, &buffer, sizeof(buffer)); +#else + cmd->buf = buffer; +#endif + cmd->used_len = 0; + cmd->total_len = BUFFER_LENGTH; + + /* buffer = MRVL_CMD */ + strncpy((char *)buffer, CMD_NXP, strlen(CMD_NXP)); + strncpy((char *)buffer + strlen(CMD_NXP), HOSTCMD, strlen(HOSTCMD)); + + /* buffer = MRVL_CMD */ + hostcmd = (HostCmd_DS_GEN *)(buffer + cmd_header_len + sizeof(t_u32)); + + /* Point after host command header */ + pos = (t_u8 *)hostcmd + S_DS_GEN; + + cmd_len = S_DS_GEN + sizeof(HostCmd_DS_CMD_ROAMAGENT_CONTROL); + + hostcmd->command = cpu_to_le16(HostCmd_CMD_ROAMAGENT_CONTROL); + hostcmd->size = cpu_to_le16(cmd_len); + hostcmd->seq_num = 0; + hostcmd->result = 0; + + roamcontrolcmd = (HostCmd_DS_CMD_ROAMAGENT_CONTROL *)pos; + + /* get current value */ + if (getControl(roamcontrolcmd) != MLAN_STATUS_SUCCESS) { + ret = MLAN_STATUS_FAILURE; + goto done; + } + + roamcontrolcmd->action = cpu_to_le16(HostCmd_ACT_GEN_SET); + switch (setreset) { + case 0: + roamcontrolcmd->Control &= value; + break; + case 1: + roamcontrolcmd->Control |= value; + break; + case 2: + roamcontrolcmd->HostEvent &= value; + break; + case 3: + roamcontrolcmd->HostEvent |= value; + break; + } + + /* Put buffer length */ + memcpy(buffer + cmd_header_len, &cmd_len, sizeof(t_u32)); + + /* Initialize the ifr structure */ + memset(&ifr, 0, sizeof(ifr)); + strncpy(ifr.ifr_ifrn.ifrn_name, dev_name, strlen(dev_name)); + ifr.ifr_ifru.ifru_data = (void *)cmd; + /* Perform ioctl */ + if (ioctl(sockfd, MLAN_ETH_PRIV, &ifr)) { + perror("ioctl[roamcontrol]"); + printf("ERR:Command sending failed!\n"); + ret = -EFAULT; + goto done; + } + + if (le16_to_cpu(hostcmd->result)) { + printf("\nHostCmd Error: ReturnCode=%#04x, Result=%#04x\n\n", + le16_to_cpu(hostcmd->command), + le16_to_cpu(hostcmd->result)); + } else { + printf("\nHostCmd Success: ReturnCode=%#04x, Result=%#04x\n\n", + le16_to_cpu(hostcmd->command), + le16_to_cpu(hostcmd->result)); + } + +done: + if (buffer) + free(buffer); + if (cmd) + free(cmd); + return ret; +} + +/** + * @brief Issue setra enable command + * + * @param argc number of arguments + * @param argv A pointer to arguments array + * + * @return MLAN_STATUS_SUCCESS--success, otherwise--fail + */ +static int +roamSetEnableControl(int argc, char *argv[]) +{ + return roamSetControl(argc, argv, 1, ROAM_CONTROL_ENABLE); +} + +/** + * @brief Issue setra disable command + * + * @param argc number of arguments + * @param argv A pointer to arguments array + * + * @return MLAN_STATUS_SUCCESS--success, otherwise--fail + */ +static int +roamSetDisableControl(int argc, char *argv[]) +{ + return roamSetControl(argc, argv, 0, ROAM_CONTROL_DISABLE); +} + +/** + * @brief Issue setra suspend command + * + * @param argc number of arguments + * @param argv A pointer to arguments array + * + * @return MLAN_STATUS_SUCCESS--success, otherwise--fail + */ +static int +roamSetSuspendControl(int argc, char *argv[]) +{ + return roamSetControl(argc, argv, 1, ROAM_CONTROL_SUSPEND); +} + +/** + * @brief Issue setra resume command + * + * @param argc number of arguments + * @param argv A pointer to arguments array + * + * @return MLAN_STATUS_SUCCESS--success, otherwise--fail + */ +static int +roamSetResumeControl(int argc, char *argv[]) +{ + return roamSetControl(argc, argv, 0, ROAM_CONTROL_RESUME); +} + +/** + * @brief Issue setra crossband command + * + * @param argc number of arguments + * @param argv A pointer to argument array + * + * @return MLAN_STATUS_SUCCESS--success, otherwise--fail + */ +static int +roamSetCrossband(int argc, char *argv[]) +{ + if (argc != 1) { + printf("Invalid Usage \n"); + return MLAN_STATUS_FAILURE; + } + if (strncmp(argv[0], "enable", strlen("enable")) == 0) { + return roamSetControl(argc, argv, 1, CROSSBAND_ENABLE); + } else if (strncmp(argv[0], "disable", strlen("disable")) == 0) { + return roamSetControl(argc, argv, 0, CROSSBAND_DISABLE); + } + + printf("Invalid Usage \n"); + return MLAN_STATUS_FAILURE; +} + +/** + * @brief Issue setra event command + * + * @param argc number of arguments + * @param argv A pointer to argument array + * + * @return MLAN_STATUS_SUCCESS--success, otherwise--fail + */ +static int +roamSetEventBitmap(int argc, char *argv[]) +{ + int i, enableFlag, found = 0; + t_u8 value; + if (argc > 4 || argc < 2) { + printf("Invalid Usage \n"); + return MLAN_STATUS_FAILURE; + } + if (strncmp(argv[0], "enable", strlen("enable")) == 0) { + enableFlag = 3; + value = HOST_EVENT_NBOR_DISABLE & HOST_EVENT_ROAM_DISABLE + & HOST_EVENT_STATE_DISABLE; + } else if (strncmp(argv[0], "disable", strlen("disable")) == 0) { + enableFlag = 2; + value = HOST_EVENT_NBOR_ENABLE | HOST_EVENT_ROAM_ENABLE + | HOST_EVENT_STATE_ENABLE; + } else { + printf("Invalid parameter %s \n", argv[0]); + return MLAN_STATUS_FAILURE; + } + + for (i = 1; i < argc; i++) { + found = 0; + if (strncmp(argv[i], "neighbor", strlen("neighbor")) == 0) { + found = 1; + if (enableFlag == 3) { + value |= HOST_EVENT_NBOR_ENABLE; + } else { + value &= HOST_EVENT_NBOR_DISABLE; + } + } + if (strncmp(argv[i], "roam", strlen("roam")) == 0) { + found = 1; + if (enableFlag == 3) { + value |= HOST_EVENT_ROAM_ENABLE; + } else { + value &= HOST_EVENT_ROAM_DISABLE; + } + } + if (strncmp(argv[i], "state", strlen("state")) == 0) { + found = 1; + if (enableFlag == 3) { + value |= HOST_EVENT_STATE_ENABLE; + } else { + value &= HOST_EVENT_STATE_DISABLE; + } + } + if (found == 0) { + printf("Invalid parameter %s \n", argv[i]); + return MLAN_STATUS_FAILURE; + } + } + + return roamSetControl(argc, argv, enableFlag, value); +} + +/** + * @brief Set the Roaming agent configuration parameters to FW. + * + * @param argc number of arguments + * @param argv A pointer to arguments array + * + * @return MLAN_STATUS_SUCCESS--success, otherwise--fail + */ +int +process_set_ra_config(int argc, char *argv[]) +{ + sub_cmd_exec_t subCmds[] = { + {"rssi", 2, 1, roamSetRssiStatsThreshold}, + {"prebcnmiss", 2, 1, roamSetPreBeaconLoss}, + {"failcnt", 2, 1, roamSetFailureCount}, + {"neighbor", 2, 0, printSetNeighborDeprecation}, + {"nparams", 2, 1, roamSetNborParams}, + {"maintain", 2, 1, roamSetNborMaintenance}, + {"scanperiod", 2, 1, roamSetScanPeriod}, + {"backoff", 2, 1, roamSetBackOff}, + {"enable", 2, 1, roamSetEnableControl}, + {"disable", 2, 1, roamSetDisableControl}, + {"suspend", 2, 1, roamSetSuspendControl}, + {"resume", 2, 1, roamSetResumeControl}, + {"metrics", 2, 1, roamSetMetrics}, + {"crossband", 2, 1, roamSetCrossband}, + {"event", 2, 1, roamSetEventBitmap} + }; + + return process_sub_cmd(subCmds, NELEMENTS(subCmds), argc, argv); +} diff --git a/mxm_wifiex/wlan_src/mapp/mlanutl/mlanroamagent.h b/mxm_wifiex/wlan_src/mapp/mlanutl/mlanroamagent.h new file mode 100644 index 0000000..8604353 --- /dev/null +++ b/mxm_wifiex/wlan_src/mapp/mlanutl/mlanroamagent.h @@ -0,0 +1,320 @@ +/** @file mlanroamagent.h + * + * @brief This files contains mlanutl roamagent command handling. + * + * + * Copyright 2014-2020 NXP + * + * NXP CONFIDENTIAL + * The source code contained or described herein and all documents related to + * the source code (Materials) are owned by NXP, its + * suppliers and/or its licensors. Title to the Materials remains with NXP, + * its suppliers and/or its licensors. The Materials contain + * trade secrets and proprietary and confidential information of NXP, its + * suppliers and/or its licensors. The Materials are protected by worldwide copyright + * and trade secret laws and treaty provisions. No part of the Materials may be + * used, copied, reproduced, modified, published, uploaded, posted, + * transmitted, distributed, or disclosed in any way without NXP's prior + * express written permission. + * + * No license under any patent, copyright, trade secret or other intellectual + * property right is granted to or conferred upon you by disclosure or delivery + * of the Materials, either expressly, by implication, inducement, estoppel or + * otherwise. Any license under such intellectual property rights must be + * express and approved by NXP in writing. + * + */ +/************************************************************************ +Change log: + 08/11/2009: initial version +************************************************************************/ + +#ifndef _MLANROAMAGENT_H_ +#define _MLANROAMAGENT_H_ + +/** Bit definitions */ +#ifndef BIT +#define BIT(x) (1UL << (x)) +#endif + +/* Define actionsd for HostCmd_DS_CMD_ROAMAGENT_NEIGHBORLIST_MAINTENANCE */ +/** Blacklist */ +#define HostCmd_ACT_ADD_TO_BLACKLIST 0x0001 +/** Flushing blacklisted entry */ +#define HostCmd_ACT_REMOVE_FROM_BLACKLIST 0x0002 + +/** Roaming scanmode: discovery */ +#define DISCOVERY_MODE 1 +/** Roaming scanmode: tracking */ +#define TRACKING_MODE 2 + +/** Threshold configuration: RSSI */ +#define RSSI_THRESHOLD 1 +/** Threshold configuration: SNR */ +#define SNR_THRESHOLD 2 + +#ifdef BIG_ENDIAN_SUPPORT +/** Bit values for Qualified Neighbor RSSI Entry */ +#define BIT_NEIGHFLAG_RSSI 0x80000000 +/** Bit values for Qualified Neighbor AGE Entry */ +#define BIT_NEIGHFLAG_AGE 0x40000000 +/** Bit values for Qualified Neighbor Blacklist Entry */ +#define BIT_NEIGHFLAG_BLACKLIST 0x20000000 +/** Bit values for Qualified Neighbor Admission Capacity */ +#define BIT_NEIGHFLAG_ADMISSION_CAP 0x10000000 +/** Bit values for Qualified Neighbor Uplink RSSI */ +#define BIT_NEIGHFLAG_UPLINK_RSSI 0x08000000 +#else +/** Bit values for Qualified Neighbor RSSI Entry */ +#define BIT_NEIGHFLAG_RSSI 0x01 +/** Bit values for Qualified Neighbor AGE Entry */ +#define BIT_NEIGHFLAG_AGE 0x02 +/** Bit values for Qualified Neighbor Blacklist Entry */ +#define BIT_NEIGHFLAG_BLACKLIST 0x04 +/** Bit values for Qualified Neighbor Admission Capacity */ +#define BIT_NEIGHFLAG_ADMISSION_CAP 0x08 +/** Bit values for Qualified Neighbor Uplink RSSI */ +#define BIT_NEIGHFLAG_UPLINK_RSSI 0x10 +#endif + +/** milliseconds time conversion data */ +typedef struct exactTime { + t_u16 hrs; /**< Number of hours */ + t_u16 mins; /**< Number of minutes */ + t_u16 secs; /**< Number of seconds */ + t_u16 msecs; /**< Number of milliseconds left */ +} ExactTime_t; + +/** ROAMAGENT HostEvent bitmasks */ +typedef enum { + HOST_EVENT_NBOR_DISABLE = 6, /* reset bit 0 */ + HOST_EVENT_NBOR_ENABLE = 1, /* set bit 0 */ + HOST_EVENT_ROAM_DISABLE = 5, /* reset bit 1 */ + HOST_EVENT_ROAM_ENABLE = 2, /* set bit 1 */ + HOST_EVENT_STATE_DISABLE = 3, /* reset bit 2 */ + HOST_EVENT_STATE_ENABLE = 4, /* reset bit 2 */ +} __ATTRIB_PACK__ HostEvent_e; + +/** ROAMAGENT_CONTROL command identifiers */ +typedef enum { + ROAM_CONTROL_DISABLE = 6, /* reset bit 0 */ + ROAM_CONTROL_ENABLE = 1, /* set bit 0 */ + ROAM_CONTROL_RESUME = 5, /* reset bit 1 */ + ROAM_CONTROL_SUSPEND = 2, /* set bit 1 */ + CROSSBAND_DISABLE = 3, /* reset bit 2 */ + CROSSBAND_ENABLE = 4 /* set bit 2 */ +} __ATTRIB_PACK__ RoamControl_e; + +/* + * Definitions of roaming state and other constants + */ +/** Enum Definitations: Roaming agent state */ +typedef enum { + STATE_DISCONNECTED, + STATE_STABLE, + STATE_DEGRADING, + STATE_UNACCEPTABLE, + STATE_HARDROAM, + STATE_LINKLOSS, + STATE_SOFTROAM, + STATE_SUSPEND, + STATE_CMD_SUSPEND, + STATE_ASYNCASSOC_SUSPEND +} RoamingAgentState; + +/** statistics threshold High RSSI */ +typedef struct { + /** Header */ + MrvlIEtypesHeader_t Header; + /** RSSI threshold (dBm) */ + t_u8 Value; + /** reporting frequency */ + t_u8 Frequency; +} __ATTRIB_PACK__ MrvlIEtypes_BeaconHighRssiThreshold_t, + MrvlIEtypes_BeaconLowRssiThreshold_t, + MrvlIEtypes_BeaconHighSnrThreshold_t, + MrvlIEtypes_BeaconLowSnrThreshold_t; + +/** HostCmd_DS_CMD_ROAMAGENT_STATISTICS_THRESHOLD */ +typedef struct { + /** Action */ + t_u16 action; + /** roaming state */ + t_u8 State; + /** active/configured user */ + t_u8 Profile; + /** TLV buffer */ + t_u8 TlvBuffer[1]; + /* MrvlIEtypes_BeaconHighRssiThreshold_t BeaconHighRssiThreshold; + * MrvlIEtypes_BeaconLowRssiThreshold_t BeaconLowRssiThreshold; + * MrvlIEtypes_BeaconHighSnrThreshold_t BeaconHighSnrThreshold; + * MrvlIEtypes_BeaconLowSnrThreshold_t BeaconLowSnrThreshold; + * MrvlIEtypes_BeaconsMissed_t PreBeaconMissed; + * MrvlIEtypes_FailureCount_t FailureCnt; + */ +} __ATTRIB_PACK__ HostCmd_DS_CMD_ROAMAGENT_STATISTICS_THRESHOLD; + +typedef struct { + /** */ + signed char RssiHighLevel; + /** */ + signed char RssiLowLevel; + /** */ + signed char RssiNborDiff; + +} __ATTRIB_PACK__ HostCmd_DS_CMD_ROAMAGENT_ROAM_THRESHOLD; + +#define ROAM_THRESH_MAX 4 + +/** HostCmd_DS_CMD_ROAMAGENT_NEIGHBOR_ASSESSMENT */ +typedef struct { + /** Action */ + t_u16 action; + /** configured qualifying snr */ + signed char ConfQualSignalStrength; + /** active qualifying snr */ + signed char ActiveQualSignalStrength; + /** qualifying neighbor count */ + t_u16 QualifyingNumNeighbor; + /** inactivity in # scans */ + t_u16 StaleCount; + /** inactivity in time (ms) */ + t_u32 StalePeriod; + /** blacklist duration in ms due to minor failures */ + t_u32 ShortBlacklistPeriod; + /** blacklist duration in ms due to severe failures */ + t_u32 LongBlacklistPeriod; + + HostCmd_DS_CMD_ROAMAGENT_ROAM_THRESHOLD RoamThresh[ROAM_THRESH_MAX]; + +} __ATTRIB_PACK__ HostCmd_DS_CMD_ROAMAGENT_NEIGHBOR_ASSESSMENT; + +/** HostCmd_DS_CMD_ROAMAGENT_NEIGHBORLIST */ +typedef struct { + /** Action */ + t_u16 action; + /** Reserved */ + t_u16 Reserved; + /** TLV buffer */ + t_u8 TlvBuffer[1]; + /* MrvlIEtypes_NeighborEntry_t Neighbors[MRVL_ROAM_MAX_NEIGHBORS]; + * MRVL_ROAM_MAX_NEIGHBORS = 5 + */ +} __ATTRIB_PACK__ HostCmd_DS_CMD_ROAMAGENT_NEIGHBORLIST; + +/** neighbor entry details roaming agent */ +typedef struct { + /** Header */ + MrvlIEtypesHeader_t Header; + /** bssid of neighbor */ + t_u8 Bssid[ETH_ALEN]; + /** Reserved */ + t_u16 Reserved; + /** neighbor snr */ + t_s16 SignalStrength; + /** neighbor age */ + t_u16 Age; + /** bit map for qualified neighbor */ + t_u32 QualifiedNeighborBitmap; + /** blacklist duration in ms */ + t_u32 BlackListDuration; +} __ATTRIB_PACK__ MrvlIEtypes_NeighborEntry_t; + +/** HostCmd_DS_ROAMAGENT_ADV_METRIC_THRESHOLD */ +typedef struct { + /** Action */ + t_u16 action; + /** Beacon RSSI Metrics,Data RSSI Metrics or PER Metrics */ + t_u16 Metrics; + /** Percentage FER Threshold value to exceed for making a roam decision */ + t_u8 UcFerThresholdValue; + /** Percentage PER Threshold value to exceed for making a roam decision */ + t_u8 UcPerThresholdValue; + /** Reserved for later use */ + t_u8 Reserved[2]; + /** Time (ms) for which FER should prevail in stable state */ + t_u32 StableFERPeriod_ms; + /** Time (ms) for which FER should prevail in degrading state */ + t_u32 DegradingFERPeriod_ms; + /** Time (ms) for which FER should prevail in unacceptable state */ + t_u32 UnacceptableFERPeriod_ms; + /** Time (ms) for which FER should prevail in stable state */ + t_u32 StablePERPeriod_ms; + /** Time (ms) for which PER should prevail in degrading state */ + t_u32 DegradingPERPeriod_ms; + /** Time (ms) for which PER should prevail in unacceptable state */ + t_u32 UnacceptablePERPeriod_ms; + /** Number of TX packets to exceed in period_ms ms for the FER for Roam */ + t_u32 UiFerPktThreshold; + /** Number of TX packets to exceed in period_ms ms for the PER for Roam */ + t_u32 UiPerPktThreshold; + /** Time in ms for which inactivity should prevail for state transition */ + t_u32 InactivityPeriodThreshold_ms; + /** With Data RSSI Metrics, Roam only when RX packets in period_ms ms exceeds this */ + t_u32 UiRxPktThreshold; +} __ATTRIB_PACK__ HostCmd_DS_CMD_ROAMAGENT_ADV_METRIC_THRESHOLD; + +/** scan period for each search mode and state for roaming agent */ +typedef struct { + /** Header */ + MrvlIEtypesHeader_t Header; + /** search mode */ + t_u16 SearchMode; + /** roaming state */ + t_u16 State; + /** scan period value */ + t_u32 ScanPeriod; +} __ATTRIB_PACK__ MrvlIEtypes_NeighborScanPeriod_t; + +/** HostCmd_DS_CMD_ROAMAGENT_CONTROL */ +typedef struct { + /** Action */ + t_u16 action; + /** enable control */ + t_u8 Control; + /** host event control */ + t_u8 HostEvent; +} __ATTRIB_PACK__ HostCmd_DS_CMD_ROAMAGENT_CONTROL; + +/** HostCmd_DS_CMD_ROAMAGENT_BACKOFF */ +typedef struct { + /** Action */ + t_u16 action; + /** minimum scans */ + t_u16 Scans; + /** backoff period */ + t_u32 Period; +} __ATTRIB_PACK__ HostCmd_DS_CMD_ROAMAGENT_BACKOFF; + +/** HostCmd_DS_CMD_ROAMAGENT_NEIGHBOR_SCANPERIOD */ +typedef struct { + /** Action */ + t_u16 action; + /** Reserved */ + t_u16 Reserved; + /** scanPeriod TLV */ + MrvlIEtypes_NeighborScanPeriod_t scanPeriod; +} __ATTRIB_PACK__ HostCmd_DS_CMD_ROAMAGENT_NEIGHBOR_SCANPERIOD; + +/** HostCmd_DS_CMD_ROAMAGENT_NEIGHBOR_SCANPERIOD_RSP */ +typedef struct { + /** Action */ + t_u16 action; + /** Reserved */ + t_u16 Reserved; + /** TLV buffer */ + t_u8 TlvBuffer[1]; + /* MrvlIEtypes_NeighborScanPeriod_t scanPeriod[MRVL_ROAM_SCAN_PERIODS]; + * MRVL_ROAM_SCAN_PERIODS = 6 + */ +} __ATTRIB_PACK__ HostCmd_DS_CMD_ROAMAGENT_NEIGHBOR_SCANPERIOD_RSP; + +/** HostCmd_DS_CMD_ROAMAGENT_NEIGHBORLIST_MAINTENANCE */ +typedef struct { + /** Action */ + t_u16 action; + /** BSSID */ + t_u8 BSSID[ETH_ALEN]; +} __ATTRIB_PACK__ HostCmd_DS_CMD_ROAMAGENT_NEIGHBORLIST_MAINTENANCE; + +#endif /* _MLANROAMAGENT_H_ */ diff --git a/mxm_wifiex/wlan_src/mapp/mlanutl/mlanscanagent.c b/mxm_wifiex/wlan_src/mapp/mlanutl/mlanscanagent.c new file mode 100644 index 0000000..e018202 --- /dev/null +++ b/mxm_wifiex/wlan_src/mapp/mlanutl/mlanscanagent.c @@ -0,0 +1,848 @@ +/** @file mlanscanagent.c + * + * @brief This files contains mlanutl scanagent command handling. + * + * Usage: mlanutl mlanX scanagent [...] + * + * + * Copyright 2014-2020 NXP + * + * NXP CONFIDENTIAL + * The source code contained or described herein and all documents related to + * the source code (Materials) are owned by NXP, its + * suppliers and/or its licensors. Title to the Materials remains with NXP, + * its suppliers and/or its licensors. The Materials contain + * trade secrets and proprietary and confidential information of NXP, its + * suppliers and/or its licensors. The Materials are protected by worldwide copyright + * and trade secret laws and treaty provisions. No part of the Materials may be + * used, copied, reproduced, modified, published, uploaded, posted, + * transmitted, distributed, or disclosed in any way without NXP's prior + * express written permission. + * + * No license under any patent, copyright, trade secret or other intellectual + * property right is granted to or conferred upon you by disclosure or delivery + * of the Materials, either expressly, by implication, inducement, estoppel or + * otherwise. Any license under such intellectual property rights must be + * express and approved by NXP in writing. + * + */ +/************************************************************************ +Change log: + 08/11/2009: initial version +************************************************************************/ + +#include "mlanutl.h" +#include "mlanhostcmd.h" +#include "mlanoffload.h" +#include "mlanscanagent.h" + +/******************************************************** + Local Variables +********************************************************/ + +/******************************************************** + Global Variables +********************************************************/ + +/******************************************************** + Local Functions +********************************************************/ + +/** + * @brief scanagent configure scan table + * + * @param age_limit age limit + * @param hold_limit hold limit + * + * @return MLAN_STATUS_SUCCESS on success, otherwise error code + */ +static int +scanagent_cfg_scan_table_limits(t_u32 age_limit, t_u32 hold_limit) +{ + int ret = 0; + struct ifreq ifr; + t_u8 *buffer = NULL, *pos = NULL; + t_u32 cmd_len = 0, cmd_header_len; + struct eth_priv_cmd *cmd = NULL; + HostCmd_DS_GEN *hostcmd = NULL; + HostCmd_DS_SCANAGENT_SCAN_TABLE_LIMITS *scan_table_limits = NULL; + + cmd_header_len = strlen(CMD_NXP) + strlen(HOSTCMD); + cmd_len = S_DS_GEN + sizeof(HostCmd_DS_SCANAGENT_SCAN_TABLE_LIMITS); + + buffer = (t_u8 *)malloc(BUFFER_LENGTH); + if (buffer == NULL) { + fprintf(stderr, "Cannot alloc memory\n"); + return -ENOMEM; + } + memset(buffer, 0, BUFFER_LENGTH); + + cmd = (struct eth_priv_cmd *)malloc(sizeof(struct eth_priv_cmd)); + if (!cmd) { + printf("ERR:Cannot allocate buffer for command!\n"); + free(buffer); + return -ENOMEM; + } + + /* Fill up buffer */ +#ifdef USERSPACE_32BIT_OVER_KERNEL_64BIT + memset(cmd, 0, sizeof(struct eth_priv_cmd)); + memcpy(&cmd->buf, &buffer, sizeof(buffer)); +#else + cmd->buf = buffer; +#endif + cmd->used_len = 0; + cmd->total_len = BUFFER_LENGTH; + + /* buffer = MRVL_CMD */ + strncpy((char *)buffer, CMD_NXP, strlen(CMD_NXP)); + strncpy((char *)buffer + strlen(CMD_NXP), HOSTCMD, strlen(HOSTCMD)); + + /* buffer = MRVL_CMD */ + hostcmd = (HostCmd_DS_GEN *)(buffer + cmd_header_len + sizeof(t_u32)); + hostcmd->command = cpu_to_le16(HostCmd_CMD_SCANAGENT_SCAN_TABLE_LIMITS); + hostcmd->size = cpu_to_le16(cmd_len); + hostcmd->seq_num = 0; + hostcmd->result = 0; + + /* Put buffer length */ + memcpy(buffer + cmd_header_len, &cmd_len, sizeof(t_u32)); + + /* Point after host command header */ + pos = (t_u8 *)hostcmd + S_DS_GEN; + + scan_table_limits = (HostCmd_DS_SCANAGENT_SCAN_TABLE_LIMITS *)pos; + scan_table_limits->table_age_limit = cpu_to_le16(age_limit); + scan_table_limits->table_hold_limit = cpu_to_le16(hold_limit); + + /* 0 set values are ignored by firmware */ + scan_table_limits->action = cpu_to_le16(HostCmd_ACT_GEN_SET); + + /* Initialize the ifr structure */ + memset(&ifr, 0, sizeof(ifr)); + strncpy(ifr.ifr_ifrn.ifrn_name, dev_name, strlen(dev_name)); + ifr.ifr_ifru.ifru_data = (void *)cmd; + /* Perform ioctl */ + if (ioctl(sockfd, MLAN_ETH_PRIV, &ifr)) { + perror("ioctl[scanAgentIoctl]"); + printf("ERR:Command sending failed!\n"); + ret = -EFAULT; + goto done; + } + + printf("\nAge limit = %7d seconds\n", + le16_to_cpu(scan_table_limits->table_age_limit)); + printf("Hold limit = %7d seconds\n\n", + le16_to_cpu(scan_table_limits->table_hold_limit)); + +done: + if (buffer) + free(buffer); + if (cmd) + free(cmd); + return ret; +} + +/** + * @brief Set scanagent age limit + * + * @param argc number of arguments + * @param argv A pointer to arguments array + * + * @return MLAN_STATUS_SUCCESS on success, otherwise error code + */ +static int +scanagent_age_limit(int argc, char *argv[]) +{ + t_u32 age_limit = 0; + + if (argc) { + age_limit = atoi(argv[0]); + } + + return scanagent_cfg_scan_table_limits(age_limit, 0); +} + +/** + * @brief Set scanagent hold limit + * + * @param argc number of arguments + * @param argv A pointer to arguments array + * + * @return MLAN_STATUS_SUCCESS on success, otherwise error code + */ +static int +scanagent_hold_limit(int argc, char *argv[]) +{ + t_u32 hold_limit = 0; + + if (argc) { + hold_limit = atoi(argv[0]); + } + + return scanagent_cfg_scan_table_limits(0, hold_limit); +} + +/** + * @brief Set scanagent scan timing + * + * @param argc number of arguments + * @param argv A pointer to arguments array + * + * @return MLAN_STATUS_SUCCESS on success, otherwise error code + */ +static int +scanagent_timing(int argc, char *argv[]) +{ + int ret = 0; + struct ifreq ifr; + int idx; + t_u8 *buffer = NULL, *pos = NULL; + t_u32 cmd_len = 0, cmd_header_len = 0, sel = 0; + struct eth_priv_cmd *cmd = NULL; + HostCmd_DS_GEN *hostcmd = NULL; + HostCmd_DS_SCANAGENT_CONFIG_TIMING *cfg_timing_cmd = NULL; + MrvlIEtypes_ConfigScanTiming_t *cfg_timing_tlv = NULL; + timing_sel_t sel_str[] = { {"disconnected", 1}, + {"adhoc", 1}, + {"fullpower", 1}, + {"ieeeps", 1}, + {"periodic", 1} + }; + + cmd_header_len = strlen(CMD_NXP) + strlen(HOSTCMD); + cmd_len = S_DS_GEN + sizeof(t_u16); + + buffer = (t_u8 *)malloc(BUFFER_LENGTH); + if (buffer == NULL) { + fprintf(stderr, "Cannot alloc memory\n"); + return -ENOMEM; + } + memset(buffer, 0, BUFFER_LENGTH); + + cmd = (struct eth_priv_cmd *)malloc(sizeof(struct eth_priv_cmd)); + if (!cmd) { + printf("ERR:Cannot allocate buffer for command!\n"); + free(buffer); + return -ENOMEM; + } + + /* Fill up buffer */ +#ifdef USERSPACE_32BIT_OVER_KERNEL_64BIT + memset(cmd, 0, sizeof(struct eth_priv_cmd)); + memcpy(&cmd->buf, &buffer, sizeof(buffer)); +#else + cmd->buf = buffer; +#endif + cmd->used_len = 0; + cmd->total_len = BUFFER_LENGTH; + + /* buffer = MRVL_CMD */ + strncpy((char *)buffer, CMD_NXP, strlen(CMD_NXP)); + strncpy((char *)buffer + strlen(CMD_NXP), HOSTCMD, strlen(HOSTCMD)); + + /* buffer = MRVL_CMD */ + hostcmd = (HostCmd_DS_GEN *)(buffer + cmd_header_len + sizeof(t_u32)); + hostcmd->command = cpu_to_le16(HostCmd_CMD_SCANAGENT_SCAN_TIMING); + hostcmd->seq_num = 0; + hostcmd->result = 0; + + /* Point after host command header */ + pos = (t_u8 *)hostcmd + S_DS_GEN; + + cfg_timing_cmd = (HostCmd_DS_SCANAGENT_CONFIG_TIMING *)pos; + cfg_timing_cmd->action = cpu_to_le16(HostCmd_ACT_GEN_GET); + + cfg_timing_tlv + = (MrvlIEtypes_ConfigScanTiming_t *)cfg_timing_cmd->tlv_buffer; + + if (argc == 5) { + cfg_timing_cmd->action = cpu_to_le16(HostCmd_ACT_GEN_SET); + cfg_timing_tlv->header.type = cpu_to_le16(TLV_TYPE_SCAN_TIMING); + cfg_timing_tlv->header.len = + cpu_to_le16(sizeof(MrvlIEtypes_ConfigScanTiming_t) + - sizeof(cfg_timing_tlv->header)); + + for (idx = 0; (unsigned int)idx < NELEMENTS(sel_str); idx++) { + if (strncmp(argv[0], + sel_str[idx].str, + sel_str[idx].match_len) == 0) { + sel = idx + 1; + break; + } + } + + if (idx == NELEMENTS(sel_str)) { + printf("Wrong argument for mode selected \"%s\"\n", + argv[0]); + ret = -EINVAL; + goto done; + } + + /* + * HostCmd_DS_ScanagentTimingMode_e; + * TIMING_MODE_INVALID = 0, + * TIMING_MODE_DISCONNECTED = 1, + * TIMING_MODE_ADHOC = 2, + * TIMING_MODE_FULL_POWER = 3, + * TIMING_MODE_IEEE_PS = 4, + * TIMING_MODE_PERIODIC_PS = 5, + */ + cfg_timing_tlv->mode = cpu_to_le32(sel); + cfg_timing_tlv->dwell = cpu_to_le32(atoi(argv[1])); + cfg_timing_tlv->max_off = cpu_to_le32(atoi(argv[2])); + cfg_timing_tlv->min_link = cpu_to_le32(atoi(argv[3])); + cfg_timing_tlv->rsp_timeout = cpu_to_le32(atoi(argv[4])); + + cmd_len += sizeof(MrvlIEtypes_ConfigScanTiming_t); + } + + hostcmd->size = cpu_to_le16(cmd_len); + + /* Put buffer length */ + memcpy(buffer + cmd_header_len, &cmd_len, sizeof(t_u32)); + + /* Initialize the ifr structure */ + memset(&ifr, 0, sizeof(ifr)); + strncpy(ifr.ifr_ifrn.ifrn_name, dev_name, strlen(dev_name)); + ifr.ifr_ifru.ifru_data = (void *)cmd; + /* Perform ioctl */ + if (ioctl(sockfd, MLAN_ETH_PRIV, &ifr)) { + perror("ioctl[scanAgentIoctl]"); + printf("ERR:Command sending failed!\n"); + ret = -EFAULT; + goto done; + } + + ret = process_host_cmd_resp(HOSTCMD, buffer); + +done: + if (buffer) + free(buffer); + if (cmd) + free(cmd); + return ret; +} + +/** + * @brief Set scanagent profile scan period + * + * @param argc number of arguments + * @param argv A pointer to arguments array + * + * @return MLAN_STATUS_SUCCESS on success, otherwise error code + */ +static int +scanagent_profile_period(int argc, char *argv[]) +{ + int ret = 0; + struct ifreq ifr; + t_u8 *buffer = NULL, *pos = NULL; + t_u32 cmd_len = 0, cmd_header_len = 0; + struct eth_priv_cmd *cmd = NULL; + HostCmd_DS_GEN *hostcmd = NULL; + HostCmd_DS_SCANAGENT_CONFIG_PROFILE_SCAN *cfg_profile_scan = NULL; + + cmd_header_len = strlen(CMD_NXP) + strlen(HOSTCMD); + cmd_len = S_DS_GEN + sizeof(HostCmd_DS_SCANAGENT_CONFIG_PROFILE_SCAN); + + buffer = (t_u8 *)malloc(BUFFER_LENGTH); + if (buffer == NULL) { + fprintf(stderr, "Cannot alloc memory\n"); + return -ENOMEM; + } + memset(buffer, 0, BUFFER_LENGTH); + + cmd = (struct eth_priv_cmd *)malloc(sizeof(struct eth_priv_cmd)); + if (!cmd) { + printf("ERR:Cannot allocate buffer for command!\n"); + free(buffer); + return -ENOMEM; + } + + /* Fill up buffer */ +#ifdef USERSPACE_32BIT_OVER_KERNEL_64BIT + memset(cmd, 0, sizeof(struct eth_priv_cmd)); + memcpy(&cmd->buf, &buffer, sizeof(buffer)); +#else + cmd->buf = buffer; +#endif + cmd->used_len = 0; + cmd->total_len = BUFFER_LENGTH; + + /* buffer = MRVL_CMD */ + strncpy((char *)buffer, CMD_NXP, strlen(CMD_NXP)); + strncpy((char *)buffer + strlen(CMD_NXP), HOSTCMD, strlen(HOSTCMD)); + + /* buffer = MRVL_CMD */ + hostcmd = (HostCmd_DS_GEN *)(buffer + cmd_header_len + sizeof(t_u32)); + hostcmd->command = + cpu_to_le16(HostCmd_CMD_SCANAGENT_CONFIG_PROFILE_SCAN); + hostcmd->size = cpu_to_le16(cmd_len); + hostcmd->seq_num = 0; + hostcmd->result = 0; + + /* Point after host command header */ + pos = (t_u8 *)hostcmd + S_DS_GEN; + + cfg_profile_scan = (HostCmd_DS_SCANAGENT_CONFIG_PROFILE_SCAN *)pos; + if (argc == 1) { + cfg_profile_scan->action = cpu_to_le16(HostCmd_ACT_GEN_SET); + cfg_profile_scan->scan_interval = cpu_to_le16(atoi(argv[0])); + } else { + cfg_profile_scan->action = cpu_to_le16(HostCmd_ACT_GEN_GET); + } + + /* Put buffer length */ + memcpy(buffer + cmd_header_len, &cmd_len, sizeof(t_u32)); + + /* Initialize the ifr structure */ + memset(&ifr, 0, sizeof(ifr)); + strncpy(ifr.ifr_ifrn.ifrn_name, dev_name, strlen(dev_name)); + ifr.ifr_ifru.ifru_data = (void *)cmd; + /* Perform ioctl */ + if (ioctl(sockfd, MLAN_ETH_PRIV, &ifr)) { + perror("ioctl[scanAgentIoctl]"); + printf("ERR:Command sending failed!\n"); + ret = -EFAULT; + goto done; + } + + cfg_profile_scan->scan_interval = + le16_to_cpu(cfg_profile_scan->scan_interval); + if ((int)cfg_profile_scan->scan_interval == 0) + printf("\nProfile Scan interval: \n\n"); + else + printf("\nProfile Scan interval: %d seconds\n\n", + (int)cfg_profile_scan->scan_interval); + +done: + if (buffer) + free(buffer); + if (cmd) + free(cmd); + return ret; +} + +/** + * @brief scanagent parse entry selection + * + * @param argc number of arguments + * @param argv A pointer to arguments array + * @param psel A pointer to scanagent entry selection + * + * @return None + */ +static void +scanAgentParseEntrySel(int argc, char *argv[], + HostCmd_DS_SCANAGENT_TABLE_MAINTENANCE *psel, + int *cmd_len) +{ + int arg_idx, tmp_idx; + t_u8 *tlv_pos; + MrvlIEtypes_SsIdParamSet_t *ssid; + MrvlIEtypes_Bssid_List_t *bssid; + unsigned int mac[ETH_ALEN]; + + tlv_pos = (t_u8 *)psel->tlv_buffer; + + for (arg_idx = 0; arg_idx < argc; arg_idx++) { + if (strncmp(argv[arg_idx], "ssid=", strlen("ssid=")) == 0) { + ssid = (MrvlIEtypes_SsIdParamSet_t *)tlv_pos; + ssid->header.type = cpu_to_le16(TLV_TYPE_SSID); + ssid->header.len = + strlen(argv[arg_idx]) - strlen("ssid="); + strncpy((char *)ssid->ssid, + (argv[arg_idx] + strlen("ssid=")), + ssid->header.len); + tlv_pos += + ssid->header.len + sizeof(MrvlIEtypesHeader_t); + ssid->header.len = cpu_to_le16(ssid->header.len); + + } else if (strncmp(argv[arg_idx], "bssid=", strlen("bssid=")) == + 0) { + bssid = (MrvlIEtypes_Bssid_List_t *)tlv_pos; + bssid->header.type = cpu_to_le16(TLV_TYPE_BSSID); + bssid->header.len = ETH_ALEN; + /* + * "bssid" token string handler + */ + sscanf(argv[arg_idx] + strlen("bssid="), + "%2x:%2x:%2x:%2x:%2x:%2x", mac + 0, mac + 1, + mac + 2, mac + 3, mac + 4, mac + 5); + for (tmp_idx = 0; + (unsigned int)tmp_idx < NELEMENTS(mac); + tmp_idx++) { + bssid->bssid[tmp_idx] = (t_u8)mac[tmp_idx]; + } + tlv_pos += + bssid->header.len + sizeof(MrvlIEtypesHeader_t); + bssid->header.len = cpu_to_le16(bssid->header.len); + + } else if (strncmp(argv[arg_idx], "age=", strlen("age=")) == 0) { + psel->age = + cpu_to_le32(atoi + (argv[arg_idx] + strlen("age="))); + + } else if (strncmp(argv[arg_idx], "id=", strlen("id=")) == 0) { + psel->scan_request_id = + cpu_to_le32(atoi + (argv[arg_idx] + strlen("id="))); + } + } + + *cmd_len += (tlv_pos - psel->tlv_buffer); +} + +/** + * @brief scanagent execute scan + * + * @param argc number of arguments + * @param argv A pointer to arguments array + * + * @return MLAN_STATUS_SUCCESS on success, otherwise error code + */ +static int +scanagent_exec_scan(int argc, char *argv[]) +{ + int ret = 0; + struct ifreq ifr; + int arg_idx, tmp_idx; + t_u32 cmd_len = 0, cmd_header_len = 0; + t_u8 *buffer = NULL, *pos = NULL, *tlv_pos = NULL; + struct eth_priv_cmd *cmd = NULL; + HostCmd_DS_GEN *hostcmd = NULL; + HostCmd_DS_SCANAGENT_SCAN_EXEC *scan_exec = NULL; + MrvlIEtypes_SsIdParamSet_t *ssid = NULL; + MrvlIEtypes_Bssid_List_t *bssid = NULL; + MrvlIEtypes_ConfigScanTiming_t *cfg_timing_tlv = NULL; + unsigned int mac[ETH_ALEN]; + + cmd_header_len = strlen(CMD_NXP) + strlen(HOSTCMD); + cmd_len = (S_DS_GEN + sizeof(HostCmd_DS_SCANAGENT_SCAN_EXEC) + - sizeof(scan_exec->tlv_buffer)); + + buffer = (t_u8 *)malloc(BUFFER_LENGTH); + if (buffer == NULL) { + fprintf(stderr, "Cannot alloc memory\n"); + return -ENOMEM; + } + memset(buffer, 0, BUFFER_LENGTH); + + cmd = (struct eth_priv_cmd *)malloc(sizeof(struct eth_priv_cmd)); + if (!cmd) { + printf("ERR:Cannot allocate buffer for command!\n"); + free(buffer); + return -ENOMEM; + } + + /* Fill up buffer */ +#ifdef USERSPACE_32BIT_OVER_KERNEL_64BIT + memset(cmd, 0, sizeof(struct eth_priv_cmd)); + memcpy(&cmd->buf, &buffer, sizeof(buffer)); +#else + cmd->buf = buffer; +#endif + cmd->used_len = 0; + cmd->total_len = BUFFER_LENGTH; + + /* buffer = MRVL_CMD */ + strncpy((char *)buffer, CMD_NXP, strlen(CMD_NXP)); + strncpy((char *)buffer + strlen(CMD_NXP), HOSTCMD, strlen(HOSTCMD)); + + /* buffer = MRVL_CMD */ + hostcmd = (HostCmd_DS_GEN *)(buffer + cmd_header_len + sizeof(t_u32)); + hostcmd->command = cpu_to_le16(HostCmd_CMD_SCANAGENT_SCAN_EXEC); + hostcmd->size = 0; + hostcmd->seq_num = 0; + hostcmd->result = 0; + + /* Point after host command header */ + pos = (t_u8 *)hostcmd + S_DS_GEN; + + scan_exec = (HostCmd_DS_SCANAGENT_SCAN_EXEC *)pos; + tlv_pos = scan_exec->tlv_buffer; + + for (arg_idx = 0; arg_idx < argc; arg_idx++) { + if (strncmp(argv[arg_idx], "ssid=", strlen("ssid=")) == 0) { + /* + * "ssid" token string handler + */ + ssid = (MrvlIEtypes_SsIdParamSet_t *)tlv_pos; + ssid->header.type = cpu_to_le16(TLV_TYPE_SSID); + ssid->header.len = + strlen(argv[arg_idx]) - strlen("ssid="); + strncpy((char *)ssid->ssid, + argv[arg_idx] + strlen("ssid="), + ssid->header.len); + tlv_pos += + ssid->header.len + sizeof(MrvlIEtypesHeader_t); + ssid->header.len = cpu_to_le16(ssid->header.len); + } else if (strncmp(argv[arg_idx], "bssid=", strlen("bssid=")) == + 0) { + bssid = (MrvlIEtypes_Bssid_List_t *)tlv_pos; + bssid->header.type = cpu_to_le16(TLV_TYPE_BSSID); + bssid->header.len = ETH_ALEN; + /* + * "bssid" token string handler + */ + sscanf(argv[arg_idx] + strlen("bssid="), + "%2x:%2x:%2x:%2x:%2x:%2x", mac + 0, mac + 1, + mac + 2, mac + 3, mac + 4, mac + 5); + for (tmp_idx = 0; + (unsigned int)tmp_idx < NELEMENTS(mac); + tmp_idx++) { + bssid->bssid[tmp_idx] = (t_u8)mac[tmp_idx]; + } + tlv_pos += + bssid->header.len + sizeof(MrvlIEtypesHeader_t); + bssid->header.len = cpu_to_le16(bssid->header.len); + } else if (strncmp(argv[arg_idx], "type=", strlen("type=")) == + 0) { + /* + if (strcmp(argv[arg_idx] + strlen("type="), "prof") == 0) { + scan_exec->scan_type = CONFIG_PROFILE; + } else { + scan_exec->scan_type = CONFIG_SITE_SURVEY; + } + */ + scan_exec->scan_type = CONFIG_SITE_SURVEY; + scan_exec->scan_type = + cpu_to_le16(scan_exec->scan_type); + } else if (strncmp(argv[arg_idx], "group=", strlen("group=")) == + 0) { + sscanf(argv[arg_idx] + strlen("group="), "0x%x", + &tmp_idx); + scan_exec->chan_group = cpu_to_le32(tmp_idx); + } else if (strncmp(argv[arg_idx], "delay=", strlen("delay=")) == + 0) { + /* + * "delay" token string handler + */ + sscanf(argv[arg_idx] + strlen("delay="), + "%d", (int *)&scan_exec->delay); + scan_exec->delay = cpu_to_le32(scan_exec->delay); + } else if (strncmp(argv[arg_idx], "timing=", strlen("timing=")) + == 0) { + cfg_timing_tlv = + (MrvlIEtypes_ConfigScanTiming_t *)tlv_pos; + cfg_timing_tlv->header.type = + cpu_to_le16(TLV_TYPE_SCAN_TIMING); + cfg_timing_tlv->header.len = ((sizeof(cfg_timing_tlv) + - + sizeof(cfg_timing_tlv-> + header))); + /* + * "timing" token string handler + */ + sscanf(argv[arg_idx] + strlen("timing="), "%d,%d,%d,%d", + (int *)&cfg_timing_tlv->dwell, + (int *)&cfg_timing_tlv->max_off, + (int *)&cfg_timing_tlv->min_link, + (int *)&cfg_timing_tlv->rsp_timeout); + + cfg_timing_tlv->mode = 0; + cfg_timing_tlv->dwell = + cpu_to_le32(cfg_timing_tlv->dwell); + cfg_timing_tlv->max_off = + cpu_to_le32(cfg_timing_tlv->max_off); + cfg_timing_tlv->min_link = + cpu_to_le32(cfg_timing_tlv->min_link); + cfg_timing_tlv->rsp_timeout = + cpu_to_le32(cfg_timing_tlv->rsp_timeout); + + tlv_pos += sizeof(MrvlIEtypesHeader_t); + tlv_pos += cfg_timing_tlv->header.len; + cfg_timing_tlv->header.len = + cpu_to_le16(cfg_timing_tlv->header.len); + } + } + + cmd_len += (tlv_pos - scan_exec->tlv_buffer); + hostcmd->size = cpu_to_le16(cmd_len); + + /* Put buffer length */ + memcpy(buffer + cmd_header_len, &cmd_len, sizeof(t_u32)); + + /* Initialize the ifr structure */ + memset(&ifr, 0, sizeof(ifr)); + strncpy(ifr.ifr_ifrn.ifrn_name, dev_name, strlen(dev_name)); + ifr.ifr_ifru.ifru_data = (void *)cmd; + /* Perform ioctl */ + if (ioctl(sockfd, MLAN_ETH_PRIV, &ifr)) { + perror("ioctl[scanAgentIoctl]"); + printf("ERR:Command sending failed!\n"); + ret = -EFAULT; + goto done; + } else { + printf("\nScan Scheduled, ID = %d\n\n", + (int)le32_to_cpu(scan_exec->scan_req_id_out)); + } + +done: + if (buffer) + free(buffer); + if (cmd) + free(cmd); + return ret; +} + +/** + * @brief Issue a scanagent cmd_type subcommand + * + * @param argc number of arguments + * @param argv A pointer to arguments array + * @param cmd_type command type + * + * @return MLAN_STATUS_SUCCESS on success, otherwise error code + */ +static int +scanagent_table_entry_sub_cmd(int argc, char *argv[], + HostCmd_DS_ScanagentTableMaintenance_e cmd_type) +{ + int ret = 0; + struct ifreq ifr; + t_u8 *buffer = NULL, *pos = NULL; + t_u32 cmd_len = 0, cmd_header_len = 0; + struct eth_priv_cmd *cmd = NULL; + HostCmd_DS_GEN *hostcmd = NULL; + HostCmd_DS_SCANAGENT_TABLE_MAINTENANCE *table_maintenance = NULL; + + cmd_header_len = strlen(CMD_NXP) + strlen(HOSTCMD); + cmd_len = (S_DS_GEN + sizeof(HostCmd_DS_SCANAGENT_TABLE_MAINTENANCE) + - sizeof(table_maintenance->tlv_buffer)); + + buffer = (t_u8 *)malloc(BUFFER_LENGTH); + if (buffer == NULL) { + fprintf(stderr, "Cannot alloc memory\n"); + return -ENOMEM; + } + memset(buffer, 0, BUFFER_LENGTH); + + cmd = (struct eth_priv_cmd *)malloc(sizeof(struct eth_priv_cmd)); + if (!cmd) { + printf("ERR:Cannot allocate buffer for command!\n"); + free(buffer); + return -ENOMEM; + } + + /* Fill up buffer */ +#ifdef USERSPACE_32BIT_OVER_KERNEL_64BIT + memset(cmd, 0, sizeof(struct eth_priv_cmd)); + memcpy(&cmd->buf, &buffer, sizeof(buffer)); +#else + cmd->buf = buffer; +#endif + cmd->used_len = 0; + cmd->total_len = BUFFER_LENGTH; + + /* buffer = MRVL_CMD */ + strncpy((char *)buffer, CMD_NXP, strlen(CMD_NXP)); + strncpy((char *)buffer + strlen(CMD_NXP), HOSTCMD, strlen(HOSTCMD)); + + /* buffer = MRVL_CMD */ + hostcmd = (HostCmd_DS_GEN *)(buffer + cmd_header_len + sizeof(t_u32)); + hostcmd->command = cpu_to_le16(HostCmd_CMD_SCANAGENT_TABLE_MAINTENANCE); + hostcmd->size = 0; + hostcmd->seq_num = 0; + hostcmd->result = 0; + + /* Point after host command header */ + pos = (t_u8 *)hostcmd + S_DS_GEN; + + table_maintenance = (HostCmd_DS_SCANAGENT_TABLE_MAINTENANCE *)pos; + table_maintenance->action = cpu_to_le16((t_u16)cmd_type); + + scanAgentParseEntrySel(argc, argv, table_maintenance, (int *)&cmd_len); + + hostcmd->size = cpu_to_le16(cmd_len); + + /* Put buffer length */ + memcpy(buffer + cmd_header_len, &cmd_len, sizeof(t_u32)); + + /* Initialize the ifr structure */ + memset(&ifr, 0, sizeof(ifr)); + strncpy(ifr.ifr_ifrn.ifrn_name, dev_name, strlen(dev_name)); + ifr.ifr_ifru.ifru_data = (void *)cmd; + /* Perform ioctl */ + if (ioctl(sockfd, MLAN_ETH_PRIV, &ifr)) { + perror("ioctl[scanAgentIoctl]"); + printf("ERR:Command sending failed!\n"); + ret = -EFAULT; + goto done; + } + +done: + if (buffer) + free(buffer); + if (cmd) + free(cmd); + return ret; +} + +/** + * @brief Issue a scanagent table lock subcommand + * + * @param argc number of arguments + * @param argv A pointer to arguments array + * + * @return MLAN_STATUS_SUCCESS on success, otherwise error code + */ +static int +scanagent_table_lock(int argc, char *argv[]) +{ + return scanagent_table_entry_sub_cmd(argc, argv, SCAN_TABLE_OP_LOCK); +} + +/** + * @brief Issue a scanagent table unlock subcommand + * + * @param argc number of arguments + * @param argv A pointer to arguments array + * + * @return MLAN_STATUS_SUCCESS on success, otherwise error code + */ +static int +scanagent_table_unlock(int argc, char *argv[]) +{ + return scanagent_table_entry_sub_cmd(argc, argv, SCAN_TABLE_OP_UNLOCK); +} + +/** + * @brief Issue a scanagent table purge subcommand + * + * @param argc number of arguments + * @param argv A pointer to arguments array + * + * @return MLAN_STATUS_SUCCESS on success, otherwise error code + */ +static int +scanagent_table_purge(int argc, char *argv[]) +{ + return scanagent_table_entry_sub_cmd(argc, argv, SCAN_TABLE_OP_PURGE); +} + +/** + * @brief Issue a scanagent command + * + * @param argc number of arguments + * @param argv A pointer to arguments array + * + * @return MLAN_STATUS_SUCCESS--success, otherwise--fail + */ +int +process_scanagent(int argc, char *argv[]) +{ + sub_cmd_exec_t sub_cmd[] = { + {"timing", 2, 1, scanagent_timing}, + {"scan", 2, 1, scanagent_exec_scan}, + {"lock", 2, 1, scanagent_table_lock}, + {"unlock", 2, 1, scanagent_table_unlock}, + {"purge", 2, 1, scanagent_table_purge}, + {"profile", 2, 1, scanagent_profile_period}, + {"holdlimit", 2, 1, scanagent_hold_limit}, + {"agelimit", 2, 1, scanagent_age_limit} + }; + + return process_sub_cmd(sub_cmd, NELEMENTS(sub_cmd), argc, argv); +} diff --git a/mxm_wifiex/wlan_src/mapp/mlanutl/mlanscanagent.h b/mxm_wifiex/wlan_src/mapp/mlanutl/mlanscanagent.h new file mode 100644 index 0000000..9ed5242 --- /dev/null +++ b/mxm_wifiex/wlan_src/mapp/mlanutl/mlanscanagent.h @@ -0,0 +1,155 @@ +/** @file mlanscanagent.h + * + * @brief This files contains mlanutl scanagent command handling. + * + * + * Copyright 2014-2020 NXP + * + * NXP CONFIDENTIAL + * The source code contained or described herein and all documents related to + * the source code (Materials) are owned by NXP, its + * suppliers and/or its licensors. Title to the Materials remains with NXP, + * its suppliers and/or its licensors. The Materials contain + * trade secrets and proprietary and confidential information of NXP, its + * suppliers and/or its licensors. The Materials are protected by worldwide copyright + * and trade secret laws and treaty provisions. No part of the Materials may be + * used, copied, reproduced, modified, published, uploaded, posted, + * transmitted, distributed, or disclosed in any way without NXP's prior + * express written permission. + * + * No license under any patent, copyright, trade secret or other intellectual + * property right is granted to or conferred upon you by disclosure or delivery + * of the Materials, either expressly, by implication, inducement, estoppel or + * otherwise. Any license under such intellectual property rights must be + * express and approved by NXP in writing. + * + */ +/************************************************************************ +Change log: + 08/11/2009: initial version +************************************************************************/ + +#ifndef _MLAN_SCANAGENT_H_ +#define _MLAN_SCANAGENT_H_ + +typedef struct { + /** Action GET or SET */ + t_u16 action; + /** scan interval */ + t_u16 scan_interval; +} __ATTRIB_PACK__ HostCmd_DS_SCANAGENT_CONFIG_PROFILE_SCAN; + +typedef struct { + t_u32 scan_req_id_out; + /**< Scan request id */ + t_u32 delay; /**< Delay */ + t_u32 chan_group; /**< Channel Group */ + t_u16 scan_type; /**< Scan type */ + t_u16 reserved; /**< Reserved */ + + t_u8 tlv_buffer[1]; /**< Rest is TLV buffer */ + + /* MrvlIEtypes_SsIdParamSet_t + * MrvlIEtypes_Bssid_List_t + * MrvlIEtypes_ConfigScanTiming_t + */ +} __ATTRIB_PACK__ HostCmd_DS_SCANAGENT_SCAN_EXEC; + +typedef struct { + /** Action Set or get */ + t_u16 action; + /** Reserved */ + t_u16 reserved; + /** Table age limit */ + t_u16 table_age_limit; + /** Table hold limit */ + t_u16 table_hold_limit; +} __ATTRIB_PACK__ HostCmd_DS_SCANAGENT_SCAN_TABLE_LIMITS; + +typedef struct { + /** Action Set or get */ + t_u16 action; + /** TLV buffer starts here */ + t_u8 tlv_buffer[1]; + /* MrvlIEtypes_ConfigScanTiming_t */ +} __ATTRIB_PACK__ HostCmd_DS_SCANAGENT_CONFIG_TIMING; + +typedef struct { + /** HostCmd_DS_ScanagentTableMaintenance_e action */ + t_u16 action; + /** Reserved */ + t_u16 reserved; + /** Request Id, 0 to disable */ + t_u32 scan_request_id; + /** Age, 0 to disable */ + t_u32 age; + /** TLV Buffer follows */ + t_u8 tlv_buffer[1]; + + /* MrvlIEtypes_SsIdParamSet_t + * MrvlIEtypes_Bssid_List_t + */ +} __ATTRIB_PACK__ HostCmd_DS_SCANAGENT_TABLE_MAINTENANCE; + +/** ENUM definition: Scanagent Table Maintenance */ +typedef enum { + SCAN_TABLE_OP_INVALID = 0, + + SCAN_TABLE_OP_LOCK = 1, + SCAN_TABLE_OP_UNLOCK = 2, + SCAN_TABLE_OP_PURGE = 3, + +} __ATTRIB_PACK__ HostCmd_DS_ScanagentTableMaintenance_e; + +/** MrvlIEtypes_SsIdParamSet_t */ +typedef struct _MrvlIEtypes_SsIdParamSet_t { + /** Header */ + MrvlIEtypesHeader_t header; + /** SSID */ + t_u8 ssid[1]; +} __ATTRIB_PACK__ MrvlIEtypes_SsIdParamSet_t; + +/** _MrvlIEtypes_Bssid_List_t */ +typedef struct _MrvlIEtypes_Bssid_List_t { + /** Header */ + MrvlIEtypesHeader_t header; + /** BSSID */ + t_u8 bssid[ETH_ALEN]; +} __ATTRIB_PACK__ MrvlIEtypes_Bssid_List_t; + +typedef struct { + /** Header */ + MrvlIEtypesHeader_t header; + + t_u32 mode; /**< Mode */ + t_u32 dwell; /**< Dwell */ + t_u32 max_off; /**< Max. off */ + t_u32 min_link;/**< Minimum Link */ + t_u32 rsp_timeout; + /**< Rsp Timeout */ + +} __ATTRIB_PACK__ MrvlIEtypes_ConfigScanTiming_t; + +/** ENUM definition: ScanAgentScanType */ +typedef enum { + CONFIG_SITE_SURVEY = 0, + CONFIG_NEIGHBOR = 1, + CONFIG_PROFILE = 2, + CONFIG_ARBITRARY_CHANNEL = 3, + +} __ATTRIB_PACK__ HostCmd_DS_ScanagentScanType_e; + +/** ENUM definition: ScanAgentScanTimingMode */ +typedef enum { + TIMING_MODE_INVALID = 0, + + TIMING_MODE_DISCONNECTED = 1, + TIMING_MODE_ADHOC = 2, + TIMING_MODE_FULL_POWER = 3, + TIMING_MODE_IEEE_PS = 4, + TIMING_MODE_PERIODIC_PS = 5, + +} __ATTRIB_PACK__HostCmd_DS_ScanagentTimingMode_e; + +int process_host_cmd_resp(char *cmd_name, t_u8 *buf); +#endif /* _MLAN_SCANAGENT_H_ */ diff --git a/mxm_wifiex/wlan_src/mapp/mlanutl/mlanutl.c b/mxm_wifiex/wlan_src/mapp/mlanutl/mlanutl.c new file mode 100644 index 0000000..6accad6 --- /dev/null +++ b/mxm_wifiex/wlan_src/mapp/mlanutl/mlanutl.c @@ -0,0 +1,20430 @@ +/** @file mlanutl.c + * + * @brief Program to control parameters in the mlandriver + * + * Usage: mlanutl mlanX cmd [...] + * + * + * Copyright 2014-2020 NXP + * + * NXP CONFIDENTIAL + * The source code contained or described herein and all documents related to + * the source code (Materials) are owned by NXP, its + * suppliers and/or its licensors. Title to the Materials remains with NXP, + * its suppliers and/or its licensors. The Materials contain + * trade secrets and proprietary and confidential information of NXP, its + * suppliers and/or its licensors. The Materials are protected by worldwide copyright + * and trade secret laws and treaty provisions. No part of the Materials may be + * used, copied, reproduced, modified, published, uploaded, posted, + * transmitted, distributed, or disclosed in any way without NXP's prior + * express written permission. + * + * No license under any patent, copyright, trade secret or other intellectual + * property right is granted to or conferred upon you by disclosure or delivery + * of the Materials, either expressly, by implication, inducement, estoppel or + * otherwise. Any license under such intellectual property rights must be + * express and approved by NXP in writing. + * + */ +/************************************************************************ +Change log: + 11/04/2011: initial version +************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "mlanutl.h" + +/** Supported stream modes */ +#define HT_STREAM_MODE_1X1 0x11 +#define HT_STREAM_MODE_2X2 0x22 + +/** mlanutl version number */ +#define MLANUTL_VER "M1.3" + +/** Initial number of total private ioctl calls */ +#define IW_INIT_PRIV_NUM 128 +/** Maximum number of total private ioctl calls supported */ +#define IW_MAX_PRIV_NUM 1024 + +/** Termination flag */ +int terminate_flag = 0; + +typedef struct { + t_u8 chanNum; /**< Channel Number */ + t_u8 chanLoad; /**< Channel Load fraction */ + t_s16 anpi; /**< Channel ANPI */ + +} ChanRptInfo_t; + +/******************************************************** + Local Variables +********************************************************/ +#define BAND_B (1U << 0) +#define BAND_G (1U << 1) +#define BAND_A (1U << 2) +#define BAND_GN (1U << 3) +#define BAND_AN (1U << 4) +#define BAND_GAC (1U << 5) +#define BAND_AAC (1U << 6) +#define BAND_GAX (1U << 8) +#define BAND_AAX (1U << 9) +static char *band[] = { + "B", + "G", + "A", + "GN", + "AN", + "GAC", + "AAC", + "11P", + "GAX", + "AAX", +}; + +/** Stringification of rateId enumeration */ +const char *rateIdStr[] = { "1", "2", "5.5", "11", "--", + "6", "9", "12", "18", "24", "36", "48", "54", "--", + "M0", "M1", "M2", "M3", "M4", "M5", "M6", "M7", + "H0", "H1", "H2", "H3", "H4", "H5", "H6", "H7" +}; + +#ifdef DEBUG_LEVEL1 +#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 MREG_D MBIT(9) + +#define MMPA_D MBIT(15) +#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 +static int process_dot11_txrx(int argc, char *argv[]); +#ifdef RX_PACKET_COALESCE +static int process_rx_pkt_coalesce_cfg(int argc, char *argv[]); +static void print_rx_packet_coalesc_help(void); +#endif +static int process_version(int argc, char *argv[]); +static int process_bandcfg(int argc, char *argv[]); +static int process_hostcmd(int argc, char *argv[]); +static int process_httxcfg(int argc, char *argv[]); +static int process_htcapinfo(int argc, char *argv[]); +static int process_addbapara(int argc, char *argv[]); +static int process_aggrpriotbl(int argc, char *argv[]); +static int process_addbareject(int argc, char *argv[]); +static int process_delba(int argc, char *argv[]); +static int process_rejectaddbareq(int argc, char *argv[]); +static int process_vhtcfg(int argc, char *argv[]); +static int process_opermodecfg(int argc, char *argv[]); +static int process_datarate(int argc, char *argv[]); +static int process_txratecfg(int argc, char *argv[]); +static int process_getlog(int argc, char *argv[]); +static int process_getcfgchanlist(int argc, char *argv[]); +static int process_esuppmode(int argc, char *argv[]); +static int process_passphrase(int argc, char *argv[]); +static int process_deauth(int argc, char *argv[]); +#ifdef UAP_SUPPORT +static int process_getstalist(int argc, char *argv[]); +#endif +#ifdef WIFI_DIRECT_SUPPORT +#if defined(STA_SUPPORT) && defined(UAP_SUPPORT) +static int process_bssrole(int argc, char *argv[]); +#endif +#endif +#ifdef STA_SUPPORT +static int process_setuserscan(int argc, char *argv[]); +static int wlan_process_getscantable(int argc, char *argv[], + wlan_ioctl_user_scan_cfg *scan_req); +static int wlan_process_getchanstats(int argc, char *argv[]); +static int process_getchanstats(int argc, char *argv[]); +static int process_getscantable(int argc, char *argv[]); +static int process_extcapcfg(int argc, char *argv[]); +static int process_cancelscan(int argc, char *argv[]); +#endif +static int process_deepsleep(int argc, char *argv[]); +static int process_ipaddr(int argc, char *argv[]); +static int process_otpuserdata(int argc, char *argv[]); +static int process_countrycode(int argc, char *argv[]); +static int process_tcpackenh(int argc, char *argv[]); +#ifdef REASSOCIATION +static int process_assocessid(int argc, char *argv[]); +#endif +#ifdef STA_SUPPORT +static int process_listeninterval(int argc, char *argv[]); +static int process_psmode(int argc, char *argv[]); +#endif +#ifdef DEBUG_LEVEL1 +static int process_drvdbg(int argc, char *argv[]); +#endif +static int process_hscfg(int argc, char *argv[]); +static int process_hssetpara(int argc, char *argv[]); +static int process_wakeupresaon(int argc, char *argv[]); +static int process_mgmtfilter(int argc, char *argv[]); +static int process_scancfg(int argc, char *argv[]); +static int process_aggrctrl(int argc, char *argv[]); +static int process_usbaggrctrl(int argc, char *argv[]); +static int process_warmreset(int argc, char *argv[]); +static int process_txpowercfg(int argc, char *argv[]); +static int process_pscfg(int argc, char *argv[]); +static int process_bcntimeoutcfg(int argc, char *argv[]); +static int process_sleeppd(int argc, char *argv[]); +static int process_txcontrol(int argc, char *argv[]); +static int process_dfs_offload_enable(int argc, char *argv[]); +static int process_customie(int argc, char *argv[]); +static int process_regrdwr(int argc, char *argv[]); +static int process_rdeeprom(int argc, char *argv[]); +static int process_memrdwr(int argc, char *argv[]); +#ifdef SDIO +static int process_sdcmd52rw(int argc, char *argv[]); +#endif +static int process_mefcfg(int argc, char *argv[]); +static int process_cfgdata(int argc, char *argv[]); +static int process_mgmtframetx(int argc, char *argv[]); +static int process_mgmt_frame_passthrough(int argc, char *argv[]); +static int process_hotspot_config(int argc, char *argv[]); +static int process_qconfig(int argc, char *argv[]); +static int process_addts(int argc, char *argv[]); +static int process_delts(int argc, char *argv[]); +static int process_wmm_qstatus(int argc, char *argv[]); +static int process_wmm_ts_status(int argc, char *argv[]); +static int process_qos_config(int argc, char *argv[]); +static int process_macctrl(int argc, char *argv[]); +static int process_fwmacaddr(int argc, char *argv[]); +static int process_regioncode(int argc, char *argv[]); +static int process_cfpinfo(int argc, char *argv[]); +static int process_offchannel(int argc, char *argv[]); +static int process_linkstats(int argc, char *argv[]); +#if defined(STA_SUPPORT) +static int process_pmfcfg(int argc, char *argv[]); +#endif +static int process_verext(int argc, char *argv[]); +static int process_usb_suspend(int argc, char *argv[]); +static int process_usb_resume(int argc, char *argv[]); +#if defined(STA_SUPPORT) && defined(STA_WEXT) +static int process_radio_ctrl(int argc, char *argv[]); +#endif +static int process_wmm_cfg(int argc, char *argv[]); +static int process_wmm_param_config(int argc, char *argv[]); +static int process_min_ba_threshold_cfg(int argc, char *argv[]); +#if defined(STA_SUPPORT) +static int process_11d_cfg(int argc, char *argv[]); +static int process_11d_clr_tbl(int argc, char *argv[]); +#endif +#ifndef OPCHAN +static int process_wws_cfg(int argc, char *argv[]); +#endif +#if defined(REASSOCIATION) +static int process_set_get_reassoc(int argc, char *argv[]); +#endif +static int process_txbuf_cfg(int argc, char *argv[]); +#ifdef STA_SUPPORT +static int process_set_get_auth_type(int argc, char *argv[]); +#endif +static int process_11h_local_pwr_constraint(int argc, char *argv[]); +static int process_ht_stream_cfg(int argc, char *argv[]); +static int process_mimo_switch(int argc, char *argv[]); +static int process_thermal(int argc, char *argv[]); +static int process_beacon_interval(int argc, char *argv[]); +static int process_cwmode(int argc, char *argv[]); +#ifdef STA_SUPPORT +static int process_get_signal(int argc, char *argv[]); +static int process_get_signal_ext(int argc, char *argv[]); +static int process_signalext_cfg(int argc, char *argv[]); +#endif +static int process_inactivity_timeout_ext(int argc, char *argv[]); +static int process_11n_amsdu_aggr_ctrl(int argc, char *argv[]); +static int process_tx_bf_cap_ioctl(int argc, char *argv[]); +#ifdef SDIO +static int process_sdio_clock_ioctl(int argc, char *argv[]); +#endif +#ifdef SDIO +static int process_sdio_mpa_ctrl(int argc, char *argv[]); +#endif +static int process_sleep_params(int argc, char *argv[]); +static int process_dfs_testing(int argc, char *argv[]); +static int process_cfp_code(int argc, char *argv[]); +static int process_set_get_tx_rx_ant(int argc, char *argv[]); +static int process_get_txpwrlimit(int argc, char *argv[]); +static int process_get_chnrgpwr(int argc, char *argv[]); +static int process_compare_rgpwr(int argc, char *argv[]); +static int process_comparetrpc(int argc, char *argv[]); +static int process_sysclock(int argc, char *argv[]); +static int process_get_key(int argc, char *argv[]); +static int process_associate_ssid_bssid(int argc, char *argv[]); +static int process_tx_bf_cfg(int argc, char *argv[]); +static int process_wps_cfg(int argc, char *argv[]); +static int process_port_ctrl(int argc, char *argv[]); +static int process_bypassed_packet(int argc, char *argv[]); +/* #ifdef FW_WAKEUP_METHOD */ +static int process_fw_wakeup_method(int argc, char *argv[]); +/* #endif */ +#ifdef SDIO +static int process_sdcmd53rw(int argc, char *argv[]); +#endif +#ifdef WIFI_DIRECT_SUPPORT +static int process_cfg_noa_opp_ps(int argc, char *argv[]); +#endif +static int process_dscpmap(int argc, char *argv[]); +#ifdef WIFI_DIRECT_SUPPORT +static int process_miracastcfg(int argc, char *argv[]); +#endif +static int process_coex_rx_winsize(int argc, char *argv[]); +static int process_dfs_repeater(int argc, char *argv[]); +#ifdef PCIE +static int process_pcie_reg_rw(int argc, char *argv[]); +static int process_pcie_bar0_reg_rw(int argc, char *argv[]); +#endif +static int process_get_sensor_temp(int argc, char *argv[]); +static int process_chan_graph(int argc, char *argv[]); +static int process_extend_channel_switch(int argc, char *argv[]); +static int process_auto_arp(int argc, char *argv[]); +static int process_txrxhistogram(int argc, char *argv[]); +static int process_per_pkt_cfg(int argc, char *argv[]); +static int process_ind_rst_cfg(int argc, char *argv[]); +static int process_cloud_keep_alive(int argc, char *argv[]); +int process_tsf(int argc, char *argv[]); +static int process_dyn_bw(int argc, char *argv[]); +static int process_robustcoex(int argc, char *argv[]); +static int process_dmcs(int argc, char *argv[]); +#if defined(PCIE) +static int process_ssu_cmd(int argc, char *argv[]); +#endif +static int process_ctrldeauth(int argc, char *argv[]); +static int process_bootsleep(int argc, char *argv[]); +static int process_11axcfg(int argc, char *argv[]); +static int process_11axcmdcfg(int argc, char *argv[]); +static int process_twt_setup(int argc, char *argv[]); +static int process_twt_teardown(int argc, char *argv[]); + +static int process_rx_abort_cfg(int argc, char *argv[]); +static int process_rx_abort_cfg_ext(int argc, char *argv[]); +static int process_tx_ampdu_prot_mode(int argc, char *argv[]); +static int process_rate_adapt_cfg(int argc, char *argv[]); +static int process_cck_desense_cfg(int argc, char *argv[]); +static int process_lpm(int argc, char *argv[]); + +struct command_node command_list[] = { + {"version", process_version}, + {"bandcfg", process_bandcfg}, + {"hostcmd", process_hostcmd}, + {"httxcfg", process_httxcfg}, + {"htcapinfo", process_htcapinfo}, + {"addbapara", process_addbapara}, + {"aggrpriotbl", process_aggrpriotbl}, + {"addbareject", process_addbareject}, + {"delba", process_delba}, + {"rejectaddbareq", process_rejectaddbareq}, + {"vhtcfg", process_vhtcfg}, + {"opermodecfg", process_opermodecfg}, + {"getdatarate", process_datarate}, + {"txratecfg", process_txratecfg}, + {"getlog", process_getlog}, + {"esuppmode", process_esuppmode}, + {"passphrase", process_passphrase}, + {"deauth", process_deauth}, +#ifdef UAP_SUPPORT + {"getstalist", process_getstalist}, +#endif +#ifdef WIFI_DIRECT_SUPPORT +#if defined(STA_SUPPORT) && defined(UAP_SUPPORT) + {"bssrole", process_bssrole}, +#endif +#endif +#ifdef STA_SUPPORT + {"setuserscan", process_setuserscan}, + {"getscantable", process_getscantable}, + {"getchanstats", process_getchanstats}, + {"extcapcfg", process_extcapcfg}, + {"cancelscan", process_cancelscan}, +#endif + {"deepsleep", process_deepsleep}, + {"ipaddr", process_ipaddr}, + {"otpuserdata", process_otpuserdata}, + {"countrycode", process_countrycode}, + {"tcpackenh", process_tcpackenh}, +#ifdef REASSOCIATION + {"assocessid", process_assocessid}, + {"assocessid_bssid", process_assocessid}, +#endif +#ifdef STA_SUPPORT + {"listeninterval", process_listeninterval}, + {"psmode", process_psmode}, +#endif +#ifdef DEBUG_LEVEL1 + {"drvdbg", process_drvdbg}, +#endif + {"hscfg", process_hscfg}, + {"hssetpara", process_hssetpara}, + {"wakeupreason", process_wakeupresaon}, + {"mgmtfilter", process_mgmtfilter}, + {"scancfg", process_scancfg}, + {"aggrctrl", process_aggrctrl}, + {"usbaggrctrl", process_usbaggrctrl}, + {"warmreset", process_warmreset}, + {"txpowercfg", process_txpowercfg}, + {"pscfg", process_pscfg}, + {"bcntimeoutcfg", process_bcntimeoutcfg}, + {"sleeppd", process_sleeppd}, + {"txcontrol", process_txcontrol}, + {"dfs_offload", process_dfs_offload_enable}, + {"customie", process_customie}, + {"regrdwr", process_regrdwr}, + {"rdeeprom", process_rdeeprom}, + {"memrdwr", process_memrdwr}, +#ifdef SDIO + {"sdcmd52rw", process_sdcmd52rw}, +#endif + {"mefcfg", process_mefcfg}, + {"cfgdata", process_cfgdata}, + {"mgmtframetx", process_mgmtframetx}, + {"mgmtframectrl", process_mgmt_frame_passthrough}, + {"hotspotcfg", process_hotspot_config}, + {"qconfig", process_qconfig}, + {"addts", process_addts}, + {"delts", process_delts}, + {"ts_status", process_wmm_ts_status}, + {"qstatus", process_wmm_qstatus}, + {"qoscfg", process_qos_config}, + {"macctrl", process_macctrl}, + {"fwmacaddr", process_fwmacaddr}, + {"regioncode", process_regioncode}, + {"cfpinfo", process_cfpinfo}, + {"offchannel", process_offchannel}, + {"linkstats", process_linkstats}, +#if defined(STA_SUPPORT) + {"pmfcfg", process_pmfcfg}, +#endif + {"verext", process_verext}, + {"usbsuspend", process_usb_suspend}, + {"usbresume", process_usb_resume}, +#if defined(STA_SUPPORT) && defined(STA_WEXT) + {"radioctrl", process_radio_ctrl}, +#endif + {"wmmcfg", process_wmm_cfg}, + {"wmmparamcfg", process_wmm_param_config}, + {"min_ba_threshold", process_min_ba_threshold_cfg}, +#if defined(STA_SUPPORT) + {"11dcfg", process_11d_cfg}, + {"11dclrtbl", process_11d_clr_tbl}, +#endif +#ifndef OPCHAN + {"wwscfg", process_wws_cfg}, +#endif +#if defined(REASSOCIATION) + {"reassoctrl", process_set_get_reassoc}, +#endif + {"txbufcfg", process_txbuf_cfg}, +#ifdef STA_SUPPORT + {"authtype", process_set_get_auth_type}, +#endif + {"powercons", process_11h_local_pwr_constraint}, + {"htstreamcfg", process_ht_stream_cfg}, + {"mimoswitch", process_mimo_switch}, + {"thermal", process_thermal}, + {"bcninterval", process_beacon_interval}, + {"cwmode", process_cwmode}, +#ifdef STA_SUPPORT + {"getsignal", process_get_signal}, + {"getsignalext", process_get_signal_ext}, + {"getsignalextv2", process_get_signal_ext}, + {"signalextcfg", process_signalext_cfg}, +#endif + {"inactivityto", process_inactivity_timeout_ext}, + {"amsduaggrctrl", process_11n_amsdu_aggr_ctrl}, + {"httxbfcap", process_tx_bf_cap_ioctl}, +#ifdef SDIO + {"sdioclock", process_sdio_clock_ioctl}, +#endif +#ifdef SDIO + {"mpactrl", process_sdio_mpa_ctrl}, +#endif + {"sleepparams", process_sleep_params}, + {"dfstesting", process_dfs_testing}, + {"cfpcode", process_cfp_code}, + {"antcfg", process_set_get_tx_rx_ant}, + {"get_chnrgpwr", process_get_chnrgpwr}, + {"comparergpwr", process_compare_rgpwr}, + {"get_txpwrlimit", process_get_txpwrlimit}, + {"getcfgchanlist", process_getcfgchanlist}, + {"comparetrpc", process_comparetrpc}, + {"dscpmap", process_dscpmap}, + {"changraph", process_chan_graph}, + {"getkey", process_get_key}, + {"associate", process_associate_ssid_bssid}, + {"httxbfcfg", process_tx_bf_cfg}, + {"wpssession", process_wps_cfg}, + {"port_ctrl", process_port_ctrl}, + {"pb_bypass", process_bypassed_packet}, +/* #ifdef FW_WAKEUP_METHOD */ + {"fwwakeupmethod", process_fw_wakeup_method}, +/* #endif */ + {"sysclock", process_sysclock}, +#ifdef SDIO + {"sdcmd53rw", process_sdcmd53rw}, +#endif +#ifdef RX_PACKET_COALESCE + {"rxpktcoal_cfg", process_rx_pkt_coalesce_cfg}, +#endif +#ifdef WIFI_DIRECT_SUPPORT + {"cfg_noa", process_cfg_noa_opp_ps}, + {"cfg_opp_ps", process_cfg_noa_opp_ps}, +#endif +#ifdef WIFI_DIRECT_SUPPORT + {"miracastcfg", process_miracastcfg}, +#endif + {"coex_rx_winsize", process_coex_rx_winsize}, + {"dfs_repeater", process_dfs_repeater}, +#ifdef PCIE + {"pcieregrw", process_pcie_reg_rw}, + {"pciebar0regrw", process_pcie_bar0_reg_rw}, +#endif + {"get_sensor_temp", process_get_sensor_temp}, + {"channel_switch", process_extend_channel_switch}, + {"auto_arp", process_auto_arp}, + {"txrxhistogram", process_txrxhistogram}, + {"indrstcfg", process_ind_rst_cfg}, + {"cloud_keep_alive", process_cloud_keep_alive}, + {"tsf", process_tsf}, + {"dot11_txrx", process_dot11_txrx}, + {"per_pkt_cfg", process_per_pkt_cfg}, + {"dyn_bw", process_dyn_bw}, + {"robustcoex", process_robustcoex}, +#if defined(PCIE) + {"ssu", process_ssu_cmd}, +#endif + {"ctrldeauth", process_ctrldeauth}, + {"bootsleep", process_bootsleep}, + {"dmcs", process_dmcs}, + {"11axcfg", process_11axcfg}, + {"11axcmd", process_11axcmdcfg}, + {"twt_setup", process_twt_setup}, + {"twt_teardown", process_twt_teardown}, + {"rx_abort_cfg", process_rx_abort_cfg}, + {"rx_abort_cfg_ext", process_rx_abort_cfg_ext}, + {"tx_ampdu_prot_mode", process_tx_ampdu_prot_mode}, + {"rate_adapt_cfg", process_rate_adapt_cfg}, + {"cck_desense_cfg", process_cck_desense_cfg}, + {"lpm", process_lpm}, +}; + +static char *usage[] = { + "Usage: ", + " mlanutl -v (version)", + " mlanutl [...]", + " where", + " ifname : wireless network interface name, such as mlanX or uapX", + " cmd :", + " 11dcfg", + " 11dclrtbl", + " addbapara", + " addbareject", + " addts", + " aggrpriotbl", + " amsduaggrctrl", + " antcfg", +#ifdef REASSOCIATION + " assocessid", + " assocessid_bssid", +#endif + " associate", + " authtype", + " bandcfg", + " bcninterval", +#ifdef WIFI_DIRECT_SUPPORT +#if defined(STA_SUPPORT) && defined(UAP_SUPPORT) + " bssrole", +#endif +#endif + " cfgdata", + " cfpcode", + " changraph", + " coex_rx_winsize", + " countrycode", + " customie", + " deauth", + " deepsleep", + " delba", + " delts", + " dfstesting", + " dfs_repeater", +#ifdef DEBUG_LEVEL1 + " drvdbg", +#endif + " dscpmap", + " esuppmode", +#ifdef STA_SUPPORT + " extcapcfg", + " cancelscan", +#endif + " fwmacaddr", +/* #ifdef FW_WAKEUP_METHOD */ + " fwwakeupmethod", +/* #endif */ + " getdatarate", + " getkey", + " getlog", +#ifdef STA_SUPPORT + " getscantable", +#endif + " getsignal", +#ifdef UAP_SUPPORT + " getstalist", +#endif + " hostcmd", + " hotspotcfg", + " hscfg", + " hssetpara", + " mgmtfilter", + " htcapinfo", + " htstreamcfg", + " mimoswitch", +#ifdef STA_SUPPORT + " signalextcfg", + " getsignalext", + " getsignalextv2", +#endif + " httxbfcap", + " httxbfcfg", + " httxcfg", + " inactivityto", + " ipaddr", + " linkstats", +#ifdef STA_SUPPORT + " listeninterval", +#endif + " macctrl", + " mefcfg", + " memrdwr", +#ifdef WIFI_DIRECT_SUPPORT + " miracastcfg", +#endif + " mgmtframectrl", + " mgmtframetx", +#ifdef SDIO + " mpactrl", +#endif +#ifdef WIFI_DIRECT_SUPPORT + " cfg_noa", + " cfg_opp_ps", +#endif + " offchannel", + " otpuserdata", + " passphrase", + " pb_bypass", +#ifdef PCIE + " pcieregrw", +#endif +#if defined(STA_SUPPORT) + " pmfcfg", +#endif + " port_ctrl", + " powercons", + " pscfg", +#ifdef STA_SUPPORT + " psmode", +#endif + " qconfig", + " qoscfg", + " qstatus", +#ifdef STA_WEXT + " radioctrl", +#endif + " rdeeprom", +#if defined(REASSOCIATION) + " reassoctrl", +#endif + " regioncode", + " cfpinfo", + " regrdwr", + " rejectaddbareq", + " scancfg", +#ifdef SDIO + " sdcmd52rw", + " sdcmd53rw", + " sdioclock", +#endif +#ifdef STA_SUPPORT + " setuserscan", +#endif + " sleepparams", + " sleeppd", + " sysclock", + " tcpackenh", + " thermal", + " ts_status", + " tsf", + " txbufcfg", + " txcontrol", + " txpowercfg", + " txratecfg", + " aggrctrl", + " usbaggrctrl", + " usbresume", + " usbsuspend", + " verext", + " version", + " vhtcfg", + " opermodecfg", + " wakeupreason", + " warmreset", + " wmmcfg", + " wmmparamcfg", + " min_ba_threshold", + " wpssession", +#ifndef OPCHAN + " wwscfg", +#endif +#ifdef RX_PACKET_COALESCE + " rxpktcoal_cfg", +#endif + " get_sensor_temp", + " channel_switch", + " indrstcfg", + " cloud_keep_alive", + " dfs_offload", + + " cwmode", + " dyn_bw", + " txrxhistogram", + " per_pkt_cfg", + " dot11_txrx", + " robustcoex", + " ctrldeauth", + " dmcs", + " 11axcfg", + " 11axcmd", + " twt_setup", + " twt_teardown", + " rx_abort_cfg", + " rx_abort_cfg_ext", + " tx_ampdu_prot_mode", + " rate_adapt_cfg", + " cck_desense_cfg", + " get_chnrgpwr", + " comparergpwr", + " get_txpwrlimit", + " comparetrpc", + " getcfgchanlist", + " lpm", +}; + +/** Socket */ +t_s32 sockfd; +/** Device name */ +char dev_name[IFNAMSIZ + 1]; +#define HOSTCMD "hostcmd" + +static char *config_get_line(char *s, int size, FILE * stream, int *line, + char **_pos); +static int parse_line(char *line, char *args[], t_u16 args_count); +#define BSSID_FILTER 1 +#define SSID_FILTER 2 +/******************************************************** + Global Variables +********************************************************/ + +int setuserscan_filter = 0; +int num_ssid_filter = 0; +/******************************************************** + Local Functions +********************************************************/ + +/** + * @brief isdigit for String. + * + * @param x Char string + * @return MLAN_STATUS_FAILURE for non-digit. + * MLAN_STATUS_SUCCESS for digit + */ +static int +ISDIGIT(char *x) +{ + unsigned int i; + for (i = 0; i < strlen(x); i++) + if (isdigit(x[i]) == 0) + return MLAN_STATUS_FAILURE; + return MLAN_STATUS_SUCCESS; +} + +/** + * Check of decimal or hex string + * @param num string + */ +#define IS_HEX_OR_DIGIT(num) \ + (strncasecmp("0x", (num), 2)?ISDIGIT((num)):ishexstring((num))) + +/** + * @brief Convert char to hex integer + * + * @param chr Char to convert + * @return Hex integer or 0 + */ +int +hexval(t_s32 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 Hump hex data + * + * @param prompt A pointer prompt buffer + * @param p A pointer to data buffer + * @param len The len of data buffer + * @param delim Delim char + * @return Hex integer + */ +t_void +hexdump(char *prompt, t_void *p, t_s32 len, char delim) +{ + t_s32 i; + t_u8 *s = p; + + if (prompt) { + printf("%s: len=%d\n", prompt, (int)len); + } + for (i = 0; i < len; i++) { + if (i != len - 1) + printf("%02x%c", *s++, delim); + else + printf("%02x\n", *s); + if ((i + 1) % 16 == 0) + printf("\n"); + } + printf("\n"); +} + +/** + * @brief Convert char to hex integer + * + * @param chr Char + * @return Hex integer + */ +t_u8 +hexc2bin(char chr) +{ + if (chr >= '0' && chr <= '9') + chr -= '0'; + else if (chr >= 'A' && chr <= 'F') + chr -= ('A' - 10); + else if (chr >= 'a' && chr <= 'f') + chr -= ('a' - 10); + + return chr; +} + +/** + * @brief Convert string to hex integer + * + * @param s A pointer string buffer + * @return Hex integer + */ +t_u32 +a2hex(char *s) +{ + t_u32 val = 0; + + if (!strncasecmp("0x", s, 2)) { + s += 2; + } + + while (*s && isxdigit(*s)) { + val = (val << 4) + hexc2bin(*s++); + } + + return val; +} + +/* + * @brief Convert String to integer + * + * @param value A pointer to string + * @return Integer + */ +t_u32 +a2hex_or_atoi(char *value) +{ + if (value[0] == '0' && (value[1] == 'X' || value[1] == 'x')) { + return a2hex(value + 2); + } else { + return (t_u32)atoi(value); + } +} + +/** + * @brief Convert string to hex + * + * @param ptr A pointer to data buffer + * @param chr A pointer to return integer + * @return A pointer to next data field + */ +char * +convert2hex(char *ptr, t_u8 *chr) +{ + t_u8 val; + + for (val = 0; *ptr && isxdigit(*ptr); ptr++) { + val = (val * 16) + hexval(*ptr); + } + + *chr = val; + + return ptr; +} + +/** + * @brief Check the Hex String + * @param s A pointer to the string + * @return MLAN_STATUS_SUCCESS --HexString, MLAN_STATUS_FAILURE --not HexString + */ +int +ishexstring(char *s) +{ + int ret = MLAN_STATUS_FAILURE; + t_s32 tmp; + + if (!strncasecmp("0x", s, 2)) { + s += 2; + } + while (*s) { + tmp = toupper(*s); + if (((tmp >= 'A') && (tmp <= 'F')) || + ((tmp >= '0') && (tmp <= '9'))) { + ret = MLAN_STATUS_SUCCESS; + } else { + ret = MLAN_STATUS_FAILURE; + break; + } + s++; + } + + return ret; +} + +/** + * @brief Convert String to Integer + * @param buf A pointer to the string + * @return Integer + */ +int +atoval(char *buf) +{ + if (!strncasecmp(buf, "0x", 2)) + return a2hex(buf + 2); + else if (!ishexstring(buf)) + return a2hex(buf); + else + return atoi(buf); +} + +/** + * @brief Display usage + * + * @return NA + */ +static t_void +display_usage(t_void) +{ + t_u32 i; + for (i = 0; i < NELEMENTS(usage); i++) + fprintf(stderr, "%s\n", usage[i]); +} + +/** + * @brief Find and execute command + * + * @param argc Number of arguments + * @param argv A pointer to arguments array + * @return MLAN_STATUS_SUCCESS for success, otherwise failure + */ +static int +process_command(int argc, char *argv[]) +{ + int i = 0, ret = MLAN_STATUS_NOTFOUND; + struct command_node *node = NULL; + + for (i = 0; i < (int)NELEMENTS(command_list); i++) { + node = &command_list[i]; + if (!strcasecmp(node->name, argv[2])) { + ret = node->handler(argc, argv); + break; + } + } + + return ret; +} + +/** + * @brief Converts a string to hex value + * + * @param str A pointer to the string + * @param raw A pointer to the raw data buffer + * @return Number of bytes read + **/ +int +string2raw(char *str, unsigned char *raw) +{ + int len = (strlen(str) + 1) / 2; + + do { + if (!isxdigit(*str)) { + return -1; + } + *str = toupper(*str); + *raw = CHAR2INT(*str) << 4; + ++str; + *str = toupper(*str); + if (*str == '\0') + break; + *raw |= CHAR2INT(*str); + ++raw; + } while (*++str != '\0'); + return len; +} + +/** + * @brief Prepare command buffer + * @param buffer Command buffer to be filled + * @param cmd Command id + * @param num Number of arguments + * @param args Arguments list + * @return MLAN_STATUS_SUCCESS + */ +static int +prepare_buffer(t_u8 *buffer, char *cmd, t_u32 num, char *args[]) +{ + t_u8 *pos = NULL; + unsigned int i = 0; + + memset(buffer, 0, BUFFER_LENGTH); + + /* Flag it for our use */ + pos = buffer; + strncpy((char *)pos, CMD_NXP, strlen(CMD_NXP)); + pos += (strlen(CMD_NXP)); + + /* Insert command */ + strncpy((char *)pos, (char *)cmd, strlen(cmd)); + pos += (strlen(cmd)); + + /* Insert arguments */ + for (i = 0; i < num; i++) { + strncpy((char *)pos, args[i], strlen(args[i])); + pos += strlen(args[i]); + if (i < (num - 1)) { + strncpy((char *)pos, " ", strlen(" ")); + pos += 1; + } + } + + return MLAN_STATUS_SUCCESS; +} + +/** + * @brief Determine the netlink number + * + * @param i socket number + * + * @return Netlink number to use + */ +static int +get_netlink_num(int i) +{ + FILE *fp; + int netlink_num = NETLINK_NXP; + char str[64]; + char *srch = "netlink_num"; + char filename[64]; + + /* Try to open old driver proc: /proc/mwlan/configX first */ + if (i == 0) + strcpy(filename, "/proc/mwlan/config"); + else if (i > 0) + sprintf(filename, "/proc/mwlan/config%d", i); + fp = fopen(filename, "r"); + if (!fp) { + /* Try to open multi-adapter driver proc: /proc/mwlan/adapterX/config if old proc access fail */ + snprintf(filename, sizeof(filename), + "/proc/mwlan/adapter%d/config", i); + fp = fopen(filename, "r"); + } + + if (fp) { + while (!feof(fp)) { + fgets(str, sizeof(str), fp); + if (strncmp(str, srch, strlen(srch)) == 0) { + netlink_num = atoi(str + strlen(srch) + 1); + break; + } + } + fclose(fp); + } else { + return -1; + } + return netlink_num; +} + +/** + * @brief Read event data from netlink socket + * + * @param sk_fd Netlink socket handler + * @param buffer Pointer to the data buffer + * @param nlh Pointer to netlink message header + * @param msg Pointer to message header + * + * @return Number of bytes read or MLAN_EVENT_FAILURE + */ +int +read_event_netlink_socket(int sk_fd, unsigned char *buffer, + struct nlmsghdr *nlh, struct msghdr *msg) +{ + int count = -1; + count = recvmsg(sk_fd, msg, 0); +#if DEBUG + printf("DBG:Waiting for message from NETLINK.\n"); +#endif + if (count < 0) { + printf("ERR:NETLINK read failed!\n"); + terminate_flag++; + return MLAN_EVENT_FAILURE; + } +#if DEBUG + printf("DBG:Received message payload (%d)\n", count); +#endif + if (count > NLMSG_SPACE(NL_MAX_PAYLOAD)) { + printf("ERR:Buffer overflow!\n"); + return MLAN_EVENT_FAILURE; + } + memset(buffer, 0, NL_MAX_PAYLOAD); + memcpy(buffer, NLMSG_DATA(nlh), count - NLMSG_HDRLEN); +#if DEBUG + hexdump(buffer, count - NLMSG_HDRLEN, ' '); +#endif + return count - NLMSG_HDRLEN; +} + +/** + * @brief Configure and read event data from netlink socket + * + * @param sk_fd Array of netlink sockets + * @param no_of_sk Number of netlink sockets opened + * @param recv_buf Pointer to the array of evt_buf structures + * @param timeout Socket listen timeout value + * @param nlh Pointer to netlink message header + * @param msg Pointer to message header + * + * @return Number of bytes read or MLAN_EVENT_FAILURE + */ +int +read_event(int *sk_fd, int no_of_sk, evt_buf *recv_buf, int timeout, + struct nlmsghdr *nlh, struct msghdr *msg) +{ + struct timeval tv; + fd_set rfds; + int i = 0, max_sk_fd = sk_fd[0]; + int ret = MLAN_EVENT_FAILURE; + + /* Setup read fds */ + FD_ZERO(&rfds); + for (i = 0; i < no_of_sk; i++) { + if (sk_fd[i] > max_sk_fd) + max_sk_fd = sk_fd[i]; + + if (sk_fd[i] > 0) + FD_SET(sk_fd[i], &rfds); + } + + /* Initialize timeout value */ + if (timeout != 0) + tv.tv_sec = timeout; + else + tv.tv_sec = UAP_RECV_WAIT_DEFAULT; + tv.tv_usec = 0; + + /* Wait for reply */ + ret = select(max_sk_fd + 1, &rfds, NULL, NULL, &tv); + if (ret == -1) { + /* Error */ + terminate_flag++; + return MLAN_EVENT_FAILURE; + } else if (!ret) { + /* Timeout. Try again */ + return MLAN_EVENT_FAILURE; + } + for (i = 0; i < no_of_sk; i++) { + if (sk_fd[i] > 0) { + if (FD_ISSET(sk_fd[i], &rfds)) { + /* Success */ + recv_buf[i].flag = 1; + recv_buf[i].length = + read_event_netlink_socket(sk_fd[i], + recv_buf[i]. + buffer, nlh, + msg); + ret += recv_buf[i].length; + } + } + } + return ret; +} + +/** + * @brief Signal handler + * + * @param sig Received signal number + * + * @return N/A + */ +void +sig_handler(int sig) +{ + printf("Stopping application.\n"); + terminate_flag = 1; +} + +/** + * @brief Wait event specified by event ID, and return back the pointer. + * + * @param eventID Event ID + * @param pEvent Pointer to the Event buffer + * @param pEventLen Pointer to the Event Length + * + * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_FAILURE + */ +static int +wait_event(t_u32 eventID, t_u8 *pEvent, int *pEventLen) +{ + int nl_sk[MAX_NO_OF_DEVICES]; + struct nlmsghdr *nlh = NULL; + struct sockaddr_nl src_addr, dest_addr; + struct msghdr msg; + struct iovec iov; + evt_buf evt_recv_buf[MAX_NO_OF_DEVICES]; + int num_events = 0; + event_header *event = NULL; + int ret = MLAN_EVENT_FAILURE; + int netlink_num[MAX_NO_OF_DEVICES]; + char if_name[IFNAMSIZ + 1]; + t_u32 event_id = 0; + int i = 0, no_of_sk = 0; + int buf_len = 0; + + if (!pEvent || !pEventLen) { + printf("ERR:Input paramater(s) 'pEvent' or 'pEventLen' is NULL"); + goto done; + } + + buf_len = *pEventLen; + *pEventLen = 0; + + /* Currently, we support maximum 4 devices */ + /* TODO: determine no_of_sk at run time */ + no_of_sk = MAX_NO_OF_DEVICES; + + for (i = 0; i < no_of_sk; i++) { + /* Initialise */ + nl_sk[i] = -1; + netlink_num[i] = get_netlink_num(i); + if (netlink_num[i] >= 0) { + /* Open netlink socket */ + nl_sk[i] = socket(PF_NETLINK, SOCK_RAW, netlink_num[i]); + if (nl_sk[i] < 0) { + printf("ERR:Could not open netlink socket.\n"); + ret = MLAN_EVENT_FAILURE; + goto done; + } + + /* Set source address */ + memset(&src_addr, 0, sizeof(src_addr)); + src_addr.nl_family = AF_NETLINK; + src_addr.nl_pid = getpid(); /* Our PID */ + src_addr.nl_groups = NL_MULTICAST_GROUP; + + /* Bind socket with source address */ + if (bind + (nl_sk[i], (struct sockaddr *)&src_addr, + sizeof(src_addr)) < 0) { + printf("ERR:Could not bind socket!\n"); + ret = MLAN_EVENT_FAILURE; + goto done; + } + + /* Set destination address */ + memset(&dest_addr, 0, sizeof(dest_addr)); + dest_addr.nl_family = AF_NETLINK; + dest_addr.nl_pid = 0; /* Kernel */ + dest_addr.nl_groups = NL_MULTICAST_GROUP; + + /* Initialize netlink header */ + nlh = (struct nlmsghdr *) + malloc(NLMSG_SPACE(NL_MAX_PAYLOAD)); + if (!nlh) { + printf("ERR: Could not alloc buffer\n"); + ret = MLAN_EVENT_FAILURE; + goto done; + } + memset(nlh, 0, NLMSG_SPACE(NL_MAX_PAYLOAD)); + + /* Initialize I/O vector */ + iov.iov_base = (void *)nlh; + iov.iov_len = NLMSG_SPACE(NL_MAX_PAYLOAD); + + /* Initialize message header */ + memset(&msg, 0, sizeof(struct msghdr)); + msg.msg_name = (void *)&dest_addr; + msg.msg_namelen = sizeof(dest_addr); + msg.msg_iov = &iov; + msg.msg_iovlen = 1; + + memset(&evt_recv_buf[i], 0, sizeof(evt_buf)); + } + } + + signal(SIGTERM, sig_handler); + signal(SIGINT, sig_handler); + signal(SIGALRM, sig_handler); + while (1) { + if (terminate_flag) { + printf("Stopping!\n"); + break; + } + ret = read_event(nl_sk, no_of_sk, evt_recv_buf, 0, nlh, &msg); + + /* No result. Loop again */ + if (ret == MLAN_EVENT_FAILURE) { + continue; + } + if (ret == 0) { + /* Zero bytes received */ + printf("ERR:Received zero bytes!\n"); + continue; + } + for (i = 0; i < no_of_sk; i++) { + if (evt_recv_buf[i].flag == 1) { + num_events++; + + memcpy(&event_id, evt_recv_buf[i].buffer, + sizeof(event_id)); + if (((event_id & 0xFF000000) == 0x80000000) || + ((event_id & 0xFF000000) == 0)) { + event = (event_header + *)(evt_recv_buf[i].buffer); + } else { + memset(if_name, 0, IFNAMSIZ + 1); + memcpy(if_name, evt_recv_buf[i].buffer, + IFNAMSIZ); + event = (event_header + *)((t_u8 *)(evt_recv_buf[i]. + buffer) + + IFNAMSIZ); + ret -= IFNAMSIZ; + evt_recv_buf[i].length -= IFNAMSIZ; + } + if (event->event_id == eventID) { + if (buf_len > evt_recv_buf[i].length) { + *pEventLen = + evt_recv_buf[i].length; + memcpy(pEvent, (t_u8 *)event, + evt_recv_buf[i].length); + } else { + printf("ERR:Buffer length exceeded \n"); + } + goto done; + } + /* Reset event flag after reading */ + evt_recv_buf[i].flag = 0; + } + } + fflush(stdout); + } + +done: + for (i = 0; i < no_of_sk; i++) { + if (nl_sk[i] > 0) + close(nl_sk[i]); + } + if (nlh) + free(nlh); + return 0; + +} + +/** + * @brief Set Robustcoex gpiocfg + * + * @param argc Number of arguments + * @param argv Pointer to the arguments array + * + * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_FAILURE + */ +static int +process_robustcoex(int argc, char *argv[]) +{ + t_u8 *buffer = NULL; + struct eth_priv_cmd *cmd; + struct ifreq ifr; + + if (argc <= 4) { + printf("Err: Invalid number of arguments\n"); + printf("Usage: ./mlanutl robustcoex [gpiocfg] [value]\n"); + return MLAN_STATUS_FAILURE; + } + if (strcmp(argv[3], "gpiocfg") == 0) { + if (argc != 7 && argc != 5) { + printf("ERR: Invalid number of arguments\n"); + printf("Usage: ./mlanutl robustcoex gpiocfg [Enable][Gpionum][Gpiopolarity]\n"); + printf("Usage: ./mlanutl robustcoex gpiocfg [Disable]\n"); + return MLAN_STATUS_FAILURE; + } + } else { + printf("ERR: Invalid arguments\n"); + printf("Usage: ./mlanutl robustcoex [gpiocfg][value]\n"); + return MLAN_STATUS_FAILURE; + } + /* Initialize buffer */ + buffer = (t_u8 *)malloc(BUFFER_LENGTH); + if (!buffer) { + printf("ERR:Cannot allocate buffer for command!\n"); + return MLAN_STATUS_FAILURE; + } + + prepare_buffer(buffer, argv[2], (argc - 3), &argv[3]); + cmd = (struct eth_priv_cmd *)malloc(sizeof(struct eth_priv_cmd)); + if (!cmd) { + printf("ERR:Cannot allocate buffer for command!\n"); + free(buffer); + return MLAN_STATUS_FAILURE; + } + + /* Fill up buffer */ +#ifdef USERSPACE_32BIT_OVER_KERNEL_64BIT + memset(cmd, 0, sizeof(struct eth_priv_cmd)); + memcpy(&cmd->buf, &buffer, sizeof(buffer)); +#else + cmd->buf = buffer; +#endif + cmd->used_len = 0; + cmd->total_len = BUFFER_LENGTH; + + /* Perform IOCTL */ + memset(&ifr, 0, sizeof(struct ifreq)); + strncpy(ifr.ifr_ifrn.ifrn_name, dev_name, strlen(dev_name)); + ifr.ifr_ifru.ifru_data = (void *)cmd; + + if (ioctl(sockfd, MLAN_ETH_PRIV, &ifr)) { + perror("mlanutl"); + fprintf(stderr, "mlanutl: robustcoex fail\n"); + if (cmd) + free(cmd); + if (buffer) + free(buffer); + return MLAN_STATUS_FAILURE; + } + + if (buffer) + free(buffer); + if (cmd) + free(cmd); + + return MLAN_STATUS_SUCCESS; +} + +/** + * @brief Set/get DMCS config + * + * @param argc Number of arguments + * @param argv Pointer to the arguments array + * + * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_FAILURE + */ +static int +process_dmcs(int argc, char *argv[]) +{ + t_u8 *buffer = NULL; + struct eth_priv_cmd *cmd; + struct ifreq ifr; + struct eth_priv_dmcs_status *status; + int i = 0, j = 0; + + if (argc <= 3 || argc > 5) { + printf("Err: Invalid number of arguments\n"); + printf("Usage: ./mlanutl dmcs [subcmd] [value]\n"); + return MLAN_STATUS_FAILURE; + } + if ((*argv[3] != '0') && (*argv[3] != '1')) { + printf("Err: Invalid input argument of [subcmd]!\n"); + printf("Currently, we only support 0 and 1 for [subcmd]\n"); + return MLAN_STATUS_FAILURE; + } + if (*argv[3] == '0') { + if (argc != 5) { + printf("Err: Invalid number of arguments for disable/enable DMCS\n"); + printf("Usage: ./mlanutl dmcs [subcmd] [value]\n"); + return MLAN_STATUS_FAILURE; + } + } + buffer = (t_u8 *)malloc(BUFFER_LENGTH); + if (!buffer) { + printf("ERR:Cannot allocate buffer for command!\n"); + return MLAN_STATUS_FAILURE; + } + prepare_buffer(buffer, argv[2], (argc - 3), &argv[3]); + cmd = (struct eth_priv_cmd *)malloc(sizeof(struct eth_priv_cmd)); + if (!cmd) { + printf("ERR:Cannot allocate buffer for command!\n"); + free(buffer); + return MLAN_STATUS_FAILURE; + } + /* Fill up buffer */ +#ifdef USERSPACE_32BIT_OVER_KERNEL_64BIT + memset(cmd, 0, sizeof(struct eth_priv_cmd)); + memcpy(&cmd->buf, &buffer, sizeof(buffer)); +#else + cmd->buf = buffer; +#endif + cmd->used_len = 0; + cmd->total_len = BUFFER_LENGTH; + + /* Perform IOCTL */ + memset(&ifr, 0, sizeof(struct ifreq)); + strncpy(ifr.ifr_ifrn.ifrn_name, dev_name, strlen(dev_name)); + ifr.ifr_ifru.ifru_data = (void *)cmd; + + if (ioctl(sockfd, MLAN_ETH_PRIV, &ifr)) { + perror("mlanutl"); + fprintf(stderr, "mlanutl: dmcs fail\n"); + if (cmd) + free(cmd); + if (buffer) + free(buffer); + return MLAN_STATUS_FAILURE; + } + /* Process get status response */ + if (*argv[3] == '1') { + status = (struct eth_priv_dmcs_status *)buffer; + printf("mapping policy: %d\n", status->mapping_policy); + for (i = 0; i < MAX_NUM_MAC; i++) { + printf("radio_status[%d]:\n", i); + printf("\tradio id: %d\n", + status->radio_status[i].radio_id); + printf("\trunning mode: %d\n", + status->radio_status[i].running_mode); + for (j = 0; j < 2; j++) { + printf("\tchan_status[%d]:\n", j); + printf("\t\tchannel: %d\n", + status->radio_status[i].chan_status[j]. + channel); + printf("\t\tap count: %d\n", + status->radio_status[i].chan_status[j]. + ap_count); + printf("\t\tsta count: %d\n", + status->radio_status[i].chan_status[j]. + sta_count); + } + } + } + + if (buffer) + free(buffer); + if (cmd) + free(cmd); + return MLAN_STATUS_SUCCESS; +} + +#if defined(PCIE) +/** + * @brief Enable SSU support + * + * @param argc Number of arguments + * @param argv Pointer to the arguments array + * + * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_FAILURE + */ +static int +process_ssu_cmd(int argc, char *argv[]) +{ + t_u8 *buffer = NULL; + struct eth_priv_cmd *cmd = NULL; + struct ifreq ifr; + char *args[30], *pos = NULL; + int li = 0, cmd_found = 0; + char *line = NULL; + FILE *fp = NULL; + ssu_params_cfg *ssu_params = NULL; + int ret = 0; + int ssu_mode = 0; + int used_len = 0; + + if ((argc != 3) && (argc != 4)) { + printf("Err: Invalid number of arguments\n"); + printf("Usage: ./mlanutl ssu\n"); + printf("Usage: ./mlanutl ssu config/ssu.conf\n"); + printf("Usage: ./mlanutl ssu 2\n"); + return MLAN_STATUS_FAILURE; + } + + /* Initialize buffer */ + buffer = (t_u8 *)malloc(BUFFER_LENGTH); + if (!buffer) { + printf("ERR:Cannot allocate buffer for command!\n"); + return MLAN_STATUS_FAILURE; + } + if (argc == 4) { + ssu_mode = (t_u8)a2hex_or_atoi(argv[3]); + used_len = + strlen(CMD_NXP) + strlen(argv[2]) + + sizeof(ssu_params_cfg); + } else { + used_len = strlen(CMD_NXP) + strlen(argv[2]); + } + prepare_buffer(buffer, argv[2], 0, NULL); + if (argc == 4 && (ssu_mode != 2)) { + line = (char *)malloc(MAX_CONFIG_LINE); + if (!line) { + printf("ERR:Cannot allocate memory for line\n"); + ret = MLAN_STATUS_FAILURE; + goto done; + } + memset(line, 0, MAX_CONFIG_LINE); + ssu_params = + (ssu_params_cfg *) (buffer + strlen(CMD_NXP) + + strlen(argv[2])); + ssu_params->ssu_mode = 0; + fp = fopen(argv[3], "r"); + if (fp == NULL) { + fprintf(stderr, "Cannot open file %s\n", argv[3]); + ret = MLAN_STATUS_FAILURE; + goto done; + } + /* Parse file and process */ + while (config_get_line(line, MAX_CONFIG_LINE, fp, &li, &pos)) { + parse_line(line, args, 30); + if (!cmd_found && + strncmp(args[0], "ssu_params_cfg", strlen(args[0]))) + continue; + cmd_found = 1; + if (strcmp(args[0], "nskip") == 0) + ssu_params->nskip = + (t_u32)a2hex_or_atoi(args[1]); + else if (strcmp(args[0], "nsel") == 0) + ssu_params->nsel = + (t_u32)a2hex_or_atoi(args[1]); + else if (strcmp(args[0], "adcdownsample") == 0) + ssu_params->adcdownsample = + (t_u32)a2hex_or_atoi(args[1]); + else if (strcmp(args[0], "mask_adc_pkt") == 0) + ssu_params->mask_adc_pkt = + (t_u32)a2hex_or_atoi(args[1]); + else if (strcmp(args[0], "out_16bits") == 0) + ssu_params->out_16bits = + (t_u32)a2hex_or_atoi(args[1]); + else if (strcmp(args[0], "spec_pwr_enable") == 0) + ssu_params->spec_pwr_enable = + (t_u32)a2hex_or_atoi(args[1]); + else if (strcmp(args[0], "rate_reduction") == 0) + ssu_params->rate_deduction = + (t_u32)a2hex_or_atoi(args[1]); + else if (strcmp(args[0], "n_pkt_avg") == 0) + ssu_params->n_pkt_avg = + (t_u32)a2hex_or_atoi(args[1]); + } + } else if (ssu_mode == 2) { + ssu_params = + (ssu_params_cfg *) (buffer + strlen(CMD_NXP) + + strlen(argv[2])); + ssu_params->ssu_mode = 2; + } + cmd = (struct eth_priv_cmd *)malloc(sizeof(struct eth_priv_cmd)); + if (!cmd) { + printf("ERR:Cannot allocate buffer for command!\n"); + ret = MLAN_STATUS_FAILURE; + goto done; + + } + /* Fill up buffer */ +#ifdef USERSPACE_32BIT_OVER_KERNEL_64BIT + memset(cmd, 0, sizeof(struct eth_priv_cmd)); + memcpy(&cmd->buf, &buffer, sizeof(buffer)); +#else + cmd->buf = buffer; +#endif + cmd->used_len = used_len; + cmd->total_len = BUFFER_LENGTH; + + /* Perform IOCTL */ + memset(&ifr, 0, sizeof(struct ifreq)); + strncpy(ifr.ifr_ifrn.ifrn_name, dev_name, strlen(dev_name)); + ifr.ifr_ifru.ifru_data = (void *)cmd; + + if (ioctl(sockfd, MLAN_ETH_PRIV, &ifr)) { + perror("mlanutl"); + fprintf(stderr, "mlanutl: ssu command fail\n"); + ret = MLAN_STATUS_FAILURE; + } +done: + if (line) + free(line); + if (fp) + fclose(fp); + if (buffer) + free(buffer); + if (cmd) + free(cmd); + + return ret; +} +#endif + +/** + * @brief Get one line from the File + * + * @param fp File handler + * @param str Storage location for data. + * @param size Maximum number of characters to read. + * @param lineno A pointer to return current line number + * @return returns string or NULL + */ +char * +mlan_config_get_line(FILE * fp, char *str, t_s32 size, int *lineno) +{ + char *start, *end; + int out, next_line; + + if (!fp || !str) + return NULL; + + do { +read_line: + if (!fgets(str, size, fp)) + break; + start = str; + start[size - 1] = '\0'; + end = start + strlen(str); + (*lineno)++; + + out = 1; + while (out && (start < end)) { + next_line = 0; + /* Remove empty lines and lines starting with # */ + switch (start[0]) { + case ' ': /* White space */ + case '\t': /* Tab */ + start++; + break; + case '#': + case '\n': + case '\0': + next_line = 1; + break; + case '\r': + if (start[1] == '\n') + next_line = 1; + else + start++; + break; + default: + out = 0; + break; + } + if (next_line) + goto read_line; + } + + /* Remove # comments unless they are within a double quoted + * string. Remove trailing white space. */ + end = strstr(start, "\""); + if (end) { + end = strstr(end + 1, "\""); + if (!end) + end = start; + } else + end = start; + + end = strstr(end + 1, "#"); + if (end) + *end-- = '\0'; + else + end = start + strlen(start) - 1; + + out = 1; + while (out && (start < end)) { + switch (*end) { + case ' ': /* White space */ + case '\t': /* Tab */ + case '\n': + case '\r': + *end = '\0'; + end--; + break; + default: + out = 0; + break; + } + } + + if (*start == '\0') + continue; + + return start; + } while (1); + + return NULL; +} + +/** + * @brief Parse function for a configuration line + * + * @param s Storage buffer for data + * @param size Maximum size of data + * @param stream File stream pointer + * @param line Pointer to current line within the file + * @param _pos Output string or NULL + * @return String or NULL + */ +static char * +config_get_line(char *s, int size, FILE * stream, int *line, char **_pos) +{ + *_pos = mlan_config_get_line(stream, s, size, line); + return *_pos; +} + +/** + * @brief Converts colon separated MAC address to hex value + * + * @param mac A pointer to the colon separated MAC string + * @param raw A pointer to the hex data buffer + * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE + * MAC_BROADCAST - if broadcast mac + * MAC_MULTICAST - if multicast mac + */ +static int +mac2raw(char *mac, t_u8 *raw) +{ + unsigned int temp_raw[ETH_ALEN]; + int num_tokens = 0; + int i; + + if (strlen(mac) != ((2 * ETH_ALEN) + (ETH_ALEN - 1))) { + return MLAN_STATUS_FAILURE; + } + num_tokens = sscanf(mac, "%2x:%2x:%2x:%2x:%2x:%2x", + temp_raw + 0, temp_raw + 1, temp_raw + 2, + temp_raw + 3, temp_raw + 4, temp_raw + 5); + if (num_tokens != ETH_ALEN) { + return MLAN_STATUS_FAILURE; + } + for (i = 0; i < num_tokens; i++) + raw[i] = (t_u8)temp_raw[i]; + + if (memcmp(raw, "\xff\xff\xff\xff\xff\xff", ETH_ALEN) == 0) { + return MAC_BROADCAST; + } else if (raw[0] & 0x01) { + return MAC_MULTICAST; + } + return MLAN_STATUS_SUCCESS; +} + +/** + * @brief Parses a command line + * + * @param line The line to parse + * @param args Pointer to the argument buffer to be filled in + * @param args_count Max number of elements which can be filled in buffer 'args' + * @return Number of arguments in the line or EOF + */ +static int +parse_line(char *line, char *args[], t_u16 args_count) +{ + int arg_num = 0; + int is_start = 0; + int is_quote = 0; + int length = 0; + int i = 0; + + arg_num = 0; + length = strlen(line); + /* Process line */ + + /* Find number of arguments */ + is_start = 0; + is_quote = 0; + for (i = 0; (i < length) && (arg_num < args_count); i++) { + /* Ignore leading spaces */ + if (is_start == 0) { + if (line[i] == ' ') { + continue; + } else if (line[i] == '\t') { + continue; + } else if (line[i] == '\n') { + break; + } else { + is_start = 1; + args[arg_num] = &line[i]; + arg_num++; + } + } + if (is_start == 1) { + /* Ignore comments */ + if (line[i] == '#') { + if (is_quote == 0) { + line[i] = '\0'; + arg_num--; + } + break; + } + /* Separate by '=' */ + if (line[i] == '=') { + line[i] = '\0'; + is_start = 0; + continue; + } + /* Separate by ',' */ + if (line[i] == ',') { + line[i] = '\0'; + is_start = 0; + continue; + } + /* Change ',' to ' ', but not inside quotes */ + if ((line[i] == ',') && (is_quote == 0)) { + line[i] = ' '; + continue; + } + } + /* Remove newlines */ + if (line[i] == '\n') { + line[i] = '\0'; + } + /* Check for quotes */ + if (line[i] == '"') { + is_quote = (is_quote == 1) ? 0 : 1; + continue; + } + if (((line[i] == ' ') || (line[i] == '\t')) && (is_quote == 0)) { + line[i] = '\0'; + is_start = 0; + continue; + } + } + return arg_num; +} + +/** + * @brief Process version + * @param argc Number of arguments + * @param argv A pointer to arguments array + * @return MLAN_STATUS_SUCCESS--success, otherwise--fail + */ +static int +process_version(int argc, char *argv[]) +{ + t_u8 *buffer = NULL; + struct eth_priv_cmd *cmd = NULL; + struct ifreq ifr; + + /* Initialize buffer */ + buffer = (t_u8 *)malloc(BUFFER_LENGTH); + if (!buffer) { + printf("ERR:Cannot allocate buffer for command!\n"); + return MLAN_STATUS_FAILURE; + } + + prepare_buffer(buffer, argv[2], 0, NULL); + + cmd = (struct eth_priv_cmd *)malloc(sizeof(struct eth_priv_cmd)); + if (!cmd) { + printf("ERR:Cannot allocate buffer for command!\n"); + free(buffer); + return MLAN_STATUS_FAILURE; + } + + /* Fill up buffer */ +#ifdef USERSPACE_32BIT_OVER_KERNEL_64BIT + memset(cmd, 0, sizeof(struct eth_priv_cmd)); + memcpy(&cmd->buf, &buffer, sizeof(buffer)); +#else + cmd->buf = buffer; +#endif + cmd->used_len = 0; + cmd->total_len = BUFFER_LENGTH; + + /* Perform IOCTL */ + memset(&ifr, 0, sizeof(struct ifreq)); + strncpy(ifr.ifr_ifrn.ifrn_name, dev_name, strlen(dev_name)); + ifr.ifr_ifru.ifru_data = (void *)cmd; + + if (ioctl(sockfd, MLAN_ETH_PRIV, &ifr)) { + perror("mlanutl"); + fprintf(stderr, "mlanutl: version fail\n"); + if (cmd) + free(cmd); + if (buffer) + free(buffer); + return MLAN_STATUS_FAILURE; + } + + /* Process result */ + printf("Version string received: %s\n", buffer); + + if (buffer) + free(buffer); + if (cmd) + free(cmd); + + return MLAN_STATUS_SUCCESS; +} + +/** + * @brief Process band configuration + * @param argc Number of arguments + * @param argv A pointer to arguments array + * @return MLAN_STATUS_SUCCESS--success, otherwise--fail + */ +static int +process_bandcfg(int argc, char *argv[]) +{ + t_u8 *buffer = NULL; + int i; + struct eth_priv_cmd *cmd = NULL; + struct eth_priv_bandcfg *bandcfg = NULL; + struct ifreq ifr; + + /* Initialize buffer */ + buffer = (t_u8 *)malloc(BUFFER_LENGTH); + if (!buffer) { + printf("ERR:Cannot allocate buffer for command!\n"); + return MLAN_STATUS_FAILURE; + } + + prepare_buffer(buffer, argv[2], (argc - 3), &argv[3]); + + cmd = (struct eth_priv_cmd *)malloc(sizeof(struct eth_priv_cmd)); + if (!cmd) { + printf("ERR:Cannot allocate buffer for command!\n"); + free(buffer); + return MLAN_STATUS_FAILURE; + } + + /* Fill up buffer */ +#ifdef USERSPACE_32BIT_OVER_KERNEL_64BIT + memset(cmd, 0, sizeof(struct eth_priv_cmd)); + memcpy(&cmd->buf, &buffer, sizeof(buffer)); +#else + cmd->buf = buffer; +#endif + cmd->used_len = 0; + cmd->total_len = BUFFER_LENGTH; + + /* Perform IOCTL */ + memset(&ifr, 0, sizeof(struct ifreq)); + strncpy(ifr.ifr_ifrn.ifrn_name, dev_name, strlen(dev_name)); + ifr.ifr_ifru.ifru_data = (void *)cmd; + + if (ioctl(sockfd, MLAN_ETH_PRIV, &ifr)) { + perror("mlanutl"); + fprintf(stderr, "mlanutl: bandcfg fail\n"); + if (cmd) + free(cmd); + if (buffer) + free(buffer); + return MLAN_STATUS_FAILURE; + } + + /* Process result */ + bandcfg = (struct eth_priv_bandcfg *)buffer; + if (argc == 3) { + /* GET operation */ + printf("Band Configuration:\n"); + printf(" Infra Band: 0x%x (", (int)bandcfg->config_bands); + for (i = 0; i < 10; i++) { + if ((bandcfg->config_bands >> i) & 0x1) + printf(" %s", band[i]); + } + printf(" )\n"); + printf(" Adhoc Start Band: 0x%x (", + (int)bandcfg->adhoc_start_band); + for (i = 0; i < 10; i++) { + if ((bandcfg->adhoc_start_band >> i) & 0x1) + printf(" %s", band[i]); + } + printf(" )\n"); + printf(" Adhoc Start Channel: %d\n", + (int)bandcfg->adhoc_channel); + } + + if (buffer) + free(buffer); + if (cmd) + free(cmd); + + return MLAN_STATUS_SUCCESS; +} + +/** + * @brief get hostcmd data + * + * @param ln A pointer to line number + * @param buf A pointer to hostcmd data + * @param size A pointer to the return size of hostcmd buffer + * @return MLAN_STATUS_SUCCESS + */ +static int +mlan_get_hostcmd_data(FILE * fp, int *ln, t_u8 *buf, t_u16 *size) +{ + t_s32 errors = 0, i; + char line[512], *pos, *pos1, *pos2, *pos3; + t_u16 len; + + while ((pos = mlan_config_get_line(fp, line, sizeof(line), ln))) { + (*ln)++; + if (strcmp(pos, "}") == 0) { + break; + } + + pos1 = strchr(pos, ':'); + if (pos1 == NULL) { + printf("Line %d: Invalid hostcmd line '%s'\n", *ln, + pos); + errors++; + continue; + } + *pos1++ = '\0'; + + pos2 = strchr(pos1, '='); + if (pos2 == NULL) { + printf("Line %d: Invalid hostcmd line '%s'\n", *ln, + pos); + errors++; + continue; + } + *pos2++ = '\0'; + + len = a2hex_or_atoi(pos1); + if (len < 1 || len > BUFFER_LENGTH) { + printf("Line %d: Invalid hostcmd line '%s'\n", *ln, + pos); + errors++; + continue; + } + + *size += len; + + if (*pos2 == '"') { + pos2++; + pos3 = strchr(pos2, '"'); + if (pos3 == NULL) { + printf("Line %d: invalid quotation '%s'\n", *ln, + pos); + errors++; + continue; + } + *pos3 = '\0'; + memset(buf, 0, len); + memmove(buf, pos2, MIN(strlen(pos2), len)); + buf += len; + } else if (*pos2 == '\'') { + pos2++; + pos3 = strchr(pos2, '\''); + if (pos3 == NULL) { + printf("Line %d: invalid quotation '%s'\n", *ln, + pos); + errors++; + continue; + } + *pos3 = ','; + for (i = 0; i < len; i++) { + pos3 = strchr(pos2, ','); + if (pos3 != NULL) { + *pos3 = '\0'; + *buf++ = (t_u8)a2hex_or_atoi(pos2); + pos2 = pos3 + 1; + } else + *buf++ = 0; + } + } else if (*pos2 == '{') { + t_u16 tlvlen = 0, tmp_tlvlen; + mlan_get_hostcmd_data(fp, ln, buf + len, &tlvlen); + tmp_tlvlen = tlvlen; + while (len--) { + *buf++ = (t_u8)(tmp_tlvlen & 0xff); + tmp_tlvlen >>= 8; + } + *size += tlvlen; + buf += tlvlen; + } else { + t_u32 value = a2hex_or_atoi(pos2); + while (len--) { + *buf++ = (t_u8)(value & 0xff); + value >>= 8; + } + } + } + return MLAN_STATUS_SUCCESS; +} + +/** + * @brief Prepare host-command buffer + * @param fp File handler + * @param cmd_name Command name + * @param buf A pointer to comand buffer + * @return MLAN_STATUS_SUCCESS--success, otherwise--fail + */ +int +prepare_host_cmd_buffer(FILE * fp, char *cmd_name, t_u8 *buf) +{ + char line[256], cmdname[256], *pos, cmdcode[10]; + HostCmd_DS_GEN *hostcmd; + t_u32 hostcmd_size = 0; + int ln = 0; + int cmdname_found = 0, cmdcode_found = 0; + + hostcmd = (HostCmd_DS_GEN *)(buf + sizeof(t_u32)); + hostcmd->command = 0xffff; + + snprintf(cmdname, sizeof(cmdname), "%s={", cmd_name); + cmdname_found = 0; + while ((pos = mlan_config_get_line(fp, line, sizeof(line), &ln))) { + if (strcmp(pos, cmdname) == 0) { + cmdname_found = 1; + snprintf(cmdcode, sizeof(cmdcode), "CmdCode="); + cmdcode_found = 0; + while ((pos = + mlan_config_get_line(fp, line, sizeof(line), + &ln))) { + if (strncmp(pos, cmdcode, strlen(cmdcode)) == 0) { + t_u16 len = 0; + cmdcode_found = 1; + hostcmd->command = + a2hex_or_atoi(pos + + strlen(cmdcode)); + hostcmd->size = S_DS_GEN; + mlan_get_hostcmd_data(fp, &ln, + buf + + sizeof(t_u32) + + hostcmd->size, + &len); + hostcmd->size += len; + break; + } + } + if (!cmdcode_found) { + fprintf(stderr, + "mlanutl: CmdCode not found in conf file\n"); + return MLAN_STATUS_FAILURE; + } + break; + } + } + + if (!cmdname_found) { + fprintf(stderr, + "mlanutl: cmdname '%s' is not found in conf file\n", + cmd_name); + return MLAN_STATUS_FAILURE; + } + + hostcmd->seq_num = 0; + hostcmd->result = 0; + hostcmd->command = cpu_to_le16(hostcmd->command); + hostcmd->size = cpu_to_le16(hostcmd->size); + + hostcmd_size = (t_u32)(hostcmd->size); + memcpy(buf, (t_u8 *)&hostcmd_size, sizeof(t_u32)); + + return MLAN_STATUS_SUCCESS; +} + +/** + * @brief Prints a MAC address in colon separated form from raw data + * + * @param raw A pointer to the hex data buffer + * @return N/A + */ +void +print_mac(t_u8 *raw) +{ + printf("%02x:%02x:%02x:%02x:%02x:%02x", (unsigned int)raw[0], + (unsigned int)raw[1], (unsigned int)raw[2], (unsigned int)raw[3], + (unsigned int)raw[4], (unsigned int)raw[5]); + return; +} + +/** + * @brief Process host_cmd response + * @param cmd_name Command name + * @param buf A pointer to the response buffer + * @return MLAN_STATUS_SUCCESS--success, otherwise--fail + */ +int +process_host_cmd_resp(char *cmd_name, t_u8 *buf) +{ + t_u32 hostcmd_size = 0; + HostCmd_DS_GEN *hostcmd = NULL; + int ret = MLAN_STATUS_SUCCESS; + + buf += strlen(CMD_NXP) + strlen(cmd_name); + memcpy((t_u8 *)&hostcmd_size, buf, sizeof(t_u32)); + buf += sizeof(t_u32); + + hostcmd = (HostCmd_DS_GEN *)buf; + hostcmd->command = le16_to_cpu(hostcmd->command); + hostcmd->size = le16_to_cpu(hostcmd->size); + hostcmd->seq_num = le16_to_cpu(hostcmd->seq_num); + hostcmd->result = le16_to_cpu(hostcmd->result); + + hostcmd->command &= ~HostCmd_RET_BIT; + if (!hostcmd->result) { + switch (hostcmd->command) { + case HostCmd_CMD_CFG_DATA: + { + HostCmd_DS_802_11_CFG_DATA *pstcfgData = + (HostCmd_DS_802_11_CFG_DATA *)(buf + + S_DS_GEN); + pstcfgData->data_len = + le16_to_cpu(pstcfgData->data_len); + pstcfgData->action = + le16_to_cpu(pstcfgData->action); + + if (pstcfgData->action == HostCmd_ACT_GEN_GET) { + hexdump("cfgdata", pstcfgData->data, + pstcfgData->data_len, ' '); + } + break; + } + case HostCmd_CMD_802_11_TPC_ADAPT_REQ: + { + mlan_ioctl_11h_tpc_resp *tpcIoctlResp = + (mlan_ioctl_11h_tpc_resp *)(buf + + S_DS_GEN); + if (tpcIoctlResp->status_code == 0) { + printf("tpcrequest: txPower(%d), linkMargin(%d), rssi(%d)\n", tpcIoctlResp->tx_power, tpcIoctlResp->link_margin, tpcIoctlResp->rssi); + } else { + printf("tpcrequest: failure, status = %d\n", tpcIoctlResp->status_code); + } + break; + } + case HostCmd_CMD_802_11_CRYPTO: + { + t_u16 alg = + le16_to_cpu((t_u16) + *(buf + S_DS_GEN + + sizeof(t_u16))); + if (alg == CIPHER_TEST_AES_CCM || + alg == CIPHER_TEST_GCMP) { + HostCmd_DS_802_11_CRYPTO_AES_CCM + *cmd_aes_ccm = + (HostCmd_DS_802_11_CRYPTO_AES_CCM + *)(buf + S_DS_GEN); + + cmd_aes_ccm->encdec + = + le16_to_cpu(cmd_aes_ccm-> + encdec); + cmd_aes_ccm->algorithm = + le16_to_cpu(cmd_aes_ccm-> + algorithm); + cmd_aes_ccm->key_length = + le16_to_cpu(cmd_aes_ccm-> + key_length); + cmd_aes_ccm->nonce_length = + le16_to_cpu(cmd_aes_ccm-> + nonce_length); + cmd_aes_ccm->AAD_length = + le16_to_cpu(cmd_aes_ccm-> + AAD_length); + cmd_aes_ccm->data.header.type = + le16_to_cpu(cmd_aes_ccm->data. + header.type); + cmd_aes_ccm->data.header.len = + le16_to_cpu(cmd_aes_ccm->data. + header.len); + + printf("crypto_result: encdec=%d algorithm=%d, KeyLen=%d," " NonceLen=%d,AADLen=%d,dataLen=%d\n", cmd_aes_ccm->encdec, cmd_aes_ccm->algorithm, cmd_aes_ccm->key_length, cmd_aes_ccm->nonce_length, cmd_aes_ccm->AAD_length, cmd_aes_ccm->data.header.len); + + hexdump("Key", cmd_aes_ccm->key, + cmd_aes_ccm->key_length, ' '); + hexdump("Nonce", cmd_aes_ccm->nonce, + cmd_aes_ccm->nonce_length, ' '); + hexdump("AAD", cmd_aes_ccm->AAD, + cmd_aes_ccm->AAD_length, ' '); + hexdump("Data", cmd_aes_ccm->data.data, + cmd_aes_ccm->data.header.len, + ' '); + } else if (alg == CIPHER_TEST_WAPI) { + HostCmd_DS_802_11_CRYPTO_WAPI *cmd_wapi + = + (HostCmd_DS_802_11_CRYPTO_WAPI + *) (buf + S_DS_GEN); + + cmd_wapi->encdec + = le16_to_cpu(cmd_wapi->encdec); + cmd_wapi->algorithm + = + le16_to_cpu(cmd_wapi-> + algorithm); + cmd_wapi->key_length = + le16_to_cpu(cmd_wapi-> + key_length); + cmd_wapi->nonce_length = + le16_to_cpu(cmd_wapi-> + nonce_length); + cmd_wapi->AAD_length = + le16_to_cpu(cmd_wapi-> + AAD_length); + + printf("crypto_result: encdec=%d algorithm=%d, KeyLen=%d," " NonceLen=%d,AADLen=%d,dataLen=%d\n", cmd_wapi->encdec, cmd_wapi->algorithm, cmd_wapi->key_length, cmd_wapi->nonce_length, cmd_wapi->AAD_length, cmd_wapi->data_length); + + hexdump("Key", cmd_wapi->key, + cmd_wapi->key_length, ' '); + hexdump("Nonce", cmd_wapi->nonce, + cmd_wapi->nonce_length, ' '); + hexdump("AAD", cmd_wapi->AAD, + cmd_wapi->AAD_length, ' '); + } else { + HostCmd_DS_802_11_CRYPTO *cmd = + (HostCmd_DS_802_11_CRYPTO *)(buf + + + S_DS_GEN); + cmd->encdec = le16_to_cpu(cmd->encdec); + cmd->algorithm = + le16_to_cpu(cmd->algorithm); + cmd->key_IV_length = + le16_to_cpu(cmd->key_IV_length); + cmd->key_length = + le16_to_cpu(cmd->key_length); + cmd->data.header.type = + le16_to_cpu(cmd->data.header. + type); + cmd->data.header.len = + le16_to_cpu(cmd->data.header. + len); + + printf("crypto_result: encdec=%d algorithm=%d,KeyIVLen=%d," " KeyLen=%d,dataLen=%d\n", cmd->encdec, cmd->algorithm, cmd->key_IV_length, cmd->key_length, cmd->data.header.len); + hexdump("KeyIV", cmd->keyIV, + cmd->key_IV_length, ' '); + hexdump("Key", cmd->key, + cmd->key_length, ' '); + hexdump("Data", cmd->data.data, + cmd->data.header.len, ' '); + } + break; + } + case HostCmd_CMD_802_11_AUTO_TX: + { + HostCmd_DS_802_11_AUTO_TX *at = + (HostCmd_DS_802_11_AUTO_TX *)(buf + + S_DS_GEN); + + if (le16_to_cpu(at->action) == + HostCmd_ACT_GEN_GET) { + if (S_DS_GEN + sizeof(at->action) == + hostcmd->size) { + printf("auto_tx not configured\n"); + + } else { + MrvlIEtypesHeader_t *header = + &at->auto_tx.header; + + header->type = + le16_to_cpu(header-> + type); + header->len = + le16_to_cpu(header-> + len); + + if ((S_DS_GEN + + sizeof(at->action) + + + sizeof(MrvlIEtypesHeader_t) + + header->len == + hostcmd->size) && + (header->type == + TLV_TYPE_AUTO_TX)) { + + AutoTx_MacFrame_t *atmf + = + &at->auto_tx. + auto_tx_mac_frame; + + printf("Interval: %d second(s)\n", le16_to_cpu(atmf->interval)); + printf("Priority: %#x\n", atmf->priority); + printf("Frame Length: %d\n", le16_to_cpu(atmf->frame_len)); + printf("Dest Mac Address: " "%02x:%02x:%02x:%02x:%02x:%02x\n", atmf->dest_mac_addr[0], atmf->dest_mac_addr[1], atmf->dest_mac_addr[2], atmf->dest_mac_addr[3], atmf->dest_mac_addr[4], atmf->dest_mac_addr[5]); + printf("Src Mac Address: " "%02x:%02x:%02x:%02x:%02x:%02x\n", atmf->src_mac_addr[0], atmf->src_mac_addr[1], atmf->src_mac_addr[2], atmf->src_mac_addr[3], atmf->src_mac_addr[4], atmf->src_mac_addr[5]); + + hexdump("Frame Payload", + atmf->payload, + le16_to_cpu + (atmf-> + frame_len) + - + MLAN_MAC_ADDR_LENGTH + * 2, ' '); + } else { + printf("incorrect auto_tx command response\n"); + } + } + } + break; + } + case HostCmd_CMD_802_11_SUBSCRIBE_EVENT: + { + HostCmd_DS_802_11_SUBSCRIBE_EVENT *se = + (HostCmd_DS_802_11_SUBSCRIBE_EVENT + *)(buf + S_DS_GEN); + if (le16_to_cpu(se->action) == + HostCmd_ACT_GEN_GET) { + int len = + S_DS_GEN + + sizeof + (HostCmd_DS_802_11_SUBSCRIBE_EVENT); + printf("\nEvent\t\tValue\tFreq\tsubscribed\n\n"); + while (len < hostcmd->size) { + MrvlIEtypesHeader_t *header = + (MrvlIEtypesHeader_t + *)(buf + len); + switch (le16_to_cpu + (header->type)) { + case TLV_TYPE_RSSI_LOW: + { + MrvlIEtypes_RssiThreshold_t + *low_rssi + = + (MrvlIEtypes_RssiThreshold_t + *)(buf + + + len); + printf("Beacon Low RSSI\t%d\t%d\t%s\n", low_rssi->RSSI_value, low_rssi->RSSI_freq, (le16_to_cpu(se->events) & 0x0001) ? "yes" : "no"); + break; + } + case TLV_TYPE_SNR_LOW: + { + MrvlIEtypes_SnrThreshold_t + *low_snr + = + (MrvlIEtypes_SnrThreshold_t + *)(buf + + + len); + printf("Beacon Low SNR\t%d\t%d\t%s\n", low_snr->SNR_value, low_snr->SNR_freq, (le16_to_cpu(se->events) & 0x0002) ? "yes" : "no"); + break; + } + case TLV_TYPE_FAILCOUNT: + { + MrvlIEtypes_FailureCount_t + *failure_count + = + (MrvlIEtypes_FailureCount_t + *)(buf + + + len); + printf("Failure Count\t%d\t%d\t%s\n", failure_count->fail_value, failure_count->fail_freq, (le16_to_cpu(se->events) & 0x0004) ? "yes" : "no"); + break; + } + case TLV_TYPE_BCNMISS: + { + MrvlIEtypes_BeaconsMissed_t + *bcn_missed + = + (MrvlIEtypes_BeaconsMissed_t + *)(buf + + + len); + printf("Beacon Missed\t%d\tN/A\t%s\n", bcn_missed->beacon_missed, (le16_to_cpu(se->events) & 0x0008) ? "yes" : "no"); + break; + } + case TLV_TYPE_RSSI_HIGH: + { + MrvlIEtypes_RssiThreshold_t + *high_rssi + = + (MrvlIEtypes_RssiThreshold_t + *)(buf + + + len); + printf("Bcn High RSSI\t%d\t%d\t%s\n", high_rssi->RSSI_value, high_rssi->RSSI_freq, (le16_to_cpu(se->events) & 0x0010) ? "yes" : "no"); + break; + } + + case TLV_TYPE_SNR_HIGH: + { + MrvlIEtypes_SnrThreshold_t + *high_snr + = + (MrvlIEtypes_SnrThreshold_t + *)(buf + + + len); + printf("Beacon High SNR\t%d\t%d\t%s\n", high_snr->SNR_value, high_snr->SNR_freq, (le16_to_cpu(se->events) & 0x0020) ? "yes" : "no"); + break; + } + case TLV_TYPE_RSSI_LOW_DATA: + { + MrvlIEtypes_RssiThreshold_t + *low_rssi + = + (MrvlIEtypes_RssiThreshold_t + *)(buf + + + len); + printf("Data Low RSSI\t%d\t%d\t%s\n", low_rssi->RSSI_value, low_rssi->RSSI_freq, (le16_to_cpu(se->events) & 0x0040) ? "yes" : "no"); + break; + } + case TLV_TYPE_SNR_LOW_DATA: + { + MrvlIEtypes_SnrThreshold_t + *low_snr + = + (MrvlIEtypes_SnrThreshold_t + *)(buf + + + len); + printf("Data Low SNR\t%d\t%d\t%s\n", low_snr->SNR_value, low_snr->SNR_freq, (le16_to_cpu(se->events) & 0x0080) ? "yes" : "no"); + break; + } + case TLV_TYPE_RSSI_HIGH_DATA: + { + MrvlIEtypes_RssiThreshold_t + *high_rssi + = + (MrvlIEtypes_RssiThreshold_t + *)(buf + + + len); + printf("Data High RSSI\t%d\t%d\t%s\n", high_rssi->RSSI_value, high_rssi->RSSI_freq, (le16_to_cpu(se->events) & 0x0100) ? "yes" : "no"); + break; + } + case TLV_TYPE_SNR_HIGH_DATA: + { + MrvlIEtypes_SnrThreshold_t + *high_snr + = + (MrvlIEtypes_SnrThreshold_t + *)(buf + + + len); + printf("Data High SNR\t%d\t%d\t%s\n", high_snr->SNR_value, high_snr->SNR_freq, (le16_to_cpu(se->events) & 0x0200) ? "yes" : "no"); + break; + } + case TLV_TYPE_LINK_QUALITY: + { + MrvlIEtypes_LinkQuality_t + *link_qual + = + (MrvlIEtypes_LinkQuality_t + *)(buf + + + len); + printf("Link Quality Parameters:\n"); + printf("------------------------\n"); + printf("Link Quality Event Subscribed\t%s\n", (le16_to_cpu(se->events) & 0x0400) ? "yes" : "no"); + printf("Link SNR Threshold = %d\n", le16_to_cpu(link_qual->link_SNR_thrs)); + printf("Link SNR Frequency = %d\n", le16_to_cpu(link_qual->link_SNR_freq)); + printf("Min Rate Value = %d\n", le16_to_cpu(link_qual->min_rate_val)); + printf("Min Rate Frequency = %d\n", le16_to_cpu(link_qual->min_rate_freq)); + printf("Tx Latency Value = %d\n", le32_to_cpu(link_qual->tx_latency_val)); + printf("Tx Latency Threshold = %d\n", le32_to_cpu(link_qual->tx_latency_thrs)); + + break; + } + case TLV_TYPE_PRE_BEACON_LOST: + { + MrvlIEtypes_PreBeaconLost_t + *pre_bcn_lost + = + (MrvlIEtypes_PreBeaconLost_t + *)(buf + + + len); + printf("------------------------\n"); + printf("Pre-Beacon Lost Event Subscribed\t%s\n", (le16_to_cpu(se->events) & 0x0800) ? "yes" : "no"); + printf("Pre-Beacon Lost: %d\n", pre_bcn_lost->pre_beacon_lost); + break; + } + default: + printf("Unknown subscribed event TLV Type=%#x," " Len=%d\n", le16_to_cpu(header->type), le16_to_cpu(header->len)); + break; + } + + len += (sizeof + (MrvlIEtypesHeader_t) + + + le16_to_cpu(header-> + len)); + } + } + 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: + { + HostCmd_DS_REG *preg = + (HostCmd_DS_REG *)(buf + S_DS_GEN); + preg->action = le16_to_cpu(preg->action); + if (preg->action == HostCmd_ACT_GEN_GET) { + preg->value = le32_to_cpu(preg->value); + printf("value = 0x%08x\n", preg->value); + } + break; + } + case HostCmd_CMD_MEM_ACCESS: + { + HostCmd_DS_MEM *pmem = + (HostCmd_DS_MEM *)(buf + S_DS_GEN); + pmem->action = le16_to_cpu(pmem->action); + if (pmem->action == HostCmd_ACT_GEN_GET) { + pmem->value = le32_to_cpu(pmem->value); + printf("value = 0x%08x\n", pmem->value); + } + break; + } + case HostCmd_CMD_LINK_STATS_SUMMARY: + { + HostCmd_DS_LINK_STATS_SUMMARY *linkstats = + (HostCmd_DS_LINK_STATS_SUMMARY *)(buf + + S_DS_GEN); + /* GET operation */ + printf("Link Statistics: \n"); + /* format */ + printf("Duration: %u\n", + (int)le32_to_cpu(linkstats-> + timeSinceLastQuery_ms)); + + printf("Beacon count: %u\n", + le16_to_cpu(linkstats->bcnCnt)); + printf("Beacon missing: %u\n", + le16_to_cpu(linkstats->bcnMiss)); + printf("Beacon RSSI avg: %d\n", + le16_to_cpu(linkstats->bcnRssiAvg)); + printf("Beacon SNR avg: %d\n", + le16_to_cpu(linkstats->bcnSnrAvg)); + + printf("Rx packets: %u\n", + (int)le32_to_cpu(linkstats->rxPkts)); + printf("Rx RSSI avg: %d\n", + le16_to_cpu(linkstats->rxRssiAvg)); + printf("Rx SNR avg: %d\n", + le16_to_cpu(linkstats->rxSnrAvg)); + + printf("Tx packets: %u\n", + (int)le32_to_cpu(linkstats->txPkts)); + printf("Tx Attempts: %u\n", + (int)le32_to_cpu(linkstats->txAttempts)); + printf("Tx Failures: %u\n", + (int)le32_to_cpu(linkstats->txFailures)); + printf("Tx Initial Rate: %s\n", + rateIdStr[linkstats->txInitRate]); + + printf("Tx AC VO: %u [ %u ]\n", + le16_to_cpu(linkstats-> + txQueuePktCnt[WMM_AC_VO]), + (int)le32_to_cpu(linkstats-> + txQueueDelay[WMM_AC_VO]) + / 1000); + printf("Tx AC VI: %u [ %u ]\n", + le16_to_cpu(linkstats-> + txQueuePktCnt[WMM_AC_VI]), + (int)le32_to_cpu(linkstats-> + txQueueDelay[WMM_AC_VI]) + / 1000); + printf("Tx AC BE: %u [ %u ]\n", + le16_to_cpu(linkstats-> + txQueuePktCnt[WMM_AC_BE]), + (int)le32_to_cpu(linkstats-> + txQueueDelay[WMM_AC_BE]) + / 1000); + printf("Tx AC BK: %u [ %u ]\n", + le16_to_cpu(linkstats-> + txQueuePktCnt[WMM_AC_BK]), + (int)le32_to_cpu(linkstats-> + txQueueDelay[WMM_AC_BK]) + / 1000); + break; + } + case HostCmd_CMD_WMM_PARAM_CONFIG: + { + HostCmd_DS_WMM_PARAM_CONFIG *wmm_param = + (HostCmd_DS_WMM_PARAM_CONFIG *) (buf + + S_DS_GEN); + printf("WMM Params: \n"); + printf("\tBE: AIFSN=%d, CW_MAX=%d CW_MIN=%d, TXOP=%d\n", wmm_param->ac_params[AC_BE].aci_aifsn.aifsn, wmm_param->ac_params[AC_BE].ecw.ecw_max, wmm_param->ac_params[AC_BE].ecw.ecw_min, le16_to_cpu(wmm_param->ac_params[AC_BE].tx_op_limit)); + printf("\tBK: AIFSN=%d, CW_MAX=%d CW_MIN=%d, TXOP=%d\n", wmm_param->ac_params[AC_BK].aci_aifsn.aifsn, wmm_param->ac_params[AC_BK].ecw.ecw_max, wmm_param->ac_params[AC_BK].ecw.ecw_min, le16_to_cpu(wmm_param->ac_params[AC_BK].tx_op_limit)); + printf("\tVI: AIFSN=%d, CW_MAX=%d CW_MIN=%d, TXOP=%d\n", wmm_param->ac_params[AC_VI].aci_aifsn.aifsn, wmm_param->ac_params[AC_VI].ecw.ecw_max, wmm_param->ac_params[AC_VI].ecw.ecw_min, le16_to_cpu(wmm_param->ac_params[AC_VI].tx_op_limit)); + printf("\tVO: AIFSN=%d, CW_MAX=%d CW_MIN=%d, TXOP=%d\n", wmm_param->ac_params[AC_VO].aci_aifsn.aifsn, wmm_param->ac_params[AC_VO].ecw.ecw_max, wmm_param->ac_params[AC_VO].ecw.ecw_min, le16_to_cpu(wmm_param->ac_params[AC_VO].tx_op_limit)); + break; + } + default: + printf("HOSTCMD_RESP: CmdCode=%#04x, Size=%#04x," + " SeqNum=%#04x, Result=%#04x\n", + hostcmd->command, hostcmd->size, + hostcmd->seq_num, hostcmd->result); + hexdump("payload", + (t_void *)(buf + S_DS_GEN), + hostcmd->size - S_DS_GEN, ' '); + break; + } + } else { + printf("HOSTCMD failed: CmdCode=%#04x, Size=%#04x," + " SeqNum=%#04x, Result=%#04x\n", + hostcmd->command, hostcmd->size, + hostcmd->seq_num, hostcmd->result); + } + return ret; +} + +/** + * @brief Trims leading and traling spaces only + * @param str A pointer to argument string + * @return pointer to trimmed string + */ +char * +trim_spaces(char *str) +{ + char *str_end = NULL; + + if (!str) + return NULL; + + /* Trim leading spaces */ + while (!*str && isspace(*str)) + str++; + + if (*str == 0) /* All spaces? */ + return str; + + /* Trim trailing spaces */ + str_end = str + strlen(str) - 1; + while (str_end > str && isspace(*str_end)) + str_end--; + + /* null terminate the string */ + *(str_end + 1) = '\0'; + + return str; +} + +/** + * @brief Process hostcmd command + * @param argc Number of arguments + * @param argv A pointer to arguments array + * @return MLAN_STATUS_SUCCESS--success, otherwise--fail + */ +static int +process_hostcmd(int argc, char *argv[]) +{ + t_u8 *buffer = NULL, *raw_buf = NULL; + struct eth_priv_cmd *cmd = NULL; + struct ifreq ifr; + FILE *fp = NULL; + FILE *fp_raw = NULL; + FILE *fp_dtsi = NULL; + char cmdname[256]; + boolean call_ioctl = TRUE; + t_u32 buf_len = 0, i, j, k; + char *line = NULL, *pos = NULL; + int li = 0, blk_count = 0, ob = 0; + int ret = MLAN_STATUS_SUCCESS; + + struct cmd_node { + char cmd_string[256]; + struct cmd_node *next; + }; + struct cmd_node *command = NULL, *header = NULL, *new_node = NULL; + + if (argc < 5) { + printf("Error: invalid no of arguments\n"); + printf("Syntax: ./mlanutl mlanX hostcmd \n"); + ret = MLAN_STATUS_FAILURE; + goto done; + } + + snprintf(cmdname, sizeof(cmdname), "%s", argv[4]); + + if (!strcmp(cmdname, "generate_raw")) { + call_ioctl = FALSE; + } + + if (!call_ioctl && argc != 6) { + printf("Error: invalid no of arguments\n"); + printf("Syntax: ./mlanutl mlanX hostcmd %s \n", cmdname); + ret = MLAN_STATUS_FAILURE; + goto done; + } + + fp = fopen(argv[3], "r"); + if (fp == NULL) { + fprintf(stderr, "Cannot open file %s\n", argv[3]); + ret = MLAN_STATUS_FAILURE; + goto done; + } + + /* Initialize buffer */ + buffer = (t_u8 *)malloc(BUFFER_LENGTH); + if (!buffer) { + printf("ERR:Cannot allocate buffer for command!\n"); + fclose(fp); + ret = MLAN_STATUS_FAILURE; + goto done; + } + memset(buffer, 0, BUFFER_LENGTH); + + if (call_ioctl) { + /* Prepare the hostcmd buffer */ + prepare_buffer(buffer, argv[2], 0, NULL); + if (MLAN_STATUS_FAILURE == + prepare_host_cmd_buffer(fp, cmdname, + buffer + strlen(CMD_NXP) + + strlen(argv[2]))) { + fclose(fp); + ret = MLAN_STATUS_FAILURE; + goto done; + } + fclose(fp); + } else { + line = (char *)malloc(MAX_CONFIG_LINE); + if (!line) { + printf("ERR:Cannot allocate memory for line\n"); + fclose(fp); + ret = MLAN_STATUS_FAILURE; + goto done; + } + memset(line, 0, MAX_CONFIG_LINE); + + while (config_get_line(line, MAX_CONFIG_LINE, fp, &li, &pos)) { + line = trim_spaces(line); + if (line[strlen(line) - 1] == '{') { + if (ob == 0) { + new_node = + (struct cmd_node *) + malloc(sizeof(struct cmd_node)); + if (!new_node) { + printf("ERR:Cannot allocate memory for cmd_node\n"); + fclose(fp); + ret = MLAN_STATUS_FAILURE; + goto done; + } + memset(new_node, 0, + sizeof(struct cmd_node)); + new_node->next = NULL; + if (blk_count == 0) { + header = new_node; + command = new_node; + } else { + command->next = new_node; + command = new_node; + } + strncpy(command->cmd_string, line, + (strchr(line, '=') - line)); + memmove(command->cmd_string, + trim_spaces(command-> + cmd_string), + strlen(trim_spaces + (command->cmd_string)) + + 1); + } + ob++; + continue; /* goto while() */ + } + if (line[strlen(line) - 1] == '}') { + ob--; + if (ob == 0) + blk_count++; + continue; /* goto while() */ + } + } + + rewind(fp); /* Set the source file pointer to the beginning again */ + command = header; /* Set 'command' at the beginning of the command list */ + + fp_raw = fopen(argv[5], "w"); + if (fp_raw == NULL) { + fprintf(stderr, + "Cannot open the destination raw_data file %s\n", + argv[5]); + fclose(fp); + ret = MLAN_STATUS_FAILURE; + goto done; + } + + /* prepare .dtsi output */ + snprintf(cmdname, sizeof(cmdname), "%s.dtsi", argv[5]); + fp_dtsi = fopen(cmdname, "w"); + if (fp_dtsi == NULL) { + fprintf(stderr, "Cannot open the destination file %s\n", + cmdname); + fclose(fp); + fclose(fp_raw); + ret = MLAN_STATUS_FAILURE; + goto done; + } + + for (k = 0; k < blk_count && command != NULL; k++) { + if (MLAN_STATUS_FAILURE == + prepare_host_cmd_buffer(fp, command->cmd_string, + buffer)) + memset(buffer, 0, BUFFER_LENGTH); + + memcpy(&buf_len, buffer, sizeof(t_u32)); + if (buf_len) { + raw_buf = buffer + sizeof(t_u32); /* raw_buf points to start of actual */ + printf("buf_len = %d\n", (int)buf_len); + if (k > 0) + fprintf(fp_raw, "\n\n"); + fprintf(fp_raw, "%s={\n", command->cmd_string); + fprintf(fp_dtsi, + "/ {\n\tmarvell_cfgdata {\n\t\tmarvell,%s = /bits/ 8 <\n", + command->cmd_string); + i = j = 0; + while (i < buf_len) { + for (j = 0; j < 16; j++) { + fprintf(fp_raw, "%02x ", + *(raw_buf + i)); + if (i >= 8) { + fprintf(fp_dtsi, + "0x%02x", + *(raw_buf + i)); + if ((j < 16 - 1) && + (i < buf_len - 1)) + fprintf(fp_dtsi, + " "); + } + if (++i >= buf_len) + break; + } + fputc('\n', fp_raw); + fputc('\n', fp_dtsi); + } + fprintf(fp_raw, "}"); + fprintf(fp_dtsi, "\t\t>;\n\t};\n};\n"); + } + command = command->next; + rewind(fp); + } + + fclose(fp_dtsi); + fclose(fp_raw); + fclose(fp); + } + + if (call_ioctl) { + cmd = (struct eth_priv_cmd *) + malloc(sizeof(struct eth_priv_cmd)); + if (!cmd) { + printf("ERR:Cannot allocate buffer for command!\n"); + ret = MLAN_STATUS_FAILURE; + goto done; + } + + /* Fill up buffer */ +#ifdef USERSPACE_32BIT_OVER_KERNEL_64BIT + memset(cmd, 0, sizeof(struct eth_priv_cmd)); + memcpy(&cmd->buf, &buffer, sizeof(buffer)); +#else + cmd->buf = buffer; +#endif + cmd->used_len = 0; + cmd->total_len = BUFFER_LENGTH; + + /* Perform IOCTL */ + memset(&ifr, 0, sizeof(struct ifreq)); + strncpy(ifr.ifr_ifrn.ifrn_name, dev_name, strlen(dev_name)); + ifr.ifr_ifru.ifru_data = (void *)cmd; + + if (ioctl(sockfd, MLAN_ETH_PRIV, &ifr)) { + perror("mlanutl"); + fprintf(stderr, "mlanutl: hostcmd fail\n"); + ret = MLAN_STATUS_FAILURE; + goto done; + } + + /* Process result */ + process_host_cmd_resp(argv[2], buffer); + } + +done: + while (header) { + command = header; + header = header->next; + free(command); + } + if (line) + free(line); + if (buffer) + free(buffer); + if (cmd) + free(cmd); + return ret; +} + +/** + * @brief Process HT Tx configuration + * @param argc Number of arguments + * @param argv A pointer to arguments array + * @return MLAN_STATUS_SUCCESS--success, otherwise--fail + */ +static int +process_httxcfg(int argc, char *argv[]) +{ + t_u8 *buffer = NULL; + t_u32 *data = NULL; + struct eth_priv_cmd *cmd = NULL; + struct ifreq ifr; + + /* Initialize buffer */ + buffer = (t_u8 *)malloc(BUFFER_LENGTH); + if (!buffer) { + printf("ERR:Cannot allocate buffer for command!\n"); + return MLAN_STATUS_FAILURE; + } + + prepare_buffer(buffer, argv[2], (argc - 3), &argv[3]); + + cmd = (struct eth_priv_cmd *)malloc(sizeof(struct eth_priv_cmd)); + if (!cmd) { + printf("ERR:Cannot allocate buffer for command!\n"); + free(buffer); + return MLAN_STATUS_FAILURE; + } + + /* Fill up buffer */ +#ifdef USERSPACE_32BIT_OVER_KERNEL_64BIT + memset(cmd, 0, sizeof(struct eth_priv_cmd)); + memcpy(&cmd->buf, &buffer, sizeof(buffer)); +#else + cmd->buf = buffer; +#endif + cmd->used_len = 0; + cmd->total_len = BUFFER_LENGTH; + + /* Perform IOCTL */ + memset(&ifr, 0, sizeof(struct ifreq)); + strncpy(ifr.ifr_ifrn.ifrn_name, dev_name, strlen(dev_name)); + ifr.ifr_ifru.ifru_data = (void *)cmd; + + if (ioctl(sockfd, MLAN_ETH_PRIV, &ifr)) { + perror("mlanutl"); + fprintf(stderr, "mlanutl: httxcfg fail\n"); + if (cmd) + free(cmd); + if (buffer) + free(buffer); + return MLAN_STATUS_FAILURE; + } + + if (argc == 3) { + /* Get result */ + data = (t_u32 *)buffer; + printf("HT Tx cfg: \n"); + printf(" BG band: 0x%08x\n", data[0]); + printf(" A band: 0x%08x\n", data[1]); + } + + if (buffer) + free(buffer); + if (cmd) + free(cmd); + + return MLAN_STATUS_SUCCESS; +} + +/** + * @brief Process HT capability configuration + * @param argc Number of arguments + * @param argv A pointer to arguments array + * @return MLAN_STATUS_SUCCESS--success, otherwise--fail + */ +static int +process_htcapinfo(int argc, char *argv[]) +{ + t_u8 *buffer = NULL; + struct eth_priv_cmd *cmd = NULL; + struct eth_priv_htcapinfo *ht_cap = NULL; + struct ifreq ifr; + + /* Initialize buffer */ + buffer = (t_u8 *)malloc(BUFFER_LENGTH); + if (!buffer) { + printf("ERR:Cannot allocate buffer for command!\n"); + return MLAN_STATUS_FAILURE; + } + + prepare_buffer(buffer, argv[2], (argc - 3), &argv[3]); + + cmd = (struct eth_priv_cmd *)malloc(sizeof(struct eth_priv_cmd)); + if (!cmd) { + printf("ERR:Cannot allocate buffer for command!\n"); + free(buffer); + return MLAN_STATUS_FAILURE; + } + + /* Fill up buffer */ +#ifdef USERSPACE_32BIT_OVER_KERNEL_64BIT + memset(cmd, 0, sizeof(struct eth_priv_cmd)); + memcpy(&cmd->buf, &buffer, sizeof(buffer)); +#else + cmd->buf = buffer; +#endif + cmd->used_len = 0; + cmd->total_len = BUFFER_LENGTH; + + /* Perform IOCTL */ + memset(&ifr, 0, sizeof(struct ifreq)); + strncpy(ifr.ifr_ifrn.ifrn_name, dev_name, strlen(dev_name)); + ifr.ifr_ifru.ifru_data = (void *)cmd; + + if (ioctl(sockfd, MLAN_ETH_PRIV, &ifr)) { + perror("mlanutl"); + fprintf(stderr, "mlanutl: htcapinfo fail\n"); + if (cmd) + free(cmd); + if (buffer) + free(buffer); + return MLAN_STATUS_FAILURE; + } + + /* Process result */ + if (argc == 3) { + ht_cap = (struct eth_priv_htcapinfo *)buffer; + printf("HT cap info: \n"); + printf(" BG band: 0x%08x\n", ht_cap->ht_cap_info_bg); + printf(" A band: 0x%08x\n", ht_cap->ht_cap_info_a); + } + + if (buffer) + free(buffer); + if (cmd) + free(cmd); + + return MLAN_STATUS_SUCCESS; +} + +/** + * @brief Process HT Add BA parameters + * @param argc Number of arguments + * @param argv A pointer to arguments array + * @return MLAN_STATUS_SUCCESS--success, otherwise--fail + */ +static int +process_addbapara(int argc, char *argv[]) +{ + t_u8 *buffer = NULL; + struct eth_priv_cmd *cmd = NULL; + struct ifreq ifr; + struct eth_priv_addba *addba = NULL; + + /* Initialize buffer */ + buffer = (t_u8 *)malloc(BUFFER_LENGTH); + if (!buffer) { + printf("ERR:Cannot allocate buffer for command!\n"); + return MLAN_STATUS_FAILURE; + } + + prepare_buffer(buffer, argv[2], (argc - 3), &argv[3]); + + cmd = (struct eth_priv_cmd *)malloc(sizeof(struct eth_priv_cmd)); + if (!cmd) { + printf("ERR:Cannot allocate buffer for command!\n"); + free(buffer); + return MLAN_STATUS_FAILURE; + } + + /* Fill up buffer */ +#ifdef USERSPACE_32BIT_OVER_KERNEL_64BIT + memset(cmd, 0, sizeof(struct eth_priv_cmd)); + memcpy(&cmd->buf, &buffer, sizeof(buffer)); +#else + cmd->buf = buffer; +#endif + cmd->used_len = 0; + cmd->total_len = BUFFER_LENGTH; + + /* Perform IOCTL */ + memset(&ifr, 0, sizeof(struct ifreq)); + strncpy(ifr.ifr_ifrn.ifrn_name, dev_name, strlen(dev_name)); + ifr.ifr_ifru.ifru_data = (void *)cmd; + + if (ioctl(sockfd, MLAN_ETH_PRIV, &ifr)) { + perror("mlanutl"); + fprintf(stderr, "mlanutl: addbapara fail\n"); + if (cmd) + free(cmd); + if (buffer) + free(buffer); + return MLAN_STATUS_FAILURE; + } + + if (argc == 3) { + /* Get */ + addba = (struct eth_priv_addba *)buffer; + printf("Add BA configuration: \n"); + printf(" Time out : %d\n", addba->time_out); + printf(" TX window: %d\n", addba->tx_win_size); + printf(" RX window: %d\n", addba->rx_win_size); + printf(" TX AMSDU : %d\n", addba->tx_amsdu); + printf(" RX AMSDU : %d\n", addba->rx_amsdu); + } + + if (buffer) + free(buffer); + if (cmd) + free(cmd); + + return MLAN_STATUS_SUCCESS; +} + +/** + * @brief Process Aggregation priority table parameters + * @param argc Number of arguments + * @param argv A pointer to arguments array + * @return MLAN_STATUS_SUCCESS--success, otherwise--fail + */ +static int +process_aggrpriotbl(int argc, char *argv[]) +{ + t_u8 *buffer = NULL; + struct eth_priv_cmd *cmd = NULL; + struct ifreq ifr; + int i; + + /* Initialize buffer */ + buffer = (t_u8 *)malloc(BUFFER_LENGTH); + if (!buffer) { + printf("ERR:Cannot allocate buffer for command!\n"); + return MLAN_STATUS_FAILURE; + } + + prepare_buffer(buffer, argv[2], (argc - 3), &argv[3]); + + cmd = (struct eth_priv_cmd *)malloc(sizeof(struct eth_priv_cmd)); + if (!cmd) { + printf("ERR:Cannot allocate buffer for command!\n"); + free(buffer); + return MLAN_STATUS_FAILURE; + } + + /* Fill up buffer */ +#ifdef USERSPACE_32BIT_OVER_KERNEL_64BIT + memset(cmd, 0, sizeof(struct eth_priv_cmd)); + memcpy(&cmd->buf, &buffer, sizeof(buffer)); +#else + cmd->buf = buffer; +#endif + cmd->used_len = 0; + cmd->total_len = BUFFER_LENGTH; + + /* Perform IOCTL */ + memset(&ifr, 0, sizeof(struct ifreq)); + strncpy(ifr.ifr_ifrn.ifrn_name, dev_name, strlen(dev_name)); + ifr.ifr_ifru.ifru_data = (void *)cmd; + + if (ioctl(sockfd, MLAN_ETH_PRIV, &ifr)) { + perror("mlanutl"); + fprintf(stderr, "mlanutl: aggrpriotbl fail\n"); + if (cmd) + free(cmd); + if (buffer) + free(buffer); + return MLAN_STATUS_FAILURE; + } + + if (argc == 3) { + /* Get */ + printf("Aggregation priority table cfg: \n"); + printf(" TID AMPDU AMSDU \n"); + for (i = 0; i < MAX_NUM_TID; i++) { + printf(" %d %3d %3d \n", + i, buffer[2 * i], buffer[2 * i + 1]); + } + } + + if (buffer) + free(buffer); + if (cmd) + free(cmd); + + return MLAN_STATUS_SUCCESS; +} + +/** + * @brief Process HT Add BA reject configurations + * @param argc Number of arguments + * @param argv A pointer to arguments array + * @return MLAN_STATUS_SUCCESS--success, otherwise--fail + */ +static int +process_addbareject(int argc, char *argv[]) +{ + t_u8 *buffer = NULL; + struct eth_priv_cmd *cmd = NULL; + struct ifreq ifr; + int i; + + /* Initialize buffer */ + buffer = (t_u8 *)malloc(BUFFER_LENGTH); + if (!buffer) { + printf("ERR:Cannot allocate buffer for command!\n"); + return MLAN_STATUS_FAILURE; + } + + prepare_buffer(buffer, argv[2], (argc - 3), &argv[3]); + + cmd = (struct eth_priv_cmd *)malloc(sizeof(struct eth_priv_cmd)); + if (!cmd) { + printf("ERR:Cannot allocate buffer for command!\n"); + free(buffer); + return MLAN_STATUS_FAILURE; + } + + /* Fill up buffer */ +#ifdef USERSPACE_32BIT_OVER_KERNEL_64BIT + memset(cmd, 0, sizeof(struct eth_priv_cmd)); + memcpy(&cmd->buf, &buffer, sizeof(buffer)); +#else + cmd->buf = buffer; +#endif + cmd->used_len = 0; + cmd->total_len = BUFFER_LENGTH; + + /* Perform IOCTL */ + memset(&ifr, 0, sizeof(struct ifreq)); + strncpy(ifr.ifr_ifrn.ifrn_name, dev_name, strlen(dev_name)); + ifr.ifr_ifru.ifru_data = (void *)cmd; + + if (ioctl(sockfd, MLAN_ETH_PRIV, &ifr)) { + perror("mlanutl"); + fprintf(stderr, "mlanutl: addbareject fail\n"); + if (cmd) + free(cmd); + if (buffer) + free(buffer); + return MLAN_STATUS_FAILURE; + } + + if (argc == 3) { + /* Get */ + printf("Add BA reject configuration: \n"); + printf(" TID Reject \n"); + for (i = 0; i < MAX_NUM_TID; i++) { + printf(" %d %d\n", i, buffer[i]); + } + } + + if (buffer) + free(buffer); + if (cmd) + free(cmd); + + return MLAN_STATUS_SUCCESS; +} + +/** + * @brief Process HT Del BA command + * @param argc Number of arguments + * @param argv A pointer to arguments array + * @return MLAN_STATUS_SUCCESS--success, otherwise--fail + */ +static int +process_delba(int argc, char *argv[]) +{ + t_u8 *buffer = NULL; + struct eth_priv_cmd *cmd = NULL; + struct ifreq ifr; + + /* Initialize buffer */ + buffer = (t_u8 *)malloc(BUFFER_LENGTH); + if (!buffer) { + printf("ERR:Cannot allocate buffer for command!\n"); + return MLAN_STATUS_FAILURE; + } + + prepare_buffer(buffer, argv[2], (argc - 3), &argv[3]); + + cmd = (struct eth_priv_cmd *)malloc(sizeof(struct eth_priv_cmd)); + if (!cmd) { + printf("ERR:Cannot allocate buffer for command!\n"); + free(buffer); + return MLAN_STATUS_FAILURE; + } + + /* Fill up buffer */ +#ifdef USERSPACE_32BIT_OVER_KERNEL_64BIT + memset(cmd, 0, sizeof(struct eth_priv_cmd)); + memcpy(&cmd->buf, &buffer, sizeof(buffer)); +#else + cmd->buf = buffer; +#endif + cmd->used_len = 0; + cmd->total_len = BUFFER_LENGTH; + + /* Perform IOCTL */ + memset(&ifr, 0, sizeof(struct ifreq)); + strncpy(ifr.ifr_ifrn.ifrn_name, dev_name, strlen(dev_name)); + ifr.ifr_ifru.ifru_data = (void *)cmd; + + if (ioctl(sockfd, MLAN_ETH_PRIV, &ifr)) { + perror("mlanutl"); + fprintf(stderr, "mlanutl: delba fail\n"); + if (cmd) + free(cmd); + if (buffer) + free(buffer); + return MLAN_STATUS_FAILURE; + } + + if (buffer) + free(buffer); + if (cmd) + free(cmd); + + return MLAN_STATUS_SUCCESS; +} + +/** + * @brief Process reject addba req command + * @param argc Number of arguments + * @param argv A pointer to arguments array + * @return MLAN_STATUS_SUCCESS--success, otherwise--fail + */ +static int +process_rejectaddbareq(int argc, char *argv[]) +{ + t_u8 *buffer = NULL; + struct eth_priv_cmd *cmd = NULL; + struct ifreq ifr; + + /* Initialize buffer */ + buffer = (t_u8 *)malloc(BUFFER_LENGTH); + if (!buffer) { + printf("ERR:Cannot allocate buffer for command!\n"); + return MLAN_STATUS_FAILURE; + } + + prepare_buffer(buffer, argv[2], (argc - 3), &argv[3]); + + cmd = (struct eth_priv_cmd *)malloc(sizeof(struct eth_priv_cmd)); + if (!cmd) { + printf("ERR:Cannot allocate buffer for command!\n"); + free(buffer); + return MLAN_STATUS_FAILURE; + } + + /* Fill up buffer */ +#ifdef USERSPACE_32BIT_OVER_KERNEL_64BIT + memset(cmd, 0, sizeof(struct eth_priv_cmd)); + memcpy(&cmd->buf, &buffer, sizeof(buffer)); +#else + cmd->buf = buffer; +#endif + cmd->used_len = 0; + cmd->total_len = BUFFER_LENGTH; + + /* Perform IOCTL */ + memset(&ifr, 0, sizeof(struct ifreq)); + strncpy(ifr.ifr_ifrn.ifrn_name, dev_name, strlen(dev_name)); + ifr.ifr_ifru.ifru_data = (void *)cmd; + + if (ioctl(sockfd, MLAN_ETH_PRIV, &ifr)) { + perror("mlanutl"); + fprintf(stderr, "mlanutl: rejectaddbareq fail\n"); + if (cmd) + free(cmd); + if (buffer) + free(buffer); + return MLAN_STATUS_FAILURE; + } + + /* Process result */ + printf("Reject addba req command response: %s\n", buffer); + + if (buffer) + free(buffer); + if (cmd) + free(cmd); + + return MLAN_STATUS_SUCCESS; +} + +/** + * @brief Implement Minimum BA Threshold command + * @param argc Number of arguments + * @param argv A pointer to arguments array + * @return MLAN_STATUS_SUCCESS--success, otherwise--fail + */ +static int +process_min_ba_threshold_cfg(int argc, char *argv[]) +{ + int ret = 0; + t_u8 min_ba_thres = 0; + t_u8 *buffer = NULL; + struct eth_priv_cmd *cmd = NULL; + struct ifreq ifr; + + /* Initialize buffer */ + buffer = (t_u8 *)malloc(BUFFER_LENGTH); + if (!buffer) { + printf("ERR:Cannot allocate buffer for command!\n"); + ret = MLAN_STATUS_FAILURE; + goto done; + } + memset(buffer, 0, BUFFER_LENGTH); + + /* Sanity tests */ + if (argc < 3 || argc > 4) { + printf("Error: invalid no of arguments\n"); + printf("mlanutl mlanX min_ba_threshold [#]\n"); + ret = MLAN_STATUS_FAILURE; + goto done; + } + + prepare_buffer(buffer, argv[2], (argc - 3), &argv[3]); + + cmd = (struct eth_priv_cmd *)malloc(sizeof(struct eth_priv_cmd)); + if (!cmd) { + printf("ERR:Cannot allocate buffer for command!\n"); + ret = MLAN_STATUS_FAILURE; + goto done; + } + + /* Fill up buffer */ +#ifdef USERSPACE_32BIT_OVER_KERNEL_64BIT + memset(cmd, 0, sizeof(struct eth_priv_cmd)); + memcpy(&cmd->buf, &buffer, sizeof(buffer)); +#else + cmd->buf = buffer; +#endif + cmd->used_len = 0; + cmd->total_len = BUFFER_LENGTH; + + /* Perform IOCTL */ + memset(&ifr, 0, sizeof(struct ifreq)); + strncpy(ifr.ifr_ifrn.ifrn_name, dev_name, strlen(dev_name)); + ifr.ifr_ifru.ifru_data = (void *)cmd; + + if (ioctl(sockfd, MLAN_ETH_PRIV, &ifr)) { + perror("mlanutl"); + fprintf(stderr, "mlanutl: min_ba_threshold fail\n"); + ret = MLAN_STATUS_FAILURE; + goto done; + } + + /* Process result */ + if (argc == 3) { + memcpy(&min_ba_thres, buffer, sizeof(min_ba_thres)); + printf("Min Tx BA Threshold: %d\n", min_ba_thres); + } + +done: + if (buffer) + free(buffer); + if (cmd) + free(cmd); + + return ret; +} + +/** + * @brief Process VHT configuration + * @param argc Number of arguments + * @param argv A pointer to arguments array + * @return MLAN_STATUS_SUCCESS--success, otherwise--fail + */ +static int +process_vhtcfg(int argc, char *argv[]) +{ + t_u8 *buffer = NULL; + struct eth_priv_cmd *cmd = NULL; + struct eth_priv_vhtcfg vhtcfg; + struct ifreq ifr; + t_u8 i, num = 0; + + /* Initialize buffer */ + buffer = (t_u8 *)malloc(BUFFER_LENGTH); + if (!buffer) { + printf("ERR:Cannot allocate buffer for command!\n"); + return MLAN_STATUS_FAILURE; + } + + /* Sanity tests */ + if (argc < 5) { + printf("Insufficient parameters\n"); + printf("For STA interface: mlanutl mlanX vhtcfg [bwcfg] [vhtcap]\n"); + printf("For uAP interface: mlanutl uapX vhtcfg [bwcfg] [vhtcap] [vht_tx_mcs] [vht_rx_mcs]\n"); + free(buffer); + return MLAN_STATUS_FAILURE; + } + + prepare_buffer(buffer, argv[2], (argc - 3), &argv[3]); + + cmd = (struct eth_priv_cmd *)malloc(sizeof(struct eth_priv_cmd)); + if (!cmd) { + printf("ERR:Cannot allocate buffer for command!\n"); + free(buffer); + return MLAN_STATUS_FAILURE; + } + + /* Fill up buffer */ +#ifdef USERSPACE_32BIT_OVER_KERNEL_64BIT + memset(cmd, 0, sizeof(struct eth_priv_cmd)); + memcpy(&cmd->buf, &buffer, sizeof(buffer)); +#else + cmd->buf = buffer; +#endif + cmd->used_len = 0; + cmd->total_len = BUFFER_LENGTH; + + /* Perform IOCTL */ + memset(&ifr, 0, sizeof(struct ifreq)); + strncpy(ifr.ifr_ifrn.ifrn_name, dev_name, strlen(dev_name)); + ifr.ifr_ifru.ifru_data = (void *)cmd; + + if (ioctl(sockfd, MLAN_ETH_PRIV, &ifr)) { + perror("mlanutl"); + fprintf(stderr, "mlanutl: vhtcfg fail\n"); + if (cmd) + free(cmd); + if (buffer) + free(buffer); + return MLAN_STATUS_FAILURE; + } + + /* Process result */ + /* the first attribute is the number of vhtcfg entries */ + num = *buffer; + if (argc == 5) { + /* GET operation */ + printf("11AC VHT Configuration: \n"); + for (i = 0; i < num; i++) { + memcpy(&vhtcfg, buffer + 1 + i * sizeof(vhtcfg), + sizeof(vhtcfg)); + /* Band */ + if (vhtcfg.band == 1) + printf("Band: 2.4G\n"); + else + printf("Band: 5G\n"); + /* BW confi9 */ + + if (vhtcfg.bwcfg == 0) + printf(" BW config: Follow BW in the 11N config\n"); + else + printf(" BW config: Follow BW in VHT Capabilities\n"); + + /* Tx/Rx */ + if (vhtcfg.txrx & 0x1) + printf(" VHT operation for Tx: 0x%08x\n", + vhtcfg.vht_cap_info); + if (vhtcfg.txrx & 0x2) + /* VHT capabilities */ + printf(" VHT Capabilities Info: 0x%08x\n", + vhtcfg.vht_cap_info); + /* MCS */ + if (vhtcfg.txrx & 0x2) { + printf(" Tx MCS set: 0x%04x\n", + vhtcfg.vht_tx_mcs); + printf(" Rx MCS set: 0x%04x\n", + vhtcfg.vht_rx_mcs); + } + } + } else { + /* SET operation */ + } + + if (buffer) + free(buffer); + if (cmd) + free(cmd); + + return MLAN_STATUS_SUCCESS; +} + +/** + * @brief Process Operating Mode Notification configuration + * @param argc Number of arguments + * @param argv A pointer to arguments array + * @return MLAN_STATUS_SUCCESS--success, otherwise--fail + */ +static int +process_opermodecfg(int argc, char *argv[]) +{ + t_u8 *buffer = NULL; + struct eth_priv_cmd *cmd = NULL; + struct eth_priv_opermodecfg *cfg = NULL; + struct ifreq ifr; + + /* Initialize buffer */ + buffer = (t_u8 *)malloc(BUFFER_LENGTH); + if (!buffer) { + printf("ERR:Cannot allocate buffer for command!\n"); + return MLAN_STATUS_FAILURE; + } + + prepare_buffer(buffer, argv[2], (argc - 3), &argv[3]); + + cmd = (struct eth_priv_cmd *)malloc(sizeof(struct eth_priv_cmd)); + if (!cmd) { + printf("ERR:Cannot allocate buffer for command!\n"); + free(buffer); + return MLAN_STATUS_FAILURE; + } + + /* Fill up buffer */ +#ifdef USERSPACE_32BIT_OVER_KERNEL_64BIT + memset(cmd, 0, sizeof(struct eth_priv_cmd)); + memcpy(&cmd->buf, &buffer, sizeof(buffer)); +#else + cmd->buf = buffer; +#endif + cmd->used_len = 0; + cmd->total_len = BUFFER_LENGTH; + + /* Perform IOCTL */ + memset(&ifr, 0, sizeof(struct ifreq)); + strncpy(ifr.ifr_ifrn.ifrn_name, dev_name, strlen(dev_name)); + ifr.ifr_ifru.ifru_data = (void *)cmd; + + if (ioctl(sockfd, MLAN_ETH_PRIV, &ifr)) { + perror("mlanutl"); + fprintf(stderr, "mlanutl: opermodecfg fail\n"); + if (cmd) + free(cmd); + if (buffer) + free(buffer); + return MLAN_STATUS_FAILURE; + } + + /* Process result */ + cfg = (struct eth_priv_opermodecfg *)(buffer); + printf("11AC Operating Mode Notification Configuration: \n"); + printf(" bw: %d\n", cfg->bw); + printf(" nss: %d\n", cfg->nss); + + if (buffer) + free(buffer); + if (cmd) + free(cmd); + + return MLAN_STATUS_SUCCESS; +} + +static char *rate_format[4] = { "LG", "HT", "VHT", "HE" }; + +static char *lg_rate[] = { "1 Mbps", "2 Mbps", "5.5 Mbps", "11 Mbps", + "6 Mbps", "9 Mbps", "12 Mbps", "18 Mbps", + "24 Mbps", "36 Mbps", "48 Mbps", "54 Mbps" +}; + +/** + * @brief Process Get data rate + * @param argc Number of arguments + * @param argv A pointer to arguments array + * @return MLAN_STATUS_SUCCESS--success, otherwise--fail + */ +static int +process_datarate(int argc, char *argv[]) +{ + t_u8 *buffer = NULL; + struct eth_priv_cmd *cmd = NULL; + struct eth_priv_data_rate *datarate = NULL; + struct ifreq ifr; + char *bw[] = { "20 MHz", "40 MHz", "80 MHz", "160 MHz" }; + + /* Initialize buffer */ + buffer = (t_u8 *)malloc(BUFFER_LENGTH); + if (!buffer) { + printf("ERR:Cannot allocate buffer for command!\n"); + return MLAN_STATUS_FAILURE; + } + + prepare_buffer(buffer, argv[2], 0, NULL); + + cmd = (struct eth_priv_cmd *)malloc(sizeof(struct eth_priv_cmd)); + if (!cmd) { + printf("ERR:Cannot allocate buffer for command!\n"); + free(buffer); + return MLAN_STATUS_FAILURE; + } + + /* Fill up buffer */ +#ifdef USERSPACE_32BIT_OVER_KERNEL_64BIT + memset(cmd, 0, sizeof(struct eth_priv_cmd)); + memcpy(&cmd->buf, &buffer, sizeof(buffer)); +#else + cmd->buf = buffer; +#endif + cmd->used_len = 0; + cmd->total_len = BUFFER_LENGTH; + + /* Perform IOCTL */ + memset(&ifr, 0, sizeof(struct ifreq)); + strncpy(ifr.ifr_ifrn.ifrn_name, dev_name, strlen(dev_name)); + ifr.ifr_ifru.ifru_data = (void *)cmd; + + if (ioctl(sockfd, MLAN_ETH_PRIV, &ifr)) { + perror("mlanutl"); + fprintf(stderr, "mlanutl: getdatarate fail\n"); + if (cmd) + free(cmd); + if (buffer) + free(buffer); + return MLAN_STATUS_FAILURE; + } + + /* Process result */ + datarate = (struct eth_priv_data_rate *)buffer; + printf("Data Rate:\n"); + printf(" TX: \n"); + if (datarate->tx_rate_format <= 3) { + printf(" Type: %s\n", rate_format[datarate->tx_rate_format]); + if ((datarate->tx_rate_format == 0) && + datarate->tx_data_rate <= 11) + /* LG */ + printf(" Rate: %s\n", + lg_rate[datarate->tx_data_rate]); + else { + /* HT and VHT */ + if (datarate->tx_bw <= 3) + printf(" BW: %s\n", bw[datarate->tx_bw]); + if (datarate->tx_rate_format < 3) { + if (datarate->tx_gi == 0) + printf(" GI: Long\n"); + else + printf(" GI: Short\n"); + } else if (datarate->tx_rate_format == 3) { + switch (datarate->tx_gi) { + case 0: + printf(" GI: 1xHELTF + GI 0.8us \n"); + break; + case 1: + printf(" GI: 2xHELTF + GI 0.8us \n"); + break; + case 2: + printf(" GI: 2xHELTF + GI 1.6us \n"); + break; + case 3: + printf(" GI: 4xHELTF + GI 0.8us DCM=0 and STBC=0 or\n" " 4xHELTF + GI 3.2us Otherwise \n"); + break; + } + } + if (datarate->tx_rate_format >= 2) + printf(" NSS: %d\n", datarate->tx_nss + 1); + if (datarate->tx_mcs_index != 0xFF) + printf(" MCS: MCS %d\n", + (int)datarate->tx_mcs_index); + else + printf(" MCS: Auto\n"); + if (datarate->tx_rate_format < 3) + printf(" Rate: %f Mbps\n", + (float)datarate->tx_data_rate / 2); + } + } + + printf(" RX: \n"); + if (datarate->rx_rate_format <= 3) { + printf(" Type: %s\n", rate_format[datarate->rx_rate_format]); + if ((datarate->rx_rate_format == 0) && + datarate->rx_data_rate <= 11) + /* LG */ + printf(" Rate: %s\n", + lg_rate[datarate->rx_data_rate]); + else { + /* HT and VHT */ + if (datarate->rx_bw <= 3) + printf(" BW: %s\n", bw[datarate->rx_bw]); + if (datarate->rx_rate_format < 3) { + if (datarate->rx_gi == 0) + printf(" GI: Long\n"); + else + printf(" GI: Short\n"); + } else if (datarate->rx_rate_format == 3) { + switch (datarate->rx_gi) { + case 0: + printf(" GI: 1xHELTF + GI 0.8us \n"); + break; + case 1: + printf(" GI: 2xHELTF + GI 0.8us \n"); + break; + case 2: + printf(" GI: 2xHELTF + GI 1.6us \n"); + break; + case 3: + printf(" GI: 4xHELTF + GI 0.8us DCM=0 and STBC=0 or\n" " 4xHELTF + GI 3.2us Otherwise \n"); + break; + } + } + if (datarate->rx_rate_format >= 2) + printf(" NSS: %d\n", datarate->rx_nss + 1); + if (datarate->rx_mcs_index != 0xFF) + printf(" MCS: MCS %d\n", + (int)datarate->rx_mcs_index); + else + printf(" MCS: Auto\n"); + if (datarate->rx_rate_format < 3) + printf(" Rate: %f Mbps\n", + (float)datarate->rx_data_rate / 2); + } + } + + if (buffer) + free(buffer); + if (cmd) + free(cmd); + + return MLAN_STATUS_SUCCESS; +} + +/** + * @brief Process tx rate configuration + * @param argc Number of arguments + * @param argv A pointer to arguments array + * @return MLAN_STATUS_SUCCESS--success, otherwise--fail + */ +static int +process_txratecfg(int argc, char *argv[]) +{ + t_u8 *buffer = NULL; + struct eth_priv_cmd *cmd = NULL; + struct eth_priv_tx_rate_cfg *txratecfg = NULL; + struct ifreq ifr; + + /* Initialize buffer */ + buffer = (t_u8 *)malloc(BUFFER_LENGTH); + if (!buffer) { + printf("ERR:Cannot allocate buffer for command!\n"); + return MLAN_STATUS_FAILURE; + } + + prepare_buffer(buffer, argv[2], (argc - 3), &argv[3]); + + cmd = (struct eth_priv_cmd *)malloc(sizeof(struct eth_priv_cmd)); + if (!cmd) { + printf("ERR:Cannot allocate buffer for command!\n"); + free(buffer); + return MLAN_STATUS_FAILURE; + } + + /* Fill up buffer */ +#ifdef USERSPACE_32BIT_OVER_KERNEL_64BIT + memset(cmd, 0, sizeof(struct eth_priv_cmd)); + memcpy(&cmd->buf, &buffer, sizeof(buffer)); +#else + cmd->buf = buffer; +#endif + cmd->used_len = 0; + cmd->total_len = BUFFER_LENGTH; + + /* Perform IOCTL */ + memset(&ifr, 0, sizeof(struct ifreq)); + strncpy(ifr.ifr_ifrn.ifrn_name, dev_name, strlen(dev_name)); + ifr.ifr_ifru.ifru_data = (void *)cmd; + + if (ioctl(sockfd, MLAN_ETH_PRIV, &ifr)) { + perror("mlanutl"); + fprintf(stderr, "mlanutl: txratecfg fail\n"); + if (cmd) + free(cmd); + if (buffer) + free(buffer); + return MLAN_STATUS_FAILURE; + } + + /* Process result */ + txratecfg = (struct eth_priv_tx_rate_cfg *)buffer; + if (argc == 3) { + /* GET operation */ + printf("Tx Rate Configuration: \n"); + /* format */ + if (txratecfg->rate_format == 0xFF) { + printf(" Type: 0xFF (Auto)\n"); + } else if (txratecfg->rate_format <= 3) { + printf(" Type: %d (%s)\n", + txratecfg->rate_format, + rate_format[txratecfg->rate_format]); + if (txratecfg->rate_format == 0) + printf(" Rate Index: %d (%s)\n", + txratecfg->rate_index, + lg_rate[txratecfg->rate_index]); + else if (txratecfg->rate_format >= 1) + printf(" MCS Index: %d\n", + (int)txratecfg->rate_index); + if (txratecfg->rate_format == 2 || + txratecfg->rate_format == 3) + printf(" NSS: %d\n", + (int)txratecfg->nss); + if (txratecfg->rate_setting == 0xffff) + printf("Rate setting :Preamble type/BW/GI/STBC/.. : auto \n"); + else { + printf("Preamble type: %x\n", + (txratecfg->rate_setting & 0x0003)); + printf("BW: %x\n", + (txratecfg->rate_setting & 0x001C) >> 2); + printf("LTF + GI size %x\n", + (txratecfg->rate_setting & 0x0060) >> 5); + printf("STBC %x\n", + (txratecfg->rate_setting & 0x0080) >> 7); + printf("DCM %x\n", + (txratecfg->rate_setting & 0x0100) >> 8); + printf("Coding %x\n", + (txratecfg->rate_setting & 0x0200) >> 9); + printf("maxPE %x\n", + (txratecfg-> + rate_setting & 0x3000) >> 12); + } + } else { + printf(" Unknown rate format.\n"); + } + } + + if (buffer) + free(buffer); + if (cmd) + free(cmd); + + return MLAN_STATUS_SUCCESS; +} + +/** + * @brief Process get channel list used by cfg80211 + * @param argc Number of arguments + * @param argv A pointer to arguments array + * @return MLAN_STATUS_SUCCESS--success, otherwise--fail + */ +static int +process_getcfgchanlist(int argc, char *argv[]) +{ + t_u8 *buffer = NULL; + struct eth_priv_cmd *cmd = NULL; + struct ifreq ifr; + int i = 0; + wlan_ieee80211_chan_list *chan_list = NULL; + + /* Initialize buffer */ + buffer = (t_u8 *)malloc(BUFFER_LENGTH); + if (!buffer) { + printf("ERR:Cannot allocate buffer for command!\n"); + return MLAN_STATUS_FAILURE; + } + + prepare_buffer(buffer, argv[2], (argc - 3), &argv[3]); + + cmd = (struct eth_priv_cmd *)malloc(sizeof(struct eth_priv_cmd)); + if (!cmd) { + printf("ERR:Cannot allocate buffer for command!\n"); + free(buffer); + return MLAN_STATUS_FAILURE; + } + + /* Fill up buffer */ +#ifdef USERSPACE_32BIT_OVER_KERNEL_64BIT + memset(cmd, 0, sizeof(struct eth_priv_cmd)); + memcpy(&cmd->buf, &buffer, sizeof(buffer)); +#else + cmd->buf = buffer; +#endif + cmd->used_len = 0; + cmd->total_len = BUFFER_LENGTH; + + /* Perform IOCTL */ + memset(&ifr, 0, sizeof(struct ifreq)); + strncpy(ifr.ifr_ifrn.ifrn_name, dev_name, strlen(dev_name)); + ifr.ifr_ifru.ifru_data = (void *)cmd; + + if (ioctl(sockfd, MLAN_ETH_PRIV, &ifr)) { + perror("mlanutl"); + fprintf(stderr, "mlanutl: getcfgchanlist\n"); + if (cmd) + free(cmd); + if (buffer) + free(buffer); + return MLAN_STATUS_FAILURE; + } + /* Process results */ + chan_list = (wlan_ieee80211_chan_list *) buffer; + printf("Channel Flags:\n"); + printf(" IEEE80211_CHAN_DISABLED = 1<<0\n"); + printf(" IEEE80211_CHAN_NO_IR = 1<<1\n"); + printf(" IEEE80211_CHAN_RADAR = 1<<3\n"); + printf(" IEEE80211_CHAN_NO_HT40PLUS = 1<<4\n"); + printf(" IEEE80211_CHAN_NO_HT40MINUS = 1<<5\n"); + printf(" IEEE80211_CHAN_NO_OFDM = 1<<6\n"); + printf(" IEEE80211_CHAN_NO_80MHZ = 1<<7\n"); + printf(" IEEE80211_CHAN_NO_160MHZ = 1<<8\n"); + printf(" IEEE80211_CHAN_INDOOR_ONLY = 1<<9\n"); + printf(" IEEE80211_CHAN_IR_CONCURRENT = 1<<10\n"); + printf(" IEEE80211_CHAN_NO_20MHZ = 1<<11\n"); + printf(" IEEE80211_CHAN_NO_10MHZ = 1<<12\n"); + printf("--------------------------------------------"); + printf("--------------------------------------------\n"); + printf("# | chan | freq | disable | NO_IR | RADAR |NO_OFDM|NO_HT40+|NO_HT40-|NO_80| dfs_state\n"); + printf("--------------------------------------------"); + printf("--------------------------------------------\n"); + for (i = 0; i < chan_list->num_chan; i++) { + if (!(chan_list->chan_list[i].flags & IEEE80211_CHAN_RADAR)) { + printf(" [%03d] %04d %c %c %c %c %c %c %c %c\n", chan_list->chan_list[i].hw_value, chan_list->chan_list[i].center_freq, (chan_list->chan_list[i].flags & IEEE80211_CHAN_DISABLED) ? 'Y' : '-', (chan_list->chan_list[i].flags & IEEE80211_CHAN_NO_IR) ? 'Y' : '-', (chan_list->chan_list[i].flags & IEEE80211_CHAN_RADAR) ? 'Y' : '-', (chan_list->chan_list[i].flags & IEEE80211_CHAN_NO_OFDM) ? 'Y' : '-', (chan_list->chan_list[i].flags & IEEE80211_CHAN_NO_HT40PLUS) ? 'Y' : '-', (chan_list->chan_list[i].flags & IEEE80211_CHAN_NO_HT40MINUS) ? 'Y' : '-', (chan_list->chan_list[i].flags & IEEE80211_CHAN_NO_80MHZ) ? 'Y' : '-', '-'); + } else if (chan_list->chan_list[i].dfs_state == DFS_USEABLE) { + printf(" [%03d] %04d %c %c %c %c %c %c %c %c\n", chan_list->chan_list[i].hw_value, chan_list->chan_list[i].center_freq, (chan_list->chan_list[i].flags & IEEE80211_CHAN_DISABLED) ? 'Y' : '-', (chan_list->chan_list[i].flags & IEEE80211_CHAN_NO_IR) ? 'Y' : '-', (chan_list->chan_list[i].flags & IEEE80211_CHAN_RADAR) ? 'Y' : '-', (chan_list->chan_list[i].flags & IEEE80211_CHAN_NO_OFDM) ? 'Y' : '-', (chan_list->chan_list[i].flags & IEEE80211_CHAN_NO_HT40PLUS) ? 'Y' : '-', (chan_list->chan_list[i].flags & IEEE80211_CHAN_NO_HT40MINUS) ? 'Y' : '-', (chan_list->chan_list[i].flags & IEEE80211_CHAN_NO_80MHZ) ? 'Y' : '-', 'U'); + } else if (chan_list->chan_list[i].dfs_state == DFS_UNAVAILABLE) { + printf(" [%03d] %04d %c %c %c %c %c %c %c %c\n", chan_list->chan_list[i].hw_value, chan_list->chan_list[i].center_freq, (chan_list->chan_list[i].flags & IEEE80211_CHAN_DISABLED) ? 'Y' : '-', (chan_list->chan_list[i].flags & IEEE80211_CHAN_NO_IR) ? 'Y' : '-', (chan_list->chan_list[i].flags & IEEE80211_CHAN_RADAR) ? 'Y' : '-', (chan_list->chan_list[i].flags & IEEE80211_CHAN_NO_OFDM) ? 'Y' : '-', (chan_list->chan_list[i].flags & IEEE80211_CHAN_NO_HT40PLUS) ? 'Y' : '-', (chan_list->chan_list[i].flags & IEEE80211_CHAN_NO_HT40MINUS) ? 'Y' : '-', (chan_list->chan_list[i].flags & IEEE80211_CHAN_NO_80MHZ) ? 'Y' : '-', 'N'); + } else if (chan_list->chan_list[i].dfs_state == DFS_AVAILABLE) { + printf(" [%03d] %04d %c %c %c %c %c %c %c %c\n", chan_list->chan_list[i].hw_value, chan_list->chan_list[i].center_freq, (chan_list->chan_list[i].flags & IEEE80211_CHAN_DISABLED) ? 'Y' : '-', (chan_list->chan_list[i].flags & IEEE80211_CHAN_NO_IR) ? 'Y' : '-', (chan_list->chan_list[i].flags & IEEE80211_CHAN_RADAR) ? 'Y' : '-', (chan_list->chan_list[i].flags & IEEE80211_CHAN_NO_OFDM) ? 'Y' : '-', (chan_list->chan_list[i].flags & IEEE80211_CHAN_NO_HT40PLUS) ? 'Y' : '-', (chan_list->chan_list[i].flags & IEEE80211_CHAN_NO_HT40MINUS) ? 'Y' : '-', (chan_list->chan_list[i].flags & IEEE80211_CHAN_NO_80MHZ) ? 'Y' : '-', 'A'); + } + } + + if (buffer) + free(buffer); + if (cmd) + free(cmd); + + return MLAN_STATUS_SUCCESS; + +} + +/** + * @brief Process get wireless stats + * @param argc Number of arguments + * @param argv A pointer to arguments array + * @return MLAN_STATUS_SUCCESS--success, otherwise--fail + */ +static int +process_getlog(int argc, char *argv[]) +{ + t_u8 *buffer = NULL; + struct eth_priv_cmd *cmd = NULL; + struct eth_priv_get_log *stats = NULL; + struct ifreq ifr; + struct timeval tv; + int i = 0; + + /* Initialize buffer */ + buffer = (t_u8 *)malloc(BUFFER_LENGTH); + if (!buffer) { + printf("ERR:Cannot allocate buffer for command!\n"); + return MLAN_STATUS_FAILURE; + } + + prepare_buffer(buffer, argv[2], (argc - 3), &argv[3]); + + cmd = (struct eth_priv_cmd *)malloc(sizeof(struct eth_priv_cmd)); + if (!cmd) { + printf("ERR:Cannot allocate buffer for command!\n"); + free(buffer); + return MLAN_STATUS_FAILURE; + } + + /* Fill up buffer */ +#ifdef USERSPACE_32BIT_OVER_KERNEL_64BIT + memset(cmd, 0, sizeof(struct eth_priv_cmd)); + memcpy(&cmd->buf, &buffer, sizeof(buffer)); +#else + cmd->buf = buffer; +#endif + cmd->used_len = 0; + cmd->total_len = BUFFER_LENGTH; + + /* Perform IOCTL */ + memset(&ifr, 0, sizeof(struct ifreq)); + strncpy(ifr.ifr_ifrn.ifrn_name, dev_name, strlen(dev_name)); + ifr.ifr_ifru.ifru_data = (void *)cmd; + + if (ioctl(sockfd, MLAN_ETH_PRIV, &ifr)) { + perror("mlanutl"); + fprintf(stderr, "mlanutl: getlog fail\n"); + if (cmd) + free(cmd); + if (buffer) + free(buffer); + return MLAN_STATUS_FAILURE; + } + + gettimeofday(&tv, NULL); + + /* Process results */ + stats = (struct eth_priv_get_log *)buffer; + printf("Get log: timestamp %d.%06d sec\n", (int)tv.tv_sec, + (int)tv.tv_usec); + printf("dot11GroupTransmittedFrameCount %u\n" + "dot11FailedCount %u\n" + "dot11RetryCount %u\n" + "dot11MultipleRetryCount %u\n" + "dot11FrameDuplicateCount %u\n" + "dot11RTSSuccessCount %u\n" + "dot11RTSFailureCount %u\n" + "dot11ACKFailureCount %u\n" + "dot11ReceivedFragmentCount %u\n" + "dot11GroupReceivedFrameCount %u\n" + "dot11FCSErrorCount %u\n" + "dot11TransmittedFrameCount %u\n" + "wepicverrcnt-1 %u\n" + "wepicverrcnt-2 %u\n" + "wepicverrcnt-3 %u\n" + "wepicverrcnt-4 %u\n" + "beaconReceivedCount %u\n" + "beaconMissedCount %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], stats->bcn_rcv_cnt, + stats->bcn_miss_cnt); + if (cmd->used_len == sizeof(struct eth_priv_get_log)) { + printf("dot11TransmittedFragmentCount %u\n", + stats->tx_frag_cnt); + printf("dot11QosTransmittedFragmentCount "); + for (i = 0; i < 8; i++) { + printf("%u ", stats->qos_tx_frag_cnt[i]); + } + printf("\ndot11QosFailedCount "); + for (i = 0; i < 8; i++) { + printf("%u ", stats->qos_failed_cnt[i]); + } + printf("\ndot11QosRetryCount "); + for (i = 0; i < 8; i++) { + printf("%u ", stats->qos_retry_cnt[i]); + } + printf("\ndot11QosMultipleRetryCount "); + for (i = 0; i < 8; i++) { + printf("%u ", stats->qos_multi_retry_cnt[i]); + } + printf("\ndot11QosFrameDuplicateCount "); + for (i = 0; i < 8; i++) { + printf("%u ", stats->qos_frm_dup_cnt[i]); + } + printf("\ndot11QosRTSSuccessCount "); + for (i = 0; i < 8; i++) { + printf("%u ", stats->qos_rts_suc_cnt[i]); + } + printf("\ndot11QosRTSFailureCount "); + for (i = 0; i < 8; i++) { + printf("%u ", stats->qos_rts_failure_cnt[i]); + } + printf("\ndot11QosACKFailureCount "); + for (i = 0; i < 8; i++) { + printf("%u ", stats->qos_ack_failure_cnt[i]); + } + printf("\ndot11QosReceivedFragmentCount "); + for (i = 0; i < 8; i++) { + printf("%u ", stats->qos_rx_frag_cnt[i]); + } + printf("\ndot11QosTransmittedFrameCount "); + for (i = 0; i < 8; i++) { + printf("%u ", stats->qos_tx_frm_cnt[i]); + } + printf("\ndot11QosDiscardedFrameCount "); + for (i = 0; i < 8; i++) { + printf("%u ", stats->qos_discarded_frm_cnt[i]); + } + printf("\ndot11QosMPDUsReceivedCount "); + for (i = 0; i < 8; i++) { + printf("%u ", stats->qos_mpdus_rx_cnt[i]); + } + printf("\ndot11QosRetriesReceivedCount "); + for (i = 0; i < 8; i++) { + printf("%u ", stats->qos_retries_rx_cnt[i]); + } + printf("\ndot11RSNAStatsCMACICVErrors %u\n" + "dot11RSNAStatsCMACReplays %u\n" + "dot11RSNAStatsRobustMgmtCCMPReplays %u\n" + "dot11RSNAStatsTKIPICVErrors %u\n" + "dot11RSNAStatsTKIPReplays %u\n" + "dot11RSNAStatsCCMPDecryptErrors %u\n" + "dot11RSNAstatsCCMPReplays %u\n" + "dot11TransmittedAMSDUCount %u\n" + "dot11FailedAMSDUCount %u\n" + "dot11RetryAMSDUCount %u\n" + "dot11MultipleRetryAMSDUCount %u\n" + "dot11TransmittedOctetsInAMSDUCount %llu\n" + "dot11AMSDUAckFailureCount %u\n" + "dot11ReceivedAMSDUCount %u\n" + "dot11ReceivedOctetsInAMSDUCount %llu\n" + "dot11TransmittedAMPDUCount %u\n" + "dot11TransmittedMPDUsInAMPDUCount %u\n" + "dot11TransmittedOctetsInAMPDUCount %llu\n" + "dot11AMPDUReceivedCount %u\n" + "dot11MPDUInReceivedAMPDUCount %u\n" + "dot11ReceivedOctetsInAMPDUCount %llu\n" + "dot11AMPDUDelimiterCRCErrorCount %u\n", + stats->cmacicv_errors, + stats->cmac_replays, + stats->mgmt_ccmp_replays, + stats->tkipicv_errors, + stats->tkip_replays, + stats->ccmp_decrypt_errors, + stats->ccmp_replays, + stats->tx_amsdu_cnt, + stats->failed_amsdu_cnt, + stats->retry_amsdu_cnt, + stats->multi_retry_amsdu_cnt, + stats->tx_octets_in_amsdu_cnt, + stats->amsdu_ack_failure_cnt, + stats->rx_amsdu_cnt, + stats->rx_octets_in_amsdu_cnt, + stats->tx_ampdu_cnt, + stats->tx_mpdus_in_ampdu_cnt, + stats->tx_octets_in_ampdu_cnt, + stats->ampdu_rx_cnt, + stats->mpdu_in_rx_ampdu_cnt, + stats->rx_octets_in_ampdu_cnt, + stats->ampdu_delimiter_crc_error_cnt); + } + + if (buffer) + free(buffer); + if (cmd) + free(cmd); + + return MLAN_STATUS_SUCCESS; +} + +/** + * @brief Process esuppmode command + * @param argc Number of arguments + * @param argv A pointer to arguments array + * @return MLAN_STATUS_SUCCESS--success, otherwise--fail + */ +static int +process_esuppmode(int argc, char *argv[]) +{ + t_u8 *buffer = NULL; + struct eth_priv_cmd *cmd = NULL; + struct eth_priv_esuppmode_cfg *esuppmodecfg = NULL; + struct ifreq ifr; + + /* Initialize buffer */ + buffer = (t_u8 *)malloc(BUFFER_LENGTH); + if (!buffer) { + printf("ERR:Cannot allocate buffer for command!\n"); + return MLAN_STATUS_FAILURE; + } + + prepare_buffer(buffer, argv[2], (argc - 3), &argv[3]); + + cmd = (struct eth_priv_cmd *)malloc(sizeof(struct eth_priv_cmd)); + if (!cmd) { + printf("ERR:Cannot allocate buffer for command!\n"); + free(buffer); + return MLAN_STATUS_FAILURE; + } + + /* Fill up buffer */ +#ifdef USERSPACE_32BIT_OVER_KERNEL_64BIT + memset(cmd, 0, sizeof(struct eth_priv_cmd)); + memcpy(&cmd->buf, &buffer, sizeof(buffer)); +#else + cmd->buf = buffer; +#endif + cmd->used_len = 0; + cmd->total_len = BUFFER_LENGTH; + + /* Perform IOCTL */ + memset(&ifr, 0, sizeof(struct ifreq)); + strncpy(ifr.ifr_ifrn.ifrn_name, dev_name, strlen(dev_name)); + ifr.ifr_ifru.ifru_data = (void *)cmd; + + if (ioctl(sockfd, MLAN_ETH_PRIV, &ifr)) { + perror("mlanutl"); + fprintf(stderr, "mlanutl: esuppmode fail\n"); + if (cmd) + free(cmd); + if (buffer) + free(buffer); + return MLAN_STATUS_FAILURE; + } + + /* Process result */ + esuppmodecfg = (struct eth_priv_esuppmode_cfg *)buffer; + if (argc == 3) { + /* GET operation */ + printf("Esupplicant Mode Configuration: \n"); + /* RSN mode */ + printf(" RSN mode: 0x%x ( ", esuppmodecfg->rsn_mode); + if (esuppmodecfg->rsn_mode & MBIT(0)) + printf("No-RSN "); + if (esuppmodecfg->rsn_mode & MBIT(3)) + printf("WPA "); + if (esuppmodecfg->rsn_mode & MBIT(4)) + printf("WPA-None "); + if (esuppmodecfg->rsn_mode & MBIT(5)) + printf("WPA2 "); + printf(")\n"); + /* Pairwise cipher */ + printf(" Pairwise cipher: 0x%x ( ", + esuppmodecfg->pairwise_cipher); + if (esuppmodecfg->pairwise_cipher & MBIT(2)) + printf("TKIP "); + if (esuppmodecfg->pairwise_cipher & MBIT(3)) + printf("AES "); + printf(")\n"); + /* Group cipher */ + printf(" Group cipher: 0x%x ( ", + esuppmodecfg->group_cipher); + if (esuppmodecfg->group_cipher & MBIT(2)) + printf("TKIP "); + if (esuppmodecfg->group_cipher & MBIT(3)) + printf("AES "); + printf(")\n"); + } + + if (buffer) + free(buffer); + if (cmd) + free(cmd); + + return MLAN_STATUS_SUCCESS; +} + +/** + * @brief Process passphrase command + * @param argc Number of arguments + * @param argv A pointer to arguments array + * @return MLAN_STATUS_SUCCESS--success, otherwise--fail + */ +static int +process_passphrase(int argc, char *argv[]) +{ + t_u8 *buffer = NULL; + struct eth_priv_cmd *cmd = NULL; + struct ifreq ifr; + + /* Initialize buffer */ + buffer = (t_u8 *)malloc(BUFFER_LENGTH); + if (!buffer) { + printf("ERR:Cannot allocate buffer for command!\n"); + return MLAN_STATUS_FAILURE; + } + + /* The argument being a string, this requires special handling */ + prepare_buffer(buffer, argv[2], 0, NULL); + if (argc >= 4) { + strcpy((char *)(buffer + strlen(CMD_NXP) + strlen(argv[2])), + argv[3]); + } + + cmd = (struct eth_priv_cmd *)malloc(sizeof(struct eth_priv_cmd)); + if (!cmd) { + printf("ERR:Cannot allocate buffer for command!\n"); + free(buffer); + return MLAN_STATUS_FAILURE; + } + + /* Fill up buffer */ +#ifdef USERSPACE_32BIT_OVER_KERNEL_64BIT + memset(cmd, 0, sizeof(struct eth_priv_cmd)); + memcpy(&cmd->buf, &buffer, sizeof(buffer)); +#else + cmd->buf = buffer; +#endif + cmd->used_len = 0; + cmd->total_len = BUFFER_LENGTH; + + /* Perform IOCTL */ + memset(&ifr, 0, sizeof(struct ifreq)); + strncpy(ifr.ifr_ifrn.ifrn_name, dev_name, strlen(dev_name)); + ifr.ifr_ifru.ifru_data = (void *)cmd; + + if (ioctl(sockfd, MLAN_ETH_PRIV, &ifr)) { + perror("mlanutl"); + fprintf(stderr, "mlanutl: passphrase fail\n"); + if (cmd) + free(cmd); + if (buffer) + free(buffer); + return MLAN_STATUS_FAILURE; + } + + /* Process result */ + printf("Passphrase Configuration: %s\n", (char *)buffer); + + if (buffer) + free(buffer); + if (cmd) + free(cmd); + + return MLAN_STATUS_SUCCESS; +} + +/** + * @brief Process deauth command + * @param argc Number of arguments + * @param argv A pointer to arguments array + * @return MLAN_STATUS_SUCCESS--success, otherwise--fail + */ +static int +process_deauth(int argc, char *argv[]) +{ + t_u8 *buffer = NULL; + struct eth_priv_cmd *cmd = NULL; + struct ifreq ifr; + + /* Initialize buffer */ + buffer = (t_u8 *)malloc(BUFFER_LENGTH); + if (!buffer) { + printf("ERR:Cannot allocate buffer for command!\n"); + return MLAN_STATUS_FAILURE; + } + + /* The argument being a string, this requires special handling */ + prepare_buffer(buffer, argv[2], 0, NULL); + if (argc >= 4) { + strcpy((char *)(buffer + strlen(CMD_NXP) + strlen(argv[2])), + argv[3]); + } + + cmd = (struct eth_priv_cmd *)malloc(sizeof(struct eth_priv_cmd)); + if (!cmd) { + printf("ERR:Cannot allocate buffer for command!\n"); + free(buffer); + return MLAN_STATUS_FAILURE; + } + + /* Fill up buffer */ +#ifdef USERSPACE_32BIT_OVER_KERNEL_64BIT + memset(cmd, 0, sizeof(struct eth_priv_cmd)); + memcpy(&cmd->buf, &buffer, sizeof(buffer)); +#else + cmd->buf = buffer; +#endif + cmd->used_len = 0; + cmd->total_len = BUFFER_LENGTH; + + /* Perform IOCTL */ + memset(&ifr, 0, sizeof(struct ifreq)); + strncpy(ifr.ifr_ifrn.ifrn_name, dev_name, strlen(dev_name)); + ifr.ifr_ifru.ifru_data = (void *)cmd; + + if (ioctl(sockfd, MLAN_ETH_PRIV, &ifr)) { + perror("mlanutl"); + fprintf(stderr, "mlanutl: deauth fail\n"); + if (cmd) + free(cmd); + if (buffer) + free(buffer); + return MLAN_STATUS_FAILURE; + } + + if (buffer) + free(buffer); + if (cmd) + free(cmd); + + return MLAN_STATUS_SUCCESS; +} + +#ifdef UAP_SUPPORT +/** + * @brief Process getstalist command + * @param argc Number of arguments + * @param argv A pointer to arguments array + * @return MLAN_STATUS_SUCCESS--success, otherwise--fail + */ +static int +process_getstalist(int argc, char *argv[]) +{ + t_u8 *buffer = NULL; + struct eth_priv_cmd *cmd = NULL; + struct ifreq ifr; + struct eth_priv_getstalist *list = NULL; + int i = 0, rssi = 0; + + /* Initialize buffer */ + buffer = (t_u8 *)malloc(BUFFER_LENGTH); + if (!buffer) { + printf("ERR:Cannot allocate buffer for command!\n"); + return MLAN_STATUS_FAILURE; + } + + /* The argument being a string, this requires special handling */ + prepare_buffer(buffer, argv[2], 0, NULL); + + cmd = (struct eth_priv_cmd *)malloc(sizeof(struct eth_priv_cmd)); + if (!cmd) { + printf("ERR:Cannot allocate buffer for command!\n"); + free(buffer); + return MLAN_STATUS_FAILURE; + } + + /* Fill up buffer */ +#ifdef USERSPACE_32BIT_OVER_KERNEL_64BIT + memset(cmd, 0, sizeof(struct eth_priv_cmd)); + memcpy(&cmd->buf, &buffer, sizeof(buffer)); +#else + cmd->buf = buffer; +#endif + cmd->used_len = 0; + cmd->total_len = BUFFER_LENGTH; + + /* Perform IOCTL */ + memset(&ifr, 0, sizeof(struct ifreq)); + strncpy(ifr.ifr_ifrn.ifrn_name, dev_name, strlen(dev_name)); + ifr.ifr_ifru.ifru_data = (void *)cmd; + + if (ioctl(sockfd, MLAN_ETH_PRIV, &ifr)) { + perror("mlanutl"); + fprintf(stderr, "mlanutl: getstalist fail\n"); + if (cmd) + free(cmd); + if (buffer) + free(buffer); + return MLAN_STATUS_FAILURE; + } + list = (struct eth_priv_getstalist *)(buffer + strlen(CMD_NXP) + + strlen(argv[2])); + + printf("Number of STA = %d\n\n", list->sta_count); + + for (i = 0; i < list->sta_count; i++) { + printf("STA %d information:\n", i + 1); + printf("=====================\n"); + printf("MAC Address: "); + print_mac(list->client_info[i].mac_address); + printf("\nPower mgmt status: %s\n", + (list->client_info[i].power_mgmt_status == + 0) ? "active" : "power save"); + + /** On some platform, s8 is same as unsigned char*/ + rssi = (int)list->client_info[i].rssi; + if (rssi > 0x7f) + rssi = -(256 - rssi); + printf("Rssi : %d dBm\n\n", rssi); + } + + if (buffer) + free(buffer); + if (cmd) + free(cmd); + + return MLAN_STATUS_SUCCESS; +} +#endif + +#ifdef WIFI_DIRECT_SUPPORT +#if defined(STA_SUPPORT) && defined(UAP_SUPPORT) +/** + * @brief Process BSS role command + * @param argc Number of arguments + * @param argv A pointer to arguments array + * @return MLAN_STATUS_SUCCESS--success, otherwise--fail + */ +static int +process_bssrole(int argc, char *argv[]) +{ + t_u8 *buffer = NULL; + struct eth_priv_cmd *cmd = NULL; + struct ifreq ifr; + + /* Initialize buffer */ + buffer = (t_u8 *)malloc(BUFFER_LENGTH); + if (!buffer) { + printf("ERR:Cannot allocate buffer for command!\n"); + return MLAN_STATUS_FAILURE; + } + + prepare_buffer(buffer, argv[2], (argc - 3), &argv[3]); + + cmd = (struct eth_priv_cmd *)malloc(sizeof(struct eth_priv_cmd)); + if (!cmd) { + printf("ERR:Cannot allocate buffer for command!\n"); + free(buffer); + return MLAN_STATUS_FAILURE; + } + + /* Fill up buffer */ +#ifdef USERSPACE_32BIT_OVER_KERNEL_64BIT + memset(cmd, 0, sizeof(struct eth_priv_cmd)); + memcpy(&cmd->buf, &buffer, sizeof(buffer)); +#else + cmd->buf = buffer; +#endif + cmd->used_len = 0; + cmd->total_len = BUFFER_LENGTH; + + /* Perform IOCTL */ + memset(&ifr, 0, sizeof(struct ifreq)); + strncpy(ifr.ifr_ifrn.ifrn_name, dev_name, strlen(dev_name)); + ifr.ifr_ifru.ifru_data = (void *)cmd; + + if (ioctl(sockfd, MLAN_ETH_PRIV, &ifr)) { + perror("mlanutl"); + fprintf(stderr, "mlanutl: bssrole fail\n"); + if (cmd) + free(cmd); + if (buffer) + free(buffer); + return MLAN_STATUS_FAILURE; + } + + /* Process result */ + if (argc == 3) { + /* GET operation */ + printf("BSS role: %d\n", buffer[0]); + } + + if (buffer) + free(buffer); + if (cmd) + free(cmd); + + return MLAN_STATUS_SUCCESS; +} +#endif +#endif + +#ifdef STA_SUPPORT +/** + * @brief Helper function for process_getscantable_idx + * + * @param pbuf A pointer to the buffer + * @param buf_len Buffer length + * + * @return NA + * + */ +static void +dump_scan_elems(const t_u8 *pbuf, uint buf_len) +{ + uint idx; + uint marker = 2 + pbuf[1]; + + for (idx = 0; idx < buf_len; idx++) { + if (idx % 0x10 == 0) { + printf("\n%04x: ", idx); + } + + if (idx == marker) { + printf("|"); + marker = idx + pbuf[idx + 1] + 2; + } else { + printf(" "); + } + + printf("%02x ", pbuf[idx]); + } + + printf("\n"); +} + +/** + * @brief Helper function for process_getscantable_idx + * Find next element + * + * @param pp_ie_out Pointer of a IEEEtypes_Generic_t structure pointer + * @param p_buf_left Integer pointer, which contains the number of left p_buf + * + * @return MLAN_STATUS_SUCCESS on success, otherwise MLAN_STATUS_FAILURE + */ +static int +scantable_elem_next(IEEEtypes_Generic_t **pp_ie_out, int *p_buf_left) +{ + IEEEtypes_Generic_t *pie_gen; + t_u8 *p_next; + + if (*p_buf_left < 2) { + return MLAN_STATUS_FAILURE; + } + + pie_gen = *pp_ie_out; + + p_next = (t_u8 *)pie_gen + (pie_gen->ieee_hdr.len + + sizeof(pie_gen->ieee_hdr)); + *p_buf_left -= (p_next - (t_u8 *)pie_gen); + + *pp_ie_out = (IEEEtypes_Generic_t *)p_next; + + if (*p_buf_left <= 0) { + return MLAN_STATUS_FAILURE; + } + + return MLAN_STATUS_SUCCESS; +} + + /** + * @brief Helper function for process_getscantable_idx + * scantable find element + * + * @param ie_buf Pointer of the IE buffer + * @param ie_buf_len IE buffer length + * @param ie_type IE type + * @param ppie_out Pointer to the IEEEtypes_Generic_t structure pointer + * @return MLAN_STATUS_SUCCESS on success, otherwise MLAN_STATUS_FAILURE + */ +static int +scantable_find_elem(t_u8 *ie_buf, + unsigned int ie_buf_len, + IEEEtypes_ElementId_e ie_type, + IEEEtypes_Generic_t **ppie_out) +{ + int found; + unsigned int ie_buf_left; + + ie_buf_left = ie_buf_len; + + found = FALSE; + + *ppie_out = (IEEEtypes_Generic_t *)ie_buf; + + do { + found = ((*ppie_out)->ieee_hdr.element_id == ie_type); + + } while (!found && + (scantable_elem_next(ppie_out, (int *)&ie_buf_left) == 0)); + + if (!found) { + *ppie_out = NULL; + } + + return found ? MLAN_STATUS_SUCCESS : MLAN_STATUS_FAILURE; +} + + /** + * @brief Helper function for process_getscantable_idx + * It gets SSID from IE + * + * @param ie_buf IE buffer + * @param ie_buf_len IE buffer length + * @param pssid SSID + * @param ssid_buf_max Size of SSID + * @return MLAN_STATUS_SUCCESS on success, otherwise MLAN_STATUS_FAILURE + */ +static int +scantable_get_ssid_from_ie(t_u8 *ie_buf, + unsigned int ie_buf_len, + t_u8 *pssid, unsigned int ssid_buf_max) +{ + int retval; + IEEEtypes_Generic_t *pie_gen; + + retval = scantable_find_elem(ie_buf, ie_buf_len, SSID, &pie_gen); + if (retval == MLAN_STATUS_SUCCESS) + memcpy(pssid, pie_gen->data, + MIN(pie_gen->ieee_hdr.len, ssid_buf_max)); + else + return MLAN_STATUS_FAILURE; + + return retval; +} + +/** + * @brief Display detailed information for a specific scan table entry + * + * @param cmd_name Command name + * @param prsp_info_req Scan table entry request structure + * @return MLAN_STATUS_SUCCESS--success, otherwise--fail + */ +int +process_getscantable_idx(char *cmd_name, + wlan_ioctl_get_scan_table_info *prsp_info_req) +{ + int ret = 0; + t_u8 *buffer = NULL; + struct eth_priv_cmd *cmd = NULL; + struct ifreq ifr; + + t_u8 *pcurrent; + char ssid[33]; + t_u16 tmp_cap; + t_u8 tsf[8]; + t_u16 beacon_interval; + t_u16 cap_info; + wlan_ioctl_get_scan_table_info *prsp_info; + + wlan_get_scan_table_fixed fixed_fields; + t_u32 fixed_field_length; + t_u32 bss_info_length; + + memset(ssid, 0x00, sizeof(ssid)); + + buffer = (t_u8 *)malloc(BUFFER_LENGTH); + if (!buffer) { + printf("ERR:Cannot allocate buffer for command!\n"); + return MLAN_STATUS_FAILURE; + } + + prepare_buffer(buffer, cmd_name, 0, NULL); + + prsp_info = + (wlan_ioctl_get_scan_table_info *)(buffer + strlen(CMD_NXP) + + strlen(cmd_name)); + + memcpy(prsp_info, prsp_info_req, + sizeof(wlan_ioctl_get_scan_table_info)); + + cmd = (struct eth_priv_cmd *)malloc(sizeof(struct eth_priv_cmd)); + if (!cmd) { + printf("ERR:Cannot allocate buffer for command!\n"); + free(buffer); + return MLAN_STATUS_FAILURE; + } + + /* Fill up buffer */ +#ifdef USERSPACE_32BIT_OVER_KERNEL_64BIT + memset(cmd, 0, sizeof(struct eth_priv_cmd)); + memcpy(&cmd->buf, &buffer, sizeof(buffer)); +#else + cmd->buf = buffer; +#endif + cmd->used_len = 0; + cmd->total_len = BUFFER_LENGTH; + + /* + * Set up and execute the ioctl call + */ + memset(&ifr, 0, sizeof(struct ifreq)); + strncpy(ifr.ifr_ifrn.ifrn_name, dev_name, strlen(dev_name)); + ifr.ifr_ifru.ifru_data = (void *)cmd; + + if (ioctl(sockfd, MLAN_ETH_PRIV, &ifr)) { + if (errno == EAGAIN) { + ret = -EAGAIN; + } else { + perror("mlanutl"); + fprintf(stderr, "mlanutl: getscantable fail\n"); + ret = MLAN_STATUS_FAILURE; + } + if (cmd) + free(cmd); + if (buffer) + free(buffer); + return ret; + } + + prsp_info = (wlan_ioctl_get_scan_table_info *)buffer; + if (prsp_info->scan_number == 0) { + printf("mlanutl: getscantable ioctl - index out of range\n"); + if (cmd) + free(cmd); + if (buffer) + free(buffer); + return -EINVAL; + } + + pcurrent = prsp_info->scan_table_entry_buf; + + memcpy((t_u8 *)&fixed_field_length, + (t_u8 *)pcurrent, sizeof(fixed_field_length)); + pcurrent += sizeof(fixed_field_length); + + memcpy((t_u8 *)&bss_info_length, + (t_u8 *)pcurrent, sizeof(bss_info_length)); + pcurrent += sizeof(bss_info_length); + + memcpy((t_u8 *)&fixed_fields, (t_u8 *)pcurrent, sizeof(fixed_fields)); + pcurrent += fixed_field_length; + + /* Time stamp is 8 byte long */ + memcpy(tsf, pcurrent, sizeof(tsf)); + pcurrent += sizeof(tsf); + bss_info_length -= sizeof(tsf); + + /* Beacon interval is 2 byte long */ + memcpy(&beacon_interval, pcurrent, sizeof(beacon_interval)); + pcurrent += sizeof(beacon_interval); + bss_info_length -= sizeof(beacon_interval); + + /* Capability information is 2 byte long */ + memcpy(&cap_info, pcurrent, sizeof(cap_info)); + pcurrent += sizeof(cap_info); + bss_info_length -= sizeof(cap_info); + + scantable_get_ssid_from_ie(pcurrent, + bss_info_length, (t_u8 *)ssid, sizeof(ssid)); + + printf("\n*** [%s], %02x:%02x:%02x:%02x:%02x:%2x\n", + ssid, + fixed_fields.bssid[0], + fixed_fields.bssid[1], + fixed_fields.bssid[2], + fixed_fields.bssid[3], + fixed_fields.bssid[4], fixed_fields.bssid[5]); + memcpy(&tmp_cap, &cap_info, sizeof(tmp_cap)); + printf("Channel = %d, SS = %d, ChanLoad = %d%% CapInfo = 0x%04x, BcnIntvl = %d\n", fixed_fields.channel, 255 - fixed_fields.rssi, fixed_fields.chan_load, tmp_cap, beacon_interval); + + printf("TSF Values: AP(0x%02x%02x%02x%02x%02x%02x%02x%02x), ", + tsf[7], tsf[6], tsf[5], tsf[4], tsf[3], tsf[2], tsf[1], tsf[0]); + + printf("Network(0x%016llx)\n", fixed_fields.network_tsf); + printf("\n"); + printf("Element Data (%d bytes)\n", (int)bss_info_length); + printf("------------"); + dump_scan_elems(pcurrent, bss_info_length); + printf("\n"); + + if (buffer) + free(buffer); + if (cmd) + free(cmd); + + return MLAN_STATUS_SUCCESS; +} + +/** + * @brief channel validation. + * @param scan_req A pointer to wlan_ioctl_user_scan_cfg structure + * @param chan_num channel number + * + * @return MLAN_STATUS_SUCCESS--success, otherwise--fail + */ +int +wlan_is_channel_valid(wlan_ioctl_user_scan_cfg *scan_req, t_u8 chan_number) +{ + int ret = -1; + int i; + if (scan_req && scan_req->chan_list[0].chan_number) { + for (i = 0; + i < WLAN_IOCTL_USER_SCAN_CHAN_MAX && + scan_req->chan_list[i].chan_number; i++) { + if (scan_req->chan_list[i].chan_number == chan_number) { + ret = 0; + break; + } + } + } else { + ret = 0; + } + return ret; +} + +/** + * @brief filter_ssid_result + * @param scan_req A pointer to wlan_ioctl_user_scan_cfg structure + * @param num_ssid_rqst Number of SSIDs which are filterted + * @param bss_info A pointer to current bss information structure + * @return 0--success, otherwise--fail + */ + +int +filter_ssid_result(wlan_ioctl_user_scan_cfg *scan_req, int num_ssid_rqst, + wlan_ioctl_get_bss_info *bss_info) +{ + int i, ret = 1; + + for (i = 0; i < num_ssid_rqst; i++) { + if ((memcmp(scan_req->ssid_list[i].ssid, bss_info->ssid, + (int)bss_info->ssid_len)) == 0) { + return 0; + } + } + return ret; +} + +/** + * @brief Process getchanstats + * @param argc Number of arguments + * @param argv A pointer to arguments array + * @return MLAN_STATUS_SUCCESS--success, otherwise--fail + */ +static int +wlan_process_getchanstats(int argc, char *argv[]) +{ + t_u8 *buffer = NULL; + struct eth_priv_cmd *cmd = NULL; + struct ifreq ifr; + int ret = 0; + int idx = 0; + int i = 0; + chan_stats *stats = NULL; + t_u16 chan_load = 0; + + buffer = (t_u8 *)malloc(BUFFER_LENGTH); + if (!buffer) { + printf("ERR:Cannot allocate buffer for command!\n"); + return MLAN_STATUS_FAILURE; + } + + cmd = (struct eth_priv_cmd *)malloc(sizeof(struct eth_priv_cmd)); + if (!cmd) { + printf("ERR:Cannot allocate buffer for command!\n"); + free(buffer); + return MLAN_STATUS_FAILURE; + } + + /* Fill up buffer */ +#ifdef USERSPACE_32BIT_OVER_KERNEL_64BIT + memset(cmd, 0, sizeof(struct eth_priv_cmd)); + memcpy(&cmd->buf, &buffer, sizeof(buffer)); +#else + cmd->buf = buffer; +#endif + cmd->used_len = 0; + cmd->total_len = BUFFER_LENGTH; + + prepare_buffer(buffer, argv[2], 0, NULL); + + /* Set up and execute the ioctl call */ + memset(&ifr, 0, sizeof(struct ifreq)); + strncpy(ifr.ifr_ifrn.ifrn_name, dev_name, strlen(dev_name)); + ifr.ifr_ifru.ifru_data = (void *)cmd; + + if (ioctl(sockfd, MLAN_ETH_PRIV, &ifr)) { + perror("mlanutl"); + fprintf(stderr, "mlanutl: getchload fail\n"); + ret = MLAN_STATUS_FAILURE; + if (cmd) + free(cmd); + if (buffer) + free(buffer); + return ret; + } + + stats = (chan_stats *) buffer; + /* Display scan results */ + printf("----------------------------------------------------------- \n"); + printf("# | Channel | BSS | minrss | maxrss | NF | CH load \n"); + printf("----------------------------------------------------------- \n"); + + for (i = 0; i < stats->num_in_chan_stats; i++) { + if (stats->stats[i].cca_scan_duration) { + chan_load = + stats->stats[i].cca_busy_duration * 100 / + stats->stats[i].cca_scan_duration; + printf("%02u| %03d | %03d | %02d | %02d | %02d | %02d\n", idx, stats->stats[i].chan_num, stats->stats[i].total_networks, stats->stats[i].min_rss, stats->stats[i].max_rss, stats->stats[i].noise, chan_load); + idx++; + } + } + + if (buffer) + free(buffer); + if (cmd) + free(cmd); + + return MLAN_STATUS_SUCCESS; +} + +/** + * @brief Process getscantable command + * @param argc Number of arguments + * @param argv A pointer to arguments array + * @param scan_req A pointer to wlan_ioctl_user_scan_cfg structure + * @return MLAN_STATUS_SUCCESS--success, otherwise--fail + */ +static int +wlan_process_getscantable(int argc, char *argv[], + wlan_ioctl_user_scan_cfg *scan_req) +{ + t_u8 *buffer = NULL; + struct eth_priv_cmd *cmd = NULL; + struct ifreq ifr; + + struct wlan_ioctl_get_scan_list *scan_list_head = NULL; + struct wlan_ioctl_get_scan_list *scan_list_node = NULL; + struct wlan_ioctl_get_scan_list *curr = NULL, *next = NULL; + + t_u32 total_scan_res = 0; + + unsigned int scan_start; + int idx, ret = 0; + int i = 0; + t_u8 *pcurrent; + t_u8 *pnext; + IEEEtypes_ElementId_e *pelement_id; + t_u8 *pelement_len; + int ssid_idx; + int insert = 0; + int sort_by_channel = 0; + t_u8 *pbyte; + t_u16 new_ss = 0; + t_u16 curr_ss = 0; + t_u8 new_ch = 0; + t_u8 curr_ch = 0; + + IEEEtypes_VendorSpecific_t *pwpa_ie; + const t_u8 wpa_oui[4] = { 0x00, 0x50, 0xf2, 0x01 }; + + IEEEtypes_WmmParameter_t *pwmm_ie; + const t_u8 wmm_oui[4] = { 0x00, 0x50, 0xf2, 0x02 }; + IEEEtypes_VendorSpecific_t *pwps_ie; + const t_u8 wps_oui[4] = { 0x00, 0x50, 0xf2, 0x04 }; + + int displayed_info; + + wlan_ioctl_get_scan_table_info rsp_info_req; + wlan_ioctl_get_scan_table_info *prsp_info; + + wlan_get_scan_table_fixed fixed_fields; + t_u32 fixed_field_length; + t_u32 bss_info_length; + wlan_ioctl_get_bss_info *bss_info; + + buffer = (t_u8 *)malloc(BUFFER_LENGTH); + if (!buffer) { + printf("ERR:Cannot allocate buffer for command!\n"); + return MLAN_STATUS_FAILURE; + } + + cmd = (struct eth_priv_cmd *)malloc(sizeof(struct eth_priv_cmd)); + if (!cmd) { + printf("ERR:Cannot allocate buffer for command!\n"); + free(buffer); + return MLAN_STATUS_FAILURE; + } + + /* Fill up buffer */ +#ifdef USERSPACE_32BIT_OVER_KERNEL_64BIT + memset(cmd, 0, sizeof(struct eth_priv_cmd)); + memcpy(&cmd->buf, &buffer, sizeof(buffer)); +#else + cmd->buf = buffer; +#endif + cmd->used_len = 0; + cmd->total_len = BUFFER_LENGTH; + + if (argc > 3 && (strcmp(argv[3], "tsf") != 0) + && (strcmp(argv[3], "help") != 0) + && (strcmp(argv[3], "ch") != 0)) { + + idx = strtol(argv[3], NULL, 10); + + if (idx >= 0) { + rsp_info_req.scan_number = idx; + ret = process_getscantable_idx(argv[2], &rsp_info_req); + if (buffer) + free(buffer); + if (cmd) + free(cmd); + return ret; + } + } + + displayed_info = FALSE; + scan_start = 1; + + do { + prepare_buffer(buffer, argv[2], 0, NULL); + prsp_info = + (wlan_ioctl_get_scan_table_info *)(buffer + + strlen(CMD_NXP) + + strlen(argv[2])); + + prsp_info->scan_number = scan_start; + + /* + * Set up and execute the ioctl call + */ + memset(&ifr, 0, sizeof(struct ifreq)); + strncpy(ifr.ifr_ifrn.ifrn_name, dev_name, strlen(dev_name)); + ifr.ifr_ifru.ifru_data = (void *)cmd; + + if (ioctl(sockfd, MLAN_ETH_PRIV, &ifr)) { + if (errno == EAGAIN) { + ret = -EAGAIN; + } else { + perror("mlanutl"); + fprintf(stderr, "mlanutl: getscantable fail\n"); + ret = MLAN_STATUS_FAILURE; + } + if (cmd) + free(cmd); + if (buffer) + free(buffer); + return ret; + } + + prsp_info = (wlan_ioctl_get_scan_table_info *)buffer; + pcurrent = 0; + pnext = prsp_info->scan_table_entry_buf; + total_scan_res += prsp_info->scan_number; + + for (idx = 0; (unsigned int)idx < prsp_info->scan_number; idx++) { + /* Alloc memory for new node for next BSS */ + scan_list_node = (struct wlan_ioctl_get_scan_list *) + malloc(sizeof(struct wlan_ioctl_get_scan_list)); + if (scan_list_node == NULL) { + printf("Error: allocate memory for scan_list_head failed\n"); + return -ENOMEM; + } + memset(scan_list_node, 0, + sizeof(struct wlan_ioctl_get_scan_list)); + + /* + * Set pcurrent to pnext in case pad bytes are at the end + * of the last IE we processed. + */ + pcurrent = pnext; + + /* Start extracting each BSS to prepare a linked list */ + memcpy((t_u8 *)&fixed_field_length, + (t_u8 *)pcurrent, sizeof(fixed_field_length)); + pcurrent += sizeof(fixed_field_length); + + memcpy((t_u8 *)&bss_info_length, + (t_u8 *)pcurrent, sizeof(bss_info_length)); + pcurrent += sizeof(bss_info_length); + + memcpy((t_u8 *)&fixed_fields, + (t_u8 *)pcurrent, sizeof(fixed_fields)); + pcurrent += fixed_field_length; + + scan_list_node->fixed_buf.fixed_field_length = + fixed_field_length; + scan_list_node->fixed_buf.bss_info_length = + bss_info_length; + scan_list_node->fixed_buf.fixed_fields = fixed_fields; + + bss_info = &scan_list_node->bss_info_buf; + + /* Set next to be the start of the next scan entry */ + pnext = pcurrent + bss_info_length; + + if (bss_info_length >= + (sizeof(bss_info->tsf) + + sizeof(bss_info->beacon_interval) + + sizeof(bss_info->cap_info))) { + + /* time stamp is 8 byte long */ + memcpy(bss_info->tsf, pcurrent, + sizeof(bss_info->tsf)); + pcurrent += sizeof(bss_info->tsf); + bss_info_length -= sizeof(bss_info->tsf); + + /* beacon interval is 2 byte long */ + memcpy(&bss_info->beacon_interval, pcurrent, + sizeof(bss_info->beacon_interval)); + pcurrent += sizeof(bss_info->beacon_interval); + bss_info_length -= + sizeof(bss_info->beacon_interval); + /* capability information is 2 byte long */ + memcpy(&bss_info->cap_info, pcurrent, + sizeof(bss_info->cap_info)); + pcurrent += sizeof(bss_info->cap_info); + bss_info_length -= sizeof(bss_info->cap_info); + } + + bss_info->wmm_cap = ' '; /* M (WMM), C (WMM-Call Admission Control) */ + bss_info->wps_cap = ' '; /* "S" */ + bss_info->dot11k_cap = ' '; /* "K" */ + bss_info->dot11r_cap = ' '; /* "R" */ + bss_info->ht_cap = ' '; /* "N" */ + bss_info->vht_cap[0] = ' '; + bss_info->vht_cap[1] = ' '; + /* "P" for Privacy (WEP) since "W" is WPA, and "2" is RSN/WPA2 */ + bss_info->priv_cap = + bss_info->cap_info.privacy ? 'P' : ' '; + + memset(bss_info->ssid, 0, MRVDRV_MAX_SSID_LENGTH + 1); + bss_info->ssid_len = 0; + + while (bss_info_length >= 2) { + pelement_id = (IEEEtypes_ElementId_e *)pcurrent; + pelement_len = pcurrent + 1; + pcurrent += 2; + + if ((bss_info_length - 2) < *pelement_len) { + printf("Error when processing bss info, bss_info_length < element length\n"); + bss_info_length = 0; + continue; + } + + switch (*pelement_id) { + case SSID: + if (*pelement_len && + *pelement_len <= + MRVDRV_MAX_SSID_LENGTH) { + memcpy(bss_info->ssid, pcurrent, + *pelement_len); + bss_info->ssid_len = + *pelement_len; + } + break; + + case WPA_IE: + pwpa_ie = + (IEEEtypes_VendorSpecific_t *) + pelement_id; + if ((memcmp + (pwpa_ie->vend_hdr.oui, wpa_oui, + sizeof(pwpa_ie->vend_hdr.oui)) == + 0) + && (pwpa_ie->vend_hdr.oui_type == + wpa_oui[3])) { + /* WPA IE found, 'W' for WPA */ + bss_info->priv_cap = 'W'; + } else { + pwmm_ie = + (IEEEtypes_WmmParameter_t + *)pelement_id; + if ((memcmp + (pwmm_ie->vend_hdr.oui, + wmm_oui, + sizeof(pwmm_ie->vend_hdr. + oui)) == 0) + && (pwmm_ie->vend_hdr. + oui_type == + wmm_oui[3])) { + /* Check the subtype: 1 == parameter, 0 == info */ + if ((pwmm_ie->vend_hdr. + oui_subtype == 1) + && pwmm_ie-> + ac_params + [WMM_AC_VO]. + aci_aifsn.acm) { + /* Call admission on VO; 'C' for CAC */ + bss_info-> + wmm_cap + = 'C'; + } else { + /* No CAC; 'M' for uh, WMM */ + bss_info-> + wmm_cap + = 'M'; + } + } else { + pwps_ie = + (IEEEtypes_VendorSpecific_t + *)pelement_id; + if ((memcmp + (pwps_ie->vend_hdr. + oui, wps_oui, + sizeof(pwps_ie-> + vend_hdr. + oui)) == 0) + && (pwps_ie-> + vend_hdr. + oui_type == + wps_oui[3])) { + bss_info-> + wps_cap + = 'S'; + } + } + } + break; + + case RSN_IE: + /* RSN IE found; '2' for WPA2 (RSN) */ + bss_info->priv_cap = '2'; + break; + case HT_CAPABILITY: + bss_info->ht_cap = 'N'; + break; + case VHT_CAPABILITY: + bss_info->vht_cap[0] = 'A'; + bss_info->vht_cap[1] = 'C'; + break; + default: + break; + } + + pcurrent += *pelement_len; + bss_info_length -= (2 + *pelement_len); + } + + /* Create a sorted list of BSS using Insertion Sort. */ + if ((argc > 3) && !strcmp(argv[3], "ch")) { + /* Sort by channel number (ascending order) */ + new_ch = fixed_fields.channel; + sort_by_channel = 1; + } else { + /* Sort as per Signal Strength (descending order) (Default case) */ + new_ss = 255 - fixed_fields.rssi; + } + if (scan_list_head == NULL) { + /* Node is the first element in the list. */ + scan_list_head = scan_list_node; + scan_list_node->next = NULL; + scan_list_node->prev = NULL; + } else { + curr = scan_list_head; + insert = 0; + do { + if (sort_by_channel) { + curr_ch = + curr->fixed_buf. + fixed_fields.channel; + if (new_ch < curr_ch) + insert = 1; + } else { + curr_ss = + 255 - + curr->fixed_buf. + fixed_fields.rssi; + if (new_ss > curr_ss) { + insert = 1; + } + } + if (insert) { + if (curr == scan_list_head) { + /* Insert the node to head of the list */ + scan_list_node->next = + scan_list_head; + scan_list_head->prev = + scan_list_node; + scan_list_head = + scan_list_node; + } else { + /* Insert the node to current position in list */ + scan_list_node->prev = + curr->prev; + scan_list_node->next = + curr; + (curr->prev)->next = + scan_list_node; + curr->prev = + scan_list_node; + } + break; + } + if (curr->next == NULL) { + /* Insert the node to tail of the list */ + curr->next = scan_list_node; + scan_list_node->prev = curr; + scan_list_node->next = NULL; + break; + } + curr = curr->next; + } while (curr != NULL); + } + } + scan_start += prsp_info->scan_number; + } while (prsp_info->scan_number); + + /* Display scan results */ + printf("---------------------------------------"); + printf("---------------------------------------\n"); + printf("# | ch | ss | ld | bssid | cap | SSID \n"); + printf("---------------------------------------"); + printf("---------------------------------------\n"); + + for (curr = scan_list_head, idx = 0; + (curr != NULL) && ((unsigned int)idx < total_scan_res); + curr = curr->next, idx++) { + fixed_fields = curr->fixed_buf.fixed_fields; + bss_info = &curr->bss_info_buf; + if (wlan_is_channel_valid(scan_req, fixed_fields.channel)) + continue; + + if (setuserscan_filter == BSSID_FILTER) { + if (scan_req->bssid_num) { + for (i = 0; i < scan_req->bssid_num; i++) { + if (memcmp + (scan_req->bssid_list[i].bssid, + fixed_fields.bssid, ETH_ALEN)) + continue; + } + } else if (memcmp + (scan_req->specific_bssid, + fixed_fields.bssid, ETH_ALEN)) + continue; + } + if (setuserscan_filter == SSID_FILTER) { + if (filter_ssid_result + (scan_req, num_ssid_filter, bss_info)) + continue; + } + printf("%02u| %03d | %03d | %03d | %02x:%02x:%02x:%02x:%02x:%02x |", idx, fixed_fields.channel, -fixed_fields.rssi, fixed_fields.chan_load, fixed_fields.bssid[0], fixed_fields.bssid[1], fixed_fields.bssid[2], fixed_fields.bssid[3], fixed_fields.bssid[4], fixed_fields.bssid[5]); + displayed_info = TRUE; + + /* "A" for Adhoc + * "I" for Infrastructure, + * "D" for DFS (Spectrum Mgmt) + */ + printf(" %c%c%c%c%c%c%c%c%c%c | ", bss_info->cap_info.ibss ? 'A' : 'I', bss_info->priv_cap, /* P (WEP), W (WPA), 2 (WPA2) */ + bss_info->cap_info.spectrum_mgmt ? 'D' : ' ', bss_info->wmm_cap, /* M (WMM), C (WMM-Call Admission Control) */ + bss_info->dot11k_cap, /* K */ + bss_info->dot11r_cap, /* R */ + bss_info->wps_cap, /* S */ + bss_info->ht_cap, /* N */ + bss_info->vht_cap[0], /* AC */ + bss_info->vht_cap[1]); + + /* Print out the ssid or the hex values if non-printable */ + for (ssid_idx = 0; ssid_idx < (int)bss_info->ssid_len; + ssid_idx++) { + if (isprint(bss_info->ssid[ssid_idx])) { + printf("%c", bss_info->ssid[ssid_idx]); + } else { + printf("\\%02x", bss_info->ssid[ssid_idx]); + } + } + + printf("\n"); + + if (argc > 3 && strcmp(argv[3], "tsf") == 0) { + /* TSF is a u64, some formatted printing libs have trouble + printing long longs, so cast and dump as bytes */ + pbyte = (t_u8 *)&fixed_fields.network_tsf; + printf(" TSF=%02x%02x%02x%02x%02x%02x%02x%02x\n", + pbyte[7], pbyte[6], pbyte[5], pbyte[4], + pbyte[3], pbyte[2], pbyte[1], pbyte[0]); + } + } + + if (displayed_info == TRUE) { + if (argc > 3 && strcmp(argv[3], "help") == 0) { + printf("\n\n" + "Capability Legend (Not all may be supported)\n" + "-----------------\n" + " I [ Infrastructure ]\n" + " A [ Ad-hoc ]\n" + " W [ WPA IE ]\n" + " 2 [ WPA2/RSN IE ]\n" + " M [ WMM IE ]\n" + " C [ Call Admission Control - WMM IE, VO ACM set ]\n" + " D [ Spectrum Management - DFS (11h) ]\n" + " K [ 11k ]\n" + " R [ 11r ]\n" + " S [ WPS ]\n" + " N [ HT (11n) ]\n" + " AC [VHT (11ac) ]\n" "\n\n"); + } + } else { + printf("< No Scan Results >\n"); + } + + for (curr = scan_list_head; curr != NULL; curr = next) { + next = curr->next; + free(curr); + } + argv[2] = "getchanstats"; + process_getchanstats(argc, argv); + + if (buffer) + free(buffer); + if (cmd) + free(cmd); + + return MLAN_STATUS_SUCCESS; +} + +/** + * @brief Process getschstats command + * @param argc Number of arguments + * @param argv A pointer to arguments array + * @return MLAN_STATUS_SUCCESS--success, otherwise--fail + */ +static int +process_getchanstats(int argc, char *argv[]) +{ + return wlan_process_getchanstats(argc, argv); +} + +/** + * @brief Process getscantable command + * @param argc Number of arguments + * @param argv A pointer to arguments array + * @param scan_req A pointer to wlan_ioctl_user_scan_cfg structure + * @return MLAN_STATUS_SUCCESS--success, otherwise--fail + */ +static int +process_getscantable(int argc, char *argv[]) +{ + return wlan_process_getscantable(argc, argv, NULL); +} + +/** + * @brief Prepare setuserscan command buffer + * @param scan_req pointer to wlan_ioctl_user_scan_cfg structure + * @param num Number of arguments + * @param args Arguments list + * @return MLAN_STATUS_SUCCESS + */ +static int +prepare_setuserscan_buffer(wlan_ioctl_user_scan_cfg *scan_req, t_u32 num, + char *args[]) +{ + int arg_idx = 0; + int num_ssid = 0; + int num_bssid = 0; + char *parg_tok = NULL; + char *pchan_tok = NULL; + char *parg_cookie = NULL; + char *pchan_cookie = NULL; + int chan_parse_idx = 0; + int chan_cmd_idx = 0; + char chan_scratch[MAX_CHAN_SCRATCH]; + char *pscratch = NULL; + int tmp_idx = 0; + int scan_time = 0; + int is_radio_set = 0; + unsigned int mac[ETH_ALEN]; + + for (arg_idx = 0; arg_idx < (int)num; arg_idx++) { + if (strncmp(args[arg_idx], "ssid=", strlen("ssid=")) == 0) { + /* "ssid" token string handler */ + if (num_ssid < MRVDRV_MAX_SSID_LIST_LENGTH) { + strncpy(scan_req->ssid_list[num_ssid].ssid, + args[arg_idx] + strlen("ssid="), + sizeof(scan_req->ssid_list[num_ssid]. + ssid)); + + scan_req->ssid_list[num_ssid].max_len = 0; + setuserscan_filter = SSID_FILTER; + num_ssid++; + num_ssid_filter++; + } + } else if (strncmp(args[arg_idx], "bssid=", strlen("bssid=")) == + 0) { + /* "bssid" token string handler */ + if (num_bssid < MAX_BSSID_FILTER_LIST) { + sscanf(args[arg_idx] + strlen("bssid="), + "%2x:%2x:%2x:%2x:%2x:%2x", mac + 0, + mac + 1, mac + 2, mac + 3, mac + 4, + mac + 5); + setuserscan_filter = BSSID_FILTER; + for (tmp_idx = 0; + (unsigned int)tmp_idx < NELEMENTS(mac); + tmp_idx++) { + scan_req->bssid_list[num_bssid]. + bssid[tmp_idx] = + (t_u8)mac[tmp_idx]; + } + /* Update BSSID into specific_bssid field */ + if (scan_req->bssid_num == 0) { + for (tmp_idx = 0; + (unsigned int)tmp_idx < + NELEMENTS(mac); tmp_idx++) { + scan_req-> + specific_bssid[tmp_idx] + = (t_u8)mac[tmp_idx]; + } + } + num_bssid++; + scan_req->bssid_num = num_bssid; + } + + } else if (strncmp(args[arg_idx], "chan=", strlen("chan=")) == + 0) { + /* "chan" token string handler */ + parg_tok = args[arg_idx] + strlen("chan="); + + if (strlen(parg_tok) > MAX_CHAN_SCRATCH) { + printf("Error: Specified channels exceeds max limit\n"); + return MLAN_STATUS_FAILURE; + } + is_radio_set = FALSE; + + while ((parg_tok = + strtok_r(parg_tok, ",", + &parg_cookie)) != NULL) { + + memset(chan_scratch, 0x00, + sizeof(chan_scratch)); + pscratch = chan_scratch; + + for (chan_parse_idx = 0; + (unsigned int)chan_parse_idx < + strlen(parg_tok); chan_parse_idx++) { + if (isalpha + (*(parg_tok + chan_parse_idx))) { + *pscratch++ = ' '; + } + + *pscratch++ = + *(parg_tok + chan_parse_idx); + } + *pscratch = 0; + parg_tok = NULL; + + pchan_tok = chan_scratch; + + while ((pchan_tok = strtok_r(pchan_tok, " ", + &pchan_cookie)) != + NULL) { + if (isdigit(*pchan_tok)) { + scan_req-> + chan_list[chan_cmd_idx]. + chan_number = + atoi(pchan_tok); + if (scan_req-> + chan_list[chan_cmd_idx]. + chan_number > + MAX_CHAN_BG_BAND) + scan_req-> + chan_list + [chan_cmd_idx]. + radio_type = 1; + } else { + switch (toupper(*pchan_tok)) { + case 'A': + scan_req-> + chan_list + [chan_cmd_idx]. + radio_type = 1; + is_radio_set = TRUE; + break; + case 'B': + case 'G': + scan_req-> + chan_list + [chan_cmd_idx]. + radio_type = 0; + is_radio_set = TRUE; + break; + case 'N': + break; + case 'C': + scan_req-> + chan_list + [chan_cmd_idx]. + scan_type = + MLAN_SCAN_TYPE_ACTIVE; + break; + case 'P': + scan_req-> + chan_list + [chan_cmd_idx]. + scan_type = + MLAN_SCAN_TYPE_PASSIVE; + break; + default: + printf("Error: Band type not supported!\n"); + return -EOPNOTSUPP; + } + if (!chan_cmd_idx && + !scan_req-> + chan_list[chan_cmd_idx]. + chan_number && is_radio_set) + scan_req-> + chan_list + [chan_cmd_idx]. + radio_type |= + BAND_SPECIFIED; + } + pchan_tok = NULL; + } + if (((scan_req->chan_list[chan_cmd_idx]. + chan_number > MAX_CHAN_BG_BAND) + && !scan_req->chan_list[chan_cmd_idx]. + radio_type) || + ((scan_req->chan_list[chan_cmd_idx]. + chan_number < MAX_CHAN_BG_BAND) + && (scan_req->chan_list[chan_cmd_idx]. + radio_type == 1))) { + printf("Error: Invalid Radio type: chan=%d radio_type=%d\n", scan_req->chan_list[chan_cmd_idx].chan_number, scan_req->chan_list[chan_cmd_idx].radio_type); + return MLAN_STATUS_FAILURE; + } + chan_cmd_idx++; + } + } else if (strncmp(args[arg_idx], "gap=", strlen("gap=")) == 0) { + scan_req->scan_chan_gap = + atoi(args[arg_idx] + strlen("gap=")); + } else if (strncmp(args[arg_idx], "keep=", strlen("keep=")) == + 0) { + /* "keep" token string handler */ + scan_req->keep_previous_scan = + atoi(args[arg_idx] + strlen("keep=")); + } else if (strncmp(args[arg_idx], "dur=", strlen("dur=")) == 0) { + /* "dur" token string handler */ + scan_time = atoi(args[arg_idx] + strlen("dur=")); + scan_req->chan_list[0].scan_time = scan_time; + + } else if (strncmp(args[arg_idx], "wc=", strlen("wc=")) == 0) { + + if (num_ssid < MRVDRV_MAX_SSID_LIST_LENGTH) { + /* "wc" token string handler */ + pscratch = strrchr(args[arg_idx], ','); + + if (pscratch) { + *pscratch = 0; + pscratch++; + + if (isdigit(*pscratch)) { + scan_req->ssid_list[num_ssid]. + max_len = + atoi(pscratch); + } else { + scan_req->ssid_list[num_ssid]. + max_len = *pscratch; + } + } else { + /* Standard wildcard matching */ + scan_req->ssid_list[num_ssid].max_len = + 0xFF; + } + + strncpy(scan_req->ssid_list[num_ssid].ssid, + args[arg_idx] + strlen("wc="), + sizeof(scan_req->ssid_list[num_ssid]. + ssid)); + + num_ssid++; + } + } else if (strncmp(args[arg_idx], "probes=", strlen("probes=")) + == 0) { + /* "probes" token string handler */ + scan_req->num_probes = + atoi(args[arg_idx] + strlen("probes=")); + if (scan_req->num_probes > MAX_PROBES) { + fprintf(stderr, "Invalid probes (> %d)\n", + MAX_PROBES); + return -EOPNOTSUPP; + } + } else if (strncmp + (args[arg_idx], "bss_type=", + strlen("bss_type=")) == 0) { + /* "bss_type" token string handler */ + scan_req->bss_mode = + atoi(args[arg_idx] + strlen("bss_type=")); + switch (scan_req->bss_mode) { + case MLAN_SCAN_MODE_BSS: + case MLAN_SCAN_MODE_IBSS: + break; + case MLAN_SCAN_MODE_ANY: + default: + /* Set any unknown types to ANY */ + scan_req->bss_mode = MLAN_SCAN_MODE_ANY; + break; + } + } else if (strncmp + (args[arg_idx], "scan_type=", + strlen("scan_type=")) == 0) { + /* "scan_type" token string handler */ + scan_req->ext_scan_type = + atoi(args[arg_idx] + strlen("scan_type=")); + } + } + + /* Update all the channels to have the same scan time */ + for (tmp_idx = 1; tmp_idx < chan_cmd_idx; tmp_idx++) { + scan_req->chan_list[tmp_idx].scan_time = scan_time; + } + + return MLAN_STATUS_SUCCESS; +} + +/** + * @brief Process setuserscan command + * @param argc Number of arguments + * @param argv A pointer to arguments array + * @return MLAN_STATUS_SUCCESS--success, otherwise--fail + */ +static int +process_setuserscan(int argc, char *argv[]) +{ + wlan_ioctl_user_scan_cfg *scan_req = NULL; + t_u8 *pos = NULL; + t_u8 *buffer = NULL; + struct eth_priv_cmd *cmd = NULL; + struct ifreq ifr; + int status = 0; + + /* Initialize buffer */ + buffer = (t_u8 *)malloc(BUFFER_LENGTH); + if (!buffer) { + printf("ERR:Cannot allocate buffer for command!\n"); + return MLAN_STATUS_FAILURE; + } + + memset(buffer, 0, BUFFER_LENGTH); + + /* Flag it for our use */ + pos = buffer; + strncpy((char *)pos, CMD_NXP, strlen(CMD_NXP)); + pos += (strlen(CMD_NXP)); + + /* Insert command */ + strncpy((char *)pos, (char *)argv[2], strlen(argv[2])); + pos += (strlen(argv[2])); + + /* Insert arguments */ + scan_req = (wlan_ioctl_user_scan_cfg *)pos; + + if (prepare_setuserscan_buffer(scan_req, (argc - 3), &argv[3])) { + printf("ERR:Invalid parameter\n"); + free(buffer); + return MLAN_STATUS_FAILURE; + } + + cmd = (struct eth_priv_cmd *)malloc(sizeof(struct eth_priv_cmd)); + if (!cmd) { + printf("ERR:Cannot allocate buffer for command!\n"); + free(buffer); + return MLAN_STATUS_FAILURE; + } + + /* Fill up buffer */ +#ifdef USERSPACE_32BIT_OVER_KERNEL_64BIT + memset(cmd, 0, sizeof(struct eth_priv_cmd)); + memcpy(&cmd->buf, &buffer, sizeof(buffer)); +#else + cmd->buf = buffer; +#endif + cmd->used_len = 0; + cmd->total_len = BUFFER_LENGTH; + + /* Perform IOCTL */ + memset(&ifr, 0, sizeof(struct ifreq)); + strncpy(ifr.ifr_ifrn.ifrn_name, dev_name, strlen(dev_name)); + ifr.ifr_ifru.ifru_data = (void *)cmd; + + if (ioctl(sockfd, MLAN_ETH_PRIV, &ifr)) { + perror("mlanutl"); + fprintf(stderr, "mlanutl: setuserscan fail\n"); + if (cmd) + free(cmd); + if (buffer) + free(buffer); + return MLAN_STATUS_FAILURE; + } + if (argc > 3) { + if (!strcmp(argv[3], "sort_by_ch")) { + argv[3] = "ch"; + } else { + argc = 0; + } + } + do { + argv[2] = "getscantable"; + status = wlan_process_getscantable(argc, argv, scan_req); + } while (status == -EAGAIN); + + if (buffer) + free(buffer); + if (cmd) + free(cmd); + return MLAN_STATUS_SUCCESS; +} + +/** + * @brief Process extended capabilities configuration + * @param argc Number of arguments + * @param argv A pointer to arguments array + * @return MLAN_STATUS_SUCCESS--success, otherwise--fail + */ +static int +process_extcapcfg(int argc, char *argv[]) +{ + t_u8 *buffer = NULL, ext_cap[9]; + struct eth_priv_cmd *cmd = NULL; + struct ifreq ifr; + IEEEtypes_Header_t ie; + + if (argc > 4) { + printf("ERR:Incorrect number of arguments.\n"); + printf("Syntax: ./mlanutl mlanX extcapcfg \n"); + return MLAN_STATUS_FAILURE; + } + + if (argc == 4 && MLAN_STATUS_FAILURE == ishexstring(argv[3])) { + printf("ERR:Only hex digits are allowed.\n"); + printf("Syntax: ./mlanutl mlanX extcapcfg \n"); + return MLAN_STATUS_FAILURE; + } + + /* Initialize buffer */ + buffer = (t_u8 *)malloc(BUFFER_LENGTH); + if (!buffer) { + printf("ERR:Cannot allocate buffer for command!\n"); + return MLAN_STATUS_FAILURE; + } + + /* Only insert command */ + prepare_buffer(buffer, argv[2], 0, NULL); + + if (argc == 4) { + if (!strncasecmp("0x", argv[3], 2)) + argv[3] += 2; + + if (strlen(argv[3]) > 2 * sizeof(ext_cap)) { + printf("ERR:Incorrect length of arguments.\n"); + printf("Syntax: ./mlanutl mlanX extcapcfg \n"); + free(buffer); + return MLAN_STATUS_FAILURE; + } + + memset(ext_cap, 0, sizeof(ext_cap)); + ie.element_id = TLV_TYPE_EXTCAP; + ie.len = sizeof(ext_cap); + + string2raw(argv[3], ext_cap); + memcpy(buffer + strlen(CMD_NXP) + strlen(argv[2]), &ie, + sizeof(ie)); + memcpy(buffer + strlen(CMD_NXP) + strlen(argv[2]) + sizeof(ie), + ext_cap, sizeof(ext_cap)); + } + + cmd = (struct eth_priv_cmd *)malloc(sizeof(struct eth_priv_cmd)); + if (!cmd) { + printf("ERR:Cannot allocate buffer for command!\n"); + free(buffer); + return MLAN_STATUS_FAILURE; + } + + /* Fill up buffer */ +#ifdef USERSPACE_32BIT_OVER_KERNEL_64BIT + memset(cmd, 0, sizeof(struct eth_priv_cmd)); + memcpy(&cmd->buf, &buffer, sizeof(buffer)); +#else + cmd->buf = buffer; +#endif + cmd->used_len = 0; + cmd->total_len = BUFFER_LENGTH; + + /* Perform IOCTL */ + memset(&ifr, 0, sizeof(struct ifreq)); + strncpy(ifr.ifr_ifrn.ifrn_name, dev_name, strlen(dev_name)); + ifr.ifr_ifru.ifru_data = (void *)cmd; + + if (ioctl(sockfd, MLAN_ETH_PRIV, &ifr)) { + perror("mlanutl"); + fprintf(stderr, + "mlanutl: extended capabilities configure fail\n"); + if (cmd) + free(cmd); + if (buffer) + free(buffer); + return MLAN_STATUS_FAILURE; + } + + /* Process result */ + hexdump("Extended capabilities", buffer + sizeof(IEEEtypes_Header_t), + ((IEEEtypes_Header_t *)buffer)->len, ' '); + + if (buffer) + free(buffer); + if (cmd) + free(cmd); + + return MLAN_STATUS_SUCCESS; +} + +/** + * @brief Cancel ongoing scan + * @param argc Number of arguments + * @param argv A pointer to arguments array + * @return MLAN_STATUS_SUCCESS--success, otherwise--fail + */ +static int +process_cancelscan(int argc, char *argv[]) +{ + t_u8 *buffer = NULL; + struct eth_priv_cmd *cmd = NULL; + struct ifreq ifr; + + if (argc != 3) { + printf("ERR:Incorrect number of arguments.\n"); + printf("Syntax: ./mlanutl mlanX cancelscan\n"); + return MLAN_STATUS_FAILURE; + } + + /* Initialize buffer */ + buffer = (t_u8 *)malloc(BUFFER_LENGTH); + if (!buffer) { + printf("ERR:Cannot allocate buffer for command!\n"); + return MLAN_STATUS_FAILURE; + } + + /* Only insert command */ + prepare_buffer(buffer, argv[2], 0, NULL); + + cmd = (struct eth_priv_cmd *)malloc(sizeof(struct eth_priv_cmd)); + if (!cmd) { + printf("ERR:Cannot allocate buffer for command!\n"); + free(buffer); + return MLAN_STATUS_FAILURE; + } + + /* Fill up buffer */ +#ifdef USERSPACE_32BIT_OVER_KERNEL_64BIT + memset(cmd, 0, sizeof(struct eth_priv_cmd)); + memcpy(&cmd->buf, &buffer, sizeof(buffer)); +#else + cmd->buf = buffer; +#endif + cmd->used_len = 0; + cmd->total_len = BUFFER_LENGTH; + + /* Perform IOCTL */ + memset(&ifr, 0, sizeof(struct ifreq)); + strncpy(ifr.ifr_ifrn.ifrn_name, dev_name, strlen(dev_name)); + ifr.ifr_ifru.ifru_data = (void *)cmd; + + if (ioctl(sockfd, MLAN_ETH_PRIV, &ifr)) { + perror("mlanutl"); + fprintf(stderr, "mlanutl: cancel scan fail\n"); + if (cmd) + free(cmd); + if (buffer) + free(buffer); + return MLAN_STATUS_FAILURE; + } + if (buffer) + free(buffer); + if (cmd) + free(cmd); + + return MLAN_STATUS_SUCCESS; +} +#endif /* STA_SUPPORT */ + +/** + * @brief Process deep sleep configuration + * @param argc Number of arguments + * @param argv A pointer to arguments array + * @return MLAN_STATUS_SUCCESS--success, otherwise--fail + */ +static int +process_deepsleep(int argc, char *argv[]) +{ + t_u8 *buffer = NULL; + struct eth_priv_cmd *cmd = NULL; + struct ifreq ifr; + + /* Initialize buffer */ + buffer = (t_u8 *)malloc(BUFFER_LENGTH); + if (!buffer) { + printf("ERR:Cannot allocate buffer for command!\n"); + return MLAN_STATUS_FAILURE; + } + + prepare_buffer(buffer, argv[2], (argc - 3), &argv[3]); + + cmd = (struct eth_priv_cmd *)malloc(sizeof(struct eth_priv_cmd)); + if (!cmd) { + printf("ERR:Cannot allocate buffer for command!\n"); + free(buffer); + return MLAN_STATUS_FAILURE; + } + + /* Fill up buffer */ +#ifdef USERSPACE_32BIT_OVER_KERNEL_64BIT + memset(cmd, 0, sizeof(struct eth_priv_cmd)); + memcpy(&cmd->buf, &buffer, sizeof(buffer)); +#else + cmd->buf = buffer; +#endif + cmd->used_len = 0; + cmd->total_len = BUFFER_LENGTH; + + /* Perform IOCTL */ + memset(&ifr, 0, sizeof(struct ifreq)); + strncpy(ifr.ifr_ifrn.ifrn_name, dev_name, strlen(dev_name)); + ifr.ifr_ifru.ifru_data = (void *)cmd; + + if (ioctl(sockfd, MLAN_ETH_PRIV, &ifr)) { + perror("mlanutl"); + fprintf(stderr, "mlanutl: deepsleep fail\n"); + if (cmd) + free(cmd); + if (buffer) + free(buffer); + return MLAN_STATUS_FAILURE; + } + + /* Process result */ + printf("Deepsleep command response: %s\n", buffer); + + if (buffer) + free(buffer); + if (cmd) + free(cmd); + + return MLAN_STATUS_SUCCESS; +} + +/** + * @brief Process ipaddr command + * @param argc Number of arguments + * @param argv A pointer to arguments array + * @return MLAN_STATUS_SUCCESS--success, otherwise--fail + */ +static int +process_ipaddr(int argc, char *argv[]) +{ + t_u8 *buffer = NULL; + struct eth_priv_cmd *cmd = NULL; + struct ifreq ifr; + + /* Initialize buffer */ + buffer = (t_u8 *)malloc(BUFFER_LENGTH); + if (!buffer) { + printf("ERR:Cannot allocate buffer for command!\n"); + return MLAN_STATUS_FAILURE; + } + + /* The argument being a string, this requires special handling */ + prepare_buffer(buffer, argv[2], 0, NULL); + if (argc >= 4) { + strcpy((char *)(buffer + strlen(CMD_NXP) + strlen(argv[2])), + argv[3]); + } + + cmd = (struct eth_priv_cmd *)malloc(sizeof(struct eth_priv_cmd)); + if (!cmd) { + printf("ERR:Cannot allocate buffer for command!\n"); + free(buffer); + return MLAN_STATUS_FAILURE; + } + + /* Fill up buffer */ +#ifdef USERSPACE_32BIT_OVER_KERNEL_64BIT + memset(cmd, 0, sizeof(struct eth_priv_cmd)); + memcpy(&cmd->buf, &buffer, sizeof(buffer)); +#else + cmd->buf = buffer; +#endif + cmd->used_len = 0; + cmd->total_len = BUFFER_LENGTH; + + /* Perform IOCTL */ + memset(&ifr, 0, sizeof(struct ifreq)); + strncpy(ifr.ifr_ifrn.ifrn_name, dev_name, strlen(dev_name)); + ifr.ifr_ifru.ifru_data = (void *)cmd; + + if (ioctl(sockfd, MLAN_ETH_PRIV, &ifr)) { + perror("mlanutl"); + fprintf(stderr, "mlanutl: ipaddr fail\n"); + if (cmd) + free(cmd); + if (buffer) + free(buffer); + return MLAN_STATUS_FAILURE; + } + + /* Process result */ + printf("IP address Configuration: %s\n", (char *)buffer); + + if (buffer) + free(buffer); + if (cmd) + free(cmd); + + return MLAN_STATUS_SUCCESS; +} + +/** + * @brief Process otpuserdata command + * @param argc Number of arguments + * @param argv A pointer to arguments array + * @return MLAN_STATUS_SUCCESS--success, otherwise--fail + */ +static int +process_otpuserdata(int argc, char *argv[]) +{ + t_u8 *buffer = NULL; + struct eth_priv_cmd *cmd = NULL; + struct ifreq ifr; + + if (argc < 4) { + printf("ERR:No argument\n"); + return MLAN_STATUS_FAILURE; + } + + if (a2hex_or_atoi(argv[3]) > BUFFER_LENGTH) { + printf("ERR: user_data_length too big\n"); + return MLAN_STATUS_FAILURE; + } + + /* Initialize buffer */ + buffer = (t_u8 *)malloc(BUFFER_LENGTH); + if (!buffer) { + printf("ERR:Cannot allocate buffer for command!\n"); + return MLAN_STATUS_FAILURE; + } + + prepare_buffer(buffer, argv[2], (argc - 3), &argv[3]); + + cmd = (struct eth_priv_cmd *)malloc(sizeof(struct eth_priv_cmd)); + if (!cmd) { + printf("ERR:Cannot allocate buffer for command!\n"); + free(buffer); + return MLAN_STATUS_FAILURE; + } + + /* Fill up buffer */ +#ifdef USERSPACE_32BIT_OVER_KERNEL_64BIT + memset(cmd, 0, sizeof(struct eth_priv_cmd)); + memcpy(&cmd->buf, &buffer, sizeof(buffer)); +#else + cmd->buf = buffer; +#endif + cmd->used_len = 0; + cmd->total_len = BUFFER_LENGTH; + + /* Perform IOCTL */ + memset(&ifr, 0, sizeof(struct ifreq)); + strncpy(ifr.ifr_ifrn.ifrn_name, dev_name, strlen(dev_name)); + ifr.ifr_ifru.ifru_data = (void *)cmd; + + if (ioctl(sockfd, MLAN_ETH_PRIV, &ifr)) { + perror("mlanutl"); + fprintf(stderr, "mlanutl: otpuserdata fail\n"); + if (cmd) + free(cmd); + if (buffer) + free(buffer); + return MLAN_STATUS_FAILURE; + } + + /* Process result */ + hexdump("OTP user data: ", buffer, + MIN(cmd->used_len, a2hex_or_atoi(argv[3])), ' '); + + if (buffer) + free(buffer); + if (cmd) + free(cmd); + + return MLAN_STATUS_SUCCESS; +} + +/** + * @brief Process countrycode setting + * @param argc Number of arguments + * @param argv A pointer to arguments array + * @return MLAN_STATUS_SUCCESS--success, otherwise--fail + */ +static int +process_countrycode(int argc, char *argv[]) +{ + t_u8 *buffer = NULL; + struct eth_priv_cmd *cmd = NULL; + struct eth_priv_countrycode *countrycode = NULL; + struct ifreq ifr; + + /* Initialize buffer */ + buffer = (t_u8 *)malloc(BUFFER_LENGTH); + if (!buffer) { + printf("ERR:Cannot allocate buffer for command!\n"); + return MLAN_STATUS_FAILURE; + } + + /* The argument being a string, this requires special handling */ + prepare_buffer(buffer, argv[2], 0, NULL); + if (argc >= 4) { + strcpy((char *)(buffer + strlen(CMD_NXP) + strlen(argv[2])), + argv[3]); + } + + cmd = (struct eth_priv_cmd *)malloc(sizeof(struct eth_priv_cmd)); + if (!cmd) { + printf("ERR:Cannot allocate buffer for command!\n"); + free(buffer); + return MLAN_STATUS_FAILURE; + } + + /* Fill up buffer */ +#ifdef USERSPACE_32BIT_OVER_KERNEL_64BIT + memset(cmd, 0, sizeof(struct eth_priv_cmd)); + memcpy(&cmd->buf, &buffer, sizeof(buffer)); +#else + cmd->buf = buffer; +#endif + cmd->used_len = 0; + cmd->total_len = BUFFER_LENGTH; + + /* Perform IOCTL */ + memset(&ifr, 0, sizeof(struct ifreq)); + strncpy(ifr.ifr_ifrn.ifrn_name, dev_name, strlen(dev_name)); + ifr.ifr_ifru.ifru_data = (void *)cmd; + + if (ioctl(sockfd, MLAN_ETH_PRIV, &ifr)) { + perror("mlanutl"); + fprintf(stderr, "mlanutl: countrycode fail\n"); + if (cmd) + free(cmd); + if (buffer) + free(buffer); + return MLAN_STATUS_FAILURE; + } + + /* Process result */ + countrycode = (struct eth_priv_countrycode *)buffer; + if (argc == 3) { + /* GET operation */ + printf("Country code: %s\n", countrycode->country_code); + } + + if (buffer) + free(buffer); + if (cmd) + free(cmd); + + return MLAN_STATUS_SUCCESS; +} + +/** + * @brief Process TCP ACK enhancement configuration + * @param argc Number of arguments + * @param argv A pointer to arguments array + * @return MLAN_STATUS_SUCCESS--success, otherwise--fail + */ +static int +process_tcpackenh(int argc, char *argv[]) +{ + t_u8 *buffer = NULL; + struct eth_priv_cmd *cmd = NULL; + struct ifreq ifr; + + /* Initialize buffer */ + buffer = (t_u8 *)malloc(BUFFER_LENGTH); + if (!buffer) { + printf("ERR:Cannot allocate buffer for command!\n"); + return MLAN_STATUS_FAILURE; + } + + prepare_buffer(buffer, argv[2], (argc - 3), &argv[3]); + + cmd = (struct eth_priv_cmd *)malloc(sizeof(struct eth_priv_cmd)); + if (!cmd) { + printf("ERR:Cannot allocate buffer for command!\n"); + free(buffer); + return MLAN_STATUS_FAILURE; + } + + /* Fill up buffer */ +#ifdef USERSPACE_32BIT_OVER_KERNEL_64BIT + memset(cmd, 0, sizeof(struct eth_priv_cmd)); + memcpy(&cmd->buf, &buffer, sizeof(buffer)); +#else + cmd->buf = buffer; +#endif + cmd->used_len = 0; + cmd->total_len = BUFFER_LENGTH; + + /* Perform IOCTL */ + memset(&ifr, 0, sizeof(struct ifreq)); + strncpy(ifr.ifr_ifrn.ifrn_name, dev_name, strlen(dev_name)); + ifr.ifr_ifru.ifru_data = (void *)cmd; + + if (ioctl(sockfd, MLAN_ETH_PRIV, &ifr)) { + perror("mlanutl"); + fprintf(stderr, "mlanutl: tcpackenh fail\n"); + if (cmd) + free(cmd); + if (buffer) + free(buffer); + return MLAN_STATUS_FAILURE; + } + + /* Process result */ + printf("TCP Ack enhancement: "); + if (buffer[0]) + printf("enabled.\n"); + else + printf("disabled.\n"); + + if (buffer) + free(buffer); + if (cmd) + free(cmd); + + return MLAN_STATUS_SUCCESS; +} + +#ifdef REASSOCIATION +/** + * @brief Process asynced essid setting + * @param argc Number of arguments + * @param argv A pointer to arguments array + * @return MLAN_STATUS_SUCCESS--success, otherwise--fail + */ +static int +process_assocessid(int argc, char *argv[]) +{ + t_u8 *buffer = NULL; + struct eth_priv_cmd *cmd = NULL; + struct ifreq ifr; + + /* Initialize buffer */ + buffer = (t_u8 *)malloc(BUFFER_LENGTH); + if (!buffer) { + printf("ERR:Cannot allocate buffer for command!\n"); + return MLAN_STATUS_FAILURE; + } + + /* The argument being a string, this requires special handling */ + prepare_buffer(buffer, argv[2], 0, NULL); + if (argc >= 4) { + strcpy((char *)(buffer + strlen(CMD_NXP) + strlen(argv[2])), + argv[3]); + } + + cmd = (struct eth_priv_cmd *)malloc(sizeof(struct eth_priv_cmd)); + if (!cmd) { + printf("ERR:Cannot allocate buffer for command!\n"); + free(buffer); + return MLAN_STATUS_FAILURE; + } + + /* Fill up buffer */ +#ifdef USERSPACE_32BIT_OVER_KERNEL_64BIT + memset(cmd, 0, sizeof(struct eth_priv_cmd)); + memcpy(&cmd->buf, &buffer, sizeof(buffer)); +#else + cmd->buf = buffer; +#endif + cmd->used_len = 0; + cmd->total_len = BUFFER_LENGTH; + + /* Perform IOCTL */ + memset(&ifr, 0, sizeof(struct ifreq)); + strncpy(ifr.ifr_ifrn.ifrn_name, dev_name, strlen(dev_name)); + ifr.ifr_ifru.ifru_data = (void *)cmd; + + if (ioctl(sockfd, MLAN_ETH_PRIV, &ifr)) { + perror("mlanutl"); + fprintf(stderr, "mlanutl: assocessid fail\n"); + if (cmd) + free(cmd); + if (buffer) + free(buffer); + return MLAN_STATUS_FAILURE; + } + + /* Process result */ + printf("Set Asynced ESSID: %s\n", (char *)buffer); + + if (buffer) + free(buffer); + if (cmd) + free(cmd); + + return MLAN_STATUS_SUCCESS; + +} +#endif + +#ifdef STA_SUPPORT +/** + * @brief Process listen interval configuration + * @param argc number of arguments + * @param argv A pointer to arguments array + * @return MLAN_STATUS_SUCCESS--success, otherwise--fail + */ +static int +process_listeninterval(int argc, char *argv[]) +{ + t_u8 *buffer = NULL; + struct eth_priv_cmd *cmd = NULL; + struct ifreq ifr; + + /* Initialize buffer */ + buffer = (t_u8 *)malloc(BUFFER_LENGTH); + if (!buffer) { + printf("ERR:Cannot allocate buffer for command!\n"); + return MLAN_STATUS_FAILURE; + } + + prepare_buffer(buffer, argv[2], (argc - 3), &argv[3]); + + cmd = (struct eth_priv_cmd *)malloc(sizeof(struct eth_priv_cmd)); + if (!cmd) { + printf("ERR:Cannot allocate buffer for command!\n"); + free(buffer); + return MLAN_STATUS_FAILURE; + } + + /* Fill up buffer */ +#ifdef USERSPACE_32BIT_OVER_KERNEL_64BIT + memset(cmd, 0, sizeof(struct eth_priv_cmd)); + memcpy(&cmd->buf, &buffer, sizeof(buffer)); +#else + cmd->buf = buffer; +#endif + cmd->used_len = 0; + cmd->total_len = BUFFER_LENGTH; + + /* Perform IOCTL */ + memset(&ifr, 0, sizeof(struct ifreq)); + strncpy(ifr.ifr_ifrn.ifrn_name, dev_name, strlen(dev_name)); + ifr.ifr_ifru.ifru_data = (void *)cmd; + + if (ioctl(sockfd, MLAN_ETH_PRIV, &ifr)) { + perror("mlanutl"); + fprintf(stderr, "mlanutl: listen interval fail\n"); + if (cmd) + free(cmd); + if (buffer) + free(buffer); + return MLAN_STATUS_FAILURE; + } + + /* Process result */ + if (argc == 3) + printf("Listen interval command response: %s\n", buffer); + + if (buffer) + free(buffer); + if (cmd) + free(cmd); + + return MLAN_STATUS_SUCCESS; +} + +/** + * @brief Process power save mode setting + * @param argc Number of arguments + * @param argv A pointer to arguments array + * @return MLAN_STATUS_SUCCESS--success, otherwise--fail + */ +static int +process_psmode(int argc, char *argv[]) +{ + t_u8 *buffer = NULL; + struct eth_priv_cmd *cmd = NULL; + struct ifreq ifr; + int psmode = 0; + + /* Initialize buffer */ + buffer = (t_u8 *)malloc(BUFFER_LENGTH); + if (!buffer) { + printf("ERR:Cannot allocate buffer for command!\n"); + return MLAN_STATUS_FAILURE; + } + + prepare_buffer(buffer, argv[2], (argc - 3), &argv[3]); + + cmd = (struct eth_priv_cmd *)malloc(sizeof(struct eth_priv_cmd)); + if (!cmd) { + printf("ERR:Cannot allocate buffer for command!\n"); + free(buffer); + return MLAN_STATUS_FAILURE; + } + + /* Fill up buffer */ +#ifdef USERSPACE_32BIT_OVER_KERNEL_64BIT + memset(cmd, 0, sizeof(struct eth_priv_cmd)); + memcpy(&cmd->buf, &buffer, sizeof(buffer)); +#else + cmd->buf = buffer; +#endif + cmd->used_len = 0; + cmd->total_len = BUFFER_LENGTH; + + /* Perform IOCTL */ + memset(&ifr, 0, sizeof(struct ifreq)); + strncpy(ifr.ifr_ifrn.ifrn_name, dev_name, strlen(dev_name)); + ifr.ifr_ifru.ifru_data = (void *)cmd; + + if (ioctl(sockfd, MLAN_ETH_PRIV, &ifr)) { + perror("mlanutl"); + fprintf(stderr, "mlanutl: psmode fail\n"); + if (cmd) + free(cmd); + if (buffer) + free(buffer); + return MLAN_STATUS_FAILURE; + } + + /* Process result */ + psmode = *(int *)buffer; + printf("PS mode: %d\n", psmode); + + if (buffer) + free(buffer); + if (cmd) + free(cmd); + + return MLAN_STATUS_SUCCESS; +} +#endif + +#ifdef DEBUG_LEVEL1 +/** + * @brief Process driver debug configuration + * @param argc number of arguments + * @param argv A pointer to arguments array + * @return MLAN_STATUS_SUCCESS--success, otherwise--fail + */ +static int +process_drvdbg(int argc, char *argv[]) +{ + t_u8 *buffer = NULL; + struct eth_priv_cmd *cmd = NULL; + struct ifreq ifr; + t_u32 drvdbg; + + /* Initialize buffer */ + buffer = (t_u8 *)malloc(BUFFER_LENGTH); + if (!buffer) { + printf("ERR:Cannot allocate buffer for command!\n"); + return MLAN_STATUS_FAILURE; + } + + prepare_buffer(buffer, argv[2], (argc - 3), &argv[3]); + + cmd = (struct eth_priv_cmd *)malloc(sizeof(struct eth_priv_cmd)); + if (!cmd) { + printf("ERR:Cannot allocate buffer for command!\n"); + free(buffer); + return MLAN_STATUS_FAILURE; + } + + /* Fill up buffer */ +#ifdef USERSPACE_32BIT_OVER_KERNEL_64BIT + memset(cmd, 0, sizeof(struct eth_priv_cmd)); + memcpy(&cmd->buf, &buffer, sizeof(buffer)); +#else + cmd->buf = buffer; +#endif + cmd->used_len = 0; + cmd->total_len = BUFFER_LENGTH; + + /* Perform IOCTL */ + memset(&ifr, 0, sizeof(struct ifreq)); + strncpy(ifr.ifr_ifrn.ifrn_name, dev_name, strlen(dev_name)); + ifr.ifr_ifru.ifru_data = (void *)cmd; + + if (ioctl(sockfd, MLAN_ETH_PRIV, &ifr)) { + perror("mlanutl"); + fprintf(stderr, "mlanutl: drvdbg config fail\n"); + if (cmd) + free(cmd); + if (buffer) + free(buffer); + return MLAN_STATUS_FAILURE; + } + + /* Process result */ + if (argc == 3) { + memcpy(&drvdbg, buffer, sizeof(drvdbg)); + printf("drvdbg: 0x%08x\n", drvdbg); +#ifdef DEBUG_LEVEL2 + printf("MINFO (%08x) %s\n", MINFO, + (drvdbg & MINFO) ? "X" : ""); + printf("MWARN (%08x) %s\n", MWARN, + (drvdbg & MWARN) ? "X" : ""); + printf("MENTRY (%08x) %s\n", MENTRY, + (drvdbg & MENTRY) ? "X" : ""); +#endif + printf("MMPA_D (%08x) %s\n", MMPA_D, + (drvdbg & MMPA_D) ? "X" : ""); + printf("MIF_D (%08x) %s\n", MIF_D, + (drvdbg & MIF_D) ? "X" : ""); + printf("MFW_D (%08x) %s\n", MFW_D, + (drvdbg & MFW_D) ? "X" : ""); + printf("MEVT_D (%08x) %s\n", MEVT_D, + (drvdbg & MEVT_D) ? "X" : ""); + printf("MCMD_D (%08x) %s\n", MCMD_D, + (drvdbg & MCMD_D) ? "X" : ""); + printf("MDAT_D (%08x) %s\n", MDAT_D, + (drvdbg & MDAT_D) ? "X" : ""); + printf("MREG_D (%08x) %s\n", MREG_D, + (drvdbg & MREG_D) ? "X" : ""); + printf("MIOCTL (%08x) %s\n", MIOCTL, + (drvdbg & MIOCTL) ? "X" : ""); + printf("MINTR (%08x) %s\n", MINTR, + (drvdbg & MINTR) ? "X" : ""); + printf("MEVENT (%08x) %s\n", MEVENT, + (drvdbg & MEVENT) ? "X" : ""); + printf("MCMND (%08x) %s\n", MCMND, + (drvdbg & MCMND) ? "X" : ""); + printf("MDATA (%08x) %s\n", MDATA, + (drvdbg & MDATA) ? "X" : ""); + printf("MERROR (%08x) %s\n", MERROR, + (drvdbg & MERROR) ? "X" : ""); + printf("MFATAL (%08x) %s\n", MFATAL, + (drvdbg & MFATAL) ? "X" : ""); + printf("MMSG (%08x) %s\n", MMSG, (drvdbg & MMSG) ? "X" : ""); + + } + + if (buffer) + free(buffer); + if (cmd) + free(cmd); + + return MLAN_STATUS_SUCCESS; +} +#endif + +/** + * @brief Process hscfg configuration + * @param argc Number of arguments + * @param argv A pointer to arguments array + * @return MLAN_STATUS_SUCCESS--success, otherwise--fail + */ +static int +process_hscfg(int argc, char *argv[]) +{ + t_u8 *buffer = NULL; + struct eth_priv_cmd *cmd = NULL; + struct ifreq ifr; + struct eth_priv_hs_cfg *hscfg; + + /* Initialize buffer */ + buffer = (t_u8 *)malloc(BUFFER_LENGTH); + if (!buffer) { + printf("ERR:Cannot allocate buffer for command!\n"); + return MLAN_STATUS_FAILURE; + } + + prepare_buffer(buffer, argv[2], (argc - 3), &argv[3]); + + cmd = (struct eth_priv_cmd *)malloc(sizeof(struct eth_priv_cmd)); + if (!cmd) { + printf("ERR:Cannot allocate buffer for command!\n"); + free(buffer); + return MLAN_STATUS_FAILURE; + } + + /* Fill up buffer */ +#ifdef USERSPACE_32BIT_OVER_KERNEL_64BIT + memset(cmd, 0, sizeof(struct eth_priv_cmd)); + memcpy(&cmd->buf, &buffer, sizeof(buffer)); +#else + cmd->buf = buffer; +#endif + cmd->used_len = 0; + cmd->total_len = BUFFER_LENGTH; + + /* Perform IOCTL */ + memset(&ifr, 0, sizeof(struct ifreq)); + strncpy(ifr.ifr_ifrn.ifrn_name, dev_name, strlen(dev_name)); + ifr.ifr_ifru.ifru_data = (void *)cmd; + + if (ioctl(sockfd, MLAN_ETH_PRIV, &ifr)) { + perror("mlanutl"); + fprintf(stderr, "mlanutl: hscfg fail\n"); + if (cmd) + free(cmd); + if (buffer) + free(buffer); + return MLAN_STATUS_FAILURE; + } + + /* Process result */ + hscfg = (struct eth_priv_hs_cfg *)buffer; + if (argc == 3) { + /* GET operation */ + printf("HS Configuration:\n"); + printf(" Conditions: %d\n", (int)hscfg->conditions); + printf(" GPIO: %d\n", (int)hscfg->gpio); + printf(" GAP: %d\n", (int)hscfg->gap); + } + + if (buffer) + free(buffer); + if (cmd) + free(cmd); + + return MLAN_STATUS_SUCCESS; +} + +/** + * @brief Process hssetpara configuration + * @param argc Number of arguments + * @param argv A pointer to arguments array + * @return MLAN_STATUS_SUCCESS--success, otherwise--fail + */ +static int +process_hssetpara(int argc, char *argv[]) +{ + t_u8 *buffer = NULL; + struct eth_priv_cmd *cmd = NULL; + struct ifreq ifr; + + /* Initialize buffer */ + buffer = (t_u8 *)malloc(BUFFER_LENGTH); + if (!buffer) { + printf("ERR:Cannot allocate buffer for command!\n"); + return MLAN_STATUS_FAILURE; + } + + prepare_buffer(buffer, argv[2], (argc - 3), &argv[3]); + + cmd = (struct eth_priv_cmd *)malloc(sizeof(struct eth_priv_cmd)); + if (!cmd) { + printf("ERR:Cannot allocate buffer for command!\n"); + free(buffer); + return MLAN_STATUS_FAILURE; + } + + /* Fill up buffer */ +#ifdef USERSPACE_32BIT_OVER_KERNEL_64BIT + memset(cmd, 0, sizeof(struct eth_priv_cmd)); + memcpy(&cmd->buf, &buffer, sizeof(buffer)); +#else + cmd->buf = buffer; +#endif + cmd->used_len = 0; + cmd->total_len = BUFFER_LENGTH; + + /* Perform IOCTL */ + memset(&ifr, 0, sizeof(struct ifreq)); + strncpy(ifr.ifr_ifrn.ifrn_name, dev_name, strlen(dev_name)); + ifr.ifr_ifru.ifru_data = (void *)cmd; + + if (ioctl(sockfd, MLAN_ETH_PRIV, &ifr)) { + perror("mlanutl"); + fprintf(stderr, "mlanutl: hssetpara fail\n"); + if (cmd) + free(cmd); + if (buffer) + free(buffer); + return MLAN_STATUS_FAILURE; + } + + if (buffer) + free(buffer); + if (cmd) + free(cmd); + + return MLAN_STATUS_SUCCESS; +} + +/** + * @brief Process wakeup reason + * @param argc Number of arguments + * @param argv A pointer to arguments array + * @return MLAN_STATUS_SUCCESS--success, otherwise--fail + */ +static int +process_wakeupresaon(int argc, char *argv[]) +{ + t_u8 *buffer = NULL; + struct eth_priv_cmd *cmd = NULL; + struct ifreq ifr; + + /* Initialize buffer */ + buffer = (t_u8 *)malloc(BUFFER_LENGTH); + if (!buffer) { + printf("ERR:Cannot allocate buffer for command!\n"); + return MLAN_STATUS_FAILURE; + } + + prepare_buffer(buffer, argv[2], (argc - 3), &argv[3]); + + cmd = (struct eth_priv_cmd *)malloc(sizeof(struct eth_priv_cmd)); + if (!cmd) { + printf("ERR:Cannot allocate buffer for command!\n"); + free(buffer); + return MLAN_STATUS_FAILURE; + } + + /* Fill up buffer */ +#ifdef USERSPACE_32BIT_OVER_KERNEL_64BIT + memset(cmd, 0, sizeof(struct eth_priv_cmd)); + memcpy(&cmd->buf, &buffer, sizeof(buffer)); +#else + cmd->buf = buffer; +#endif + cmd->used_len = 0; + cmd->total_len = BUFFER_LENGTH; + + /* Perform IOCTL */ + memset(&ifr, 0, sizeof(struct ifreq)); + strncpy(ifr.ifr_ifrn.ifrn_name, dev_name, strlen(dev_name)); + ifr.ifr_ifru.ifru_data = (void *)cmd; + + if (ioctl(sockfd, MLAN_ETH_PRIV, &ifr)) { + perror("mlanutl"); + fprintf(stderr, "mlanutl: get wakeup reason fail\n"); + if (cmd) + free(cmd); + if (buffer) + free(buffer); + return MLAN_STATUS_FAILURE; + } + + /* Process result */ + printf("Get wakeup reason response: %s\n", buffer); + + if (buffer) + free(buffer); + if (cmd) + free(cmd); + + return MLAN_STATUS_SUCCESS; +} + +/** + * @brief Process hscfg management frame config + * @param argc Number of arguments + * @param argv A pointer to arguments array + * @return MLAN_STATUS_SUCCESS--success, otherwise--fail + */ +static int +process_mgmtfilter(int argc, char *argv[]) +{ + t_u8 *buffer = NULL; + struct eth_priv_cmd *cmd = NULL; + struct ifreq ifr; + FILE *fp = NULL; + int ret = MLAN_STATUS_SUCCESS; + char line[256], cmdname[256], *pos = NULL, *filter = NULL; + int cmdname_found = 0, name_found = 0; + int ln = 0, i = 0, numEntries = 0, len = 0; + eth_priv_mgmt_frame_wakeup hs_mgmt_filter[2]; + + if (argc < 4) { + printf("Error: invalid no of arguments\n"); + printf("Syntax: ./mlanutl mlanX mgmtfilter \n"); + ret = MLAN_STATUS_FAILURE; + goto done; + } + + memset(&hs_mgmt_filter, 0, sizeof(hs_mgmt_filter)); + /* Initialize buffer */ + buffer = (t_u8 *)malloc(BUFFER_LENGTH); + if (!buffer) { + printf("ERR:Cannot allocate buffer for command!\n"); + ret = MLAN_STATUS_FAILURE; + goto done; + } + memset(buffer, 0, BUFFER_LENGTH); + + pos = (char *)buffer; + strncpy((char *)pos, CMD_NXP, strlen(CMD_NXP)); + pos += (strlen(CMD_NXP)); + len += (strlen(CMD_NXP)); + + /* Insert command */ + strncpy((char *)pos, argv[2], strlen(argv[2])); + pos += (strlen(argv[2])); + len += (strlen(argv[2])); + + filter = pos; + + cmdname_found = 0; + snprintf(cmdname, sizeof(cmdname), "%s={", argv[2]); + + fp = fopen(argv[3], "r"); + if (fp == NULL) { + fprintf(stderr, "Cannot open file %s\n", argv[3]); + ret = MLAN_STATUS_FAILURE; + if (buffer) + free(buffer); + goto done; + } + + while ((pos = mlan_config_get_line(fp, line, sizeof(line), &ln))) { + if (strcmp(pos, cmdname) == 0) { + cmdname_found = 1; + snprintf(cmdname, sizeof(cmdname), "entry_num="); + name_found = 0; + while ((pos = + mlan_config_get_line(fp, line, sizeof(line), + &ln))) { + if (strncmp(pos, cmdname, strlen(cmdname)) == 0) { + name_found = 1; + numEntries = + a2hex_or_atoi(pos + + strlen(cmdname)); + if (numEntries > 2) { + printf("mlanutl: NumEntries exceed max number.\ + We support two entries in currently\n"); + free(buffer); + if (fp) + fclose(fp); + return MLAN_STATUS_FAILURE; + } + break; + } + } + if (!name_found) { + fprintf(stderr, + "mlanutl: NumEntries not found in file '%s'\n", + argv[3]); + break; + } + for (i = 0; i < numEntries; i++) { + snprintf(cmdname, sizeof(cmdname), "entry_%d={", + i); + name_found = 0; + while ((pos = + mlan_config_get_line(fp, line, + sizeof(line), + &ln))) { + if (strncmp + (pos, cmdname, + strlen(cmdname)) == 0) { + name_found = 1; + break; + } + } + if (!name_found) { + fprintf(stderr, + "mlanutl: %s not found in file '%s'\n", + cmdname, argv[3]); + break; + } + snprintf(cmdname, sizeof(cmdname), "action="); + name_found = 0; + while ((pos = + mlan_config_get_line(fp, line, + sizeof(line), + &ln))) { + if (strncmp + (pos, cmdname, + strlen(cmdname)) == 0) { + name_found = 1; + hs_mgmt_filter[i].action = + a2hex_or_atoi(pos + + strlen + (cmdname)); + break; + } + } + if (!name_found) { + fprintf(stderr, + "mlanutl: %s not found in file '%s'\n", + cmdname, argv[3]); + break; + } + snprintf(cmdname, sizeof(cmdname), "type="); + name_found = 0; + while ((pos = + mlan_config_get_line(fp, line, + sizeof(line), + &ln))) { + if (strncmp + (pos, cmdname, + strlen(cmdname)) == 0) { + name_found = 1; + hs_mgmt_filter[i].type = + a2hex_or_atoi(pos + + strlen + (cmdname)); + break; + } + } + if (!name_found) { + fprintf(stderr, + "mlanutl: %s not found in file '%s'\n", + cmdname, argv[3]); + break; + } + snprintf(cmdname, sizeof(cmdname), + "frame_mask="); + name_found = 0; + while ((pos = + mlan_config_get_line(fp, line, + sizeof(line), + &ln))) { + if (strncmp + (pos, cmdname, + strlen(cmdname)) == 0) { + name_found = 1; + hs_mgmt_filter[i].frame_mask = + a2hex_or_atoi(pos + + strlen + (cmdname)); + break; + } + } + if (!name_found) { + fprintf(stderr, + "mlanutl: %s not found in file '%s'\n", + cmdname, argv[3]); + break; + } + } + break; + } + } + fclose(fp); + if (!cmdname_found) { + fprintf(stderr, "mlanutl: ipPkt data not found in file '%s'\n", + argv[3]); + free(buffer); + return MLAN_STATUS_FAILURE; + } + + memcpy(filter, (t_u8 *)hs_mgmt_filter, + sizeof(eth_priv_mgmt_frame_wakeup) * numEntries); + len += sizeof(eth_priv_mgmt_frame_wakeup) * numEntries; + cmd = (struct eth_priv_cmd *)malloc(sizeof(struct eth_priv_cmd)); + if (!cmd) { + printf("ERR:Cannot allocate buffer for command!\n"); + free(buffer); + return MLAN_STATUS_FAILURE; + } + + /* Fill up buffer */ +#ifdef USERSPACE_32BIT_OVER_KERNEL_64BIT + memset(cmd, 0, sizeof(struct eth_priv_cmd)); + memcpy(&cmd->buf, &buffer, sizeof(buffer)); +#else + cmd->buf = buffer; +#endif + cmd->used_len = 0; + cmd->total_len = len; + /* Perform IOCTL */ + memset(&ifr, 0, sizeof(struct ifreq)); + strncpy(ifr.ifr_ifrn.ifrn_name, dev_name, strlen(dev_name)); + ifr.ifr_ifru.ifru_data = (void *)cmd; + + if (ioctl(sockfd, MLAN_ETH_PRIV, &ifr)) { + perror("mlanutl"); + fprintf(stderr, "mlanutl: cloud keep alive fail\n"); + if (cmd) + free(cmd); + if (buffer) + free(buffer); + return MLAN_STATUS_FAILURE; + } + + if (buffer) + free(buffer); + if (cmd) + free(cmd); + +done: + return ret; +} + +/** + * @brief Process scancfg configuration + * @param argc Number of arguments + * @param argv A pointer to arguments array + * @return MLAN_STATUS_SUCCESS--success, otherwise--fail + */ +static int +process_scancfg(int argc, char *argv[]) +{ + t_u8 *buffer = NULL; + struct eth_priv_cmd *cmd = NULL; + struct ifreq ifr; + struct eth_priv_scan_cfg *scancfg; + + /* Initialize buffer */ + buffer = (t_u8 *)malloc(BUFFER_LENGTH); + if (!buffer) { + printf("ERR:Cannot allocate buffer for command!\n"); + return MLAN_STATUS_FAILURE; + } + + prepare_buffer(buffer, argv[2], (argc - 3), &argv[3]); + + cmd = (struct eth_priv_cmd *)malloc(sizeof(struct eth_priv_cmd)); + if (!cmd) { + printf("ERR:Cannot allocate buffer for command!\n"); + free(buffer); + return MLAN_STATUS_FAILURE; + } + + /* Fill up buffer */ +#ifdef USERSPACE_32BIT_OVER_KERNEL_64BIT + memset(cmd, 0, sizeof(struct eth_priv_cmd)); + memcpy(&cmd->buf, &buffer, sizeof(buffer)); +#else + cmd->buf = buffer; +#endif + cmd->used_len = 0; + cmd->total_len = BUFFER_LENGTH; + + /* Perform IOCTL */ + memset(&ifr, 0, sizeof(struct ifreq)); + strncpy(ifr.ifr_ifrn.ifrn_name, dev_name, strlen(dev_name)); + ifr.ifr_ifru.ifru_data = (void *)cmd; + + if (ioctl(sockfd, MLAN_ETH_PRIV, &ifr)) { + perror("mlanutl"); + fprintf(stderr, "mlanutl: scancfg fail\n"); + if (cmd) + free(cmd); + if (buffer) + free(buffer); + return MLAN_STATUS_FAILURE; + } + + /* Process result */ + scancfg = (struct eth_priv_scan_cfg *)buffer; + /* Show scan configure */ + printf("Scan Configuration:\n"); + printf(" Scan Type: %d (%s)\n", scancfg->scan_type, + (scancfg->scan_type == 1) ? "Active" : (scancfg->scan_type == + 2) ? "Passive" : ""); + printf(" Scan Mode: %d (%s)\n", scancfg->scan_mode, + (scancfg->scan_mode == 1) ? "BSS" : (scancfg->scan_mode == + 2) ? "IBSS" : (scancfg-> + scan_mode == + 3) ? "Any" : + ""); + printf(" Scan Probes: %d (%s)\n", scancfg->scan_probe, + "per channel"); + printf(" Specific Scan Time: %d ms\n", + scancfg->scan_time.specific_scan_time); + printf(" Active Scan Time: %d ms\n", + scancfg->scan_time.active_scan_time); + printf(" Passive Scan Time: %d ms\n", + scancfg->scan_time.passive_scan_time); + printf(" Passive to Active Scan: %d (%s)\n", + scancfg->passive_to_active_scan, + (scancfg->passive_to_active_scan == + MLAN_PASS_TO_ACT_SCAN_EN) ? "Enable" : (scancfg-> + passive_to_active_scan + == + MLAN_PASS_TO_ACT_SCAN_DIS) + ? "Disable" : ""); + printf(" Extended Scan Support: %d (%s)\n", scancfg->ext_scan, + (scancfg->ext_scan == 1) ? "No" : (scancfg->ext_scan == + 2) ? "Yes" : (scancfg-> + ext_scan == + 3) ? "Enhanced" + : ""); + printf(" Scan channel Gap: %d ms\n", scancfg->scan_chan_gap); + + if (buffer) + free(buffer); + if (cmd) + free(cmd); + + return MLAN_STATUS_SUCCESS; +} + +/** + * @brief Process packet aggregation configuration + * @param argc number of arguments + * @param argv A pointer to arguments array + * @return MLAN_STATUS_SUCCESS--success, otherwise--fail + */ +static int +process_aggrctrl(int argc, char *argv[]) +{ + t_u8 *buffer = NULL; + struct eth_priv_cmd *cmd = NULL; + struct ifreq ifr; + aggr_ctrl_params *param = NULL; + + /* Initialize buffer */ + buffer = (t_u8 *)malloc(BUFFER_LENGTH); + if (!buffer) { + printf("ERR:Cannot allocate buffer for command!\n"); + return MLAN_STATUS_FAILURE; + } + + prepare_buffer(buffer, argv[2], (argc - 3), &argv[3]); + + cmd = (struct eth_priv_cmd *)malloc(sizeof(struct eth_priv_cmd)); + if (!cmd) { + printf("ERR:Cannot allocate buffer for command!\n"); + if (buffer) + free(buffer); + return MLAN_STATUS_FAILURE; + } + + /* Fill up buffer */ +#ifdef USERSPACE_32BIT_OVER_KERNEL_64BIT + memset(cmd, 0, sizeof(struct eth_priv_cmd)); + memcpy(&cmd->buf, &buffer, sizeof(buffer)); +#else + cmd->buf = buffer; +#endif + cmd->used_len = 0; + cmd->total_len = BUFFER_LENGTH; + + /* Perform IOCTL */ + memset(&ifr, 0, sizeof(struct ifreq)); + strncpy(ifr.ifr_ifrn.ifrn_name, dev_name, strlen(dev_name)); + ifr.ifr_ifru.ifru_data = (void *)cmd; + + if (ioctl(sockfd, MLAN_ETH_PRIV, &ifr)) { + perror("mlanutl"); + fprintf(stderr, "mlanutl: usbaggrctrl failed.\n"); + if (cmd) + free(cmd); + if (buffer) + free(buffer); + return MLAN_STATUS_FAILURE; + } + + if (argc == 3) { + /* GET operation */ + param = (aggr_ctrl_params *) buffer; + printf("TX Aggr Ctrl:\n"); + printf(" %s, Max = %d bytes, Max Pkt Num = %d, Align=%d Timeout = %d us\n", param->tx.enable ? "Enabled" : "Disabled", param->tx.aggr_max_size, param->tx.aggr_max_num, param->tx.aggr_align, param->tx.aggr_tmo); + } + + if (buffer) + free(buffer); + if (cmd) + free(cmd); + + return MLAN_STATUS_SUCCESS; +} + +/** + * @brief Process USB packet aggregation configuration + * @param argc number of arguments + * @param argv A pointer to arguments array + * @return MLAN_STATUS_SUCCESS--success, otherwise--fail + */ +static int +process_usbaggrctrl(int argc, char *argv[]) +{ + t_u8 *buffer = NULL; + struct eth_priv_cmd *cmd = NULL; + struct ifreq ifr; + aggr_params *param = NULL; + + /* Initialize buffer */ + buffer = (t_u8 *)malloc(BUFFER_LENGTH); + if (!buffer) { + printf("ERR:Cannot allocate buffer for command!\n"); + return MLAN_STATUS_FAILURE; + } + + prepare_buffer(buffer, argv[2], (argc - 3), &argv[3]); + + cmd = (struct eth_priv_cmd *)malloc(sizeof(struct eth_priv_cmd)); + if (!cmd) { + printf("ERR:Cannot allocate buffer for command!\n"); + if (buffer) + free(buffer); + return MLAN_STATUS_FAILURE; + } + + /* Fill up buffer */ +#ifdef USERSPACE_32BIT_OVER_KERNEL_64BIT + memset(cmd, 0, sizeof(struct eth_priv_cmd)); + memcpy(&cmd->buf, &buffer, sizeof(buffer)); +#else + cmd->buf = buffer; +#endif + cmd->used_len = 0; + cmd->total_len = BUFFER_LENGTH; + + /* Perform IOCTL */ + memset(&ifr, 0, sizeof(struct ifreq)); + strncpy(ifr.ifr_ifrn.ifrn_name, dev_name, strlen(dev_name)); + ifr.ifr_ifru.ifru_data = (void *)cmd; + + if (ioctl(sockfd, MLAN_ETH_PRIV, &ifr)) { + perror("mlanutl"); + fprintf(stderr, "mlanutl: usbaggrctrl failed.\n"); + if (cmd) + free(cmd); + if (buffer) + free(buffer); + return MLAN_STATUS_FAILURE; + } + + if (argc == 3) { + /* GET operation */ + param = (aggr_params *)buffer; + printf("Tx aggregation:\n"); + printf(" %s, Max = %d %s, Alignment = %d bytes, Timeout = %d us\n", param->tx_aggr_ctrl.enable ? "Enabled" : "Disabled", param->tx_aggr_ctrl.aggr_max, (param->tx_aggr_ctrl.aggr_max < 512) ? "packets" : "bytes", param->tx_aggr_ctrl.aggr_align, param->tx_aggr_ctrl.aggr_tmo); + printf("Rx aggregation:\n"); + printf(" %s, Max = %d %s, Alignment = %d bytes, Timeout = %d us\n", param->rx_deaggr_ctrl.enable ? "Enabled" : "Disabled", param->rx_deaggr_ctrl.aggr_max, (param->rx_deaggr_ctrl.aggr_max < 512) ? "packets" : "bytes", param->rx_deaggr_ctrl.aggr_align, param->rx_deaggr_ctrl.aggr_tmo); + } + + if (buffer) + free(buffer); + if (cmd) + free(cmd); + + return MLAN_STATUS_SUCCESS; +} + +/** + * @brief Process warmreset command + * @param argc Number of arguments + * @param argv A pointer to arguments array + * @return MLAN_STATUS_SUCCESS--success, otherwise--fail + */ +static int +process_warmreset(int argc, char *argv[]) +{ + t_u8 *buffer = NULL; + struct eth_priv_cmd *cmd = NULL; + struct ifreq ifr; + + /* Initialize buffer */ + buffer = (t_u8 *)malloc(BUFFER_LENGTH); + if (!buffer) { + printf("ERR:Cannot allocate buffer for command!\n"); + return MLAN_STATUS_FAILURE; + } + + /* The argument being a string, this requires special handling */ + prepare_buffer(buffer, argv[2], 0, NULL); + + cmd = (struct eth_priv_cmd *)malloc(sizeof(struct eth_priv_cmd)); + if (!cmd) { + printf("ERR:Cannot allocate buffer for command!\n"); + free(buffer); + return MLAN_STATUS_FAILURE; + } + + /* Fill up buffer */ +#ifdef USERSPACE_32BIT_OVER_KERNEL_64BIT + memset(cmd, 0, sizeof(struct eth_priv_cmd)); + memcpy(&cmd->buf, &buffer, sizeof(buffer)); +#else + cmd->buf = buffer; +#endif + cmd->used_len = 0; + cmd->total_len = BUFFER_LENGTH; + + /* Perform IOCTL */ + memset(&ifr, 0, sizeof(struct ifreq)); + strncpy(ifr.ifr_ifrn.ifrn_name, dev_name, strlen(dev_name)); + ifr.ifr_ifru.ifru_data = (void *)cmd; + + if (ioctl(sockfd, MLAN_ETH_PRIV, &ifr)) { + perror("mlanutl"); + fprintf(stderr, "mlanutl: warmreset fail\n"); + if (cmd) + free(cmd); + if (buffer) + free(buffer); + return MLAN_STATUS_FAILURE; + } + + if (buffer) + free(buffer); + if (cmd) + free(cmd); + + return MLAN_STATUS_SUCCESS; +} + +static char *bandwidth[4] = { "20 MHz", "40 MHz", "80 MHz", "160 MHz" }; + +/** + * @brief Process txpowercfg command + * @param argc Number of arguments + * @param argv A pointer to arguments array + * @return MLAN_STATUS_SUCCESS--success, otherwise--fail + */ +static int +process_txpowercfg(int argc, char *argv[]) +{ + t_u8 *buffer = NULL; + struct eth_priv_cmd *cmd = NULL; + struct ifreq ifr; + struct eth_priv_power_cfg_ext *power_ext = NULL; + struct eth_priv_power_group *power_group = NULL; + int i = 0; + + /* Initialize buffer */ + buffer = (t_u8 *)malloc(2 * BUFFER_LENGTH); + if (!buffer) { + printf("ERR:Cannot allocate buffer for command!\n"); + return MLAN_STATUS_FAILURE; + } + + prepare_buffer(buffer, argv[2], (argc - 3), &argv[3]); + + cmd = (struct eth_priv_cmd *)malloc(sizeof(struct eth_priv_cmd)); + if (!cmd) { + printf("ERR:Cannot allocate buffer for command!\n"); + free(buffer); + return MLAN_STATUS_FAILURE; + } + + /* Fill up buffer */ +#ifdef USERSPACE_32BIT_OVER_KERNEL_64BIT + memset(cmd, 0, sizeof(struct eth_priv_cmd)); + memcpy(&cmd->buf, &buffer, sizeof(buffer)); +#else + cmd->buf = buffer; +#endif + cmd->used_len = 0; + cmd->total_len = 2 * BUFFER_LENGTH; + + /* Perform IOCTL */ + memset(&ifr, 0, sizeof(struct ifreq)); + strncpy(ifr.ifr_ifrn.ifrn_name, dev_name, strlen(dev_name)); + ifr.ifr_ifru.ifru_data = (void *)cmd; + + if (ioctl(sockfd, MLAN_ETH_PRIV, &ifr)) { + perror("mlanutl"); + fprintf(stderr, "mlanutl: txpowercfg fail\n"); + if (cmd) + free(cmd); + if (buffer) + free(buffer); + return MLAN_STATUS_FAILURE; + } + + /* Process result */ + power_ext = (struct eth_priv_power_cfg_ext *)buffer; + if (argc == 3) { + /* GET operation */ + printf("Tx Power Configurations:\n"); + for (i = 0; i < power_ext->num_pwr_grp; i++) { + power_group = &power_ext->power_group[i]; + if (power_group->rate_format == MLAN_RATE_FORMAT_HT) { + if (power_group->bandwidth == MLAN_HT_BW20) { + power_group->first_rate_ind += 12; + power_group->last_rate_ind += 12; + } else if (power_group->bandwidth == + MLAN_HT_BW40) { + power_group->first_rate_ind += 140; + power_group->last_rate_ind += 140; + } + } + printf(" Power Group %d: \n", i); + printf(" Bandwidth: %3s %s\n", + rate_format[power_group->rate_format], + bandwidth[power_group->bandwidth]); + if (power_group->rate_format == 2) + /** NSS */ + printf(" NSS: %3d\n", + power_group->nss); + printf(" first rate index: %3d\n", + power_group->first_rate_ind); + printf(" last rate index: %3d\n", + power_group->last_rate_ind); + printf(" minimum power: %3d dBm\n", + power_group->power_min); + printf(" maximum power: %3d dBm\n", + power_group->power_max); + printf(" power step: %3d\n", + power_group->power_step); + printf("\n"); + power_group++; + } + } + + if (buffer) + free(buffer); + if (cmd) + free(cmd); + + return MLAN_STATUS_SUCCESS; +} + +/** + * @brief Process pscfg command + * @param argc Number of arguments + * @param argv A pointer to arguments array + * @return MLAN_STATUS_SUCCESS--success, otherwise--fail + */ +static int +process_pscfg(int argc, char *argv[]) +{ + t_u8 *buffer = NULL; + struct eth_priv_cmd *cmd = NULL; + struct ifreq ifr; + struct eth_priv_ds_ps_cfg *ps_cfg = NULL; + + /* Initialize buffer */ + buffer = (t_u8 *)malloc(BUFFER_LENGTH); + if (!buffer) { + printf("ERR:Cannot allocate buffer for command!\n"); + return MLAN_STATUS_FAILURE; + } + + prepare_buffer(buffer, argv[2], (argc - 3), &argv[3]); + + cmd = (struct eth_priv_cmd *)malloc(sizeof(struct eth_priv_cmd)); + if (!cmd) { + printf("ERR:Cannot allocate buffer for command!\n"); + free(buffer); + return MLAN_STATUS_FAILURE; + } + + /* Fill up buffer */ +#ifdef USERSPACE_32BIT_OVER_KERNEL_64BIT + memset(cmd, 0, sizeof(struct eth_priv_cmd)); + memcpy(&cmd->buf, &buffer, sizeof(buffer)); +#else + cmd->buf = buffer; +#endif + cmd->used_len = 0; + cmd->total_len = BUFFER_LENGTH; + + /* Perform IOCTL */ + memset(&ifr, 0, sizeof(struct ifreq)); + strncpy(ifr.ifr_ifrn.ifrn_name, dev_name, strlen(dev_name)); + ifr.ifr_ifru.ifru_data = (void *)cmd; + + if (ioctl(sockfd, MLAN_ETH_PRIV, &ifr)) { + perror("mlanutl"); + fprintf(stderr, "mlanutl: pscfg fail\n"); + if (cmd) + free(cmd); + if (buffer) + free(buffer); + return MLAN_STATUS_FAILURE; + } + + /* Process result */ + ps_cfg = (struct eth_priv_ds_ps_cfg *)buffer; + if (argc == 3) { + /* GET operation */ + printf("PS Configurations:\n"); + printf("%d", (int)ps_cfg->ps_null_interval); + printf(" %d", (int)ps_cfg->multiple_dtim_interval); + printf(" %d", (int)ps_cfg->listen_interval); + printf(" %d", (int)ps_cfg->bcn_miss_timeout); + printf(" %d", (int)ps_cfg->delay_to_ps); + printf(" %d", (int)ps_cfg->ps_mode); + printf("\n"); + } + + if (buffer) + free(buffer); + if (cmd) + free(cmd); + + return MLAN_STATUS_SUCCESS; +} + +/** + * @brief Process bcntimeoutcfg command + * @param argc Number of arguments + * @param argv A pointer to arguments array + * @return MLAN_STATUS_SUCCESS--success, otherwise--fail + */ +static int +process_bcntimeoutcfg(int argc, char *argv[]) +{ + t_u8 *buffer = NULL; + struct eth_priv_cmd *cmd = NULL; + struct ifreq ifr; + + if (argc != 7) { + printf("ERR:Incorrect number of arguments.\n"); + printf("Syntax: ./mlanutl mlanX bcntimeoutcfg [l] [m] [o] [p]\n"); + return -EINVAL; + } + + /* Initialize buffer */ + buffer = (t_u8 *)malloc(BUFFER_LENGTH); + if (!buffer) { + printf("ERR:Cannot allocate buffer for command!\n"); + return -ENOMEM; + } + + prepare_buffer(buffer, argv[2], (argc - 3), &argv[3]); + + cmd = (struct eth_priv_cmd *)malloc(sizeof(struct eth_priv_cmd)); + if (!cmd) { + printf("ERR:Cannot allocate buffer for command!\n"); + free(buffer); + return -ENOMEM; + } + + /* Fill up buffer */ +#ifdef USERSPACE_32BIT_OVER_KERNEL_64BIT + memset(cmd, 0, sizeof(struct eth_priv_cmd)); + memcpy(&cmd->buf, &buffer, sizeof(buffer)); +#else + cmd->buf = buffer; +#endif + cmd->used_len = 0; + cmd->total_len = BUFFER_LENGTH; + + /* Perform IOCTL */ + memset(&ifr, 0, sizeof(struct ifreq)); + strncpy(ifr.ifr_ifrn.ifrn_name, dev_name, strlen(dev_name)); + ifr.ifr_ifru.ifru_data = (void *)cmd; + + if (ioctl(sockfd, MLAN_ETH_PRIV, &ifr)) { + perror("mlanutl"); + fprintf(stderr, "mlanutl: bcntimeoutcfg fail\n"); + if (cmd) + free(cmd); + if (buffer) + free(buffer); + return -EFAULT; + } + + if (buffer) + free(buffer); + if (cmd) + free(cmd); + + return 0; +} + +/** + * @brief Process sleeppd configuration + * @param argc Number of arguments + * @param argv A pointer to arguments array + * @return MLAN_STATUS_SUCCESS--success, otherwise--fail + */ +static int +process_sleeppd(int argc, char *argv[]) +{ + t_u8 *buffer = NULL; + struct eth_priv_cmd *cmd = NULL; + struct ifreq ifr; + int sleeppd = 0; + + /* Initialize buffer */ + buffer = (t_u8 *)malloc(BUFFER_LENGTH); + if (!buffer) { + printf("ERR:Cannot allocate buffer for command!\n"); + return MLAN_STATUS_FAILURE; + } + + prepare_buffer(buffer, argv[2], (argc - 3), &argv[3]); + + cmd = (struct eth_priv_cmd *)malloc(sizeof(struct eth_priv_cmd)); + if (!cmd) { + printf("ERR:Cannot allocate buffer for command!\n"); + free(buffer); + return MLAN_STATUS_FAILURE; + } + + /* Fill up buffer */ +#ifdef USERSPACE_32BIT_OVER_KERNEL_64BIT + memset(cmd, 0, sizeof(struct eth_priv_cmd)); + memcpy(&cmd->buf, &buffer, sizeof(buffer)); +#else + cmd->buf = buffer; +#endif + cmd->used_len = 0; + cmd->total_len = BUFFER_LENGTH; + + /* Perform IOCTL */ + memset(&ifr, 0, sizeof(struct ifreq)); + strncpy(ifr.ifr_ifrn.ifrn_name, dev_name, strlen(dev_name)); + ifr.ifr_ifru.ifru_data = (void *)cmd; + + if (ioctl(sockfd, MLAN_ETH_PRIV, &ifr)) { + perror("mlanutl"); + fprintf(stderr, "mlanutl: sleeppd fail\n"); + if (cmd) + free(cmd); + if (buffer) + free(buffer); + return MLAN_STATUS_FAILURE; + } + + /* Process result */ + sleeppd = *(int *)buffer; + if (argc == 3) { + /* GET operation */ + printf("Sleep Period: %d ms\n", sleeppd); + } + + if (buffer) + free(buffer); + if (cmd) + free(cmd); + + return MLAN_STATUS_SUCCESS; +} + +/** + * @brief Process tx control configuration + * @param argc Number of arguments + * @param argv A pointer to arguments array + * @return MLAN_STATUS_SUCCESS--success, otherwise--fail + */ +static int +process_txcontrol(int argc, char *argv[]) +{ + t_u8 *buffer = NULL; + struct eth_priv_cmd *cmd = NULL; + struct ifreq ifr; + t_u32 txcontrol = 0; + + /* Initialize buffer */ + buffer = (t_u8 *)malloc(BUFFER_LENGTH); + if (!buffer) { + printf("ERR:Cannot allocate buffer for command!\n"); + return MLAN_STATUS_FAILURE; + } + + prepare_buffer(buffer, argv[2], (argc - 3), &argv[3]); + + cmd = (struct eth_priv_cmd *)malloc(sizeof(struct eth_priv_cmd)); + if (!cmd) { + printf("ERR:Cannot allocate buffer for command!\n"); + free(buffer); + return MLAN_STATUS_FAILURE; + } + + /* Fill up buffer */ +#ifdef USERSPACE_32BIT_OVER_KERNEL_64BIT + memset(cmd, 0, sizeof(struct eth_priv_cmd)); + memcpy(&cmd->buf, &buffer, sizeof(buffer)); +#else + cmd->buf = buffer; +#endif + cmd->used_len = 0; + cmd->total_len = BUFFER_LENGTH; + + /* Perform IOCTL */ + memset(&ifr, 0, sizeof(struct ifreq)); + strncpy(ifr.ifr_ifrn.ifrn_name, dev_name, strlen(dev_name)); + ifr.ifr_ifru.ifru_data = (void *)cmd; + + if (ioctl(sockfd, MLAN_ETH_PRIV, &ifr)) { + perror("mlanutl"); + fprintf(stderr, "mlanutl: txcontrol fail\n"); + if (cmd) + free(cmd); + if (buffer) + free(buffer); + return MLAN_STATUS_FAILURE; + } + + /* Process result */ + txcontrol = *(t_u32 *)buffer; + if (argc == 3) { + /* GET operation */ + printf("Tx control: 0x%x\n", txcontrol); + } + + if (buffer) + free(buffer); + if (cmd) + free(cmd); + + return MLAN_STATUS_SUCCESS; +} + +/** custom IE, auto mask value */ +#define CUSTOM_IE_AUTO_MASK 0xffff + +/** + * @brief Show usage information for the customie + * command + * + * $return N/A + **/ +void +print_custom_ie_usage(void) +{ + printf("\nUsage : customie [INDEX] [MASK] [IEBuffer]"); + printf("\n empty - Get all IE settings\n"); + printf("\n INDEX: 0 - Get/Set IE index 0 setting"); + printf("\n 1 - Get/Set IE index 1 setting"); + printf("\n 2 - Get/Set IE index 2 setting"); + printf("\n 3 - Get/Set IE index 3 setting"); + printf("\n . "); + printf("\n . "); + printf("\n . "); + printf("\n -1 - Append/Delete IE automatically"); + printf("\n Delete will delete the IE from the matching IE buffer"); + printf("\n Append will append the IE to the buffer with the same mask"); + printf("\n MASK : Management subtype mask value as per bit defintions"); + printf("\n : Bit 0 - Association request."); + printf("\n : Bit 1 - Association response."); + printf("\n : Bit 2 - Reassociation request."); + printf("\n : Bit 3 - Reassociation response."); + printf("\n : Bit 4 - Probe request."); + printf("\n : Bit 5 - Probe response."); + printf("\n : Bit 8 - Beacon."); + printf("\n MASK : MASK = 0 to clear the mask and the IE buffer"); + printf("\n IEBuffer : IE Buffer in hex (max 256 bytes)\n\n"); + return; +} + +/** + * @brief Creates a hostcmd request for custom IE settings + * and sends to the driver + * + * Usage: "customie [INDEX] [MASK] [IEBuffer]" + * + * Options: INDEX : 0 - Get/Delete IE index 0 setting + * 1 - Get/Delete IE index 1 setting + * 2 - Get/Delete IE index 2 setting + * 3 - Get/Delete IE index 3 setting + * . + * . + * . + * -1 - Append IE at the IE buffer with same MASK + * MASK : Management subtype mask value + * IEBuffer: IE Buffer in hex + * empty - Get all IE settings + * + * @param argc Number of arguments + * @param argv Pointer to the arguments + * @return N/A + **/ +static int +process_customie(int argc, char *argv[]) +{ + eth_priv_ds_misc_custom_ie *tlv = NULL; + tlvbuf_max_mgmt_ie *max_mgmt_ie_tlv = NULL; + t_u16 mgmt_subtype_mask = 0; + custom_ie *ie_ptr = NULL; + int ie_buf_len = 0, ie_len = 0, i = 0; + t_u8 *buffer = NULL; + struct eth_priv_cmd *cmd = NULL; + struct ifreq ifr; + int ret = MLAN_STATUS_SUCCESS; + + /* Initialize buffer */ + buffer = (t_u8 *)malloc(BUFFER_LENGTH); + if (!buffer) { + printf("ERR:Cannot allocate buffer for command!\n"); + return MLAN_STATUS_FAILURE; + } + prepare_buffer(buffer, argv[2], 0, NULL); + + cmd = (struct eth_priv_cmd *)malloc(sizeof(struct eth_priv_cmd)); + if (!cmd) { + printf("ERR:Cannot allocate buffer for command!\n"); + free(buffer); + return MLAN_STATUS_FAILURE; + } + + /* Fill up buffer */ +#ifdef USERSPACE_32BIT_OVER_KERNEL_64BIT + memset(cmd, 0, sizeof(struct eth_priv_cmd)); + memcpy(&cmd->buf, &buffer, sizeof(buffer)); +#else + cmd->buf = buffer; +#endif + cmd->used_len = 0; + cmd->total_len = BUFFER_LENGTH; + + /* mlanutl mlan0 customie idx flag buf */ + if (argc > 6) { + printf("ERR:Too many arguments.\n"); + print_custom_ie_usage(); + ret = MLAN_STATUS_FAILURE; + goto done; + } + /* Error checks and initialize the command length */ + if (argc > 3) { + if (((IS_HEX_OR_DIGIT(argv[3]) == MLAN_STATUS_FAILURE) && + (atoi(argv[3]) != -1)) || (atoi(argv[3]) < -1)) { + printf("ERR:Illegal index %s\n", argv[3]); + print_custom_ie_usage(); + ret = MLAN_STATUS_FAILURE; + goto done; + } + } + switch (argc) { + case 3: + break; + case 4: + if (atoi(argv[3]) < 0) { + printf("ERR:Illegal index %s. Must be either greater than or equal to 0 for Get Operation \n", argv[3]); + print_custom_ie_usage(); + ret = MLAN_STATUS_FAILURE; + goto done; + } + break; + case 5: + if (MLAN_STATUS_FAILURE == ishexstring(argv[4]) || + A2HEXDECIMAL(argv[4]) != 0) { + printf("ERR: Mask value should be 0 to clear IEBuffers.\n"); + print_custom_ie_usage(); + ret = MLAN_STATUS_FAILURE; + goto done; + } + if (atoi(argv[3]) == -1) { + printf("ERR: You must provide buffer for automatic deletion.\n"); + print_custom_ie_usage(); + ret = MLAN_STATUS_FAILURE; + goto done; + } + break; + case 6: + /* This is to check negative numbers and special symbols */ + if (MLAN_STATUS_FAILURE == IS_HEX_OR_DIGIT(argv[4])) { + printf("ERR:Mask value must be 0 or hex digits\n"); + print_custom_ie_usage(); + ret = MLAN_STATUS_FAILURE; + goto done; + } + /* If above check is passed and mask is not hex, then it must be 0 */ + if ((ISDIGIT(argv[4]) == MLAN_STATUS_SUCCESS) && atoi(argv[4])) { + printf("ERR:Mask value must be 0 or hex digits\n "); + print_custom_ie_usage(); + ret = MLAN_STATUS_FAILURE; + goto done; + } + if (MLAN_STATUS_FAILURE == ishexstring(argv[5])) { + printf("ERR:Only hex digits are allowed\n"); + print_custom_ie_usage(); + ret = MLAN_STATUS_FAILURE; + goto done; + } + ie_buf_len = strlen(argv[5]); + if (!strncasecmp("0x", argv[5], 2)) { + ie_len = (ie_buf_len - 2 + 1) / 2; + argv[5] += 2; + } else + ie_len = (ie_buf_len + 1) / 2; + if (ie_len > MAX_IE_BUFFER_LEN) { + printf("ERR:Incorrect IE length %d\n", ie_buf_len); + print_custom_ie_usage(); + ret = MLAN_STATUS_FAILURE; + goto done; + } + mgmt_subtype_mask = (t_u16)A2HEXDECIMAL(argv[4]); + break; + } + /* Initialize the command buffer */ + tlv = (eth_priv_ds_misc_custom_ie *)(buffer + strlen(CMD_NXP) + + strlen(argv[2])); + + if (tlv == NULL) { + ret = MLAN_STATUS_FAILURE; + goto done; + } + + tlv->type = MRVL_MGMT_IE_LIST_TLV_ID; + if (argc == 3 || argc == 4) { + if (argc == 3) + tlv->len = 0; + else { + tlv->len = sizeof(t_u16); + ie_ptr = (custom_ie *)(tlv->ie_data); + ie_ptr->ie_index = (t_u16)(atoi(argv[3])); + } + } else { + /* Locate headers */ + ie_ptr = (custom_ie *)(tlv->ie_data); + /* Set TLV fields */ + tlv->len = sizeof(custom_ie) + ie_len; + ie_ptr->ie_index = atoi(argv[3]); + ie_ptr->mgmt_subtype_mask = mgmt_subtype_mask; + ie_ptr->ie_length = ie_len; + if (argc == 6) + string2raw(argv[5], ie_ptr->ie_buffer); + } + /* Initialize the ifr structure */ + memset(&ifr, 0, sizeof(ifr)); + strncpy(ifr.ifr_ifrn.ifrn_name, dev_name, strlen(dev_name)); + ifr.ifr_ifru.ifru_data = (void *)cmd; + /* Perform ioctl */ + if (ioctl(sockfd, MLAN_ETH_PRIV, &ifr)) { + perror("ioctl[CUSTOM_IE_CFG]"); + printf("ERR:Command sending failed!\n"); + ret = MLAN_STATUS_FAILURE; + goto done; + } + /* Print response */ + if (argc > 4) { + printf("Custom IE setting successful\n"); + } else { + printf("Querying custom IE successful\n"); + ie_len = tlv->len; + ie_ptr = (custom_ie *)(tlv->ie_data); + while (ie_len >= (int)sizeof(custom_ie)) { + printf("Index [%d]\n", ie_ptr->ie_index); + if (ie_ptr->ie_length) + printf("Management Subtype Mask = 0x%02x\n", + (ie_ptr->mgmt_subtype_mask) == 0 ? + CUSTOM_IE_AUTO_MASK : + (ie_ptr->mgmt_subtype_mask)); + else + printf("Management Subtype Mask = 0x%02x\n", + (ie_ptr->mgmt_subtype_mask)); + hexdump("IE Buffer", (void *)ie_ptr->ie_buffer, + ie_ptr->ie_length, ' '); + ie_len -= sizeof(custom_ie) + ie_ptr->ie_length; + ie_ptr = (custom_ie *)((t_u8 *)ie_ptr + + sizeof(custom_ie) + + ie_ptr->ie_length); + } + } + max_mgmt_ie_tlv = (tlvbuf_max_mgmt_ie *)((t_u8 *)tlv + + sizeof + (eth_priv_ds_misc_custom_ie) + + tlv->len); + if (max_mgmt_ie_tlv) { + if (max_mgmt_ie_tlv->type == MRVL_MAX_MGMT_IE_TLV_ID) { + for (i = 0; i < max_mgmt_ie_tlv->count; i++) { + printf("buf%d_size = %d\n", i, + max_mgmt_ie_tlv->info[i].buf_size); + printf("number of buffers = %d\n", + max_mgmt_ie_tlv->info[i].buf_count); + printf("\n"); + } + } + } + + ret = MLAN_STATUS_SUCCESS; + +done: + if (buffer) + free(buffer); + if (cmd) + free(cmd); + return ret; +} + +/** + * @brief Process regrdwr command + * + * @param argc Number of arguments + * @param argv A pointer to arguments array + * @return MLAN_STATUS_SUCCESS--success, otherwise--fail + */ +static int +process_regrdwr(int argc, char *argv[]) +{ + t_u8 *buffer = NULL; + struct eth_priv_cmd *cmd = NULL; + struct ifreq ifr; + struct eth_priv_ds_reg_rw *reg = NULL; + + if (argc < 5 || argc > 6) { + printf("Error: invalid no of arguments\n"); + return MLAN_STATUS_FAILURE; + } + + /* Initialize buffer */ + buffer = (t_u8 *)malloc(BUFFER_LENGTH); + if (!buffer) { + printf("ERR:Cannot allocate buffer for command!\n"); + return MLAN_STATUS_FAILURE; + } + + prepare_buffer(buffer, argv[2], (argc - 3), &argv[3]); + + cmd = (struct eth_priv_cmd *)malloc(sizeof(struct eth_priv_cmd)); + if (!cmd) { + printf("ERR:Cannot allocate buffer for command!\n"); + free(buffer); + return MLAN_STATUS_FAILURE; + } + + /* Fill up buffer */ +#ifdef USERSPACE_32BIT_OVER_KERNEL_64BIT + memset(cmd, 0, sizeof(struct eth_priv_cmd)); + memcpy(&cmd->buf, &buffer, sizeof(buffer)); +#else + cmd->buf = buffer; +#endif + cmd->used_len = 0; + cmd->total_len = BUFFER_LENGTH; + + /* Perform IOCTL */ + memset(&ifr, 0, sizeof(struct ifreq)); + strncpy(ifr.ifr_ifrn.ifrn_name, dev_name, strlen(dev_name)); + ifr.ifr_ifru.ifru_data = (void *)cmd; + + if (ioctl(sockfd, MLAN_ETH_PRIV, &ifr)) { + perror("mlanutl"); + fprintf(stderr, "mlanutl: regrdwr fail\n"); + if (cmd) + free(cmd); + if (buffer) + free(buffer); + return MLAN_STATUS_FAILURE; + } + + /* Process result */ + reg = (struct eth_priv_ds_reg_rw *)buffer; + if (argc == 5) { + /* GET operation */ + printf("Value = 0x%x\n", reg->value); + } + + if (buffer) + free(buffer); + if (cmd) + free(cmd); + + return MLAN_STATUS_SUCCESS; +} + +/** + * @brief Process rdeeprom command + * + * @param argc Number of arguments + * @param argv A pointer to arguments array + * @return MLAN_STATUS_SUCCESS--success, otherwise--fail + */ +static int +process_rdeeprom(int argc, char *argv[]) +{ + t_u8 *buffer = NULL; + struct eth_priv_cmd *cmd = NULL; + struct ifreq ifr; + struct eth_priv_ds_read_eeprom *eeprom = NULL; + int i = 0; + + if (argc != 5) { + printf("Error: invalid no of arguments\n"); + return MLAN_STATUS_FAILURE; + } + + /* Initialize buffer */ + buffer = (t_u8 *)malloc(BUFFER_LENGTH); + if (!buffer) { + printf("ERR:Cannot allocate buffer for command!\n"); + return MLAN_STATUS_FAILURE; + } + + prepare_buffer(buffer, argv[2], (argc - 3), &argv[3]); + + cmd = (struct eth_priv_cmd *)malloc(sizeof(struct eth_priv_cmd)); + if (!cmd) { + printf("ERR:Cannot allocate buffer for command!\n"); + free(buffer); + return MLAN_STATUS_FAILURE; + } + + /* Fill up buffer */ +#ifdef USERSPACE_32BIT_OVER_KERNEL_64BIT + memset(cmd, 0, sizeof(struct eth_priv_cmd)); + memcpy(&cmd->buf, &buffer, sizeof(buffer)); +#else + cmd->buf = buffer; +#endif + cmd->used_len = 0; + cmd->total_len = BUFFER_LENGTH; + + /* Perform IOCTL */ + memset(&ifr, 0, sizeof(struct ifreq)); + strncpy(ifr.ifr_ifrn.ifrn_name, dev_name, strlen(dev_name)); + ifr.ifr_ifru.ifru_data = (void *)cmd; + + if (ioctl(sockfd, MLAN_ETH_PRIV, &ifr)) { + perror("mlanutl"); + fprintf(stderr, "mlanutl: rdeeprom fail\n"); + if (cmd) + free(cmd); + if (buffer) + free(buffer); + return MLAN_STATUS_FAILURE; + } + + /* Process result */ + eeprom = (struct eth_priv_ds_read_eeprom *)buffer; + if (argc == 5) { + /* GET operation */ + printf("Value:\n"); + for (i = 0; i < MIN(MAX_EEPROM_DATA, eeprom->byte_count); i++) + printf(" %02x", eeprom->value[i]); + printf("\n"); + } + + if (buffer) + free(buffer); + if (cmd) + free(cmd); + + return MLAN_STATUS_SUCCESS; +} + +/** + * @brief Process memrdwr command + * + * @param argc Number of arguments + * @param argv A pointer to arguments array + * @return MLAN_STATUS_SUCCESS--success, otherwise--fail + */ +static int +process_memrdwr(int argc, char *argv[]) +{ + t_u8 *buffer = NULL; + struct eth_priv_cmd *cmd = NULL; + struct ifreq ifr; + struct eth_priv_ds_mem_rw *mem = NULL; + + if (argc < 4 || argc > 5) { + printf("Error: invalid no of arguments\n"); + return MLAN_STATUS_FAILURE; + } + + /* Initialize buffer */ + buffer = (t_u8 *)malloc(BUFFER_LENGTH); + if (!buffer) { + printf("ERR:Cannot allocate buffer for command!\n"); + return MLAN_STATUS_FAILURE; + } + + prepare_buffer(buffer, argv[2], (argc - 3), &argv[3]); + + cmd = (struct eth_priv_cmd *)malloc(sizeof(struct eth_priv_cmd)); + if (!cmd) { + printf("ERR:Cannot allocate buffer for command!\n"); + free(buffer); + return MLAN_STATUS_FAILURE; + } + + /* Fill up buffer */ +#ifdef USERSPACE_32BIT_OVER_KERNEL_64BIT + memset(cmd, 0, sizeof(struct eth_priv_cmd)); + memcpy(&cmd->buf, &buffer, sizeof(buffer)); +#else + cmd->buf = buffer; +#endif + cmd->used_len = 0; + cmd->total_len = BUFFER_LENGTH; + + /* Perform IOCTL */ + memset(&ifr, 0, sizeof(struct ifreq)); + strncpy(ifr.ifr_ifrn.ifrn_name, dev_name, strlen(dev_name)); + ifr.ifr_ifru.ifru_data = (void *)cmd; + + if (ioctl(sockfd, MLAN_ETH_PRIV, &ifr)) { + perror("mlanutl"); + fprintf(stderr, "mlanutl: memrdwr fail\n"); + if (cmd) + free(cmd); + if (buffer) + free(buffer); + return MLAN_STATUS_FAILURE; + } + + /* Process result */ + mem = (struct eth_priv_ds_mem_rw *)buffer; + if (argc == 4) { + /* GET operation */ + printf("Value = 0x%x\n", mem->value); + } + + if (buffer) + free(buffer); + if (cmd) + free(cmd); + + return MLAN_STATUS_SUCCESS; +} + +#ifdef SDIO +/** + * @brief Process sdcmd52rw command + * + * @param argc Number of arguments + * @param argv A pointer to arguments array + * @return MLAN_STATUS_SUCCESS--success, otherwise--fail + */ +static int +process_sdcmd52rw(int argc, char *argv[]) +{ + t_u8 *buffer = NULL; + struct eth_priv_cmd *cmd = NULL; + struct ifreq ifr; + + if (argc < 5 || argc > 6) { + printf("Error: invalid no of arguments\n"); + return MLAN_STATUS_FAILURE; + } + + /* Initialize buffer */ + buffer = (t_u8 *)malloc(BUFFER_LENGTH); + if (!buffer) { + printf("ERR:Cannot allocate buffer for command!\n"); + return MLAN_STATUS_FAILURE; + } + + prepare_buffer(buffer, argv[2], (argc - 3), &argv[3]); + + cmd = (struct eth_priv_cmd *)malloc(sizeof(struct eth_priv_cmd)); + if (!cmd) { + printf("ERR:Cannot allocate buffer for command!\n"); + free(buffer); + return MLAN_STATUS_FAILURE; + } + + /* Fill up buffer */ +#ifdef USERSPACE_32BIT_OVER_KERNEL_64BIT + memset(cmd, 0, sizeof(struct eth_priv_cmd)); + memcpy(&cmd->buf, &buffer, sizeof(buffer)); +#else + cmd->buf = buffer; +#endif + cmd->used_len = 0; + cmd->total_len = BUFFER_LENGTH; + + /* Perform IOCTL */ + memset(&ifr, 0, sizeof(struct ifreq)); + strncpy(ifr.ifr_ifrn.ifrn_name, dev_name, strlen(dev_name)); + ifr.ifr_ifru.ifru_data = (void *)cmd; + + if (ioctl(sockfd, MLAN_ETH_PRIV, &ifr)) { + perror("mlanutl"); + fprintf(stderr, "mlanutl: sdcmd52rw fail\n"); + if (cmd) + free(cmd); + if (buffer) + free(buffer); + return MLAN_STATUS_FAILURE; + } + + /* Process result */ + if (argc == 5) { + /* GET operation */ + printf("Value = 0x%x\n", (int)(*buffer)); + } + + if (buffer) + free(buffer); + if (cmd) + free(cmd); + + return MLAN_STATUS_SUCCESS; +} +#endif /* SDIO */ + +#define STACK_NBYTES 100 /**< Number of bytes in stack */ +#define MAX_BYTESEQ 6 /**< Maximum byte sequence */ +#define TYPE_DNUM 1 /**< decimal number */ +#define TYPE_BYTESEQ 2 /**< byte sequence */ +#define MAX_OPERAND 0x40 /**< Maximum operands */ +#define TYPE_EQ (MAX_OPERAND+1) /**< byte comparison: == operator */ +#define TYPE_EQ_DNUM (MAX_OPERAND+2) /**< decimal comparison: =d operator */ +#define TYPE_EQ_BIT (MAX_OPERAND+3) /**< bit comparison: =b operator */ +#define TYPE_AND (MAX_OPERAND+4) /**< && operator */ +#define TYPE_OR (MAX_OPERAND+5) /**< || operator */ + +typedef struct { + t_u16 sp; /**< Stack pointer */ + t_u8 byte[STACK_NBYTES]; /**< Stack */ +} mstack_t; + +typedef struct { + t_u8 type; /**< Type */ + t_u8 reserve[3]; /**< so 4-byte align val array */ + /* byte sequence is the largest among all the operands and operators. */ + /* byte sequence format: 1 byte of num of bytes, then variable num bytes */ + t_u8 val[MAX_BYTESEQ + 1];/**< Value */ +} op_t; + +/** + * @brief push data to stack + * + * @param s a pointer to mstack_t structure + * + * @param nbytes number of byte to push to stack + * + * @param val a pointer to data buffer + * + * @return TRUE-- sucess , FALSE -- fail + * + */ +static int +push_n(mstack_t * s, t_u8 nbytes, t_u8 *val) +{ + if ((s->sp + nbytes) < STACK_NBYTES) { + memcpy((void *)(s->byte + s->sp), (const void *)val, + (size_t) nbytes); + s->sp += nbytes; + /* printf("push: n %d sp %d\n", nbytes, s->sp); */ + return TRUE; + } else /* stack full */ + return FALSE; +} + +/** + * @brief push data to stack + * + * @param s a pointer to mstack_t structure + * + * @param op a pointer to op_t structure + * + * @return TRUE-- sucess , FALSE -- fail + * + */ +static int +push(mstack_t * s, op_t * op) +{ + t_u8 nbytes; + switch (op->type) { + case TYPE_DNUM: + if (push_n(s, 4, op->val)) + return push_n(s, 1, &op->type); + return FALSE; + case TYPE_BYTESEQ: + nbytes = op->val[0]; + if (push_n(s, nbytes, op->val + 1) && + push_n(s, 1, op->val) && push_n(s, 1, &op->type)) + return TRUE; + return FALSE; + default: + return push_n(s, 1, &op->type); + } +} + +/** + * @brief parse RPN string + * + * @param s a pointer to Null-terminated string to scan. + * + * @param first_time a pointer to return first_time + * + * @return A pointer to the last token found in string. + * NULL is returned when there are no more tokens to be found. + * + */ +static char * +getop(char *s, int *first_time) +{ + const char delim[] = " \t\n"; + char *p; + if (*first_time) { + p = strtok(s, delim); + *first_time = FALSE; + } else { + p = strtok(NULL, delim); + } + return p; +} + +/** + * @brief Verify hex digit. + * + * @param c input ascii char + * @param h a pointer to return integer value of the digit char. + * @return TURE -- c is hex digit, FALSE -- c is not hex digit. + */ +static int +ishexdigit(char c, t_u8 *h) +{ + if (c >= '0' && c <= '9') { + *h = c - '0'; + return TRUE; + } else if (c >= 'a' && c <= 'f') { + *h = c - 'a' + 10; + return TRUE; + } else if (c >= 'A' && c <= 'F') { + *h = c - 'A' + 10; + return TRUE; + } + return FALSE; +} + +/** + * @brief convert hex string to integer. + * + * @param s A pointer to hex string, string length up to 2 digits. + * @return integer value. + */ +static t_u8 +hex_atoi(char *s) +{ + int i; + t_u8 digit; /* digital value */ + t_u8 t = 0; /* total value */ + + for (i = 0, t = 0; ishexdigit(s[i], &digit) && i < 2; i++) + t = 16 * t + digit; + return t; +} + +/** + * @brief Parse byte sequence in hex format string to a byte sequence. + * + * @param opstr A pointer to byte sequence in hex format string, with ':' as delimiter between two byte. + * @param val A pointer to return byte sequence string + * @return NA + */ +static void +parse_hex(char *opstr, t_u8 *val) +{ + char delim = ':'; + char *p; + char *q; + t_u8 i; + + /* +1 is for skipping over the preceding h character. */ + p = opstr + 1; + + /* First byte */ + val[1] = hex_atoi(p++); + + /* Parse subsequent bytes. */ + /* Each byte is preceded by the : character. */ + for (i = 1; *p; i++) { + q = strchr(p, delim); + if (!q) + break; + p = q + 1; + val[i + 1] = hex_atoi(p); + } + /* Set num of bytes */ + val[0] = i; +} + +/** + * @brief str2bin, convert RPN string to binary format + * + * @param str A pointer to rpn string + * @param stack A pointer to mstack_t structure + * @return MLAN_STATUS_SUCCESS--success, otherwise--fail + */ +static int +str2bin(char *str, mstack_t * stack) +{ + int first_time; + char *opstr; + op_t op; /* operator/operand */ + int dnum; + int ret = MLAN_STATUS_SUCCESS; + + memset(stack, 0, sizeof(mstack_t)); + first_time = TRUE; + while ((opstr = getop(str, &first_time)) != NULL) { + if (isdigit(*opstr)) { + op.type = TYPE_DNUM; + dnum = cpu_to_le32(atoi(opstr)); + memcpy((t_u8 *)op.val, &dnum, sizeof(dnum)); + if (!push(stack, &op)) { + printf("push decimal number failed\n"); + ret = MLAN_STATUS_FAILURE; + break; + } + } else if (*opstr == 'h') { + op.type = TYPE_BYTESEQ; + parse_hex(opstr, op.val); + if (!push(stack, &op)) { + printf("push byte sequence failed\n"); + ret = MLAN_STATUS_FAILURE; + break; + } + } else if (!strcmp(opstr, "==")) { + op.type = TYPE_EQ; + if (!push(stack, &op)) { + printf("push byte cmp operator failed\n"); + ret = MLAN_STATUS_FAILURE; + break; + } + } else if (!strcmp(opstr, "=d")) { + op.type = TYPE_EQ_DNUM; + if (!push(stack, &op)) { + printf("push decimal cmp operator failed\n"); + ret = MLAN_STATUS_FAILURE; + break; + } + } else if (!strcmp(opstr, "=b")) { + op.type = TYPE_EQ_BIT; + if (!push(stack, &op)) { + printf("push bit cmp operator failed\n"); + ret = MLAN_STATUS_FAILURE; + break; + } + } else if (!strcmp(opstr, "&&")) { + op.type = TYPE_AND; + if (!push(stack, &op)) { + printf("push AND operator failed\n"); + ret = MLAN_STATUS_FAILURE; + break; + } + } else if (!strcmp(opstr, "||")) { + op.type = TYPE_OR; + if (!push(stack, &op)) { + printf("push OR operator failed\n"); + ret = MLAN_STATUS_FAILURE; + break; + } + } else { + printf("Unknown operand\n"); + ret = MLAN_STATUS_FAILURE; + break; + } + } + return ret; +} + +#define FILTER_BYTESEQ TYPE_EQ /**< byte sequence */ +#define FILTER_DNUM TYPE_EQ_DNUM /**< decimal number */ +#define FILTER_BITSEQ TYPE_EQ_BIT /**< bit sequence */ +#define FILTER_TEST (FILTER_BITSEQ+1) /**< test */ + +#define NAME_TYPE 1 /**< Field name 'type' */ +#define NAME_PATTERN 2 /**< Field name 'pattern' */ +#define NAME_OFFSET 3 /**< Field name 'offset' */ +#define NAME_NUMBYTE 4 /**< Field name 'numbyte' */ +#define NAME_REPEAT 5 /**< Field name 'repeat' */ +#define NAME_BYTE 6 /**< Field name 'byte' */ +#define NAME_MASK 7 /**< Field name 'mask' */ +#define NAME_DEST 8 /**< Field name 'dest' */ + +static struct mef_fields { + char *name; + /**< Name */ + t_s8 nameid; + /**< Name Id. */ +} mef_fields[] = { + { + "type", NAME_TYPE}, { + "pattern", NAME_PATTERN}, { + "offset", NAME_OFFSET}, { + "numbyte", NAME_NUMBYTE}, { + "repeat", NAME_REPEAT}, { + "byte", NAME_BYTE}, { + "mask", NAME_MASK}, { + "dest", NAME_DEST} +}; + +/** + * @brief get filter data + * + * @param fp A pointer to file stream + * @param ln A pointer to line number + * @param buf A pointer to hostcmd data + * @param size A pointer to the return size of hostcmd buffer + * @return MLAN_STATUS_SUCCESS--success, otherwise--fail + */ +static int +mlan_get_filter_data(FILE * fp, int *ln, t_u8 *buf, t_u16 *size) +{ + t_s32 errors = 0, i; + char line[256], *pos = NULL, *pos1 = NULL; + t_u16 type = 0; + t_u32 pattern = 0; + t_u16 repeat = 0; + t_u16 offset = 0; + char byte_seq[50]; + char mask_seq[50]; + t_u16 numbyte = 0; + t_s8 type_find = 0; + t_s8 pattern_find = 0; + t_s8 offset_find = 0; + t_s8 numbyte_find = 0; + t_s8 repeat_find = 0; + t_s8 byte_find = 0; + t_s8 mask_find = 0; + t_s8 dest_find = 0; + char dest_seq[50]; + + *size = 0; + while ((pos = mlan_config_get_line(fp, line, sizeof(line), ln))) { + if (strcmp(pos, "}") == 0) { + break; + } + pos1 = strchr(pos, '='); + if (pos1 == NULL) { + printf("Line %d: Invalid mef_filter line '%s'\n", *ln, + pos); + errors++; + continue; + } + *pos1++ = '\0'; + for (i = 0; (t_u32)i < NELEMENTS(mef_fields); i++) { + if (strncmp + (pos, mef_fields[i].name, + strlen(mef_fields[i].name)) == 0) { + switch (mef_fields[i].nameid) { + case NAME_TYPE: + type = a2hex_or_atoi(pos1); + if ((type != FILTER_DNUM) && + (type != FILTER_BYTESEQ) + && (type != FILTER_BITSEQ) && + (type != FILTER_TEST)) { + printf("Invalid filter type:%d\n", type); + return MLAN_STATUS_FAILURE; + } + type_find = 1; + break; + case NAME_PATTERN: + pattern = a2hex_or_atoi(pos1); + pattern_find = 1; + break; + case NAME_OFFSET: + offset = a2hex_or_atoi(pos1); + offset_find = 1; + break; + case NAME_NUMBYTE: + numbyte = a2hex_or_atoi(pos1); + numbyte_find = 1; + break; + case NAME_REPEAT: + repeat = a2hex_or_atoi(pos1); + repeat_find = 1; + break; + case NAME_BYTE: + memset(byte_seq, 0, sizeof(byte_seq)); + strncpy(byte_seq, pos1, + (sizeof(byte_seq) - 1)); + byte_find = 1; + break; + case NAME_MASK: + memset(mask_seq, 0, sizeof(mask_seq)); + strncpy(mask_seq, pos1, + (sizeof(mask_seq) - 1)); + mask_find = 1; + break; + case NAME_DEST: + memset(dest_seq, 0, sizeof(dest_seq)); + strncpy(dest_seq, pos1, + (sizeof(dest_seq) - 1)); + dest_find = 1; + break; + } + break; + } + } + if (i == NELEMENTS(mef_fields)) { + printf("Line %d: unknown mef field '%s'.\n", + *line, pos); + errors++; + } + } + if (type_find == 0) { + printf("Can not find filter type\n"); + return MLAN_STATUS_FAILURE; + } + switch (type) { + case FILTER_DNUM: + if (!pattern_find || !offset_find || !numbyte_find) { + printf("Missing field for FILTER_DNUM: pattern=%d,offset=%d,numbyte=%d\n", pattern_find, offset_find, numbyte_find); + return MLAN_STATUS_FAILURE; + } + memset(line, 0, sizeof(line)); + snprintf(line, sizeof(line), "%d %d %d =d ", pattern, offset, + numbyte); + break; + case FILTER_BYTESEQ: + if (!byte_find || !offset_find || !repeat_find) { + printf("Missing field for FILTER_BYTESEQ: byte=%d,offset=%d,repeat=%d\n", byte_find, offset_find, repeat_find); + return MLAN_STATUS_FAILURE; + } + memset(line, 0, sizeof(line)); + snprintf(line, sizeof(line), "%d h%s %d == ", repeat, byte_seq, + offset); + break; + case FILTER_BITSEQ: + if (!byte_find || !offset_find || !mask_find) { + printf("Missing field for FILTER_BITSEQ: byte=%d,offset=%d,mask_find=%d\n", byte_find, offset_find, mask_find); + return MLAN_STATUS_FAILURE; + } + if (strlen(byte_seq) != strlen(mask_seq)) { + printf("byte string's length is different with mask's length!\n"); + return MLAN_STATUS_FAILURE; + } + memset(line, 0, sizeof(line)); + snprintf(line, sizeof(line), "h%s %d h%s =b ", byte_seq, offset, + mask_seq); + break; + case FILTER_TEST: + if (!byte_find || !offset_find || !repeat_find || !dest_find) { + printf("Missing field for FILTER_TEST: byte=%d,offset=%d,repeat=%d,dest=%d\n", byte_find, offset_find, repeat_find, dest_find); + return MLAN_STATUS_FAILURE; + } + memset(line, 0, sizeof(line)); + snprintf(line, sizeof(line), "h%s %d h%s %d ", dest_seq, repeat, + byte_seq, offset); + break; + } + memcpy(buf, line, strlen(line)); + *size = strlen(line); + return MLAN_STATUS_SUCCESS; +} + +#define NAME_MODE 1 /**< Field name 'mode' */ +#define NAME_ACTION 2 /**< Field name 'action' */ +#define NAME_FILTER_NUM 3 /**< Field name 'filter_num' */ +#define NAME_RPN 4 /**< Field name 'RPN' */ +static struct mef_entry_fields { + char *name; + /**< Name */ + t_s8 nameid; + /**< Name id */ +} mef_entry_fields[] = { + { + "mode", NAME_MODE}, { + "action", NAME_ACTION}, { + "filter_num", NAME_FILTER_NUM}, { +"RPN", NAME_RPN},}; + +typedef struct _MEF_ENTRY { + /** Mode */ + t_u8 Mode; + /** Size */ + t_u8 Action; + /** Size of expression */ + t_u16 ExprSize; +} MEF_ENTRY; + +/** + * @brief get mef_entry data + * + * @param fp A pointer to file stream + * @param ln A pointer to line number + * @param buf A pointer to hostcmd data + * @param size A pointer to the return size of hostcmd buffer + * @return MLAN_STATUS_SUCCESS--success, otherwise--fail + */ +static int +mlan_get_mef_entry_data(FILE * fp, int *ln, t_u8 *buf, t_u16 *size) +{ + char line[256], *pos = NULL, *pos1 = NULL; + t_u8 mode, action, filter_num = 0; + char rpn[256]; + t_s8 mode_find = 0; + t_s8 action_find = 0; + t_s8 filter_num_find = 0; + t_s8 rpn_find = 0; + char rpn_str[256]; + int rpn_len = 0; + char filter_name[50]; + t_s8 name_found = 0; + t_u16 len = 0; + int i; + int first_time = TRUE; + char *opstr = NULL; + char filter_action[10]; + t_s32 errors = 0; + MEF_ENTRY *pMefEntry = (MEF_ENTRY *) buf; + mstack_t stack; + while ((pos = mlan_config_get_line(fp, line, sizeof(line), ln))) { + if (strcmp(pos, "}") == 0) { + break; + } + pos1 = strchr(pos, '='); + if (pos1 == NULL) { + printf("Line %d: Invalid mef_entry line '%s'\n", *ln, + pos); + errors++; + continue; + } + *pos1++ = '\0'; + if (!mode_find || !action_find || !filter_num_find || !rpn_find) { + for (i = 0; + (unsigned int)i < NELEMENTS(mef_entry_fields); + i++) { + if (strncmp + (pos, mef_entry_fields[i].name, + strlen(mef_entry_fields[i].name)) == 0) { + switch (mef_entry_fields[i].nameid) { + case NAME_MODE: + mode = a2hex_or_atoi(pos1); + if (mode & ~0x7) { + printf("invalid mode=%d\n", mode); + return MLAN_STATUS_FAILURE; + } + pMefEntry->Mode = mode; + mode_find = 1; + break; + case NAME_ACTION: + action = a2hex_or_atoi(pos1); + if (action & ~0xff) { + printf("invalid action=%d\n", action); + return MLAN_STATUS_FAILURE; + } + pMefEntry->Action = action; + action_find = 1; + break; + case NAME_FILTER_NUM: + filter_num = + a2hex_or_atoi(pos1); + filter_num_find = 1; + break; + case NAME_RPN: + memset(rpn, 0, sizeof(rpn)); + strncpy(rpn, pos1, + (sizeof(rpn) - 1)); + rpn_find = 1; + break; + } + break; + } + } + if (i == NELEMENTS(mef_fields)) { + printf("Line %d: unknown mef_entry field '%s'.\n", *line, pos); + return MLAN_STATUS_FAILURE; + } + } + if (mode_find && action_find && filter_num_find && rpn_find) { + for (i = 0; i < filter_num; i++) { + opstr = getop(rpn, &first_time); + if (opstr == NULL) + break; + snprintf(filter_name, sizeof(filter_name), + "%s={", opstr); + name_found = 0; + while ((pos = + mlan_config_get_line(fp, line, + sizeof(line), + ln))) { + if (strncmp + (pos, filter_name, + strlen(filter_name)) == 0) { + name_found = 1; + break; + } + } + if (!name_found) { + fprintf(stderr, + "mlanutl: %s not found in file\n", + filter_name); + return MLAN_STATUS_FAILURE; + } + if (MLAN_STATUS_FAILURE == + mlan_get_filter_data(fp, ln, + (t_u8 *)(rpn_str + + rpn_len), + &len)) + break; + rpn_len += len; + if (i > 0) { + memcpy(rpn_str + rpn_len, filter_action, + strlen(filter_action)); + rpn_len += strlen(filter_action); + } + opstr = getop(rpn, &first_time); + if (opstr == NULL) + break; + memset(filter_action, 0, sizeof(filter_action)); + snprintf(filter_action, sizeof(filter_action), + "%s ", opstr); + } + /* Remove the last space */ + if (rpn_len > 0) { + rpn_len--; + rpn_str[rpn_len] = 0; + } + if (MLAN_STATUS_FAILURE == str2bin(rpn_str, &stack)) { + printf("Fail on str2bin!\n"); + return MLAN_STATUS_FAILURE; + } + *size = sizeof(MEF_ENTRY); + pMefEntry->ExprSize = cpu_to_le16(stack.sp); + memmove(buf + sizeof(MEF_ENTRY), stack.byte, stack.sp); + *size += stack.sp; + break; + } else if (mode_find && action_find && filter_num_find && + (filter_num == 0)) { + pMefEntry->ExprSize = 0; + *size = sizeof(MEF_ENTRY); + break; + } + } + return MLAN_STATUS_SUCCESS; +} + +/** + * @brief Process cloud keep alive command + * @param argc number of arguments + * @param argv A pointer to arguments array + * @return MLAN_STATUS_SUCCESS--success, otherwise--fail + */ +static int +process_cloud_keep_alive(int argc, char *argv[]) +{ + t_u8 *buffer = NULL; + struct eth_priv_cmd *cmd = NULL; + struct ifreq ifr; + FILE *fp = NULL; + int ret = MLAN_STATUS_SUCCESS; + char line[256], cmdname[256], *pos = NULL; + int cmdname_found = 0, name_found = 0, arg_num = 0; + int ln = 0, i = 0; + char *args[256]; + cloud_keep_alive *keep_alive = NULL; + + if (argc < 5) { + printf("Error: invalid no of arguments\n"); + printf("Syntax: ./mlanutl mlanX cloud_keep_alive \n"); + ret = MLAN_STATUS_FAILURE; + goto done; + } + + /* Initialize buffer */ + buffer = (t_u8 *)malloc(BUFFER_LENGTH); + if (!buffer) { + printf("ERR:Cannot allocate buffer for command!\n"); + ret = MLAN_STATUS_FAILURE; + goto done; + } + memset(buffer, 0, BUFFER_LENGTH); + + /* Insert command */ + strncpy((char *)buffer, argv[2], strlen(argv[2])); + + keep_alive = (cloud_keep_alive *) (buffer + strlen(argv[2])); + + cmdname_found = 0; + snprintf(cmdname, sizeof(cmdname), "%s={", argv[4]); + + fp = fopen(argv[3], "r"); + if (fp == NULL) { + fprintf(stderr, "Cannot open file %s\n", argv[3]); + ret = MLAN_STATUS_FAILURE; + if (buffer) + free(buffer); + goto done; + } + + while ((pos = mlan_config_get_line(fp, line, sizeof(line), &ln))) { + if (strcmp(pos, cmdname) == 0) { + cmdname_found = 1; + snprintf(cmdname, sizeof(cmdname), "mkeep_alive_id="); + name_found = 0; + while ((pos = + mlan_config_get_line(fp, line, sizeof(line), + &ln))) { + if (strncmp(pos, cmdname, strlen(cmdname)) == 0) { + name_found = 1; + keep_alive->mkeep_alive_id = + a2hex_or_atoi(pos + + strlen(cmdname)); + break; + } + } + if (!name_found) { + fprintf(stderr, + "mlanutl: keep alive id not found in file '%s'\n", + argv[3]); + break; + } + snprintf(cmdname, sizeof(cmdname), "enable="); + name_found = 0; + while ((pos = + mlan_config_get_line(fp, line, sizeof(line), + &ln))) { + if (strncmp(pos, cmdname, strlen(cmdname)) == 0) { + name_found = 1; + keep_alive->enable = + a2hex_or_atoi(pos + + strlen(cmdname)); + break; + } + } + if (!name_found) { + fprintf(stderr, + "mlanutl: enable not found in file '%s'\n", + argv[3]); + break; + } + if (strcmp(argv[4], "reset") == 0) { + snprintf(cmdname, sizeof(cmdname), "reset="); + name_found = 0; + while ((pos = + mlan_config_get_line(fp, line, + sizeof(line), + &ln))) { + if (strncmp + (pos, cmdname, + strlen(cmdname)) == 0) { + name_found = 1; + keep_alive->reset = + a2hex_or_atoi(pos + + strlen + (cmdname)); + break; + } + } + if (!name_found) { + fprintf(stderr, + "mlanutl: reset not found in file '%s'\n", + argv[3]); + break; + } + } + if (strcmp(argv[4], "start") == 0) { + snprintf(cmdname, sizeof(cmdname), + "sendInterval="); + name_found = 0; + while ((pos = + mlan_config_get_line(fp, line, + sizeof(line), + &ln))) { + if (strncmp + (pos, cmdname, + strlen(cmdname)) == 0) { + name_found = 1; + keep_alive->sendInterval = + a2hex_or_atoi(pos + + strlen + (cmdname)); + break; + } + } + if (!name_found) { + fprintf(stderr, + "mlanutl: sendInterval not found in file '%s'\n", + argv[3]); + break; + } + snprintf(cmdname, sizeof(cmdname), + "retryInterval="); + name_found = 0; + while ((pos = + mlan_config_get_line(fp, line, + sizeof(line), + &ln))) { + if (strncmp + (pos, cmdname, + strlen(cmdname)) == 0) { + name_found = 1; + keep_alive->retryInterval = + a2hex_or_atoi(pos + + strlen + (cmdname)); + break; + } + } + if (!name_found) { + fprintf(stderr, + "mlanutl: retryInterval not found in file '%s'\n", + argv[3]); + break; + } + snprintf(cmdname, sizeof(cmdname), + "retryCount="); + name_found = 0; + while ((pos = + mlan_config_get_line(fp, line, + sizeof(line), + &ln))) { + if (strncmp + (pos, cmdname, + strlen(cmdname)) == 0) { + name_found = 1; + keep_alive->retryCount = + a2hex_or_atoi(pos + + strlen + (cmdname)); + break; + } + } + if (!name_found) { + fprintf(stderr, + "mlanutl: retryCount not found in file '%s'\n", + argv[3]); + break; + } + snprintf(cmdname, sizeof(cmdname), + "destMacAddr="); + name_found = 0; + while ((pos = + mlan_config_get_line(fp, line, + sizeof(line), + &ln))) { + if (strncmp + (pos, cmdname, + strlen(cmdname)) == 0) { + name_found = 1; + mac2raw(pos + strlen(cmdname), + keep_alive->dst_mac); + break; + } + } + if (!name_found) { + fprintf(stderr, + "mlanutl: destination MAC address not found in file '%s'\n", + argv[3]); + break; + } + snprintf(cmdname, sizeof(cmdname), + "srcMacAddr="); + name_found = 0; + while ((pos = + mlan_config_get_line(fp, line, + sizeof(line), + &ln))) { + if (strncmp + (pos, cmdname, + strlen(cmdname)) == 0) { + name_found = 1; + mac2raw(pos + strlen(cmdname), + keep_alive->src_mac); + break; + } + } + if (!name_found) { + fprintf(stderr, + "mlanutl: source MAC address not found in file '%s'\n", + argv[3]); + break; + } + snprintf(cmdname, sizeof(cmdname), "pktLen="); + name_found = 0; + while ((pos = + mlan_config_get_line(fp, line, + sizeof(line), + &ln))) { + if (strncmp + (pos, cmdname, + strlen(cmdname)) == 0) { + name_found = 1; + keep_alive->pkt_len = + a2hex_or_atoi(pos + + strlen + (cmdname)); + break; + } + } + if (!name_found) { + fprintf(stderr, + "mlanutl: ip packet length not found in file '%s'\n", + argv[3]); + break; + } + snprintf(cmdname, sizeof(cmdname), "ipPkt="); + name_found = 0; + while ((pos = + mlan_config_get_line(fp, line, + sizeof(line), + &ln))) { + if (strncmp + (pos, cmdname, + strlen(cmdname)) == 0) { + name_found = 1; + arg_num = + parse_line(line, args, + 256); + if (arg_num < + keep_alive->pkt_len) { + fprintf(stderr, + "Invalid ipPkt or pkt_len in '%s'\n", + argv[3]); + break; + } + for (i = 0; + i < keep_alive->pkt_len; + i++) + keep_alive->pkt[i] = + (t_u8) + atoval(args + [i + 1]); + break; + } + } + if (!name_found) { + fprintf(stderr, + "mlanutl: ipPkt data not found in file '%s'\n", + argv[3]); + break; + } + } + } + } + if (!cmdname_found) { + fprintf(stderr, "mlanutl: ipPkt data not found in file '%s'\n", + argv[3]); + free(buffer); + return MLAN_STATUS_FAILURE; + } + + cmd = (struct eth_priv_cmd *)malloc(sizeof(struct eth_priv_cmd)); + if (!cmd) { + printf("ERR:Cannot allocate buffer for command!\n"); + free(buffer); + return MLAN_STATUS_FAILURE; + } + + /* Fill up buffer */ +#ifdef USERSPACE_32BIT_OVER_KERNEL_64BIT + memset(cmd, 0, sizeof(struct eth_priv_cmd)); + memcpy(&cmd->buf, &buffer, sizeof(buffer)); +#else + cmd->buf = buffer; +#endif + cmd->used_len = 0; + cmd->total_len = BUFFER_LENGTH; + /* Perform IOCTL */ + memset(&ifr, 0, sizeof(struct ifreq)); + strncpy(ifr.ifr_ifrn.ifrn_name, dev_name, strlen(dev_name)); + ifr.ifr_ifru.ifru_data = (void *)cmd; + + if (ioctl(sockfd, MLAN_ETH_PRIV, &ifr)) { + perror("mlanutl"); + fprintf(stderr, "mlanutl: cloud keep alive fail\n"); + if (cmd) + free(cmd); + if (buffer) + free(buffer); + return MLAN_STATUS_FAILURE; + } + /* Process result */ + keep_alive = (cloud_keep_alive *) (buffer + strlen(argv[2])); + if (strcmp(argv[4], "start") != 0) { + hexdump("Last cloud keep alive packet info", keep_alive->pkt, + keep_alive->pkt_len, ' '); + } + + if (buffer) + free(buffer); + if (cmd) + free(cmd); + +done: + return ret; +} + +/** + * @brief Process enable/disable DFS offload + * @param argc Number of arguments + * @param argv A pointer to arguments array + * @return MLAN_STATUS_SUCCESS--success, otherwise--fail + */ +static int +process_dfs_offload_enable(int argc, char *argv[]) +{ + t_u8 *buffer = NULL; + struct eth_priv_cmd *cmd = NULL; + struct ifreq ifr; + + /* Check arguments */ + if (argc < 3 || argc > 4) { + printf("ERR:Incorrect number of arguments!\n"); + printf("Syntax: ./mlanutl mlanX dfs_offload <0/1>\n"); + return MLAN_STATUS_FAILURE; + } + + /* Initialize buffer */ + buffer = (t_u8 *)malloc(BUFFER_LENGTH); + if (!buffer) { + printf("ERR:Cannot allocate buffer for command!\n"); + return MLAN_STATUS_FAILURE; + } + + prepare_buffer(buffer, argv[2], (argc - 3), &argv[3]); + + cmd = (struct eth_priv_cmd *)malloc(sizeof(struct eth_priv_cmd)); + if (!cmd) { + printf("ERR:Cannot allocate buffer for command!\n"); + free(buffer); + return MLAN_STATUS_FAILURE; + } + + /* Fill up buffer */ +#ifdef USERSPACE_32BIT_OVER_KERNEL_64BIT + memset(cmd, 0, sizeof(struct eth_priv_cmd)); + memcpy(&cmd->buf, &buffer, sizeof(buffer)); +#else + cmd->buf = buffer; +#endif + cmd->used_len = 0; + cmd->total_len = BUFFER_LENGTH; + + /* Perform IOCTL */ + memset(&ifr, 0, sizeof(struct ifreq)); + strncpy(ifr.ifr_ifrn.ifrn_name, dev_name, strlen(dev_name)); + ifr.ifr_ifru.ifru_data = (void *)cmd; + + if (ioctl(sockfd, MLAN_ETH_PRIV, &ifr)) { + perror("mlanutl"); + fprintf(stderr, "mlanutl: dfs offload enable/disable fail\n"); + if (cmd) + free(cmd); + if (buffer) + free(buffer); + return MLAN_STATUS_FAILURE; + } + + if (buffer) + free(buffer); + if (cmd) + free(cmd); + + return MLAN_STATUS_SUCCESS; +} + +#define MEFCFG_CMDCODE 0x009a + +/** + * @brief Process mefcfg command + * @param argc number of arguments + * @param argv A pointer to arguments array + * @return MLAN_STATUS_SUCCESS--success, otherwise--fail + */ +static int +process_mefcfg(int argc, char *argv[]) +{ + char line[256], cmdname[256], *pos = NULL; + int cmdname_found = 0, name_found = 0; + int ln = 0; + int ret = MLAN_STATUS_SUCCESS; + int i; + t_u8 *buffer = NULL; + t_u16 len = 0; + HostCmd_DS_MEF_CFG *mefcmd = NULL; + HostCmd_DS_GEN *hostcmd = NULL; + FILE *fp = NULL; + t_u32 cmd_len = 0, cmd_header_len; + struct eth_priv_cmd *cmd = NULL; + struct ifreq ifr; + + if (argc < 4) { + printf("Error: invalid no of arguments\n"); + printf("Syntax: ./mlanutl mlan0 mefcfg \n"); + exit(1); + } + + cmd_header_len = strlen(CMD_NXP) + strlen("HOSTCMD"); + cmd_len = sizeof(HostCmd_DS_GEN) + sizeof(HostCmd_DS_MEF_CFG); + buffer = (t_u8 *)malloc(BUFFER_LENGTH); + if (buffer == NULL) { + fprintf(stderr, "Cannot alloc memory\n"); + exit(1); + } + memset(buffer, 0, BUFFER_LENGTH); + + cmd = (struct eth_priv_cmd *)malloc(sizeof(struct eth_priv_cmd)); + if (!cmd) { + printf("ERR:Cannot allocate buffer for command!\n"); + free(buffer); + return MLAN_STATUS_FAILURE; + } + + /* Fill up buffer */ +#ifdef USERSPACE_32BIT_OVER_KERNEL_64BIT + memset(cmd, 0, sizeof(struct eth_priv_cmd)); + memcpy(&cmd->buf, &buffer, sizeof(buffer)); +#else + cmd->buf = buffer; +#endif + cmd->used_len = 0; + cmd->total_len = BUFFER_LENGTH; + /* buf = MRVL_CMD */ + prepare_buffer(buffer, HOSTCMD, 0, NULL); + + /* buf = MRVL_CMD */ + hostcmd = (HostCmd_DS_GEN *)(buffer + cmd_header_len + sizeof(t_u32)); + hostcmd->command = cpu_to_le16(MEFCFG_CMDCODE); + hostcmd->seq_num = 0; + hostcmd->result = 0; + /* buf = MRVL_CMD */ + mefcmd = (HostCmd_DS_MEF_CFG *)(buffer + cmd_header_len + + sizeof(t_u32) + S_DS_GEN); + +/* Host Command Population */ + snprintf(cmdname, sizeof(cmdname), "%s={", argv[2]); + cmdname_found = 0; + fp = fopen(argv[3], "r"); + if (fp == NULL) { + fprintf(stderr, "Cannot open file %s\n", argv[4]); + exit(1); + } + + while ((pos = mlan_config_get_line(fp, line, sizeof(line), &ln))) { + if (strcmp(pos, cmdname) == 0) { + cmdname_found = 1; + snprintf(cmdname, sizeof(cmdname), "Criteria="); + name_found = 0; + while ((pos = + mlan_config_get_line(fp, line, sizeof(line), + &ln))) { + if (strncmp(pos, cmdname, strlen(cmdname)) == 0) { + name_found = 1; + mefcmd->Criteria = + a2hex_or_atoi(pos + + strlen(cmdname)); + break; + } + } + if (!name_found) { + fprintf(stderr, + "mlanutl: criteria not found in file '%s'\n", + argv[3]); + break; + } + snprintf(cmdname, sizeof(cmdname), "NumEntries="); + name_found = 0; + while ((pos = + mlan_config_get_line(fp, line, sizeof(line), + &ln))) { + if (strncmp(pos, cmdname, strlen(cmdname)) == 0) { + name_found = 1; + mefcmd->NumEntries = + a2hex_or_atoi(pos + + strlen(cmdname)); + break; + } + } + if (!name_found) { + fprintf(stderr, + "mlanutl: NumEntries not found in file '%s'\n", + argv[3]); + break; + } + for (i = 0; i < mefcmd->NumEntries; i++) { + snprintf(cmdname, sizeof(cmdname), + "mef_entry_%d={", i); + name_found = 0; + while ((pos = + mlan_config_get_line(fp, line, + sizeof(line), + &ln))) { + if (strncmp + (pos, cmdname, + strlen(cmdname)) == 0) { + name_found = 1; + break; + } + } + if (!name_found) { + fprintf(stderr, + "mlanutl: %s not found in file '%s'\n", + cmdname, argv[3]); + break; + } + if (MLAN_STATUS_FAILURE == + mlan_get_mef_entry_data(fp, &ln, + (t_u8 *)hostcmd + + cmd_len, &len)) { + ret = MLAN_STATUS_FAILURE; + break; + } + cmd_len += len; + } + break; + } + } + fclose(fp); + /* buf = MRVL_CMD */ + memcpy(buffer + cmd_header_len, (t_u8 *)&cmd_len, sizeof(t_u32)); + + if (!cmdname_found) + fprintf(stderr, + "mlanutl: cmdname '%s' not found in file '%s'\n", + argv[4], argv[3]); + + if (!cmdname_found || !name_found) { + ret = MLAN_STATUS_FAILURE; + goto mef_exit; + } + hostcmd->size = cpu_to_le16(cmd_len); + mefcmd->Criteria = cpu_to_le32(mefcmd->Criteria); + mefcmd->NumEntries = cpu_to_le16(mefcmd->NumEntries); + hexdump("mefcfg", buffer + cmd_header_len, cmd_len, ' '); + + /* Initialize the ifr structure */ + memset(&ifr, 0, sizeof(ifr)); + strncpy(ifr.ifr_ifrn.ifrn_name, dev_name, strlen(dev_name)); + ifr.ifr_ifru.ifru_data = (void *)cmd; + /* Perform ioctl */ + if (ioctl(sockfd, MLAN_ETH_PRIV, &ifr)) { + perror("ioctl[MEF_CFG]"); + printf("ERR:Command sending failed!\n"); + if (buffer) + free(buffer); + if (cmd) + free(cmd); + return MLAN_STATUS_FAILURE; + } + + ret = process_host_cmd_resp(HOSTCMD, buffer); + +mef_exit: + if (buffer) + free(buffer); + if (cmd) + free(cmd); + return ret; + +} + +/** + * @brief parse hex data + * @param fp File handler + * @param dst A pointer to receive hex data + * @return length of hex data + */ +int +fparse_for_hex(FILE * fp, t_u8 *dst) +{ + char *ptr = NULL; + t_u8 *dptr = NULL; + char buf[256]; + + dptr = dst; + while (fgets(buf, sizeof(buf), fp)) { + ptr = buf; + + while (*ptr) { + /* skip leading spaces */ + while (*ptr && (isspace(*ptr) || *ptr == '\t')) + ptr++; + + /* skip blank lines and lines beginning with '#' */ + if (*ptr == '\0' || *ptr == '#') + break; + + if (isxdigit(*ptr)) { + ptr = convert2hex(ptr, dptr++); + } else { + /* Invalid character on data line */ + ptr++; + } + } + } + + return dptr - dst; +} + +/** Config data header length */ +#define CFG_DATA_HEADER_LEN 6 + +/** + * @brief Prepare cfg-data buffer + * @param argc Number of arguments + * @param argv A pointer to arguments array + * @param fp File handler + * @param buf A pointer to comand buffer + * @param cmd_header_len Length of the command header + * @return MLAN_STATUS_SUCCESS--success, otherwise--fail + */ +int +prepare_cfg_data_buffer(int argc, char *argv[], FILE * fp, t_u8 *buf, + int cmd_header_len) +{ + int ln = 0, type; + HostCmd_DS_GEN *hostcmd = NULL; + HostCmd_DS_802_11_CFG_DATA *pcfg_data = NULL; + + memset(buf, 0, BUFFER_LENGTH - cmd_header_len - sizeof(t_u32)); + hostcmd = (HostCmd_DS_GEN *)buf; + hostcmd->command = cpu_to_le16(HostCmd_CMD_CFG_DATA); + pcfg_data = (HostCmd_DS_802_11_CFG_DATA *)(buf + S_DS_GEN); + pcfg_data->action = + (argc == 4) ? HostCmd_ACT_GEN_GET : HostCmd_ACT_GEN_SET; + type = atoi(argv[3]); + if ((type < 1) || (type > 2)) { + fprintf(stderr, "mlanutl: Invalid register type\n"); + return MLAN_STATUS_FAILURE; + } else { + pcfg_data->type = type; + } + if (argc == 5) { + ln = fparse_for_hex(fp, pcfg_data->data); + } + pcfg_data->data_len = ln; + hostcmd->size = + cpu_to_le16(pcfg_data->data_len + S_DS_GEN + + CFG_DATA_HEADER_LEN); + pcfg_data->data_len = cpu_to_le16(pcfg_data->data_len); + pcfg_data->type = cpu_to_le16(pcfg_data->type); + pcfg_data->action = cpu_to_le16(pcfg_data->action); + + hostcmd->seq_num = 0; + hostcmd->result = 0; + return MLAN_STATUS_SUCCESS; +} + +/** + * @brief Process cfgdata + * @param argc number of arguments + * @param argv A pointer to arguments array + * @return MLAN_STATUS_SUCCESS--success, otherwise--fail + */ +static int +process_cfgdata(int argc, char *argv[]) +{ + t_u8 *buffer = NULL; + HostCmd_DS_GEN *hostcmd = NULL; + int ret = MLAN_STATUS_SUCCESS; + FILE *fp = NULL; + int cmd_header_len = 0; + struct eth_priv_cmd *cmd = NULL; + struct ifreq ifr; + + if (argc < 4 || argc > 5) { + printf("Error: invalid no of arguments\n"); + printf("Syntax: ./mlanutl mlanX cfgdata \n"); + exit(1); + } + + if (argc == 5) { + fp = fopen(argv[4], "r"); + if (fp == NULL) { + fprintf(stderr, "Cannot open file %s\n", argv[3]); + exit(1); + } + } + + cmd_header_len = strlen(CMD_NXP) + strlen(HOSTCMD); + + buffer = (t_u8 *)malloc(BUFFER_LENGTH); + if (buffer == NULL) { + printf("Error: allocate memory for hostcmd failed\n"); + if (argc == 5) + fclose(fp); + return -ENOMEM; + } + memset(buffer, 0, BUFFER_LENGTH); + + cmd = (struct eth_priv_cmd *)malloc(sizeof(struct eth_priv_cmd)); + if (!cmd) { + printf("ERR:Cannot allocate buffer for command!\n"); + free(buffer); + if (fp) { + fclose(fp); + } + return MLAN_STATUS_FAILURE; + } + memset(cmd, 0, sizeof(struct eth_priv_cmd)); + + /* Fill up buffer */ +#ifdef USERSPACE_32BIT_OVER_KERNEL_64BIT + memset(cmd, 0, sizeof(struct eth_priv_cmd)); + memcpy(&cmd->buf, &buffer, sizeof(buffer)); +#else + cmd->buf = buffer; +#endif + cmd->used_len = 0; + cmd->total_len = BUFFER_LENGTH; + /* buf = MRVL_CMD */ + prepare_buffer(buffer, HOSTCMD, 0, NULL); + + /* buf = MRVL_CMD */ + hostcmd = (HostCmd_DS_GEN *)(buffer + cmd_header_len + sizeof(t_u32)); + + ret = prepare_cfg_data_buffer(argc, argv, fp, (t_u8 *)hostcmd, + cmd_header_len); + if (argc == 5) + fclose(fp); + + if (ret == MLAN_STATUS_FAILURE) + goto _exit_; + + /* Initialize the ifr structure */ + memset(&ifr, 0, sizeof(ifr)); + strncpy(ifr.ifr_ifrn.ifrn_name, dev_name, strlen(dev_name)); + ifr.ifr_ifru.ifru_data = (void *)cmd; + /* Perform ioctl */ + if (ioctl(sockfd, MLAN_ETH_PRIV, &ifr)) { + perror("ioctl[CFG_DATA]"); + printf("ERR:Command sending failed!\n"); + if (buffer) + free(buffer); + if (cmd) + free(cmd); + return MLAN_STATUS_FAILURE; + } + ret = process_host_cmd_resp(HOSTCMD, buffer); + +_exit_: + if (buffer) + free(buffer); + if (cmd) + free(cmd); + + return ret; +} + +/** + * @brief Process transmission of mgmt frames + * @param argc number of arguments + * @param argv A pointer to arguments array + * @return MLAN_STATUS_SUCCESS--success, otherwise--fail + */ +static int +process_mgmtframetx(int argc, char *argv[]) +{ + struct ifreq ifr; + char *line = NULL; + FILE *config_file = NULL; + int li = 0, arg_num = 0, ret = 0, i = 0; + char *args[100], *pos = NULL, mac_addr[20]; + t_u8 peer_mac[ETH_ALEN]; + t_u16 data_len = 0, type = 0, subtype = 0; + t_u16 seq_num = 0, frag_num = 0, from_ds = 0, to_ds = 0; + eth_priv_mgmt_frame_tx *pmgmt_frame = NULL; + t_u8 *buffer = NULL; + pkt_header *hdr = NULL; + + /* Check arguments */ + if (argc != 4) { + printf("ERR:Incorrect number of arguments.\n"); + printf("Syntax: ./mlanutl mlanX mgmtframetx \n"); + exit(1); + } + + data_len = sizeof(eth_priv_mgmt_frame_tx); + + buffer = (t_u8 *)malloc(BUFFER_LENGTH); + if (!buffer) { + printf("ERR:Cannot allocate memory!\n"); + goto done; + } + memset(buffer, 0, BUFFER_LENGTH); + hdr = (pkt_header *)buffer; + pmgmt_frame = (eth_priv_mgmt_frame_tx *)(buffer + sizeof(pkt_header)); + + /* Check if file exists */ + config_file = fopen(argv[3], "r"); + if (config_file == NULL) { + printf("\nERR:Config file can not open.\n"); + goto done; + } + line = (char *)malloc(MAX_CONFIG_LINE); + if (!line) { + printf("ERR:Cannot allocate memory for line\n"); + goto done; + } + memset(line, 0, MAX_CONFIG_LINE); + + /* Parse file and process */ + while (config_get_line(line, MAX_CONFIG_LINE, config_file, &li, &pos)) { + arg_num = parse_line(line, args, 100); + if (strcmp(args[0], "PktType") == 0) { + type = (t_u16)A2HEXDECIMAL(args[1]); + pmgmt_frame->frm_ctl = (type & 0x3) << 2; + } else if (strcmp(args[0], "PktSubType") == 0) { + subtype = (t_u16)A2HEXDECIMAL(args[1]); + pmgmt_frame->frm_ctl |= subtype << 4; + } else if (strncmp(args[0], "Addr", 4) == 0) { + strncpy(mac_addr, args[1], 20); + ret = mac2raw(mac_addr, peer_mac); + if (ret != MLAN_STATUS_SUCCESS) { + printf("%s Address \n", + ret == + MLAN_STATUS_FAILURE ? "Invalid MAC" : ret + == + MAC_BROADCAST ? "Broadcast" : + "Multicast"); + if (ret == MLAN_STATUS_FAILURE) + goto done; + } + i = atoi(args[0] + 4); + switch (i) { + case 1: + memcpy(pmgmt_frame->addr1, peer_mac, ETH_ALEN); + break; + case 2: + memcpy(pmgmt_frame->addr2, peer_mac, ETH_ALEN); + break; + case 3: + memcpy(pmgmt_frame->addr3, peer_mac, ETH_ALEN); + break; + case 4: + memcpy(pmgmt_frame->addr4, peer_mac, ETH_ALEN); + break; + } + } else if (strcmp(args[0], "Data") == 0) { + for (i = 0; i < arg_num - 1; i++) + pmgmt_frame->payload[i] = + (t_u8)A2HEXDECIMAL(args[i + 1]); + data_len += arg_num - 1; + } else if (strcmp(args[0], "SeqNum") == 0) { + seq_num = (t_u16)A2HEXDECIMAL(args[1]); + pmgmt_frame->seq_ctl = seq_num << 4; + } else if (strcmp(args[0], "FragNum") == 0) { + frag_num = (t_u16)A2HEXDECIMAL(args[1]); + pmgmt_frame->seq_ctl |= frag_num; + } else if (strcmp(args[0], "FromDS") == 0) { + from_ds = (t_u16)A2HEXDECIMAL(args[1]); + pmgmt_frame->frm_ctl |= (from_ds & 0x1) << 9; + } else if (strcmp(args[0], "ToDS") == 0) { + to_ds = (t_u16)A2HEXDECIMAL(args[1]); + pmgmt_frame->frm_ctl |= (to_ds & 0x1) << 8; + } + } + pmgmt_frame->frm_len = data_len - sizeof(pmgmt_frame->frm_len); +#define MRVL_PKT_TYPE_MGMT_FRAME 0xE5 + hdr->pkt_len = data_len; + hdr->TxPktType = MRVL_PKT_TYPE_MGMT_FRAME; + hdr->TxControl = 0; + hexdump("Frame Tx", buffer, data_len + sizeof(pkt_header), ' '); + /* Send collective command */ + memset(&ifr, 0, sizeof(ifr)); + strncpy(ifr.ifr_ifrn.ifrn_name, dev_name, strlen(dev_name)); + ifr.ifr_ifru.ifru_data = (void *)buffer; + + /* Perform ioctl */ + if (ioctl(sockfd, FRAME_TX_IOCTL, &ifr)) { + perror(""); + printf("ERR:Could not send management frame.\n"); + } else { + printf("Mgmt Frame sucessfully sent.\n"); + } + +done: + if (config_file) + fclose(config_file); + if (buffer) + free(buffer); + if (line) + free(line); + return MLAN_STATUS_SUCCESS; +} + +/** + * @brief set/get management frame passthrough + * @param argc Number of arguments + * @param argv A pointer to arguments array + * @return MLAN_STATUS_SUCCESS--success, otherwise--fail + */ +static int +process_mgmt_frame_passthrough(int argc, char *argv[]) +{ + t_u8 *buffer = NULL; + struct eth_priv_cmd *cmd = NULL; + struct ifreq ifr; + t_u32 mask = 0; + + /* Initialize buffer */ + buffer = (t_u8 *)malloc(BUFFER_LENGTH); + if (!buffer) { + printf("ERR:Cannot allocate buffer for command!\n"); + return MLAN_STATUS_FAILURE; + } + + prepare_buffer(buffer, argv[2], (argc - 3), &argv[3]); + + cmd = (struct eth_priv_cmd *)malloc(sizeof(struct eth_priv_cmd)); + if (!cmd) { + printf("ERR:Cannot allocate buffer for command!\n"); + free(buffer); + return MLAN_STATUS_FAILURE; + } + + /* Fill up buffer */ +#ifdef USERSPACE_32BIT_OVER_KERNEL_64BIT + memset(cmd, 0, sizeof(struct eth_priv_cmd)); + memcpy(&cmd->buf, &buffer, sizeof(buffer)); +#else + cmd->buf = buffer; +#endif + cmd->used_len = 0; + cmd->total_len = BUFFER_LENGTH; + + /* Perform IOCTL */ + memset(&ifr, 0, sizeof(struct ifreq)); + strncpy(ifr.ifr_ifrn.ifrn_name, dev_name, strlen(dev_name)); + ifr.ifr_ifru.ifru_data = (void *)cmd; + + if (ioctl(sockfd, MLAN_ETH_PRIV, &ifr)) { + perror("mlanutl"); + fprintf(stderr, "mlanutl: htcapinfo fail\n"); + if (cmd) + free(cmd); + if (buffer) + free(buffer); + return MLAN_STATUS_FAILURE; + } + + /* Process result */ + mask = *(t_u32 *)buffer; + if (argc == 3) + printf("Registed Management Frame Mask: 0x%x\n", mask); + + if (buffer) + free(buffer); + if (cmd) + free(cmd); + + return MLAN_STATUS_SUCCESS; +} + +/** + * @brief set/get hotspot enable/disable config + * @param argc Number of arguments + * @param argv A pointer to arguments array + * @return MLAN_STATUS_SUCCESS--success, otherwise--fail + */ +static int +process_hotspot_config(int argc, char *argv[]) +{ + t_u8 *buffer = NULL; + struct eth_priv_cmd *cmd = NULL; + struct ifreq ifr; + t_u32 hotspotcfg = 0; + + /* Initialize buffer */ + buffer = (t_u8 *)malloc(BUFFER_LENGTH); + if (!buffer) { + printf("ERR:Cannot allocate buffer for command!\n"); + return MLAN_STATUS_FAILURE; + } + + prepare_buffer(buffer, argv[2], (argc - 3), &argv[3]); + + cmd = (struct eth_priv_cmd *)malloc(sizeof(struct eth_priv_cmd)); + if (!cmd) { + printf("ERR:Cannot allocate buffer for command!\n"); + free(buffer); + return MLAN_STATUS_FAILURE; + } + + /* Fill up buffer */ +#ifdef USERSPACE_32BIT_OVER_KERNEL_64BIT + memset(cmd, 0, sizeof(struct eth_priv_cmd)); + memcpy(&cmd->buf, &buffer, sizeof(buffer)); +#else + cmd->buf = buffer; +#endif + cmd->used_len = 0; + cmd->total_len = BUFFER_LENGTH; + + /* Perform IOCTL */ + memset(&ifr, 0, sizeof(struct ifreq)); + strncpy(ifr.ifr_ifrn.ifrn_name, dev_name, strlen(dev_name)); + ifr.ifr_ifru.ifru_data = (void *)cmd; + + if (ioctl(sockfd, MLAN_ETH_PRIV, &ifr)) { + perror("mlanutl"); + fprintf(stderr, "mlanutl: htcapinfo fail\n"); + if (cmd) + free(cmd); + if (buffer) + free(buffer); + return MLAN_STATUS_FAILURE; + } + + /* Process result */ + hotspotcfg = *(t_u32 *)buffer; + if (argc == 3) + printf("HotSpot 2.0 Status: 0x%x\n", hotspotcfg); + + if (buffer) + free(buffer); + if (cmd) + free(cmd); + + return MLAN_STATUS_SUCCESS; +} + +/** + * @brief read current command + * @param ptr A pointer to data + * @param curCmd A pointer to the buf which will hold current command + * @return NULL or the pointer to the left command buf + */ +static t_s8 * +readCurCmd(t_s8 *ptr, t_s8 *curCmd) +{ + t_s32 i = 0; +#define MAX_CMD_SIZE 64 /**< Max command size */ + + while (*ptr != ']' && i < (MAX_CMD_SIZE - 1)) + curCmd[i++] = *(++ptr); + + if (*ptr != ']') + return NULL; + + curCmd[i - 1] = '\0'; + + return ++ptr; +} + +/** + * @brief parse command and hex data + * @param fp A pointer to FILE stream + * @param dst A pointer to the dest buf + * @param cmd A pointer to command buf for search + * @return Length of hex data or MLAN_STATUS_FAILURE + */ +static int +fparse_for_cmd_and_hex(FILE * fp, t_u8 *dst, t_u8 *cmd) +{ + t_s8 *ptr; + t_u8 *dptr; + t_s8 buf[256], curCmd[64]; + t_s32 isCurCmd = 0; + + dptr = dst; + while (fgets((char *)buf, sizeof(buf), fp)) { + ptr = buf; + + while (*ptr) { + /* skip leading spaces */ + while (*ptr && isspace(*ptr)) + ptr++; + + /* skip blank lines and lines beginning with '#' */ + if (*ptr == '\0' || *ptr == '#') + break; + + if (*ptr == '[' && *(ptr + 1) != '/') { + ptr = readCurCmd(ptr, curCmd); + if (!ptr) + return MLAN_STATUS_FAILURE; + + if (strcasecmp((char *)curCmd, (char *)cmd)) /* Not equal */ + isCurCmd = 0; + else + isCurCmd = 1; + } + + /* Ignore the rest if it is not correct cmd */ + if (!isCurCmd) + break; + + if (*ptr == '[' && *(ptr + 1) == '/') + return dptr - dst; + + if (isxdigit(*ptr)) { + ptr = (t_s8 *)convert2hex((char *)ptr, dptr++); + } else { + /* Invalid character on data line */ + ptr++; + } + } + } + + return MLAN_STATUS_FAILURE; +} + +/** + * @brief 11ax HE capability and operation configure + * + * @param argc Number of arguments + * @param argv Pointer to the arguments array + * + * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_FAILURE + */ + +static int +process_11axcfg(int argc, char *argv[]) +{ + t_u8 *buffer = NULL; + struct eth_priv_cmd *cmd; + struct ifreq ifr; + int id_len = 0; + FILE *fp = NULL; + int ret = 0, cmd_header_len = 0; + char config_id[20]; + char filename[256]; + + if (argc != 3 && argc != 4) { + printf("Err: Invalid number of arguments\n"); + printf("Usage: ./mlanutl 11axcfg [11axcfg.conf]\n"); + return MLAN_STATUS_FAILURE; + } + /* Initialize buffer */ + buffer = (t_u8 *)malloc(BUFFER_LENGTH); + if (!buffer) { + printf("ERR:Cannot allocate buffer for command!\n"); + return MLAN_STATUS_FAILURE; + } + + cmd_header_len = strlen(CMD_NXP) + strlen(argv[2]); + prepare_buffer(buffer, argv[2], 0, NULL); + cmd = (struct eth_priv_cmd *)malloc(sizeof(struct eth_priv_cmd)); + if (!cmd) { + printf("ERR:Cannot allocate buffer for command!\n"); + free(buffer); + return MLAN_STATUS_FAILURE; + } + + /* Fill up buffer */ +#ifdef USERSPACE_32BIT_OVER_KERNEL_64BIT + memset(cmd, 0, sizeof(struct eth_priv_cmd)); + memcpy(&cmd->buf, &buffer, sizeof(buffer)); +#else + cmd->buf = buffer; +#endif + cmd->used_len = cmd_header_len; + cmd->total_len = BUFFER_LENGTH; + + if (argc == 4) { + memset(filename, 0, sizeof(filename)); + strncpy(filename, argv[3], sizeof(filename) - 1); + + fp = fopen(filename, "r"); + if (fp == NULL) { + perror("fopen"); + fprintf(stderr, "Cannot open file %s\n", argv[3]); + ret = -EFAULT;; + goto done; + } + + snprintf(config_id, sizeof(config_id), "Band"); + id_len = fparse_for_cmd_and_hex(fp, buffer + cmd_header_len, + (t_u8 *)config_id); + + snprintf(config_id, sizeof(config_id), "HECap"); + fparse_for_cmd_and_hex(fp, buffer + cmd_header_len + id_len, + (t_u8 *)config_id); + hexdump("Set 11axcfg", buffer + cmd_header_len, + sizeof(mlan_ds_11ax_he_cfg), ' '); + cmd->used_len = cmd_header_len + sizeof(mlan_ds_11ax_he_cfg); + } + /* Initialize the ifr structure */ + memset(&ifr, 0, sizeof(ifr)); + strncpy(ifr.ifr_ifrn.ifrn_name, dev_name, strlen(dev_name)); + ifr.ifr_ifru.ifru_data = (void *)cmd; + + if (ioctl(sockfd, MLAN_ETH_PRIV, &ifr)) { + perror("mlanutl: 11axcfg"); + ret = -EFAULT; + goto done; + } + hexdump("11axcfg", buffer + cmd_header_len, sizeof(mlan_ds_11ax_he_cfg), + ' '); +done: + if (fp) + fclose(fp); + + if (buffer) + free(buffer); + if (cmd) + free(cmd); + return ret; +} + +/** + * @brief Process 11ax command + * @param argc Number of arguments + * @param argv A pointer to arguments array + * @return MLAN_STATUS_SUCCESS--success, otherwise--fail + */ +static int +process_11axcmdcfg(int argc, char *argv[]) +{ + t_u8 *buffer = NULL; + struct eth_priv_cmd *cmd = NULL; + struct ifreq ifr; + mlan_ds_11ax_cmd_cfg *axcmd = NULL; + t_u32 action = 0; + t_u32 prefix_len = 0; + + /* Initialize buffer */ + buffer = (t_u8 *)malloc(BUFFER_LENGTH); + if (!buffer) { + printf("ERR:Cannot allocate buffer for command!\n"); + return MLAN_STATUS_FAILURE; + } + + if (strcmp(argv[3], "obss_pd_offset") == 0) { + sprintf(argv[3], "%d", MLAN_11AXCMD_CFG_ID_SR_OBSS_PD_OFFSET); + } else if (strcmp(argv[3], "enable_sr") == 0) { + sprintf(argv[3], "%d", MLAN_11AXCMD_CFG_ID_SR_ENABLE); + } else if (strcmp(argv[3], "beam_change") == 0) { + sprintf(argv[3], "%d", MLAN_11AXCMD_CFG_ID_BEAM_CHANGE); + } else if (strcmp(argv[3], "enable_htc") == 0) { + sprintf(argv[3], "%d", MLAN_11AXCMD_CFG_ID_HTC_ENABLE); + } else { + printf("ERR:unknown command %s!\n", argv[3]); + } + + prepare_buffer(buffer, argv[2], (argc - 3), &argv[3]); + + cmd = (struct eth_priv_cmd *)malloc(sizeof(struct eth_priv_cmd)); + if (!cmd) { + printf("ERR:Cannot allocate buffer for command!\n"); + free(buffer); + return MLAN_STATUS_FAILURE; + } + + /* Fill up buffer */ +#ifdef USERSPACE_32BIT_OVER_KERNEL_64BIT + memset(cmd, 0, sizeof(struct eth_priv_cmd)); + memcpy(&cmd->buf, &buffer, sizeof(buffer)); +#else + cmd->buf = buffer; +#endif + cmd->used_len = strlen((char *)buffer); + cmd->total_len = BUFFER_LENGTH; + + /* Perform IOCTL */ + memset(&ifr, 0, sizeof(struct ifreq)); + strncpy(ifr.ifr_ifrn.ifrn_name, dev_name, strlen(dev_name)); + ifr.ifr_ifru.ifru_data = (void *)cmd; + + if (ioctl(sockfd, MLAN_ETH_PRIV, &ifr)) { + perror("mlanutl"); + fprintf(stderr, "mlanutl: 11axcmd fail\n"); + if (cmd) + free(cmd); + if (buffer) + free(buffer); + return MLAN_STATUS_FAILURE; + } + + prefix_len += strlen(CMD_NXP) + strlen(argv[2]); + action = *(t_u32 *)(buffer + prefix_len); + if (action == MLAN_ACT_GET) { + axcmd = (mlan_ds_11ax_cmd_cfg *) (buffer + prefix_len + + sizeof(t_u32)); + switch (axcmd->sub_id) { + case MLAN_11AXCMD_SR_SUBID: + if (axcmd->param.sr_cfg.type == + MRVL_DOT11AX_OBSS_PD_OFFSET_TLV_ID) { + printf("HE SR = %d,%d\n", axcmd->param.sr_cfg.param.obss_pd_offset.offset[0], axcmd->param.sr_cfg.param.obss_pd_offset.offset[1]); + } else if (axcmd->param.sr_cfg.type == + MRVL_DOT11AX_ENABLE_SR_TLV_ID) { + printf("HE SR Spatial Reuse is %s(%d)\n", + axcmd->param.sr_cfg.param.sr_control. + control == 1 ? "enabled" : "disabled", + axcmd->param.sr_cfg.param.sr_control. + control); + } else { + printf("Unknown SR type 0x%x\n", + axcmd->param.sr_cfg.type); + } + break; + case MLAN_11AXCMD_BEAM_SUBID: + printf("HE Beam change %s(%d)\n", + axcmd->param.beam_cfg.value == + 1 ? "disabled" : "enabled", + axcmd->param.beam_cfg.value); + break; + case MLAN_11AXCMD_HTC_SUBID: + printf("HTC transmission %s(%d)\n", + axcmd->param.htc_cfg.value == + 1 ? "enabled" : "disabled", + axcmd->param.htc_cfg.value); + break; + default: + printf("Unknown sub_command 0x%x\n", axcmd->sub_id); + break; + } + } + + if (buffer) + free(buffer); + if (cmd) + free(cmd); + + return MLAN_STATUS_SUCCESS; + +} + +/** + * @brief Send a WMM AC Queue configuration command to get/set/default params + * + * Configure or get the parameters of a WMM AC queue. The command takes + * an optional Queue Id as a last parameter. Without the queue id, all + * queues will be acted upon. + * + * mlanutl mlanX qconfig set msdu [Queue Id: 0-3] + * mlanutl mlanX qconfig get [Queue Id: 0-3] + * mlanutl mlanX qconfig def [Queue Id: 0-3] + * + * @param argc number of arguments + * @param argv A pointer to arguments array + * + * @return MLAN_STATUS_SUCCESS--success, otherwise--fail + */ +static int +process_qconfig(int argc, char *argv[]) +{ + t_u8 *buffer = NULL; + struct eth_priv_cmd *cmd = NULL; + struct ifreq ifr; + wlan_ioctl_wmm_queue_config_t queue_config_cmd; + mlan_wmm_ac_e ac_idx; + mlan_wmm_ac_e ac_idx_start; + mlan_wmm_ac_e ac_idx_stop; + int cmd_header_len = 0; + int ret = 0; + + const char *ac_str_tbl[] = { "BK", "BE", "VI", "VO" }; + + if (argc < 4) { + fprintf(stderr, "Invalid number of parameters!\n"); + return -EINVAL; + } + + cmd_header_len = strlen(CMD_NXP) + strlen(argv[2]); + + buffer = (t_u8 *)malloc(BUFFER_LENGTH); + if (buffer == NULL) { + printf("Error: allocate memory for qconfig failed\n"); + return -ENOMEM; + } + memset(buffer, 0, BUFFER_LENGTH); + + cmd = (struct eth_priv_cmd *)malloc(sizeof(struct eth_priv_cmd)); + if (!cmd) { + printf("ERR:Cannot allocate buffer for command!\n"); + free(buffer); + return MLAN_STATUS_FAILURE; + } + + /* Fill up buffer */ +#ifdef USERSPACE_32BIT_OVER_KERNEL_64BIT + memset(cmd, 0, sizeof(struct eth_priv_cmd)); + memcpy(&cmd->buf, &buffer, sizeof(buffer)); +#else + cmd->buf = buffer; +#endif + cmd->used_len = 0; + cmd->total_len = BUFFER_LENGTH; + /* buf = MRVL_CMD */ + prepare_buffer(buffer, argv[2], 0, NULL); + + memset(&queue_config_cmd, 0x00, sizeof(wlan_ioctl_wmm_queue_config_t)); + /* Initialize the ifr structure */ + memset(&ifr, 0, sizeof(ifr)); + strncpy(ifr.ifr_ifrn.ifrn_name, dev_name, strlen(dev_name)); + ifr.ifr_ifru.ifru_data = (void *)cmd; + + if (strcmp(argv[3], "get") == 0) { + /* 3 4 5 */ + /* qconfig get [qid] */ + if (argc == 4) { + ac_idx_start = WMM_AC_BK; + ac_idx_stop = WMM_AC_VO; + } else if (argc == 5) { + if (atoi(argv[4]) < WMM_AC_BK || + atoi(argv[4]) > WMM_AC_VO) { + fprintf(stderr, "ERROR: Invalid Queue ID!\n"); + ret = -EINVAL; + goto done; + } + ac_idx_start = atoi(argv[4]); + ac_idx_stop = ac_idx_start; + } else { + fprintf(stderr, "Invalid number of parameters!\n"); + ret = -EINVAL; + goto done; + } + queue_config_cmd.action = WMM_QUEUE_CONFIG_ACTION_GET; + + for (ac_idx = ac_idx_start; ac_idx <= ac_idx_stop; ac_idx++) { + queue_config_cmd.accessCategory = ac_idx; + memcpy(buffer + cmd_header_len, + (t_u8 *)&queue_config_cmd, + sizeof(queue_config_cmd)); + if (ioctl(sockfd, MLAN_ETH_PRIV, &ifr)) { + perror("qconfig ioctl"); + } else { + memcpy((t_u8 *)&queue_config_cmd, + buffer + cmd_header_len, + sizeof(queue_config_cmd)); + printf("qconfig %s(%d): MSDU Lifetime GET = 0x%04x (%d)\n", ac_str_tbl[ac_idx], ac_idx, queue_config_cmd.msduLifetimeExpiry, queue_config_cmd.msduLifetimeExpiry); + } + } + } else if (strcmp(argv[3], "set") == 0) { + if ((argc >= 5) && strcmp(argv[4], "msdu") == 0) { + /* 3 4 5 6 7 */ + /* qconfig set msdu [qid] */ + if (argc == 6) { + ac_idx_start = WMM_AC_BK; + ac_idx_stop = WMM_AC_VO; + } else if (argc == 7) { + if (atoi(argv[6]) < WMM_AC_BK || + atoi(argv[6]) > WMM_AC_VO) { + fprintf(stderr, + "ERROR: Invalid Queue ID!\n"); + ret = -EINVAL; + goto done; + } + ac_idx_start = atoi(argv[6]); + ac_idx_stop = ac_idx_start; + } else { + fprintf(stderr, + "Invalid number of parameters!\n"); + ret = -EINVAL; + goto done; + } + queue_config_cmd.action = WMM_QUEUE_CONFIG_ACTION_SET; + queue_config_cmd.msduLifetimeExpiry = atoi(argv[5]); + + for (ac_idx = ac_idx_start; ac_idx <= ac_idx_stop; + ac_idx++) { + queue_config_cmd.accessCategory = ac_idx; + memcpy(buffer + cmd_header_len, + (t_u8 *)&queue_config_cmd, + sizeof(queue_config_cmd)); + if (ioctl(sockfd, MLAN_ETH_PRIV, &ifr)) { + perror("qconfig ioctl"); + } else { + memcpy((t_u8 *)&queue_config_cmd, + buffer + cmd_header_len, + sizeof(queue_config_cmd)); + printf("qconfig %s(%d): MSDU Lifetime SET = 0x%04x (%d)\n", ac_str_tbl[ac_idx], ac_idx, queue_config_cmd.msduLifetimeExpiry, queue_config_cmd.msduLifetimeExpiry); + } + } + } else { + /* Only MSDU Lifetime provisioning accepted for now */ + fprintf(stderr, "Invalid set parameter: s/b [msdu]\n"); + ret = -EINVAL; + goto done; + } + } else if (strncmp(argv[3], "def", strlen("def")) == 0) { + /* 3 4 5 */ + /* qconfig def [qid] */ + if (argc == 4) { + ac_idx_start = WMM_AC_BK; + ac_idx_stop = WMM_AC_VO; + } else if (argc == 5) { + if (atoi(argv[4]) < WMM_AC_BK || + atoi(argv[4]) > WMM_AC_VO) { + fprintf(stderr, "ERROR: Invalid Queue ID!\n"); + ret = -EINVAL; + goto done; + } + ac_idx_start = atoi(argv[4]); + ac_idx_stop = ac_idx_start; + } else { + fprintf(stderr, "Invalid number of parameters!\n"); + ret = -EINVAL; + goto done; + } + queue_config_cmd.action = WMM_QUEUE_CONFIG_ACTION_DEFAULT; + + for (ac_idx = ac_idx_start; ac_idx <= ac_idx_stop; ac_idx++) { + queue_config_cmd.accessCategory = ac_idx; + memcpy(buffer + cmd_header_len, + (t_u8 *)&queue_config_cmd, + sizeof(queue_config_cmd)); + if (ioctl(sockfd, MLAN_ETH_PRIV, &ifr)) { + perror("qconfig ioctl"); + } else { + memcpy((t_u8 *)&queue_config_cmd, + buffer + cmd_header_len, + sizeof(queue_config_cmd)); + printf("qconfig %s(%d): MSDU Lifetime DEFAULT = 0x%04x (%d)\n", ac_str_tbl[ac_idx], ac_idx, queue_config_cmd.msduLifetimeExpiry, queue_config_cmd.msduLifetimeExpiry); + } + } + } else { + fprintf(stderr, + "Invalid qconfig command; s/b [set, get, default]\n"); + ret = -EINVAL; + goto done; + } + + ret = MLAN_STATUS_SUCCESS; +done: + if (buffer) + free(buffer); + if (cmd) + free(cmd); + return ret; +} + +/** + * @brief Send an ADDTS command to the associated AP + * + * Process a given conf file for a specific TSPEC data block. Send the + * TSPEC along with any other IEs to the driver/firmware for transmission + * in an ADDTS request to the associated AP. + * + * Return the execution status of the command as well as the ADDTS response + * from the AP if any. + * + * mlanutl mlanX addts + * + * @param argc number of arguments + * @param argv A pointer to arguments array + * + * @return MLAN_STATUS_SUCCESS--success, otherwise--fail + */ +static int +process_addts(int argc, char *argv[]) +{ + t_u8 *buffer = NULL; + struct eth_priv_cmd *cmd = NULL; + struct ifreq ifr; + wlan_ioctl_wmm_addts_req_t addtsReq; + FILE *fp = NULL; + char filename[48]; + char config_id[20]; + int cmd_header_len = 0, ret = 0, copy_len = 0; + + memset(&addtsReq, 0x00, sizeof(addtsReq)); + memset(filename, 0x00, sizeof(filename)); + + if (argc != 6) { + fprintf(stderr, "Invalid number of parameters!\n"); + ret = -EINVAL; + goto done; + } + + cmd_header_len = strlen(CMD_NXP) + strlen(argv[2]); + + buffer = (t_u8 *)malloc(BUFFER_LENGTH); + if (buffer == NULL) { + printf("Error: allocate memory for buffer failed\n"); + ret = -ENOMEM; + goto done; + } + memset(buffer, 0, BUFFER_LENGTH); + + cmd = (struct eth_priv_cmd *)malloc(sizeof(struct eth_priv_cmd)); + if (!cmd) { + printf("ERR:Cannot allocate buffer for command!\n"); + ret = MLAN_STATUS_FAILURE; + goto done; + } + + /* Fill up buffer */ +#ifdef USERSPACE_32BIT_OVER_KERNEL_64BIT + memset(cmd, 0, sizeof(struct eth_priv_cmd)); + memcpy(&cmd->buf, &buffer, sizeof(buffer)); +#else + cmd->buf = buffer; +#endif + cmd->used_len = 0; + cmd->total_len = BUFFER_LENGTH; + /* buf = MRVL_CMD */ + prepare_buffer(buffer, argv[2], 0, NULL); + + strncpy(filename, argv[3], sizeof(filename) - 1); + + fp = fopen(filename, "r"); + if (fp == NULL) { + perror("fopen"); + fprintf(stderr, "Cannot open file %s\n", argv[3]); + ret = -EFAULT; + goto done; + } + + snprintf(config_id, sizeof(config_id), "tspec%d", atoi(argv[4])); + + addtsReq.ieDataLen = fparse_for_cmd_and_hex(fp, + addtsReq.ieData, + (t_u8 *)config_id); + + if (addtsReq.ieDataLen > 0) { + printf("Found %d bytes in the %s section of conf file %s\n", + (int)addtsReq.ieDataLen, config_id, filename); + } else { + fprintf(stderr, "section %s not found in %s\n", + config_id, filename); + ret = -EFAULT; + goto done; + } + + addtsReq.timeout_ms = atoi(argv[5]); + + printf("Cmd Input:\n"); + hexdump(config_id, addtsReq.ieData, addtsReq.ieDataLen, ' '); + copy_len = sizeof(addtsReq); + memcpy(buffer + cmd_header_len, (t_u8 *)&addtsReq, copy_len); + + /* Initialize the ifr structure */ + memset(&ifr, 0, sizeof(ifr)); + strncpy(ifr.ifr_ifrn.ifrn_name, dev_name, strlen(dev_name)); + ifr.ifr_ifru.ifru_data = (void *)cmd; + + if (ioctl(sockfd, MLAN_ETH_PRIV, &ifr)) { + perror("mlanutl: addts ioctl"); + ret = -EFAULT; + goto done; + } + + memcpy(&addtsReq, buffer, strlen((const char *)buffer)); + printf("Cmd Output:\n"); + printf("ADDTS Command Result = %d\n", addtsReq.commandResult); + printf("ADDTS IEEE Status = %d\n", addtsReq.ieeeStatusCode); + hexdump(config_id, addtsReq.ieData, addtsReq.ieDataLen, ' '); + +done: + if (fp) + fclose(fp); + + if (buffer) + free(buffer); + if (cmd) + free(cmd); + return ret; +} + +/** + * @brief Send a DELTS command to the associated AP + * + * Process a given conf file for a specific TSPEC data block. Send the + * TSPEC along with any other IEs to the driver/firmware for transmission + * in a DELTS request to the associated AP. + * + * Return the execution status of the command. There is no response to a + * DELTS from the AP. + * + * mlanutl mlanX delts + * + * @param argc number of arguments + * @param argv A pointer to arguments array + * + * @return MLAN_STATUS_SUCCESS--success, otherwise--fail + */ +static int +process_delts(int argc, char *argv[]) +{ + t_u8 *buffer = NULL; + struct eth_priv_cmd *cmd = NULL; + struct ifreq ifr; + wlan_ioctl_wmm_delts_req_t deltsReq; + FILE *fp = NULL; + char filename[48]; + char config_id[20]; + int cmd_header_len = 0, ret = 0, copy_len = 0; + + memset(&deltsReq, 0x00, sizeof(deltsReq)); + memset(filename, 0x00, sizeof(filename)); + + if (argc != 5) { + fprintf(stderr, "Invalid number of parameters!\n"); + ret = -EINVAL; + goto done; + } + + cmd_header_len = strlen(CMD_NXP) + strlen(argv[2]); + + buffer = (t_u8 *)malloc(BUFFER_LENGTH); + if (buffer == NULL) { + printf("Error: allocate memory for buffer failed\n"); + ret = -ENOMEM; + goto done; + } + memset(buffer, 0, BUFFER_LENGTH); + + cmd = (struct eth_priv_cmd *)malloc(sizeof(struct eth_priv_cmd)); + if (!cmd) { + printf("ERR:Cannot allocate buffer for command!\n"); + ret = MLAN_STATUS_FAILURE; + goto done; + } + + /* Fill up buffer */ +#ifdef USERSPACE_32BIT_OVER_KERNEL_64BIT + memset(cmd, 0, sizeof(struct eth_priv_cmd)); + memcpy(&cmd->buf, &buffer, sizeof(buffer)); +#else + cmd->buf = buffer; +#endif + cmd->used_len = 0; + cmd->total_len = BUFFER_LENGTH; + /* buf = MRVL_CMD */ + prepare_buffer(buffer, argv[2], 0, NULL); + + strncpy(filename, argv[3], sizeof(filename) - 1); + fp = fopen(filename, "r"); + if (fp == NULL) { + perror("fopen"); + fprintf(stderr, "Cannot open file %s\n", argv[3]); + ret = -EFAULT;; + goto done; + } + + snprintf(config_id, sizeof(config_id), "tspec%d", atoi(argv[4])); + + deltsReq.ieDataLen = fparse_for_cmd_and_hex(fp, + deltsReq.ieData, + (t_u8 *)config_id); + + if (deltsReq.ieDataLen > 0) { + printf("Found %d bytes in the %s section of conf file %s\n", + (int)deltsReq.ieDataLen, config_id, filename); + } else { + fprintf(stderr, "section %s not found in %s\n", + config_id, filename); + ret = -EFAULT; + goto done; + } + + printf("Cmd Input:\n"); + hexdump(config_id, deltsReq.ieData, deltsReq.ieDataLen, ' '); + + copy_len = + sizeof(deltsReq) - sizeof(deltsReq.ieData) + deltsReq.ieDataLen; + memcpy(buffer + cmd_header_len, (t_u8 *)&deltsReq, copy_len); + + /* Initialize the ifr structure */ + memset(&ifr, 0, sizeof(ifr)); + strncpy(ifr.ifr_ifrn.ifrn_name, dev_name, strlen(dev_name)); + ifr.ifr_ifru.ifru_data = (void *)cmd; + if (ioctl(sockfd, MLAN_ETH_PRIV, &ifr)) { + perror("delts ioctl"); + ret = -EFAULT; + goto done; + } + + memcpy(&deltsReq, buffer, strlen((const char *)buffer)); + printf("Cmd Output:\n"); + printf("DELTS Command Result = %d\n", deltsReq.commandResult); + +done: + if (fp) + fclose(fp); + + if (buffer) + free(buffer); + if (cmd) + free(cmd); + return ret; +} + +/** + * @brief Get the current status of the WMM Queues + * + * Command: mlanutl mlanX qstatus + * + * Retrieve the following information for each AC if wmm is enabled: + * - WMM IE ACM Required + * - Firmware Flow Required + * - Firmware Flow Established + * - Firmware Queue Enabled + * + * @param argc number of arguments + * @param argv A pointer to arguments array + * + * @return MLAN_STATUS_SUCCESS--success, otherwise--fail + */ +static int +process_wmm_qstatus(int argc, char *argv[]) +{ + t_u8 *buffer = NULL; + struct eth_priv_cmd *cmd = NULL; + struct ifreq ifr; + wlan_ioctl_wmm_queue_status_t qstatus; + int ret = 0; + mlan_wmm_ac_e acVal; + + if (argc != 3) { + fprintf(stderr, "Invalid number of parameters!\n"); + ret = -EINVAL; + goto done; + } + + memset(&qstatus, 0x00, sizeof(qstatus)); + + buffer = (t_u8 *)malloc(BUFFER_LENGTH); + if (buffer == NULL) { + printf("Error: allocate memory for qconfig failed\n"); + ret = -ENOMEM; + goto done; + } + memset(buffer, 0, BUFFER_LENGTH); + + cmd = (struct eth_priv_cmd *)malloc(sizeof(struct eth_priv_cmd)); + if (!cmd) { + printf("ERR:Cannot allocate buffer for command!\n"); + ret = MLAN_STATUS_FAILURE; + goto done; + } + + /* Fill up buffer */ +#ifdef USERSPACE_32BIT_OVER_KERNEL_64BIT + memset(cmd, 0, sizeof(struct eth_priv_cmd)); + memcpy(&cmd->buf, &buffer, sizeof(buffer)); +#else + cmd->buf = buffer; +#endif + cmd->used_len = 0; + cmd->total_len = BUFFER_LENGTH; + /* buf = MRVL_CMD */ + prepare_buffer(buffer, argv[2], 0, NULL); + + /* Initialize the ifr structure */ + memset(&ifr, 0, sizeof(ifr)); + strncpy(ifr.ifr_ifrn.ifrn_name, dev_name, strlen(dev_name)); + ifr.ifr_ifru.ifru_data = (void *)cmd; + + if (ioctl(sockfd, MLAN_ETH_PRIV, &ifr)) { + perror("qstatus ioctl"); + ret = -EFAULT; + goto done; + } + + memcpy(&qstatus, buffer, strlen((const char *)buffer)); + for (acVal = WMM_AC_BK; acVal <= WMM_AC_VO; acVal++) { + switch (acVal) { + case WMM_AC_BK: + printf("BK: "); + break; + case WMM_AC_BE: + printf("BE: "); + break; + case WMM_AC_VI: + printf("VI: "); + break; + case WMM_AC_VO: + printf("VO: "); + break; + default: + printf("??: "); + } + + printf("ACM[%c], FlowReq[%c], FlowCreated[%c], Enabled[%c]," + " DE[%c], TE[%c]\n", + (qstatus.acStatus[acVal].wmmAcm ? 'X' : ' '), + (qstatus.acStatus[acVal].flowRequired ? 'X' : ' '), + (qstatus.acStatus[acVal].flowCreated ? 'X' : ' '), + (qstatus.acStatus[acVal].disabled ? ' ' : 'X'), + (qstatus.acStatus[acVal].deliveryEnabled ? 'X' : ' '), + (qstatus.acStatus[acVal].triggerEnabled ? 'X' : ' ')); + } + +done: + + if (buffer) + free(buffer); + if (cmd) + free(cmd); + return ret; +} + +/** + * @brief Get the current status of the WMM Traffic Streams + * + * Command: mlanutl mlanX ts_status + * + * @param argc number of arguments + * @param argv A pointer to arguments array + * + * @return MLAN_STATUS_SUCCESS--success, otherwise--fail + */ +static int +process_wmm_ts_status(int argc, char *argv[]) +{ + t_u8 *buffer = NULL; + struct eth_priv_cmd *cmd = NULL; + struct ifreq ifr; + wlan_ioctl_wmm_ts_status_t ts_status; + int tid; + int cmd_header_len = 0, ret = 0; + + const char *ac_str_tbl[] = { "BK", "BE", "VI", "VO" }; + + if (argc != 3) { + fprintf(stderr, "Invalid number of parameters!\n"); + ret = -EINVAL; + goto done; + } + + cmd_header_len = strlen(CMD_NXP) + strlen(argv[2]); + + buffer = (t_u8 *)malloc(BUFFER_LENGTH); + if (buffer == NULL) { + printf("Error: allocate memory for qconfig failed\n"); + ret = -ENOMEM; + goto done; + } + memset(buffer, 0, BUFFER_LENGTH); + + cmd = (struct eth_priv_cmd *)malloc(sizeof(struct eth_priv_cmd)); + if (!cmd) { + printf("ERR:Cannot allocate buffer for command!\n"); + ret = MLAN_STATUS_FAILURE; + goto done; + } + + /* Fill up buffer */ +#ifdef USERSPACE_32BIT_OVER_KERNEL_64BIT + memset(cmd, 0, sizeof(struct eth_priv_cmd)); + memcpy(&cmd->buf, &buffer, sizeof(buffer)); +#else + cmd->buf = buffer; +#endif + cmd->used_len = 0; + cmd->total_len = BUFFER_LENGTH; + /* buf = MRVL_CMD */ + + printf("\nTID Valid AC UP PSB FlowDir MediumTime\n"); + printf("---------------------------------------------------\n"); + + for (tid = 0; tid <= 7; tid++) { + memset(buffer, 0, BUFFER_LENGTH); + prepare_buffer(buffer, argv[2], 0, NULL); + memset(&ts_status, 0x00, sizeof(ts_status)); + ts_status.tid = tid; + + /* Initialize the ifr structure */ + memset(&ifr, 0, sizeof(ifr)); + strncpy(ifr.ifr_ifrn.ifrn_name, dev_name, strlen(dev_name)); + ifr.ifr_ifru.ifru_data = (void *)cmd; + + memcpy(buffer + cmd_header_len, (t_u8 *)&ts_status, + sizeof(ts_status)); + + if (ioctl(sockfd, MLAN_ETH_PRIV, &ifr)) { + perror("ts_status ioctl"); + ret = -EFAULT; + goto done; + } + + memcpy(&ts_status, buffer, strlen((const char *)buffer)); + printf(" %02d %3s %2s %u %c ", + ts_status.tid, + (ts_status.valid ? "Yes" : "No"), + (ts_status. + valid ? ac_str_tbl[ts_status.accessCategory] : "--"), + ts_status.userPriority, (ts_status.psb ? 'U' : 'L')); + + if ((ts_status.flowDir & 0x03) == 0) { + printf("%s", " ---- "); + } else { + printf("%2s%4s", + (ts_status.flowDir & 0x01 ? "Up" : ""), + (ts_status.flowDir & 0x02 ? "Down" : "")); + } + + printf("%12u\n", ts_status.mediumTime); + } + printf("\n"); + +done: + + if (buffer) + free(buffer); + if (cmd) + free(cmd); + return ret; +} + +/** + * @brief Set/get WMM IE QoS info parameter + * + * @param argc number of arguments + * @param argv A pointer to arguments array + * + * @return MLAN_STATUS_SUCCESS--success, otherwise--fail + */ +static int +process_qos_config(int argc, char *argv[]) +{ + t_u8 *buffer = NULL; + struct eth_priv_cmd *cmd = NULL; + struct ifreq ifr; + + /* Initialize buffer */ + buffer = (t_u8 *)malloc(BUFFER_LENGTH); + if (!buffer) { + printf("ERR:Cannot allocate buffer for command!\n"); + return MLAN_STATUS_FAILURE; + } + + /* Sanity tests */ + if (argc < 3 || argc > 4) { + printf("Insufficient parameters\n"); + printf("mlanutl mlanX qoscfg [QoS]\n"); + free(buffer); + return MLAN_STATUS_FAILURE; + } + + prepare_buffer(buffer, argv[2], (argc - 3), &argv[3]); + + cmd = (struct eth_priv_cmd *)malloc(sizeof(struct eth_priv_cmd)); + if (!cmd) { + printf("ERR:Cannot allocate buffer for command!\n"); + free(buffer); + return MLAN_STATUS_FAILURE; + } + + /* Fill up buffer */ +#ifdef USERSPACE_32BIT_OVER_KERNEL_64BIT + memset(cmd, 0, sizeof(struct eth_priv_cmd)); + memcpy(&cmd->buf, &buffer, sizeof(buffer)); +#else + cmd->buf = buffer; +#endif + cmd->used_len = 0; + cmd->total_len = BUFFER_LENGTH; + + /* Perform IOCTL */ + memset(&ifr, 0, sizeof(struct ifreq)); + strncpy(ifr.ifr_ifrn.ifrn_name, dev_name, strlen(dev_name)); + ifr.ifr_ifru.ifru_data = (void *)cmd; + + if (ioctl(sockfd, MLAN_ETH_PRIV, &ifr)) { + perror("mlanutl"); + fprintf(stderr, "mlanutl: qoscfg fail\n"); + if (cmd) + free(cmd); + if (buffer) + free(buffer); + return MLAN_STATUS_FAILURE; + } + + /* Process result */ + if (argc == 3) { + /* GET operation */ + printf("WMM QoS Info: %#x\n", *buffer); + } + + if (buffer) + free(buffer); + if (cmd) + free(cmd); + + return MLAN_STATUS_SUCCESS; +} + +/** + * @brief Set/get MAC control configuration + * + * @param argc Number of arguments + * @param argv A pointer to arguments array + * @return MLAN_STATUS_SUCCESS--success, otherwise--fail + */ + +static int +process_macctrl(int argc, char *argv[]) +{ + t_u8 *buffer = NULL; + struct eth_priv_cmd *cmd = NULL; + struct ifreq ifr; + t_u32 mac_ctrl = 0; + + /* Initialize buffer */ + buffer = (t_u8 *)malloc(BUFFER_LENGTH); + if (!buffer) { + printf("ERR:Cannot allocate buffer for command!\n"); + return MLAN_STATUS_FAILURE; + } + + /* Sanity tests */ + if (argc < 3 || argc > 4) { + printf("Insufficient parameters\n"); + printf("mlanutl mlanX macctrl [macctrl]\n"); + free(buffer); + return MLAN_STATUS_FAILURE; + } + + prepare_buffer(buffer, argv[2], (argc - 3), &argv[3]); + + cmd = (struct eth_priv_cmd *)malloc(sizeof(struct eth_priv_cmd)); + if (!cmd) { + printf("ERR:Cannot allocate buffer for command!\n"); + free(buffer); + return MLAN_STATUS_FAILURE; + } + + /* Fill up buffer */ +#ifdef USERSPACE_32BIT_OVER_KERNEL_64BIT + memset(cmd, 0, sizeof(struct eth_priv_cmd)); + memcpy(&cmd->buf, &buffer, sizeof(buffer)); +#else + cmd->buf = buffer; +#endif + cmd->used_len = 0; + cmd->total_len = BUFFER_LENGTH; + + /* Perform IOCTL */ + memset(&ifr, 0, sizeof(struct ifreq)); + strncpy(ifr.ifr_ifrn.ifrn_name, dev_name, strlen(dev_name)); + ifr.ifr_ifru.ifru_data = (void *)cmd; + + if (ioctl(sockfd, MLAN_ETH_PRIV, &ifr)) { + perror("mlanutl"); + fprintf(stderr, "mlanutl: macctrl fail\n"); + if (cmd) + free(cmd); + if (buffer) + free(buffer); + return MLAN_STATUS_FAILURE; + } + + /* Process result */ + mac_ctrl = *(t_u32 *)buffer; + if (argc == 3) { + /* GET operation */ + printf("MAC Control: 0x%08x\n", mac_ctrl); + } + + if (buffer) + free(buffer); + if (cmd) + free(cmd); + + return MLAN_STATUS_SUCCESS; +} + +/** + * @brief Process generic commands + * @param argc Number of arguments + * @param argv A pointer to arguments array + * @return MLAN_STATUS_SUCCESS--success, otherwise--fail + */ +static int +process_generic(int argc, char *argv[]) +{ + t_u8 *buffer = NULL; + struct eth_priv_cmd *cmd = NULL; + struct ifreq ifr; + + /* Initialize buffer */ + buffer = (t_u8 *)malloc(BUFFER_LENGTH); + if (!buffer) { + printf("ERR:Cannot allocate buffer for command!\n"); + return MLAN_STATUS_FAILURE; + } + + prepare_buffer(buffer, argv[2], 0, NULL); + + cmd = (struct eth_priv_cmd *)malloc(sizeof(struct eth_priv_cmd)); + if (!cmd) { + printf("ERR:Cannot allocate buffer for command!\n"); + free(buffer); + return MLAN_STATUS_FAILURE; + } + + /* Fill up buffer */ +#ifdef USERSPACE_32BIT_OVER_KERNEL_64BIT + memset(cmd, 0, sizeof(struct eth_priv_cmd)); + memcpy(&cmd->buf, &buffer, sizeof(buffer)); +#else + cmd->buf = buffer; +#endif + cmd->used_len = 0; + cmd->total_len = BUFFER_LENGTH; + + /* Perform IOCTL */ + memset(&ifr, 0, sizeof(struct ifreq)); + strncpy(ifr.ifr_ifrn.ifrn_name, dev_name, strlen(dev_name)); + ifr.ifr_ifru.ifru_data = (void *)cmd; + + if ((ioctl(sockfd, MLAN_ETH_PRIV, &ifr)) < 0) { + perror("mlanutl"); + fprintf(stderr, "mlanutl: %s fail\n", argv[2]); + if (cmd) + free(cmd); + if (buffer) + free(buffer); + return MLAN_STATUS_FAILURE; + } + + /* Process result */ + if (argc == 3) { + /* GET operation */ + printf("%s command response received: %s\n", argv[2], buffer); + } + + if (buffer) + free(buffer); + if (cmd) + free(cmd); + + return MLAN_STATUS_SUCCESS; +} + +/** + * @brief Set/Get mlanX FW side MAC address + * @param argc Number of arguments + * @param argv A pointer to arguments array + * @return MLAN_STATUS_SUCCESS--success, otherwise--fail + */ +static int +process_fwmacaddr(int argc, char *argv[]) +{ + t_u8 *buffer = NULL; + struct eth_priv_cmd *cmd = NULL; + struct ifreq ifr; + + /* Initialize buffer */ + buffer = (t_u8 *)malloc(BUFFER_LENGTH); + if (!buffer) { + printf("ERR:Cannot allocate buffer for command!\n"); + return MLAN_STATUS_FAILURE; + } + + /* Sanity tests */ + if (argc < 3 || argc > 4) { + printf("Insufficient parameters\n"); + printf("mlanutl mlanX fwmacaddr [fwmacaddr]\n"); + free(buffer); + return MLAN_STATUS_FAILURE; + } + + prepare_buffer(buffer, argv[2], (argc - 3), &argv[3]); + + cmd = (struct eth_priv_cmd *)malloc(sizeof(struct eth_priv_cmd)); + if (!cmd) { + printf("ERR:Cannot allocate buffer for command!\n"); + free(buffer); + return MLAN_STATUS_FAILURE; + } + + /* Fill up buffer */ +#ifdef USERSPACE_32BIT_OVER_KERNEL_64BIT + memset(cmd, 0, sizeof(struct eth_priv_cmd)); + memcpy(&cmd->buf, &buffer, sizeof(buffer)); +#else + cmd->buf = buffer; +#endif + cmd->used_len = 0; + cmd->total_len = BUFFER_LENGTH; + + /* Perform IOCTL */ + memset(&ifr, 0, sizeof(struct ifreq)); + strncpy(ifr.ifr_ifrn.ifrn_name, dev_name, strlen(dev_name)); + ifr.ifr_ifru.ifru_data = (void *)cmd; + + if (ioctl(sockfd, MLAN_ETH_PRIV, &ifr)) { + perror("mlanutl"); + fprintf(stderr, "mlanutl: fwmacaddr fail\n"); + if (cmd) + free(cmd); + if (buffer) + free(buffer); + return MLAN_STATUS_FAILURE; + } + + /* Process result */ + if (argc == 3) { + /* GET operation */ + printf("FW MAC address = "); + print_mac(buffer); + printf("\n"); + } + + if (buffer) + free(buffer); + if (cmd) + free(cmd); + + return MLAN_STATUS_SUCCESS; +} + +#ifdef RX_PACKET_COALESCE +static void +print_rx_packet_coalesc_help() +{ + printf("\nUSAGE: rxpktcoal_cfg [PKT-THRESHOLD] [TIMEOUT]\n\n"); + printf("OPTIONS:"); + printf("PKT-THRESHOLD: count after which packets would be sent to host. Valid values 1-7\n"); + printf("\tTIMEOUT: Time after which packets would be sent to host Valid values 1-4\n"); + printf("\tCoalescing is disabled if both or either of PKT-THRESHOLD or TIMEOUT is zero\n\n"); + printf("\tEmpty - Get current packet coalescing settings\n"); +} + +static int +process_rx_pkt_coalesce_cfg(int argc, char *argv[]) +{ + + t_u8 *buffer = NULL; + struct eth_priv_cmd *cmd = NULL; + struct ifreq ifr; + tlvbuf_rx_pkt_coal_t *rx_pkt_info; + int ret = MLAN_STATUS_SUCCESS; + + if ((argc != 3) && (argc != 5)) { + printf("ERR:Invalid no. of arguments\n"); + print_rx_packet_coalesc_help(); + return MLAN_STATUS_FAILURE; + } + + buffer = (t_u8 *)malloc(BUFFER_LENGTH); + if (!buffer) { + printf("ERR:Cannot allocate buffer for command!\n"); + return MLAN_STATUS_FAILURE; + } + + cmd = (struct eth_priv_cmd *)malloc(sizeof(struct eth_priv_cmd)); + if (!cmd) { + printf("ERR:Cannot allocate buffer for command!\n"); + free(buffer); + return MLAN_STATUS_FAILURE; + } + + /* Fill up buffer */ +#ifdef USERSPACE_32BIT_OVER_KERNEL_64BIT + memset(cmd, 0, sizeof(struct eth_priv_cmd)); + memcpy(&cmd->buf, &buffer, sizeof(buffer)); +#else + cmd->buf = buffer; +#endif + cmd->used_len = 0; + cmd->total_len = BUFFER_LENGTH; + prepare_buffer(buffer, argv[2], (argc - 3), &argv[3]); + + /* Perform IOCTL */ + memset(&ifr, 0, sizeof(struct ifreq)); + strncpy(ifr.ifr_ifrn.ifrn_name, dev_name, strlen(dev_name)); + ifr.ifr_ifru.ifru_data = (void *)cmd; + + if ((ioctl(sockfd, MLAN_ETH_PRIV, &ifr)) < 0) { + perror("mlanutl"); + fprintf(stderr, "mlanutl: %s fail\n", argv[2]); + ret = MLAN_STATUS_FAILURE; + goto done; + } + + if (argc == 3) { /* GET operation */ + rx_pkt_info = (tlvbuf_rx_pkt_coal_t *)(buffer); + printf("RX packet coalesce configuraion:\n"); + printf("Packet threshold=%d\n", rx_pkt_info->rx_pkt_count); + printf("Timeout=%dms\n", rx_pkt_info->delay); + } else { + printf("RX packet coalesce configuration set successfully.\n"); + } + +done: + if (buffer) + free(buffer); + if (cmd) + free(cmd); + + return ret; + +} +#endif + +/** + * @brief Process regioncode configuration + * @param argc number of arguments + * @param argv A pointer to arguments array + * @return MLAN_STATUS_SUCCESS--success, otherwise--fail + */ +static int +process_regioncode(int argc, char *argv[]) +{ + t_u8 *buffer = NULL; + struct eth_priv_cmd *cmd = NULL; + struct ifreq ifr; + t_u32 regioncode; + + /* Initialize buffer */ + buffer = (t_u8 *)malloc(BUFFER_LENGTH); + if (!buffer) { + printf("ERR:Cannot allocate buffer for command!\n"); + return MLAN_STATUS_FAILURE; + } + + prepare_buffer(buffer, argv[2], (argc - 3), &argv[3]); + + cmd = (struct eth_priv_cmd *)malloc(sizeof(struct eth_priv_cmd)); + if (!cmd) { + printf("ERR:Cannot allocate buffer for command!\n"); + free(buffer); + return MLAN_STATUS_FAILURE; + } + + /* Fill up buffer */ +#ifdef USERSPACE_32BIT_OVER_KERNEL_64BIT + memset(cmd, 0, sizeof(struct eth_priv_cmd)); + memcpy(&cmd->buf, &buffer, sizeof(buffer)); +#else + cmd->buf = buffer; +#endif + cmd->used_len = 0; + cmd->total_len = BUFFER_LENGTH; + + /* Perform IOCTL */ + memset(&ifr, 0, sizeof(struct ifreq)); + strncpy(ifr.ifr_ifrn.ifrn_name, dev_name, strlen(dev_name)); + ifr.ifr_ifru.ifru_data = (void *)cmd; + + if (ioctl(sockfd, MLAN_ETH_PRIV, &ifr)) { + perror("mlanutl"); + fprintf(stderr, "mlanutl: regioncode config fail\n"); + if (cmd) + free(cmd); + if (buffer) + free(buffer); + return MLAN_STATUS_FAILURE; + } + + /* Process result */ + if (argc == 3) { + memcpy(®ioncode, buffer, sizeof(regioncode)); + printf("regioncode: %d\n", regioncode); + } + + if (buffer) + free(buffer); + if (cmd) + free(cmd); + + return MLAN_STATUS_SUCCESS; +} + +/** + * @brief Process cfpinfo get command + * @param argc Number of arguments + * @param argv Pointer to arguments array + * @return MLAN_STATUS_SUCCESS--success, otherwise--fail + */ +static int +process_cfpinfo(int argc, char *argv[]) +{ + t_u8 *data, *buffer = NULL; + struct eth_priv_cmd *cmd = NULL; + struct ifreq ifr; + t_u32 i, size = 0; + t_u32 j; + t_u32 rows, cols; + struct chan_freq_power { + t_u16 channel; + t_u32 freq; + t_u16 max_tx_power; + t_u8 passive_scan_or_radar_detect; + t_u16 flags; + t_u8 blacklist; + } *cfp; + + /* Initialize buffer */ + buffer = (t_u8 *)malloc(BUFFER_LENGTH); + if (!buffer) { + printf("ERR:Cannot allocate buffer for command!\n"); + return MLAN_STATUS_FAILURE; + } + + prepare_buffer(buffer, argv[2], (argc - 3), &argv[3]); + + cmd = (struct eth_priv_cmd *)malloc(sizeof(struct eth_priv_cmd)); + if (!cmd) { + printf("ERR:Cannot allocate buffer for command!\n"); + free(buffer); + return MLAN_STATUS_FAILURE; + } + + /* Fill up buffer */ +#ifdef USERSPACE_32BIT_OVER_KERNEL_64BIT + memset(cmd, 0, sizeof(struct eth_priv_cmd)); + memcpy(&cmd->buf, &buffer, sizeof(buffer)); +#else + cmd->buf = buffer; +#endif + cmd->used_len = 0; + cmd->total_len = BUFFER_LENGTH; + + /* Perform IOCTL */ + memset(&ifr, 0, sizeof(struct ifreq)); + strncpy(ifr.ifr_ifrn.ifrn_name, dev_name, strlen(dev_name)); + ifr.ifr_ifru.ifru_data = (void *)cmd; + + if (ioctl(sockfd, MLAN_ETH_PRIV, &ifr)) { + perror("mlanutl"); + fprintf(stderr, "mlanutl: cfpinfo cmd failed\n"); + if (cmd) + free(cmd); + if (buffer) + free(buffer); + return MLAN_STATUS_FAILURE; + } + + /* Process result */ + data = buffer; + size = *(t_u32 *)data; + if (!size) + goto out; + + /* Region code is stored in first 2 bytes, country code in next 3 bytes + * and environment, if available, in the following byte + */ + data += sizeof(size); + printf("Region Code : 0x%x\n", *(t_u16 *)data); + data += 2; + printf("Country Code : %c%c\n", *data, *(data + 1)); + data += 3; + if (size == 6) { + printf("Environment : 0x%x\n", *data); + data++; + } + /* Print cfp tables */ + size = *(t_u32 *)data; + if (!size) + goto out; + + data += sizeof(size); + printf("\n2.4GHz Channels:\n"); + printf("%8s%10s%6s%11s%16s%16s%17s\n", "Channel", "isPassive", + "isDFS", + "isDisabled", "is40MHzDisabled", + "is80MHzDisabled", "is160MHzDisabled"); + i = 0; + while (i < size) { + if (!(*data)) + goto out; + cfp = (struct chan_freq_power *)data; + printf("%8u%10u%6u%11u%16u%16c%17c\n", + cfp->channel, + (cfp->flags & NXP_CHANNEL_PASSIVE) ? 1 : 0, + cfp->passive_scan_or_radar_detect, + (cfp->flags & NXP_CHANNEL_DISABLED) ? 1 : 0, + (cfp->flags & NXP_CHANNEL_NOHT40) ? 1 : 0, '-', '-'); + data += sizeof(struct chan_freq_power); + i += sizeof(struct chan_freq_power); + } + size = *(t_u32 *)data; + if (!size) + goto out; + + data += sizeof(size); + + printf("\n5GHz Channels:\n"); + printf("%8s%10s%6s%11s%16s%16s%17s\n", "Channel", "isPassive", + "isDFS", + "isDisabled", "is40MHzDisabled", + "is80MHzDisabled", "is160MHzDisabled"); + i = 0; + while (i < size) { + if (!(*data)) + goto out; + cfp = (struct chan_freq_power *)data; + printf("%8u%10u%6u%11u%16u%16u%17c\n", + cfp->channel, + (cfp->flags & NXP_CHANNEL_PASSIVE) ? 1 : 0, + cfp->passive_scan_or_radar_detect, + (cfp->flags & NXP_CHANNEL_DISABLED) ? 1 : 0, + (cfp->flags & NXP_CHANNEL_NOHT40) ? 1 : 0, + (cfp->flags & NXP_CHANNEL_NOHT80) ? 1 : 0, '-'); + data += sizeof(struct chan_freq_power); + i += sizeof(struct chan_freq_power); + } + + /* Print power tables */ + size = *(t_u32 *)data; + if (!size) + goto out; + + data += sizeof(size); + rows = *(t_u32 *)data; + data += sizeof(size); + cols = *(t_u32 *)data; + data += sizeof(size); + if (!rows || !cols) + goto out; + + printf("\n2.4GHz Power Table:\n"); + printf("%8s ", "Channel"); + for (i = 0; i < cols - 1; i++) + printf(" m%02d", i); + + for (i = 0; i < rows; i++) { + printf("\n%8u ", *data++); + for (j = 1; j < cols; j++) + printf("%3u ", *data++); + } + printf("\n"); + size = *(t_u32 *)data; + if (!size) + goto out; + + data += sizeof(size); + rows = *(t_u32 *)data; + data += sizeof(size); + cols = *(t_u32 *)data; + data += sizeof(size); + if (!rows || !cols) + goto out; + + printf("\n5GHz Power Table:\n"); + printf("%8s ", "Channel"); + for (i = 0; i < cols - 1; i++) + printf(" m%02d", i); + + for (i = 0; i < rows; i++) { + printf("\n%8u ", *data++); + for (j = 1; j < cols; j++) + printf("%3u ", *data++); + } + /* Print Modulation Conversion Information */ + printf("\n\nModulation Conversions:\n"); + j = 0; + for (i = 0; i < 10; i++) + printf("m%02d: %s\n", j++, mod_conv_bg_1x1[i]); + for (i = 0; i < 6; i++) + printf("m%02d: %s\n", j++, mod_conv_bg_2x2[i]); + if (j >= cols - 1) + goto out; + for (i = 0; i < 6; i++) + printf("m%02d: %s\n", j++, mod_conv_a_1x1[i]); + for (i = 0; i < 6; i++) + printf("m%02d: %s\n", j++, mod_conv_a_2x2[i]); +out: + printf("\n"); + if (buffer) + free(buffer); + if (cmd) + free(cmd); + + return MLAN_STATUS_SUCCESS; +} + +/** + * @brief Process offchannel configuration + * @param argc number of arguments + * @param argv A pointer to arguments array + * @return MLAN_STATUS_SUCCESS--success, otherwise--fail + */ +static int +process_offchannel(int argc, char *argv[]) +{ + t_u8 *buffer = NULL; + struct eth_priv_cmd *cmd = NULL; + struct ifreq ifr; + + /* Initialize buffer */ + buffer = (t_u8 *)malloc(BUFFER_LENGTH); + if (!buffer) { + printf("ERR:Cannot allocate buffer for command!\n"); + return MLAN_STATUS_FAILURE; + } + + /* Sanity tests */ + if (argc < 3 || argc > 7) { + printf("Incorrect number of parameters\n"); + printf("mlanutl mlanX offchannel [ ]\n"); + free(buffer); + return MLAN_STATUS_FAILURE; + } + + prepare_buffer(buffer, argv[2], (argc - 3), &argv[3]); + + cmd = (struct eth_priv_cmd *)malloc(sizeof(struct eth_priv_cmd)); + if (!cmd) { + printf("ERR:Cannot allocate buffer for command!\n"); + free(buffer); + return MLAN_STATUS_FAILURE; + } + + /* Fill up buffer */ +#ifdef USERSPACE_32BIT_OVER_KERNEL_64BIT + memset(cmd, 0, sizeof(struct eth_priv_cmd)); + memcpy(&cmd->buf, &buffer, sizeof(buffer)); +#else + cmd->buf = buffer; +#endif + cmd->used_len = 0; + cmd->total_len = BUFFER_LENGTH; + + /* Perform IOCTL */ + memset(&ifr, 0, sizeof(struct ifreq)); + strncpy(ifr.ifr_ifrn.ifrn_name, dev_name, strlen(dev_name)); + ifr.ifr_ifru.ifru_data = (void *)cmd; + + if (ioctl(sockfd, MLAN_ETH_PRIV, &ifr)) { + perror("mlanutl"); + fprintf(stderr, "mlanutl: offchannel config fail\n"); + if (cmd) + free(cmd); + if (buffer) + free(buffer); + return MLAN_STATUS_FAILURE; + } + + /* Process result */ + printf("%s\n", buffer); + if (buffer) + free(buffer); + if (cmd) + free(cmd); + + return MLAN_STATUS_SUCCESS; +} + +/** + * @brief Process link statistics + * @param argc Number of arguments + * @param argv A pointer to arguments array + * @return MLAN_STATUS_SUCCESS--success, otherwise--fail + */ +static int +process_linkstats(int argc, char *argv[]) +{ + int ret = MLAN_STATUS_SUCCESS; + t_u8 *buffer = NULL; + t_u8 *data = NULL; + HostCmd_DS_GEN *hostcmd = NULL; + t_u32 cmd_len = 0; + struct eth_priv_cmd *cmd = NULL; + struct ifreq ifr; + + /* Initialize buffer */ + buffer = (t_u8 *)malloc(BUFFER_LENGTH); + if (!buffer) { + printf("ERR:Cannot allocate buffer for command!\n"); + return MLAN_STATUS_FAILURE; + } + + /* prepare the host cmd */ + data = buffer; + prepare_buffer(buffer, HOSTCMD, 0, NULL); + data += strlen(CMD_NXP) + strlen(HOSTCMD); + /* add buffer size field */ + cmd_len = + sizeof(HostCmd_DS_GEN) + sizeof(HostCmd_DS_LINK_STATS_SUMMARY); + cmd_len = cpu_to_le32(cmd_len); + memcpy(data, &cmd_len, sizeof(t_u32)); + data += sizeof(t_u32); + /* add cmd header */ + hostcmd = (HostCmd_DS_GEN *)data; + hostcmd->command = cpu_to_le16(HostCmd_CMD_LINK_STATS_SUMMARY); + hostcmd->size = cpu_to_le16(sizeof(HostCmd_DS_GEN)); + hostcmd->seq_num = 0; + hostcmd->result = 0; + + cmd = (struct eth_priv_cmd *)malloc(sizeof(struct eth_priv_cmd)); + if (!cmd) { + printf("ERR:Cannot allocate buffer for command!\n"); + free(buffer); + return MLAN_STATUS_FAILURE; + } + + /* Fill up buffer */ +#ifdef USERSPACE_32BIT_OVER_KERNEL_64BIT + memset(cmd, 0, sizeof(struct eth_priv_cmd)); + memcpy(&cmd->buf, &buffer, sizeof(buffer)); +#else + cmd->buf = buffer; +#endif + cmd->used_len = 0; + cmd->total_len = BUFFER_LENGTH; + + /* Perform IOCTL */ + memset(&ifr, 0, sizeof(struct ifreq)); + strncpy(ifr.ifr_ifrn.ifrn_name, dev_name, strlen(dev_name)); + ifr.ifr_ifru.ifru_data = (void *)cmd; + + if (ioctl(sockfd, MLAN_ETH_PRIV, &ifr)) { + perror("mlanutl"); + fprintf(stderr, "mlanutl: linkstats fail\n"); + if (cmd) + free(cmd); + if (buffer) + free(buffer); + return MLAN_STATUS_FAILURE; + } + + /* Process result */ + ret = process_host_cmd_resp(HOSTCMD, buffer); + + if (buffer) + free(buffer); + if (cmd) + free(cmd); + + return ret; +} + +#if defined(STA_SUPPORT) +/** + * @brief Configure PMF parameters + * + * @param argc Number of arguments + * @param argv Pointer to the arguments array + * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_FAILURE + */ +static int +process_pmfcfg(int argc, char *argv[]) +{ + t_u8 *buffer = NULL; + struct eth_priv_cmd *cmd; + struct eth_priv_pmfcfg pmfcfg; + struct ifreq ifr; + + /* Check if arguments are valid */ + if ((argc > 5) || (argc == 4) || + ((argc == 5) && ((!atoi(argv[3])) && atoi(argv[4])))) { + printf("ERR: Invalid arguments\n"); + return MLAN_STATUS_FAILURE; + } + + /* Initialize buffer */ + buffer = (t_u8 *)malloc(BUFFER_LENGTH); + if (!buffer) { + printf("ERR:Cannot allocate buffer for command!\n"); + return MLAN_STATUS_FAILURE; + } + + prepare_buffer(buffer, argv[2], (argc - 3), &argv[3]); + + cmd = (struct eth_priv_cmd *)malloc(sizeof(struct eth_priv_cmd)); + if (!cmd) { + printf("ERR:Cannot allocate buffer for command!\n"); + free(buffer); + return MLAN_STATUS_FAILURE; + } + + /* Fill up buffer */ +#ifdef USERSPACE_32BIT_OVER_KERNEL_64BIT + memset(cmd, 0, sizeof(struct eth_priv_cmd)); + memcpy(&cmd->buf, &buffer, sizeof(buffer)); +#else + cmd->buf = buffer; +#endif + cmd->used_len = 0; + cmd->total_len = BUFFER_LENGTH; + + /* Perform IOCTL */ + memset(&ifr, 0, sizeof(struct ifreq)); + strncpy(ifr.ifr_ifrn.ifrn_name, dev_name, strlen(dev_name)); + ifr.ifr_ifru.ifru_data = (void *)cmd; + + if (ioctl(sockfd, MLAN_ETH_PRIV, &ifr)) { + perror("mlanutl"); + fprintf(stderr, "mlanutl: pmfcfg fail\n"); + if (cmd) + free(cmd); + if (buffer) + free(buffer); + return MLAN_STATUS_FAILURE; + } + + /* GET operation */ + if (argc == 3) { + memcpy(&pmfcfg, buffer, sizeof(struct eth_priv_pmfcfg)); + printf("Management Frame Protection Capability: %s\n", + (pmfcfg.mfpc ? "Yes" : "No")); + if (pmfcfg.mfpc) + printf("Management Frame Protection: %s\n", + (pmfcfg.mfpr ? "Required" : "Optional")); + } + + if (buffer) + free(buffer); + if (cmd) + free(cmd); + + return MLAN_STATUS_SUCCESS; +} +#endif + +/** + * @brief Process extended version + * @param argc Number of arguments + * @param argv A pointer to arguments array + * @return MLAN_STATUS_SUCCESS--success, otherwise--fail + */ +static int +process_verext(int argc, char *argv[]) +{ + int ret = 0; + t_u8 *buffer = NULL; + struct eth_priv_cmd *cmd = NULL; + struct ifreq ifr; + + /* Initialize buffer */ + buffer = (t_u8 *)malloc(BUFFER_LENGTH); + if (!buffer) { + printf("ERR:Cannot allocate buffer for command!\n"); + ret = MLAN_STATUS_FAILURE; + goto done; + } + memset(buffer, 0, BUFFER_LENGTH); + + /* Sanity tests */ + if (argc < 3 || argc > 4) { + printf("Error: invalid no of arguments\n"); + printf("mlanutl mlanX verext [#]\n"); + ret = MLAN_STATUS_FAILURE; + goto done; + } + + prepare_buffer(buffer, argv[2], (argc - 3), &argv[3]); + + cmd = (struct eth_priv_cmd *)malloc(sizeof(struct eth_priv_cmd)); + if (!cmd) { + printf("ERR:Cannot allocate buffer for command!\n"); + ret = MLAN_STATUS_FAILURE; + goto done; + } + + /* Fill up buffer */ +#ifdef USERSPACE_32BIT_OVER_KERNEL_64BIT + memset(cmd, 0, sizeof(struct eth_priv_cmd)); + memcpy(&cmd->buf, &buffer, sizeof(buffer)); +#else + cmd->buf = buffer; +#endif + cmd->used_len = 0; + cmd->total_len = BUFFER_LENGTH; + + /* Perform IOCTL */ + memset(&ifr, 0, sizeof(struct ifreq)); + strncpy(ifr.ifr_ifrn.ifrn_name, dev_name, strlen(dev_name)); + ifr.ifr_ifru.ifru_data = (void *)cmd; + + if (ioctl(sockfd, MLAN_ETH_PRIV, &ifr)) { + perror("mlanutl"); + fprintf(stderr, "mlanutl: verext fail\n"); + ret = MLAN_STATUS_FAILURE; + goto done; + } + + /* Process result */ + if (cmd->used_len) + printf("Extended Version string received: %s\n", buffer); + +done: + if (buffer) + free(buffer); + if (cmd) + free(cmd); + + return ret; +} + +/** + * @brief Makes USB device to suspend + * @param argc Number of arguments + * @param argv A pointer to arguments array + * @return MLAN_STATUS_SUCCESS--success, otherwise--fail + */ +static int +process_usb_suspend(int argc, char *argv[]) +{ + int ret = 0, status = 0; + t_u8 *buffer = NULL; + struct eth_priv_cmd *cmd = NULL; + struct ifreq ifr; + + /* Initialize buffer */ + buffer = (t_u8 *)malloc(BUFFER_LENGTH); + if (!buffer) { + printf("ERR:Cannot allocate buffer for command!\n"); + ret = MLAN_STATUS_FAILURE; + goto done; + } + memset(buffer, 0, BUFFER_LENGTH); + + /* Sanity tests */ + if (argc != 3) { + printf("Error: invalid no of arguments\n"); + printf("mlanutl mlanX usbsuspend\n"); + ret = MLAN_STATUS_FAILURE; + goto done; + } + + prepare_buffer(buffer, argv[2], 0, NULL); + + cmd = (struct eth_priv_cmd *)malloc(sizeof(struct eth_priv_cmd)); + if (!cmd) { + printf("ERR:Cannot allocate buffer for command!\n"); + ret = MLAN_STATUS_FAILURE; + goto done; + } + + /* Fill up buffer */ +#ifdef USERSPACE_32BIT_OVER_KERNEL_64BIT + memset(cmd, 0, sizeof(struct eth_priv_cmd)); + memcpy(&cmd->buf, &buffer, sizeof(buffer)); +#else + cmd->buf = buffer; +#endif + cmd->used_len = 0; + cmd->total_len = BUFFER_LENGTH; + + /* Perform IOCTL */ + memset(&ifr, 0, sizeof(struct ifreq)); + strncpy(ifr.ifr_ifrn.ifrn_name, dev_name, strlen(dev_name)); + ifr.ifr_ifru.ifru_data = (void *)cmd; + + if (ioctl(sockfd, MLAN_ETH_PRIV, &ifr)) { + perror("mlanutl"); + fprintf(stderr, "mlanutl: usbsuspend fail\n"); + ret = MLAN_STATUS_FAILURE; + goto done; + } + memcpy(&status, buffer, sizeof(status)); + if (status == -EFAULT) + printf("USB Device is already suspended\n"); + else if (status == 0) + printf("USB Device has been suspended\n"); + +done: + if (buffer) + free(buffer); + if (cmd) + free(cmd); + return ret; +} + +/** + * @brief Process extended version + * @param argc Number of arguments + * @param argv A pointer to arguments array + * @return MLAN_STATUS_SUCCESS--success, otherwise--fail + */ +static int +process_usb_resume(int argc, char *argv[]) +{ + int ret = 0, status = 0; + t_u8 *buffer = NULL; + struct eth_priv_cmd *cmd = NULL; + struct ifreq ifr; + + /* Initialize buffer */ + buffer = (t_u8 *)malloc(BUFFER_LENGTH); + if (!buffer) { + printf("ERR:Cannot allocate buffer for command!\n"); + ret = MLAN_STATUS_FAILURE; + goto done; + } + memset(buffer, 0, BUFFER_LENGTH); + + /* Sanity tests */ + if (argc != 3) { + printf("Error: invalid no of arguments\n"); + printf("mlanutl mlanX usbresume\n"); + ret = MLAN_STATUS_FAILURE; + goto done; + } + + prepare_buffer(buffer, argv[2], 0, NULL); + + cmd = (struct eth_priv_cmd *)malloc(sizeof(struct eth_priv_cmd)); + if (!cmd) { + printf("ERR:Cannot allocate buffer for command!\n"); + ret = MLAN_STATUS_FAILURE; + goto done; + } + + /* Fill up buffer */ +#ifdef USERSPACE_32BIT_OVER_KERNEL_64BIT + memset(cmd, 0, sizeof(struct eth_priv_cmd)); + memcpy(&cmd->buf, &buffer, sizeof(buffer)); +#else + cmd->buf = buffer; +#endif + cmd->used_len = 0; + cmd->total_len = BUFFER_LENGTH; + + /* Perform IOCTL */ + memset(&ifr, 0, sizeof(struct ifreq)); + strncpy(ifr.ifr_ifrn.ifrn_name, dev_name, strlen(dev_name)); + ifr.ifr_ifru.ifru_data = (void *)cmd; + + if (ioctl(sockfd, MLAN_ETH_PRIV, &ifr)) { + perror("mlanutl"); + fprintf(stderr, "mlanutl: usbresume fail\n"); + ret = MLAN_STATUS_FAILURE; + goto done; + } + memcpy(&status, buffer, sizeof(status)); + if (status == -EFAULT) + printf("USB Device is already resumed\n"); + else if (status == 0) + printf("USB Device has been resumed\n"); + +done: + if (buffer) + free(buffer); + if (cmd) + free(cmd); + return ret; +} + +#if defined(STA_SUPPORT) && defined(STA_WEXT) +/** + * @brief Set/Get radio + * @param argc Number of arguments + * @param argv A pointer to arguments array + * @return MLAN_STATUS_SUCCESS--success, otherwise--fail + */ +static int +process_radio_ctrl(int argc, char *argv[]) +{ + int ret = 0, radio = 0; + t_u8 *buffer = NULL; + struct eth_priv_cmd *cmd = NULL; + struct ifreq ifr; + + /* Initialize buffer */ + buffer = (t_u8 *)malloc(BUFFER_LENGTH); + if (!buffer) { + printf("ERR:Cannot allocate buffer for command!\n"); + ret = MLAN_STATUS_FAILURE; + goto done; + } + memset(buffer, 0, BUFFER_LENGTH); + + /* Sanity tests */ + if (argc < 3 || argc > 4) { + printf("Error: invalid no of arguments\n"); + printf("mlanutl mlanX radioctrl [#]\n"); + ret = MLAN_STATUS_FAILURE; + goto done; + } + + prepare_buffer(buffer, argv[2], (argc - 3), &argv[3]); + + cmd = (struct eth_priv_cmd *)malloc(sizeof(struct eth_priv_cmd)); + if (!cmd) { + printf("ERR:Cannot allocate buffer for command!\n"); + ret = MLAN_STATUS_FAILURE; + goto done; + } + + /* Fill up buffer */ +#ifdef USERSPACE_32BIT_OVER_KERNEL_64BIT + memset(cmd, 0, sizeof(struct eth_priv_cmd)); + memcpy(&cmd->buf, &buffer, sizeof(buffer)); +#else + cmd->buf = buffer; +#endif + cmd->used_len = 0; + cmd->total_len = BUFFER_LENGTH; + + /* Perform IOCTL */ + memset(&ifr, 0, sizeof(struct ifreq)); + strncpy(ifr.ifr_ifrn.ifrn_name, dev_name, strlen(dev_name)); + ifr.ifr_ifru.ifru_data = (void *)cmd; + + if (ioctl(sockfd, MLAN_ETH_PRIV, &ifr)) { + perror("mlanutl"); + fprintf(stderr, "mlanutl: radioctrl fail\n"); + ret = MLAN_STATUS_FAILURE; + goto done; + } + + /* Process result */ + if (argc == 3) { + memcpy(&radio, buffer, sizeof(radio)); + if (radio == 0) { + printf("Radio is Disabled\n"); + } else if (radio == 1) { + printf("Radio is Enabled\n"); + } + } + +done: + if (buffer) + free(buffer); + if (cmd) + free(cmd); + + return ret; +} +#endif + +/** + * @brief Implement WMM enable command + * @param argc Number of arguments + * @param argv A pointer to arguments array + * @return MLAN_STATUS_SUCCESS--success, otherwise--fail + */ +static int +process_wmm_cfg(int argc, char *argv[]) +{ + int ret = 0, status = 0; + t_u8 *buffer = NULL; + struct eth_priv_cmd *cmd = NULL; + struct ifreq ifr; + + /* Initialize buffer */ + buffer = (t_u8 *)malloc(BUFFER_LENGTH); + if (!buffer) { + printf("ERR:Cannot allocate buffer for command!\n"); + ret = MLAN_STATUS_FAILURE; + goto done; + } + memset(buffer, 0, BUFFER_LENGTH); + + /* Sanity tests */ + if (argc < 3 || argc > 4) { + printf("Error: invalid no of arguments\n"); + printf("mlanutl mlanX wmmcfg [#]\n"); + ret = MLAN_STATUS_FAILURE; + goto done; + } + + prepare_buffer(buffer, argv[2], (argc - 3), &argv[3]); + + cmd = (struct eth_priv_cmd *)malloc(sizeof(struct eth_priv_cmd)); + if (!cmd) { + printf("ERR:Cannot allocate buffer for command!\n"); + ret = MLAN_STATUS_FAILURE; + goto done; + } + + /* Fill up buffer */ +#ifdef USERSPACE_32BIT_OVER_KERNEL_64BIT + memset(cmd, 0, sizeof(struct eth_priv_cmd)); + memcpy(&cmd->buf, &buffer, sizeof(buffer)); +#else + cmd->buf = buffer; +#endif + cmd->used_len = 0; + cmd->total_len = BUFFER_LENGTH; + + /* Perform IOCTL */ + memset(&ifr, 0, sizeof(struct ifreq)); + strncpy(ifr.ifr_ifrn.ifrn_name, dev_name, strlen(dev_name)); + ifr.ifr_ifru.ifru_data = (void *)cmd; + + if (ioctl(sockfd, MLAN_ETH_PRIV, &ifr)) { + perror("mlanutl"); + fprintf(stderr, "mlanutl: wmmcfg fail\n"); + ret = MLAN_STATUS_FAILURE; + goto done; + } + + /* Process result */ + if (argc == 3) { + memcpy(&status, buffer, sizeof(status)); + if (status == 0) { + printf("WMM is Disabled\n"); + } else if (status == 1) { + printf("WMM is Enabled\n"); + } + } + +done: + if (buffer) + free(buffer); + if (cmd) + free(cmd); + + return ret; +} + +static int +process_wmm_param_config(int argc, char *argv[]) +{ + int ret = MLAN_STATUS_SUCCESS; + t_u8 *buffer = NULL; + t_u8 *data = NULL; + HostCmd_DS_GEN *hostcmd = NULL; + t_u32 cmd_len = 0; + struct eth_priv_cmd *cmd = NULL; + struct ifreq ifr; + int i = 0; + t_u32 wmm_param[MAX_AC_QUEUES][5]; + t_u8 aci = 0; + t_u8 aifsn = 0; + t_u8 ecwmax = 0; + t_u8 ecwmin = 0; + t_u16 txop = 0; + HostCmd_DS_WMM_PARAM_CONFIG *cmd_data = NULL; + + /* Sanity tests */ + if ((argc < 3) || (argc > (3 + 5 * MAX_AC_QUEUES)) || + (((argc - 3) % 5) != 0)) { + printf("Incorrect number of parameters\n"); + printf("Format reference: mlanutl mlanX wmm_param_config \n"); + printf("\t[AC_BE AIFSN ECW_MAX ECW_MIN TX_OP]\n"); + printf("\t[AC_BK AIFSN ECW_MAX ECW_MIN TX_OP]\n"); + printf("\t[AC_VI AIFSN ECW_MAX ECW_MIN TX_OP]\n"); + printf("\t[AC_VO AIFSN ECW_MAX ECW_MIN TX_OP]\n"); + return MLAN_STATUS_FAILURE; + } + + for (i = 3; i < argc; i++) { + if (IS_HEX_OR_DIGIT(argv[i]) == MLAN_STATUS_FAILURE) { + printf("ERR: Only Number values are allowed\n"); + return MLAN_STATUS_FAILURE; + } + } + + i = 3; + memset(wmm_param, 0x00, sizeof(wmm_param)); + while (i < argc) { + aci = A2HEXDECIMAL(argv[i]); + aifsn = A2HEXDECIMAL(argv[i + 1]); + ecwmax = A2HEXDECIMAL(argv[i + 2]); + ecwmin = A2HEXDECIMAL(argv[i + 3]); + txop = A2HEXDECIMAL(argv[i + 4]); + if ((aci <= 3) && !wmm_param[aci][0]) { + if (((aifsn >= 2) && (aifsn <= 15)) + && (ecwmax <= 15) + && (ecwmin <= 15) + && (txop <= 0xFFFF)) { + wmm_param[aci][0] = TRUE; + wmm_param[aci][1] = aifsn; + wmm_param[aci][2] = ecwmax; + wmm_param[aci][3] = ecwmin; + wmm_param[aci][4] = txop; + } else { + printf("wmm parmams invalid\n"); + return MLAN_STATUS_FAILURE; + } + } else { + printf("aci out of range or repeated \n"); + return MLAN_STATUS_FAILURE; + } + i = i + 5; + } + + /* Initialize buffer */ + buffer = (t_u8 *)malloc(BUFFER_LENGTH); + if (!buffer) { + printf("ERR:Cannot allocate buffer for command!\n"); + return MLAN_STATUS_FAILURE; + } + memset(buffer, 0x00, BUFFER_LENGTH); + + /* prepare the host cmd */ + data = buffer; + prepare_buffer(buffer, HOSTCMD, 0, NULL); + data += strlen(CMD_NXP) + strlen(HOSTCMD); + /* add buffer size field */ + cmd_len = sizeof(HostCmd_DS_GEN) + sizeof(HostCmd_DS_WMM_PARAM_CONFIG); + cmd_len = cpu_to_le32(cmd_len); + memcpy(data, &cmd_len, sizeof(t_u32)); + data += sizeof(t_u32); + /* add cmd header */ + hostcmd = (HostCmd_DS_GEN *)data; + hostcmd->command = cpu_to_le16(HostCmd_CMD_WMM_PARAM_CONFIG); + hostcmd->size = + cpu_to_le16(sizeof(HostCmd_DS_GEN) + + sizeof(HostCmd_DS_WMM_PARAM_CONFIG)); + hostcmd->seq_num = 0; + hostcmd->result = 0; + data += sizeof(HostCmd_DS_GEN); + cmd_data = (HostCmd_DS_WMM_PARAM_CONFIG *) data; + if (argc > 3) { + cmd_data->action = ACTION_SET; + for (i = 0; i < MAX_AC_QUEUES; i++) { + if (wmm_param[i][0] == TRUE) { + cmd_data->ac_params[i].aci_aifsn.acm = 1; + cmd_data->ac_params[i].aci_aifsn.aci = (t_u8)i; + cmd_data->ac_params[i].aci_aifsn.aifsn = + (t_u8)(wmm_param[i][1]); + cmd_data->ac_params[i].ecw.ecw_max = + (t_u8)(wmm_param[i][2]); + cmd_data->ac_params[i].ecw.ecw_min = + (t_u8)(wmm_param[i][3]); + cmd_data->ac_params[i].tx_op_limit = + cpu_to_le16((t_u16)(wmm_param[i][4])); + } + } + } else + cmd_data->action = ACTION_GET; + + cmd = (struct eth_priv_cmd *)malloc(sizeof(struct eth_priv_cmd)); + if (!cmd) { + printf("ERR:Cannot allocate buffer for command!\n"); + free(buffer); + return MLAN_STATUS_FAILURE; + } + + /* Fill up buffer */ +#ifdef USERSPACE_32BIT_OVER_KERNEL_64BIT + memset(cmd, 0, sizeof(struct eth_priv_cmd)); + memcpy(&cmd->buf, &buffer, sizeof(buffer)); +#else + cmd->buf = buffer; +#endif + cmd->used_len = 0; + cmd->total_len = BUFFER_LENGTH; + + /* Perform IOCTL */ + memset(&ifr, 0, sizeof(struct ifreq)); + strncpy(ifr.ifr_ifrn.ifrn_name, dev_name, strlen(dev_name)); + ifr.ifr_ifru.ifru_data = (void *)cmd; + + if (ioctl(sockfd, MLAN_ETH_PRIV, &ifr)) { + perror("mlanutl"); + fprintf(stderr, "mlanutl: linkstats fail\n"); + if (cmd) + free(cmd); + if (buffer) + free(buffer); + return MLAN_STATUS_FAILURE; + } + + /* Process result */ + ret = process_host_cmd_resp(HOSTCMD, buffer); + + if (buffer) + free(buffer); + if (cmd) + free(cmd); + + return ret; +} + +#if defined(STA_SUPPORT) +/** + * @brief Implement 802.11D enable command + * @param argc Number of arguments + * @param argv A pointer to arguments array + * @return MLAN_STATUS_SUCCESS--success, otherwise--fail + */ +static int +process_11d_cfg(int argc, char *argv[]) +{ + int ret = 0, status = 0; + t_u8 *buffer = NULL; + struct eth_priv_cmd *cmd = NULL; + struct ifreq ifr; + + /* Initialize buffer */ + buffer = (t_u8 *)malloc(BUFFER_LENGTH); + if (!buffer) { + printf("ERR:Cannot allocate buffer for command!\n"); + ret = MLAN_STATUS_FAILURE; + goto done; + } + memset(buffer, 0, BUFFER_LENGTH); + + /* Sanity tests */ + if (argc < 3 || argc > 4) { + printf("Error: invalid no of arguments\n"); + printf("mlanutl mlanX 11dcfg [#]\n"); + ret = MLAN_STATUS_FAILURE; + goto done; + } + + prepare_buffer(buffer, argv[2], (argc - 3), &argv[3]); + + cmd = (struct eth_priv_cmd *)malloc(sizeof(struct eth_priv_cmd)); + if (!cmd) { + printf("ERR:Cannot allocate buffer for command!\n"); + ret = MLAN_STATUS_FAILURE; + goto done; + } + + /* Fill up buffer */ +#ifdef USERSPACE_32BIT_OVER_KERNEL_64BIT + memset(cmd, 0, sizeof(struct eth_priv_cmd)); + memcpy(&cmd->buf, &buffer, sizeof(buffer)); +#else + cmd->buf = buffer; +#endif + cmd->used_len = 0; + cmd->total_len = BUFFER_LENGTH; + + /* Perform IOCTL */ + memset(&ifr, 0, sizeof(struct ifreq)); + strncpy(ifr.ifr_ifrn.ifrn_name, dev_name, strlen(dev_name)); + ifr.ifr_ifru.ifru_data = (void *)cmd; + + if (ioctl(sockfd, MLAN_ETH_PRIV, &ifr)) { + perror("mlanutl"); + fprintf(stderr, "mlanutl: 11dcfg fail\n"); + ret = MLAN_STATUS_FAILURE; + goto done; + } + + /* Process result */ + if (argc == 3) { + memcpy(&status, buffer, sizeof(status)); + if (status == 0) { + printf("802.11D is Disabled\n"); + } else if (status == 1) { + printf("802.11D is Enabled\n"); + } + } + +done: + if (buffer) + free(buffer); + if (cmd) + free(cmd); + + return ret; +} + +/** + * @brief Implement 802.11D clear chan table command + * @param argc Number of arguments + * @param argv A pointer to arguments array + * @return MLAN_STATUS_SUCCESS--success, otherwise--fail + */ +static int +process_11d_clr_tbl(int argc, char *argv[]) +{ + int ret = 0; + t_u8 *buffer = NULL; + struct eth_priv_cmd *cmd = NULL; + struct ifreq ifr; + + /* Initialize buffer */ + buffer = (t_u8 *)malloc(BUFFER_LENGTH); + if (!buffer) { + printf("ERR:Cannot allocate buffer for command!\n"); + ret = MLAN_STATUS_FAILURE; + goto done; + } + memset(buffer, 0, BUFFER_LENGTH); + + /* Sanity tests */ + if (argc != 3) { + printf("Error: invalid no of arguments\n"); + printf("mlanutl mlanX 11dclrtbl\n"); + ret = MLAN_STATUS_FAILURE; + goto done; + } + + prepare_buffer(buffer, argv[2], 0, NULL); + + cmd = (struct eth_priv_cmd *)malloc(sizeof(struct eth_priv_cmd)); + if (!cmd) { + printf("ERR:Cannot allocate buffer for command!\n"); + ret = MLAN_STATUS_FAILURE; + goto done; + } + + /* Fill up buffer */ +#ifdef USERSPACE_32BIT_OVER_KERNEL_64BIT + memset(cmd, 0, sizeof(struct eth_priv_cmd)); + memcpy(&cmd->buf, &buffer, sizeof(buffer)); +#else + cmd->buf = buffer; +#endif + cmd->used_len = 0; + cmd->total_len = BUFFER_LENGTH; + + /* Perform IOCTL */ + memset(&ifr, 0, sizeof(struct ifreq)); + strncpy(ifr.ifr_ifrn.ifrn_name, dev_name, strlen(dev_name)); + ifr.ifr_ifru.ifru_data = (void *)cmd; + + if (ioctl(sockfd, MLAN_ETH_PRIV, &ifr)) { + perror("mlanutl"); + fprintf(stderr, "mlanutl: 11dclrtbl fail\n"); + ret = MLAN_STATUS_FAILURE; + goto done; + } + +done: + if (buffer) + free(buffer); + if (cmd) + free(cmd); + + return ret; +} +#endif + +#ifndef OPCHAN +/** + * @brief Set/Get WWS configuration + * @param argc Number of arguments + * @param argv A pointer to arguments array + * @return MLAN_STATUS_SUCCESS--success, otherwise--fail + */ +static int +process_wws_cfg(int argc, char *argv[]) +{ + int ret = 0, status = 0; + t_u8 *buffer = NULL; + struct eth_priv_cmd *cmd = NULL; + struct ifreq ifr; + + /* Initialize buffer */ + buffer = (t_u8 *)malloc(BUFFER_LENGTH); + if (!buffer) { + printf("ERR:Cannot allocate buffer for command!\n"); + ret = MLAN_STATUS_FAILURE; + goto done; + } + memset(buffer, 0, BUFFER_LENGTH); + + /* Sanity tests */ + if (argc < 3 || argc > 4) { + printf("Error: invalid no of arguments\n"); + printf("mlanutl mlanX wwscfg [#]\n"); + ret = MLAN_STATUS_FAILURE; + goto done; + } + + prepare_buffer(buffer, argv[2], (argc - 3), &argv[3]); + + cmd = (struct eth_priv_cmd *)malloc(sizeof(struct eth_priv_cmd)); + if (!cmd) { + printf("ERR:Cannot allocate buffer for command!\n"); + ret = MLAN_STATUS_FAILURE; + goto done; + } + + /* Fill up buffer */ +#ifdef USERSPACE_32BIT_OVER_KERNEL_64BIT + memset(cmd, 0, sizeof(struct eth_priv_cmd)); + memcpy(&cmd->buf, &buffer, sizeof(buffer)); +#else + cmd->buf = buffer; +#endif + cmd->used_len = 0; + cmd->total_len = BUFFER_LENGTH; + + /* Perform IOCTL */ + memset(&ifr, 0, sizeof(struct ifreq)); + strncpy(ifr.ifr_ifrn.ifrn_name, dev_name, strlen(dev_name)); + ifr.ifr_ifru.ifru_data = (void *)cmd; + + if (ioctl(sockfd, MLAN_ETH_PRIV, &ifr)) { + perror("mlanutl"); + fprintf(stderr, "mlanutl: wwscfg fail\n"); + ret = MLAN_STATUS_FAILURE; + goto done; + } + + /* Process result */ + if (argc == 3) { + memcpy(&status, buffer, sizeof(status)); + if (status == 1) { + printf("WWS is Enabled\n"); + } else if (status == 0) { + printf("WWS is Disabled\n"); + } + } + +done: + if (buffer) + free(buffer); + if (cmd) + free(cmd); + + return ret; +} +#endif + +#if defined(REASSOCIATION) +/** + * @brief Set/Get reassociation settings + * @param argc Number of arguments + * @param argv A pointer to arguments array + * @return MLAN_STATUS_SUCCESS--success, otherwise--fail + */ +static int +process_set_get_reassoc(int argc, char *argv[]) +{ + int ret = 0, status = 0; + t_u8 *buffer = NULL; + struct eth_priv_cmd *cmd = NULL; + struct ifreq ifr; + + /* Initialize buffer */ + buffer = (t_u8 *)malloc(BUFFER_LENGTH); + if (!buffer) { + printf("ERR:Cannot allocate buffer for command!\n"); + ret = MLAN_STATUS_FAILURE; + goto done; + } + memset(buffer, 0, BUFFER_LENGTH); + + /* Sanity tests */ + if (argc < 3 || argc > 4) { + printf("Error: invalid no of arguments\n"); + printf("mlanutl mlanX reassoctrl [#]\n"); + ret = MLAN_STATUS_FAILURE; + goto done; + } + + prepare_buffer(buffer, argv[2], (argc - 3), &argv[3]); + + cmd = (struct eth_priv_cmd *)malloc(sizeof(struct eth_priv_cmd)); + if (!cmd) { + printf("ERR:Cannot allocate buffer for command!\n"); + ret = MLAN_STATUS_FAILURE; + goto done; + } + + /* Fill up buffer */ +#ifdef USERSPACE_32BIT_OVER_KERNEL_64BIT + memset(cmd, 0, sizeof(struct eth_priv_cmd)); + memcpy(&cmd->buf, &buffer, sizeof(buffer)); +#else + cmd->buf = buffer; +#endif + cmd->used_len = 0; + cmd->total_len = BUFFER_LENGTH; + + /* Perform IOCTL */ + memset(&ifr, 0, sizeof(struct ifreq)); + strncpy(ifr.ifr_ifrn.ifrn_name, dev_name, strlen(dev_name)); + ifr.ifr_ifru.ifru_data = (void *)cmd; + + if (ioctl(sockfd, MLAN_ETH_PRIV, &ifr)) { + perror("mlanutl"); + fprintf(stderr, "mlanutl: reassoctrl fail\n"); + ret = MLAN_STATUS_FAILURE; + goto done; + } + + /* Process result */ + if (argc == 3) { + memcpy(&status, buffer, sizeof(status)); + if (status == 1) { + printf("Re-association is Enabled\n"); + } else if (status == 0) { + printf("Re-association is Disabled\n"); + } + } + +done: + if (buffer) + free(buffer); + if (cmd) + free(cmd); + + return ret; +} +#endif + +/** + * @brief Get Transmit buffer size + * @param argc Number of arguments + * @param argv A pointer to arguments array + * @return MLAN_STATUS_SUCCESS--success, otherwise--fail + */ +static int +process_txbuf_cfg(int argc, char *argv[]) +{ + int ret = 0, buf_size = 0; + t_u8 *buffer = NULL; + struct eth_priv_cmd *cmd = NULL; + struct ifreq ifr; + + /* Initialize buffer */ + buffer = (t_u8 *)malloc(BUFFER_LENGTH); + if (!buffer) { + printf("ERR:Cannot allocate buffer for command!\n"); + ret = MLAN_STATUS_FAILURE; + goto done; + } + memset(buffer, 0, BUFFER_LENGTH); + + /* Sanity tests */ + if (argc != 3) { + printf("Error: invalid no of arguments\n"); + printf("mlanutl mlanX txbufcfg\n"); + ret = MLAN_STATUS_FAILURE; + goto done; + } + + prepare_buffer(buffer, argv[2], 0, NULL); + + cmd = (struct eth_priv_cmd *)malloc(sizeof(struct eth_priv_cmd)); + if (!cmd) { + printf("ERR:Cannot allocate buffer for command!\n"); + ret = MLAN_STATUS_FAILURE; + goto done; + } + + /* Fill up buffer */ +#ifdef USERSPACE_32BIT_OVER_KERNEL_64BIT + memset(cmd, 0, sizeof(struct eth_priv_cmd)); + memcpy(&cmd->buf, &buffer, sizeof(buffer)); +#else + cmd->buf = buffer; +#endif + cmd->used_len = 0; + cmd->total_len = BUFFER_LENGTH; + + /* Perform IOCTL */ + memset(&ifr, 0, sizeof(struct ifreq)); + strncpy(ifr.ifr_ifrn.ifrn_name, dev_name, strlen(dev_name)); + ifr.ifr_ifru.ifru_data = (void *)cmd; + + if (ioctl(sockfd, MLAN_ETH_PRIV, &ifr)) { + perror("mlanutl"); + fprintf(stderr, "mlanutl: txbufcfg fail\n"); + ret = MLAN_STATUS_FAILURE; + goto done; + } + memcpy(&buf_size, buffer, sizeof(buf_size)); + printf("Transmit buffer size is %d\n", buf_size); + +done: + if (buffer) + free(buffer); + if (cmd) + free(cmd); + return ret; +} + +#ifdef STA_SUPPORT +/** + * @brief Set/Get auth type + * @param argc Number of arguments + * @param argv A pointer to arguments array + * @return MLAN_STATUS_SUCCESS--success, otherwise--fail + */ +static int +process_set_get_auth_type(int argc, char *argv[]) +{ + int ret = 0, auth_type = 0; + t_u8 *buffer = NULL; + struct eth_priv_cmd *cmd = NULL; + struct ifreq ifr; + + /* Initialize buffer */ + buffer = (t_u8 *)malloc(BUFFER_LENGTH); + if (!buffer) { + printf("ERR:Cannot allocate buffer for command!\n"); + ret = MLAN_STATUS_FAILURE; + goto done; + } + memset(buffer, 0, BUFFER_LENGTH); + + /* Sanity tests */ + if (argc < 3 || argc > 4) { + printf("Error: invalid no of arguments\n"); + printf("mlanutl mlanX authtype [#]\n"); + ret = MLAN_STATUS_FAILURE; + goto done; + } + + prepare_buffer(buffer, argv[2], (argc - 3), &argv[3]); + + cmd = (struct eth_priv_cmd *)malloc(sizeof(struct eth_priv_cmd)); + if (!cmd) { + printf("ERR:Cannot allocate buffer for command!\n"); + ret = MLAN_STATUS_FAILURE; + goto done; + } + + /* Fill up buffer */ +#ifdef USERSPACE_32BIT_OVER_KERNEL_64BIT + memset(cmd, 0, sizeof(struct eth_priv_cmd)); + memcpy(&cmd->buf, &buffer, sizeof(buffer)); +#else + cmd->buf = buffer; +#endif + cmd->used_len = 0; + cmd->total_len = BUFFER_LENGTH; + + /* Perform IOCTL */ + memset(&ifr, 0, sizeof(struct ifreq)); + strncpy(ifr.ifr_ifrn.ifrn_name, dev_name, strlen(dev_name)); + ifr.ifr_ifru.ifru_data = (void *)cmd; + + if (ioctl(sockfd, MLAN_ETH_PRIV, &ifr)) { + perror("mlanutl"); + fprintf(stderr, "mlanutl: authtype fail\n"); + ret = MLAN_STATUS_FAILURE; + goto done; + } + + /* Process result */ + if (argc == 3) { + memcpy(&auth_type, buffer, sizeof(auth_type)); + if (auth_type == 1) { + printf("802.11 shared key authentication\n"); + } else if (auth_type == 0) { + printf("802.11 open system authentication\n"); + } else if (auth_type == 3) { + printf("802.11 WPA3 SAE authentication\n"); + } else if (auth_type == 255) { + printf("Allow open system or shared key authentication\n"); + } + } + +done: + if (buffer) + free(buffer); + if (cmd) + free(cmd); + + return ret; +} +#endif + +/** + * @brief Set/get user provisioned local power constraint + * @param argc Number of arguments + * @param argv A pointer to arguments array + * @return MLAN_STATUS_SUCCESS--success, otherwise--fail + */ +static int +process_11h_local_pwr_constraint(int argc, char *argv[]) +{ + int ret = 0, power_cons = 0; + t_u8 *buffer = NULL; + struct eth_priv_cmd *cmd = NULL; + struct ifreq ifr; + + /* Initialize buffer */ + buffer = (t_u8 *)malloc(BUFFER_LENGTH); + if (!buffer) { + printf("ERR:Cannot allocate buffer for command!\n"); + ret = MLAN_STATUS_FAILURE; + goto done; + } + memset(buffer, 0, BUFFER_LENGTH); + + /* Sanity tests */ + if (argc < 3 || argc > 4) { + printf("Error: invalid no of arguments\n"); + printf("mlanutl mlanX powercons [#]\n"); + ret = MLAN_STATUS_FAILURE; + goto done; + } + + prepare_buffer(buffer, argv[2], (argc - 3), &argv[3]); + + cmd = (struct eth_priv_cmd *)malloc(sizeof(struct eth_priv_cmd)); + if (!cmd) { + printf("ERR:Cannot allocate buffer for command!\n"); + ret = MLAN_STATUS_FAILURE; + goto done; + } + + /* Fill up buffer */ +#ifdef USERSPACE_32BIT_OVER_KERNEL_64BIT + memset(cmd, 0, sizeof(struct eth_priv_cmd)); + memcpy(&cmd->buf, &buffer, sizeof(buffer)); +#else + cmd->buf = buffer; +#endif + cmd->used_len = 0; + cmd->total_len = BUFFER_LENGTH; + + /* Perform IOCTL */ + memset(&ifr, 0, sizeof(struct ifreq)); + strncpy(ifr.ifr_ifrn.ifrn_name, dev_name, strlen(dev_name)); + ifr.ifr_ifru.ifru_data = (void *)cmd; + + if (ioctl(sockfd, MLAN_ETH_PRIV, &ifr)) { + perror("mlanutl"); + fprintf(stderr, "mlanutl: powercons fail\n"); + ret = MLAN_STATUS_FAILURE; + goto done; + } + + if (argc == 3) { + /* Process result */ + memcpy(&power_cons, buffer, sizeof(power_cons)); + printf("Local power constraint is %d dbm\n", power_cons); + } + +done: + if (buffer) + free(buffer); + if (cmd) + free(cmd); + + return ret; +} + +/** + * @brief Set/get HT stream configurations + * @param argc Number of arguments + * @param argv A pointer to arguments array + * @return MLAN_STATUS_SUCCESS--success, otherwise--fail + */ +static int +process_ht_stream_cfg(int argc, char *argv[]) +{ + int ret = 0, mode = 0; + t_u8 *buffer = NULL; + struct eth_priv_cmd *cmd = NULL; + struct ifreq ifr; + + /* Initialize buffer */ + buffer = (t_u8 *)malloc(BUFFER_LENGTH); + if (!buffer) { + printf("ERR:Cannot allocate buffer for command!\n"); + ret = MLAN_STATUS_FAILURE; + goto done; + } + memset(buffer, 0, BUFFER_LENGTH); + + /* Sanity tests */ + if (argc < 3 || argc > 4) { + printf("Error: invalid no of arguments\n"); + printf("mlanutl mlanX htstreamcfg [#]\n"); + ret = MLAN_STATUS_FAILURE; + goto done; + } + + prepare_buffer(buffer, argv[2], (argc - 3), &argv[3]); + + cmd = (struct eth_priv_cmd *)malloc(sizeof(struct eth_priv_cmd)); + if (!cmd) { + printf("ERR:Cannot allocate buffer for command!\n"); + ret = MLAN_STATUS_FAILURE; + goto done; + } + + /* Fill up buffer */ +#ifdef USERSPACE_32BIT_OVER_KERNEL_64BIT + memset(cmd, 0, sizeof(struct eth_priv_cmd)); + memcpy(&cmd->buf, &buffer, sizeof(buffer)); +#else + cmd->buf = buffer; +#endif + cmd->used_len = 0; + cmd->total_len = BUFFER_LENGTH; + + /* Perform IOCTL */ + memset(&ifr, 0, sizeof(struct ifreq)); + strncpy(ifr.ifr_ifrn.ifrn_name, dev_name, strlen(dev_name)); + ifr.ifr_ifru.ifru_data = (void *)cmd; + + if (ioctl(sockfd, MLAN_ETH_PRIV, &ifr)) { + perror("mlanutl"); + fprintf(stderr, "mlanutl: htstreamcfg fail\n"); + ret = MLAN_STATUS_FAILURE; + goto done; + } + + /* Process result */ + memcpy(&mode, buffer, sizeof(mode)); + if (mode == HT_STREAM_MODE_1X1) + printf("HT stream is in 1x1 mode\n"); + else if (mode == HT_STREAM_MODE_2X2) + printf("HT stream is in 2x2 mode\n"); + +done: + if (buffer) + free(buffer); + if (cmd) + free(cmd); + + return ret; +} + +/** + * @brief Set mimo switch configurations + * @param argc Number of arguments + * @param argv A pointer to arguments array + * @return MLAN_STATUS_SUCCESS--success, otherwise--fail + */ +static int +process_mimo_switch(int argc, char *argv[]) +{ + int ret = 0; + t_u8 *buffer = NULL; + t_u8 tx_antmode = 0, rx_antmode = 0; + struct eth_priv_cmd *cmd = NULL; + struct ifreq ifr; + + /* Initialize buffer */ + buffer = (t_u8 *)malloc(BUFFER_LENGTH); + if (!buffer) { + printf("ERR:Cannot allocate buffer for command!\n"); + ret = MLAN_STATUS_FAILURE; + goto done; + } + memset(buffer, 0, BUFFER_LENGTH); + + /* Sanity tests */ + if (argc != 5) { + printf("Error: invalid no of arguments\n"); + printf("mlanutl mlanX/uapX mimoswitch [txpath_antmode] [rxpath_antmode]\n"); + ret = MLAN_STATUS_FAILURE; + goto done; + } + + tx_antmode = (t_u8)a2hex_or_atoi(argv[3]); + rx_antmode = (t_u8)a2hex_or_atoi(argv[4]); + if (! + ((tx_antmode == 1 && rx_antmode == 1) || + (tx_antmode == 2 && rx_antmode == 2) || (rx_antmode == 3 && + (tx_antmode == 1 || + tx_antmode == 3)))) { + printf("Error: invalid arguments\n"); + printf("The valid values of txpath_antmode and rxpath_antmode are 1/1 2/2 3/3 1/3 \n"); + ret = MLAN_STATUS_FAILURE; + goto done; + } + + prepare_buffer(buffer, argv[2], (argc - 3), &argv[3]); + + cmd = (struct eth_priv_cmd *)malloc(sizeof(struct eth_priv_cmd)); + if (!cmd) { + printf("ERR:Cannot allocate buffer for command!\n"); + ret = MLAN_STATUS_FAILURE; + goto done; + } + + /* Fill up buffer */ +#ifdef USERSPACE_32BIT_OVER_KERNEL_64BIT + memset(cmd, 0, sizeof(struct eth_priv_cmd)); + memcpy(&cmd->buf, &buffer, sizeof(buffer)); +#else + cmd->buf = buffer; +#endif + cmd->used_len = 0; + cmd->total_len = BUFFER_LENGTH; + + /* Perform IOCTL */ + memset(&ifr, 0, sizeof(struct ifreq)); + strncpy(ifr.ifr_ifrn.ifrn_name, dev_name, strlen(dev_name)); + ifr.ifr_ifru.ifru_data = (void *)cmd; + + if (ioctl(sockfd, MLAN_ETH_PRIV, &ifr)) { + perror("mlanutl"); + fprintf(stderr, "mlanutl: mimoswitch fail\n"); + ret = MLAN_STATUS_FAILURE; + goto done; + } + + /* Process result */ + printf("Successfully set Tx path antenna mode: %d, Rx path antenna mode: %d\n", tx_antmode, rx_antmode); + +done: + if (buffer) + free(buffer); + if (cmd) + free(cmd); + + return ret; +} + +/** + * @brief Get thermal reading + * @param argc Number of arguments + * @param argv A pointer to arguments array + * @return MLAN_STATUS_SUCCESS--success, otherwise--fail + */ +static int +process_thermal(int argc, char *argv[]) +{ + int ret = 0, thermal = 0; + t_u8 *buffer = NULL; + struct eth_priv_cmd *cmd = NULL; + struct ifreq ifr; + + /* Initialize buffer */ + buffer = (t_u8 *)malloc(BUFFER_LENGTH); + if (!buffer) { + printf("ERR:Cannot allocate buffer for command!\n"); + ret = MLAN_STATUS_FAILURE; + goto done; + } + memset(buffer, 0, BUFFER_LENGTH); + + /* Sanity tests */ + if (argc != 3) { + printf("Error: invalid no of arguments\n"); + printf("mlanutl mlanX thermal\n"); + ret = MLAN_STATUS_FAILURE; + goto done; + } + + prepare_buffer(buffer, argv[2], (argc - 3), &argv[3]); + + cmd = (struct eth_priv_cmd *)malloc(sizeof(struct eth_priv_cmd)); + if (!cmd) { + printf("ERR:Cannot allocate buffer for command!\n"); + ret = MLAN_STATUS_FAILURE; + goto done; + } + + /* Fill up buffer */ +#ifdef USERSPACE_32BIT_OVER_KERNEL_64BIT + memset(cmd, 0, sizeof(struct eth_priv_cmd)); + memcpy(&cmd->buf, &buffer, sizeof(buffer)); +#else + cmd->buf = buffer; +#endif + cmd->used_len = 0; + cmd->total_len = BUFFER_LENGTH; + + /* Perform IOCTL */ + memset(&ifr, 0, sizeof(struct ifreq)); + strncpy(ifr.ifr_ifrn.ifrn_name, dev_name, strlen(dev_name)); + ifr.ifr_ifru.ifru_data = (void *)cmd; + + if (ioctl(sockfd, MLAN_ETH_PRIV, &ifr)) { + perror("mlanutl"); + fprintf(stderr, "mlanutl: thermal fail\n"); + ret = MLAN_STATUS_FAILURE; + goto done; + } + + /* Process result */ + memcpy(&thermal, buffer, sizeof(thermal)); + printf("Thermal reading is %d\n", thermal); + +done: + if (buffer) + free(buffer); + if (cmd) + free(cmd); + + return ret; +} + +#ifdef STA_SUPPORT +/** + * @brief Get signal + * @param argc Number of arguments + * @param argv A pointer to arguments array + * @return MLAN_STATUS_SUCCESS--success, otherwise--fail + */ +static int +process_get_signal(int argc, char *argv[]) +{ +#define DATA_SIZE 12 + int ret = 0, data[DATA_SIZE], i = 0, copy_size = 0; + t_u8 *buffer = NULL; + struct eth_priv_cmd *cmd = NULL; + struct ifreq ifr; + + memset(data, 0, sizeof(data)); + /* Initialize buffer */ + buffer = (t_u8 *)malloc(BUFFER_LENGTH); + if (!buffer) { + printf("ERR:Cannot allocate buffer for command!\n"); + ret = MLAN_STATUS_FAILURE; + goto done; + } + memset(buffer, 0, BUFFER_LENGTH); + + /* Sanity tests */ + if (argc < 3 || argc > 5) { + printf("Error: invalid no of arguments\n"); + printf("mlanutl mlanX getsignal [m] [n]\n"); + ret = MLAN_STATUS_FAILURE; + goto done; + } + + prepare_buffer(buffer, argv[2], (argc - 3), &argv[3]); + + cmd = (struct eth_priv_cmd *)malloc(sizeof(struct eth_priv_cmd)); + if (!cmd) { + printf("ERR:Cannot allocate buffer for command!\n"); + ret = MLAN_STATUS_FAILURE; + goto done; + } + + /* Fill up buffer */ +#ifdef USERSPACE_32BIT_OVER_KERNEL_64BIT + memset(cmd, 0, sizeof(struct eth_priv_cmd)); + memcpy(&cmd->buf, &buffer, sizeof(buffer)); +#else + cmd->buf = buffer; +#endif + cmd->used_len = 0; + cmd->total_len = BUFFER_LENGTH; + + /* Perform IOCTL */ + memset(&ifr, 0, sizeof(struct ifreq)); + strncpy(ifr.ifr_ifrn.ifrn_name, dev_name, strlen(dev_name)); + ifr.ifr_ifru.ifru_data = (void *)cmd; + + if (ioctl(sockfd, MLAN_ETH_PRIV, &ifr)) { + perror("mlanutl"); + fprintf(stderr, "mlanutl: getsignal fail\n"); + ret = MLAN_STATUS_FAILURE; + goto done; + } + + /* Process result */ + copy_size = MIN(cmd->used_len, DATA_SIZE * sizeof(int)); + memcpy(&data, buffer, copy_size); + printf("Get signal output is\t"); + for (i = 0; i < (int)(copy_size / sizeof(int)); i++) + printf("%d\t", data[i]); + printf("\n"); + +done: + if (buffer) + free(buffer); + if (cmd) + free(cmd); + + return ret; +} + +/** + * @brief Set signalext cfg + * @param argc Number of arguments + * @param argv A pointer to arguments array + * @return MLAN_STATUS_SUCCESS--success, otherwise--fail + */ +static int +process_signalext_cfg(int argc, char *argv[]) +{ + int ret = 0; + t_u8 *buffer = NULL; + struct eth_priv_cmd *cmd = NULL; + struct ifreq ifr; + + /* Initialize buffer */ + buffer = (t_u8 *)malloc(BUFFER_LENGTH); + if (!buffer) { + printf("ERR:Cannot allocate buffer for command!\n"); + ret = MLAN_STATUS_FAILURE; + goto done; + } + memset(buffer, 0, BUFFER_LENGTH); + + /* Sanity tests */ + if (argc != 4) { + printf("Error: invalid no of arguments\n"); + printf("mlanutl mlanX signalextcfg [#]\n"); + ret = MLAN_STATUS_FAILURE; + goto done; + } + + prepare_buffer(buffer, argv[2], (argc - 3), &argv[3]); + + cmd = (struct eth_priv_cmd *)malloc(sizeof(struct eth_priv_cmd)); + if (!cmd) { + printf("ERR:Cannot allocate buffer for command!\n"); + ret = MLAN_STATUS_FAILURE; + goto done; + } + + /* Fill up buffer */ +#ifdef USERSPACE_32BIT_OVER_KERNEL_64BIT + memset(cmd, 0, sizeof(struct eth_priv_cmd)); + memcpy(&cmd->buf, &buffer, sizeof(buffer)); +#else + cmd->buf = buffer; +#endif + cmd->used_len = 0; + cmd->total_len = BUFFER_LENGTH; + + /* Perform IOCTL */ + memset(&ifr, 0, sizeof(struct ifreq)); + strncpy(ifr.ifr_ifrn.ifrn_name, dev_name, strlen(dev_name)); + ifr.ifr_ifru.ifru_data = (void *)cmd; + + if (ioctl(sockfd, MLAN_ETH_PRIV, &ifr)) { + perror("mlanutl"); + fprintf(stderr, "mlanutl: signalext cfg fail\n"); + ret = MLAN_STATUS_FAILURE; + goto done; + } + +done: + if (buffer) + free(buffer); + if (cmd) + free(cmd); + + return ret; +} + +/** + * @brief Get signal + * @param argc Number of arguments + * @param argv A pointer to arguments array + * @return MLAN_STATUS_SUCCESS--success, otherwise--fail + */ +static int +process_get_signal_ext(int argc, char *argv[]) +{ +#define MAX_NUM_PATH 3 +#define PATH_SIZE 13 +#define PATH_A 1 +#define PATH_B 2 +#define PATH_AB 3 + int ret = 0, data[PATH_SIZE * MAX_NUM_PATH] = { 0 }; + int i = 0, copy_size = 0; + t_u8 *buffer = NULL; + struct eth_priv_cmd *cmd = NULL; + struct ifreq ifr; + t_u8 num_path = 0; + + memset(data, 0, sizeof(data)); + /* Initialize buffer */ + buffer = (t_u8 *)malloc(BUFFER_LENGTH); + if (!buffer) { + printf("ERR:Cannot allocate buffer for command!\n"); + ret = MLAN_STATUS_FAILURE; + goto done; + } + memset(buffer, 0, BUFFER_LENGTH); + + /* Sanity tests */ + if (argc != 3 && argc != 4) { + printf("Error: invalid no of arguments\n"); + if (strncmp(argv[2], "getsignalextv2", strlen("getsignalextv2")) + == 0) + printf("mlanutl mlanX getsignalextv2 [m]\n"); + else if (strncmp + (argv[2], "getsignalext", strlen("getsignalext")) == 0) + printf("mlanutl mlanX getsignalext [m]\n"); + ret = MLAN_STATUS_FAILURE; + goto done; + } + + prepare_buffer(buffer, argv[2], (argc - 3), &argv[3]); + + cmd = (struct eth_priv_cmd *)malloc(sizeof(struct eth_priv_cmd)); + if (!cmd) { + printf("ERR:Cannot allocate buffer for command!\n"); + ret = MLAN_STATUS_FAILURE; + goto done; + } + + /* Fill up buffer */ +#ifdef USERSPACE_32BIT_OVER_KERNEL_64BIT + memset(cmd, 0, sizeof(struct eth_priv_cmd)); + memcpy(&cmd->buf, &buffer, sizeof(buffer)); +#else + cmd->buf = buffer; +#endif + cmd->used_len = 0; + cmd->total_len = BUFFER_LENGTH; + + /* Perform IOCTL */ + memset(&ifr, 0, sizeof(struct ifreq)); + strncpy(ifr.ifr_ifrn.ifrn_name, dev_name, strlen(dev_name)); + ifr.ifr_ifru.ifru_data = (void *)cmd; + + if (ioctl(sockfd, MLAN_ETH_PRIV, &ifr)) { + perror("mlanutl"); + fprintf(stderr, "mlanutl: getsignal fail\n"); + ret = MLAN_STATUS_FAILURE; + goto done; + } + + /* Process result */ + copy_size = cmd->used_len; + memcpy(&data, (int *)buffer, copy_size); + + num_path = copy_size / sizeof(int) / PATH_SIZE; + for (i = 0; i < num_path; i++) { + if (data[i * PATH_SIZE] == PATH_A) + printf("PATH A: %d %d %d %d %d %d %d %d %d %d %d %d\n", data[i * PATH_SIZE + 1], data[i * PATH_SIZE + 2], data[i * PATH_SIZE + 3], data[i * PATH_SIZE + 4], data[i * PATH_SIZE + 5], data[i * PATH_SIZE + 6], data[i * PATH_SIZE + 7], data[i * PATH_SIZE + 8], data[i * PATH_SIZE + 9], data[i * PATH_SIZE + 10], data[i * PATH_SIZE + 11], data[i * PATH_SIZE + 12]); + else if (data[i * PATH_SIZE] == PATH_B) + printf("PATH B: %d %d %d %d %d %d %d %d %d %d %d %d\n", data[i * PATH_SIZE + 1], data[i * PATH_SIZE + 2], data[i * PATH_SIZE + 3], data[i * PATH_SIZE + 4], data[i * PATH_SIZE + 5], data[i * PATH_SIZE + 6], data[i * PATH_SIZE + 7], data[i * PATH_SIZE + 8], data[i * PATH_SIZE + 9], data[i * PATH_SIZE + 10], data[i * PATH_SIZE + 11], data[i * PATH_SIZE + 12]); + else if (data[i * PATH_SIZE] == PATH_AB) + printf("PATH A+B: %d %d %d %d %d %d %d %d %d %d %d %d\n", data[i * PATH_SIZE + 1], data[i * PATH_SIZE + 2], data[i * PATH_SIZE + 3], data[i * PATH_SIZE + 4], data[i * PATH_SIZE + 5], data[i * PATH_SIZE + 6], data[i * PATH_SIZE + 7], data[i * PATH_SIZE + 8], data[i * PATH_SIZE + 9], data[i * PATH_SIZE + 10], data[i * PATH_SIZE + 11], data[i * PATH_SIZE + 12]); + } + printf("\n"); + +done: + if (buffer) + free(buffer); + if (cmd) + free(cmd); + + return ret; +} +#endif /* #ifdef STA_SUPPORT */ + +/** + * @brief Set/Get beacon interval + * @param argc Number of arguments + * @param argv A pointer to arguments array + * @return MLAN_STATUS_SUCCESS--success, otherwise--fail + */ +static int +process_beacon_interval(int argc, char *argv[]) +{ + int ret = 0, bcninterval = 0; + t_u8 *buffer = NULL; + struct eth_priv_cmd *cmd = NULL; + struct ifreq ifr; + + /* Initialize buffer */ + buffer = (t_u8 *)malloc(BUFFER_LENGTH); + if (!buffer) { + printf("ERR:Cannot allocate buffer for command!\n"); + ret = MLAN_STATUS_FAILURE; + goto done; + } + memset(buffer, 0, BUFFER_LENGTH); + + /* Sanity tests */ + if (argc < 3 || argc > 4) { + printf("Error: invalid no of arguments\n"); + printf("mlanutl mlanX bcninterval [#]\n"); + ret = MLAN_STATUS_FAILURE; + goto done; + } + + prepare_buffer(buffer, argv[2], (argc - 3), &argv[3]); + + cmd = (struct eth_priv_cmd *)malloc(sizeof(struct eth_priv_cmd)); + if (!cmd) { + printf("ERR:Cannot allocate buffer for command!\n"); + ret = MLAN_STATUS_FAILURE; + goto done; + } + + /* Fill up buffer */ +#ifdef USERSPACE_32BIT_OVER_KERNEL_64BIT + memset(cmd, 0, sizeof(struct eth_priv_cmd)); + memcpy(&cmd->buf, &buffer, sizeof(buffer)); +#else + cmd->buf = buffer; +#endif + cmd->used_len = 0; + cmd->total_len = BUFFER_LENGTH; + + /* Perform IOCTL */ + memset(&ifr, 0, sizeof(struct ifreq)); + strncpy(ifr.ifr_ifrn.ifrn_name, dev_name, strlen(dev_name)); + ifr.ifr_ifru.ifru_data = (void *)cmd; + + if (ioctl(sockfd, MLAN_ETH_PRIV, &ifr)) { + perror("mlanutl"); + fprintf(stderr, "mlanutl: bcninterval fail\n"); + ret = MLAN_STATUS_FAILURE; + goto done; + } + + /* Process result */ + memcpy(&bcninterval, buffer, sizeof(bcninterval)); + printf("Beacon interval is %d\n", bcninterval); + +done: + if (buffer) + free(buffer); + if (cmd) + free(cmd); + + return ret; +} + +/** + * @brief Get/Set inactivity timeout extend + * + * @param argc Number of arguments + * @param argv Pointer to the arguments array + * + * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_FAILURE + */ +static int +process_inactivity_timeout_ext(int argc, char *argv[]) +{ + t_u8 *buffer = NULL; + struct eth_priv_cmd *cmd; + int data[4]; + struct ifreq ifr; + + /* Check if arguments are valid */ + if ((argc != 3) && (argc != 6) && (argc != 7)) { + printf("ERR: Invalid arguments\n"); + return MLAN_STATUS_FAILURE; + } + + /* Initialize buffer */ + buffer = (t_u8 *)malloc(BUFFER_LENGTH); + if (!buffer) { + printf("ERR:Cannot allocate buffer for command!\n"); + return MLAN_STATUS_FAILURE; + } + + prepare_buffer(buffer, argv[2], (argc - 3), &argv[3]); + + cmd = (struct eth_priv_cmd *)malloc(sizeof(struct eth_priv_cmd)); + if (!cmd) { + printf("ERR:Cannot allocate buffer for command!\n"); + free(buffer); + return MLAN_STATUS_FAILURE; + } + + /* Fill up buffer */ +#ifdef USERSPACE_32BIT_OVER_KERNEL_64BIT + memset(cmd, 0, sizeof(struct eth_priv_cmd)); + memcpy(&cmd->buf, &buffer, sizeof(buffer)); +#else + cmd->buf = buffer; +#endif + cmd->used_len = 0; + cmd->total_len = BUFFER_LENGTH; + + /* Perform IOCTL */ + memset(&ifr, 0, sizeof(struct ifreq)); + strncpy(ifr.ifr_ifrn.ifrn_name, dev_name, strlen(dev_name)); + ifr.ifr_ifru.ifru_data = (void *)cmd; + + if (ioctl(sockfd, MLAN_ETH_PRIV, &ifr)) { + perror("mlanutl"); + fprintf(stderr, "mlanutl: inactivityto fail\n"); + if (cmd) + free(cmd); + if (buffer) + free(buffer); + return MLAN_STATUS_FAILURE; + } + + /* GET operation */ + if (argc == 3) { + memset(data, 0, sizeof(data)); + memcpy(data, buffer, sizeof(data)); + printf("Timeout unit is %d us\n" + "Inactivity timeout for unicast data is %d ms\n" + "Inactivity timeout for multicast data is %d ms\n" + "Inactivity timeout for new Rx traffic is %d ms\n", + data[0], data[1], data[2], data[3]); + } + + if (buffer) + free(buffer); + if (cmd) + free(cmd); + + return MLAN_STATUS_SUCCESS; +} + +/** + * @brief Get chnrgpwr + * + * @param argc Number of arguments + * @param argv Pointer to the arguments array + * + * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_FAILURE + */ +static int +get_chnrgpwr(FILE * fp_raw, char *argv[], t_u8 *buffer, t_u16 len, + struct eth_priv_cmd *cmd) +{ + struct ifreq ifr; + mlan_ds_misc_chnrgpwr_cfg *chnrgpwr_cfg = NULL; + int i = 0; + int j = 0; + + memset(buffer, 0, len); + /* Insert command */ + strncpy((char *)buffer, argv[2], strlen(argv[2])); + chnrgpwr_cfg = (mlan_ds_misc_chnrgpwr_cfg *) (buffer + strlen(argv[2])); + if (cmd) { + /* Fill up buffer */ +#ifdef USERSPACE_32BIT_OVER_KERNEL_64BIT + memset(cmd, 0, sizeof(struct eth_priv_cmd)); + memcpy(&cmd->buf, &buffer, sizeof(buffer)); +#else + cmd->buf = buffer; +#endif + cmd->used_len = 0; + cmd->total_len = len; + } + /* Perform IOCTL */ + memset(&ifr, 0, sizeof(struct ifreq)); + strncpy(ifr.ifr_ifrn.ifrn_name, dev_name, strlen(dev_name)); + ifr.ifr_ifru.ifru_data = (void *)cmd; + + if (ioctl(sockfd, MLAN_ETH_PRIV, &ifr)) { + perror("mlanutl"); + fprintf(stderr, "mlanutl: get_chnrgpwr fail\n"); + return MLAN_STATUS_FAILURE; + } + /* Process result */ + printf("Get region channel power table: len=%d\n", + chnrgpwr_cfg->length); + if (fp_raw) { + i = j = 0; + while (i < chnrgpwr_cfg->length) { + for (j = 0; j < 16; j++) { + fprintf(fp_raw, "%02x ", + chnrgpwr_cfg->chnrgpwr_buf[i]); + if (++i >= chnrgpwr_cfg->length) + break; + } + fputc('\n', fp_raw); + } + } + return MLAN_STATUS_SUCCESS; +} + +/** + * @brief Process Get region code channel power + * + * @param argc Number of arguments + * @param argv Pointer to the arguments array + * + * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_FAILURE + */ +static int +process_get_chnrgpwr(int argc, char *argv[]) +{ + t_u8 *buffer = NULL; + struct eth_priv_cmd *cmd = NULL; + int ret = MLAN_STATUS_SUCCESS; + FILE *fp_raw = NULL; + + /* Initialize buffer */ + buffer = (t_u8 *)malloc(sizeof(mlan_ds_misc_chnrgpwr_cfg) + + strlen(argv[2])); + if (!buffer) { + printf("ERR:Cannot allocate buffer for command!\n"); + ret = MLAN_STATUS_FAILURE; + goto done; + } + memset(buffer, 0, sizeof(mlan_ds_misc_chnrgpwr_cfg) + strlen(argv[2])); + /* Sanity tests */ + if (argc < 4) { + printf("Error: invalid no of arguments\n"); + printf("mlanutl mlanX/uapX get_chnrgpwr logfile_name\n"); + ret = MLAN_STATUS_FAILURE; + goto done; + } + cmd = (struct eth_priv_cmd *)malloc(sizeof(struct eth_priv_cmd)); + if (!cmd) { + printf("ERR:Cannot allocate buffer for command!\n"); + ret = MLAN_STATUS_FAILURE; + goto done; + } + fp_raw = fopen(argv[3], "w"); + if (fp_raw == NULL) { + fprintf(stderr, + "Cannot open the destination raw_data file %s\n", + argv[4]); + ret = MLAN_STATUS_FAILURE; + goto done; + } + ret = get_chnrgpwr(fp_raw, argv, buffer, + sizeof(mlan_ds_misc_chnrgpwr_cfg) + strlen(argv[2]), + cmd); +done: + if (fp_raw) + fclose(fp_raw); + if (buffer) + free(buffer); + if (cmd) + free(cmd); + return ret; +} + +/** + * @brief Get txpwrlimit + * + * @param argc Number of arguments + * @param argv Pointer to the arguments array + * + * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_FAILURE + */ +static int +get_txpwrlimit(FILE * fp_raw, char *argv[], t_u16 sub_band, t_u8 *buffer, + t_u16 len, struct eth_priv_cmd *cmd) +{ + struct ifreq ifr; + mlan_ds_misc_chan_trpc_cfg *trcp_cfg = NULL; + MrvlIETypes_ChanTRPCConfig_t *trpc_tlv = NULL; + MrvlIEtypes_Data_t *pTlvHdr; + int left_len; + int mod_num = 0; + int i = 0; + int j = 0; + t_u8 *pByte = NULL; + + memset(buffer, 0, len); + /* Insert command */ + strncpy((char *)buffer, argv[2], strlen(argv[2])); + trcp_cfg = (mlan_ds_misc_chan_trpc_cfg *) (buffer + strlen(argv[2])); + trcp_cfg->sub_band = sub_band; + if (cmd) { + /* Fill up buffer */ +#ifdef USERSPACE_32BIT_OVER_KERNEL_64BIT + memset(cmd, 0, sizeof(struct eth_priv_cmd)); + memcpy(&cmd->buf, &buffer, sizeof(buffer)); +#else + cmd->buf = buffer; +#endif + cmd->used_len = 0; + cmd->total_len = len; + } + /* Perform IOCTL */ + memset(&ifr, 0, sizeof(struct ifreq)); + strncpy(ifr.ifr_ifrn.ifrn_name, dev_name, strlen(dev_name)); + ifr.ifr_ifru.ifru_data = (void *)cmd; + + if (ioctl(sockfd, MLAN_ETH_PRIV, &ifr)) { + perror("mlanutl"); + fprintf(stderr, "mlanutl: get_txpwrlimit fail\n"); + if (cmd) + free(cmd); + if (buffer) + free(buffer); + return MLAN_STATUS_FAILURE; + } + /* Process result */ + printf("------------------------------------------------------------------------------------\n"); + printf("Get txpwrlimit: sub_band=0x%x len=%d\n", trcp_cfg->sub_band, + trcp_cfg->length); + pByte = trcp_cfg->trpc_buf + S_DS_GEN + 4; + left_len = trcp_cfg->length - S_DS_GEN - 4; + while (left_len >= sizeof(pTlvHdr->header)) { + pTlvHdr = (MrvlIEtypes_Data_t *)pByte; + pTlvHdr->header.len = le16_to_cpu(pTlvHdr->header.len); + + switch (le16_to_cpu(pTlvHdr->header.type)) { + case TLV_TYPE_CHAN_TRPC_CONFIG: + trpc_tlv = (MrvlIETypes_ChanTRPCConfig_t *) pTlvHdr; + printf("StartFreq: %d\n", trpc_tlv->start_freq); + printf("ChanWidth: %d\n", trpc_tlv->width); + printf("ChanNum: %d\n", trpc_tlv->chan_num); + mod_num = + (pTlvHdr->header.len - + 4) / sizeof(mod_group_setting); + printf("Pwr:"); + for (i = 0; i < mod_num; i++) { + if (i == (mod_num - 1)) + printf("%d,%d", + trpc_tlv->mod_group[i].mod_group, + trpc_tlv->mod_group[i].power); + else + printf("%d,%d,", + trpc_tlv->mod_group[i].mod_group, + trpc_tlv->mod_group[i].power); + } + printf("\n"); + break; + default: + break; + } + left_len -= (pTlvHdr->header.len + sizeof(pTlvHdr->header)); + pByte += pTlvHdr->header.len + sizeof(pTlvHdr->header); + } + if (fp_raw) { + switch (sub_band) { + case 0: + fprintf(fp_raw, "txpwrlimit_2g_get={\n"); + break; + case 0x10: + fprintf(fp_raw, "txpwrlimit_5g_sub0_get={\n"); + break; + case 0x11: + fprintf(fp_raw, "txpwrlimit_5g_sub1_get={\n"); + break; + case 0x12: + fprintf(fp_raw, "txpwrlimit_5g_sub2_get={\n"); + break; + default: + break; + } + i = j = 0; + while (i < trcp_cfg->length) { + for (j = 0; j < 16; j++) { + fprintf(fp_raw, "%02x ", trcp_cfg->trpc_buf[i]); + if (++i >= trcp_cfg->length) + break; + } + fputc('\n', fp_raw); + } + fprintf(fp_raw, "}\n\n"); + } + return MLAN_STATUS_SUCCESS; +} + +/** + * @brief Get txpwrlimit + * + * @param argc Number of arguments + * @param argv Pointer to the arguments array + * + * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_FAILURE + */ +static int +process_get_txpwrlimit(int argc, char *argv[]) +{ + t_u8 *buffer = NULL; + struct eth_priv_cmd *cmd = NULL; + int ret = MLAN_STATUS_SUCCESS; + t_u16 sub_band = 0; + FILE *fp_raw = NULL; + + /* Initialize buffer */ + buffer = (t_u8 *)malloc(sizeof(mlan_ds_misc_chan_trpc_cfg) + + strlen(argv[2])); + if (!buffer) { + printf("ERR:Cannot allocate buffer for command!\n"); + ret = MLAN_STATUS_FAILURE; + goto done; + } + memset(buffer, 0, sizeof(mlan_ds_misc_chan_trpc_cfg) + strlen(argv[2])); + /* Sanity tests */ + if (argc < 4) { + printf("Error: invalid no of arguments\n"); + printf("mlanutl mlanX/uapX get_txpwrlimit [0/0x10/0x11/0x12/0x1f/0xff]\n"); + ret = MLAN_STATUS_FAILURE; + goto done; + } + cmd = (struct eth_priv_cmd *)malloc(sizeof(struct eth_priv_cmd)); + if (!cmd) { + printf("ERR:Cannot allocate buffer for command!\n"); + ret = MLAN_STATUS_FAILURE; + goto done; + } + sub_band = a2hex_or_atoi(argv[3]); + if (argc == 5) { + fp_raw = fopen(argv[4], "w"); + if (fp_raw == NULL) { + fprintf(stderr, + "Cannot open the destination raw_data file %s\n", + argv[4]); + ret = MLAN_STATUS_FAILURE; + goto done; + } + } + switch (sub_band) { + case 0: + case 0x10: + case 0x11: + case 0x12: + ret = get_txpwrlimit(fp_raw, argv, sub_band, buffer, + sizeof(mlan_ds_misc_chan_trpc_cfg) + + strlen(argv[2]), cmd); + break; + case 0x1f: + ret = get_txpwrlimit(fp_raw, argv, 0x10, buffer, + sizeof(mlan_ds_misc_chan_trpc_cfg) + + strlen(argv[2]), cmd); + ret = get_txpwrlimit(fp_raw, argv, 0x11, buffer, + sizeof(mlan_ds_misc_chan_trpc_cfg) + + strlen(argv[2]), cmd); + ret = get_txpwrlimit(fp_raw, argv, 0x12, buffer, + sizeof(mlan_ds_misc_chan_trpc_cfg) + + strlen(argv[2]), cmd); + break; + case 0xff: + ret = get_txpwrlimit(fp_raw, argv, 0, buffer, + sizeof(mlan_ds_misc_chan_trpc_cfg) + + strlen(argv[2]), cmd); + ret = get_txpwrlimit(fp_raw, argv, 0x10, buffer, + sizeof(mlan_ds_misc_chan_trpc_cfg) + + strlen(argv[2]), cmd); + ret = get_txpwrlimit(fp_raw, argv, 0x11, buffer, + sizeof(mlan_ds_misc_chan_trpc_cfg) + + strlen(argv[2]), cmd); + ret = get_txpwrlimit(fp_raw, argv, 0x12, buffer, + sizeof(mlan_ds_misc_chan_trpc_cfg) + + strlen(argv[2]), cmd); + break; + default: + printf("Error: invalid arguments\n"); + printf("mlanutl mlanX/uapX get_txpwrlimit [0/0x10/0x11/0x12/0x1f/0xff]\n"); + break; + } +done: + if (fp_raw) + fclose(fp_raw); + if (buffer) + free(buffer); + if (cmd) + free(cmd); + return ret; +} + +/** + * @brief get hostcmd data + * + * @param ln A pointer to line number + * @param buf A pointer to hostcmd data + * @param size A pointer to the return size of hostcmd buffer + * @return MLAN_STATUS_SUCCESS + */ +static int +get_hostcmd_raw_data(FILE * fp, int *ln, t_u8 *buf, t_u16 *size) +{ + char line[512], *pos; + char *ptr = NULL; + t_u8 *dptr = NULL; + + dptr = buf; + while ((pos = mlan_config_get_line(fp, line, sizeof(line), ln))) { + (*ln)++; + if (strcmp(pos, "}") == 0) { + break; + } + ptr = line; + while (*ptr) { + /* skip leading spaces */ + while (*ptr && (isspace(*ptr) || *ptr == '\t')) + ptr++; + + /* skip blank lines and lines beginning with '#' */ + if (*ptr == '\0' || *ptr == '#') + break; + + if (isxdigit(*ptr)) { + ptr = convert2hex(ptr, dptr++); + } else { + /* Invalid character on data line */ + ptr++; + } + } + } + *size = dptr - buf; + return MLAN_STATUS_SUCCESS; +} + +/** + * @brief parse the trpc command raw data and fill in trpc table. + * + * @param trpc_raw_data trpc hostcmd raw data + * @param length total length of trcp raw data + * @param trcp_buf trpc table buffer + * @param max_chan max channel number support in trpc table + * @param chan_idx index in trcp table + * @param cmd_no buffer pointer to return cmd_no + * @param cmd_act buffer pointer to return cmd_action. + * @return next index in trpc table + */ +int +parse_trpc_raw_data(t_u8 *trpc_raw_data, t_u16 length, t_u8 *trpc_buf, + t_u8 max_chan, int *chan_idx, t_u16 *cmd_no, t_u16 *cmd_act) +{ + MrvlIETypes_ChanTRPCConfig_t *trpc_tlv = NULL; + MrvlIEtypes_Data_t *pTlvHdr; + int left_len; + t_u8 *pByte = NULL; + int idx = *chan_idx; + ChanTRPCConfig_t *pchan_trpc = + (ChanTRPCConfig_t *) ((t_u8 *)trpc_buf + + idx * sizeof(ChanTRPCConfig_t)); + *cmd_no = le16_to_cpu(*(t_u16 *)trpc_raw_data); + *cmd_act = le16_to_cpu(*(t_u16 *)(trpc_raw_data + S_DS_GEN)); + + pByte = trpc_raw_data + S_DS_GEN + 4; + left_len = length - S_DS_GEN - 4; + while (left_len >= sizeof(pTlvHdr->header)) { + if (idx >= max_chan) { + printf("trpc buf too small, idx=%d\n", idx); + break; + } + pTlvHdr = (MrvlIEtypes_Data_t *)pByte; + pTlvHdr->header.len = le16_to_cpu(pTlvHdr->header.len); + + switch (le16_to_cpu(pTlvHdr->header.type)) { + case TLV_TYPE_CHAN_TRPC_CONFIG: + trpc_tlv = (MrvlIETypes_ChanTRPCConfig_t *) pTlvHdr; + memset(pchan_trpc->mod_group, 0xff, + sizeof(pchan_trpc->mod_group)); + memcpy(&pchan_trpc->start_freq, &trpc_tlv->start_freq, + pTlvHdr->header.len); + idx++; + pchan_trpc++; + break; + default: + break; + } + left_len -= (pTlvHdr->header.len + sizeof(pTlvHdr->header)); + pByte += pTlvHdr->header.len + sizeof(pTlvHdr->header); + } + *chan_idx = idx; + return idx; +} + +/** + * @brief get trpc data from file and fill in trpc table. + * + * @param fp file handle for trpc file + * @param trpc_buf trpc table buffer + * @param max_chan max channel supported in trpc table + * @param get_flag only allow action get in the raw data + * @return num_of channel filled in trpc table + */ +int +get_trpc_data(FILE * fp, t_u8 *trpc_buf, t_u8 max_chan, t_u8 get_flag) +{ + char line[256], *pos; + int ln = 0; + t_u8 *buffer = NULL; + t_u16 size = BUFFER_LENGTH; + int chan_idx = 0; + t_u16 cmd_act = 0; + t_u16 cmd_no = 0; + + buffer = (t_u8 *)malloc(BUFFER_LENGTH); + if (!buffer) { + printf("ERR:Cannot allocate buffer for command!\n"); + goto done; + } + while ((pos = mlan_config_get_line(fp, line, sizeof(line), &ln))) { + if (strstr(pos, "={")) { + get_hostcmd_raw_data(fp, &ln, buffer, &size); + parse_trpc_raw_data(buffer, size, trpc_buf, max_chan, + &chan_idx, &cmd_no, &cmd_act); + if (cmd_no != HostCmd_CHANNEL_TRPC_CONFIG) { + chan_idx = 0; + printf("Invalid cmd_no 0x%x cmd act=%d in file\n", cmd_no, (int)cmd_act); + break; + } + } + } +done: + if (buffer) + free(buffer); + return chan_idx; +} + +/** + * @brief find the same chanTrpc on another table + * + * @param trpc_buf trpc table buffer + * @param nun_chan num of chan in trpc table buffer + * @param chan channel number + * @return NULL or find chan_trpc entry in the table + */ +ChanTRPCConfig_t * +get_trpc_entry(t_u8 *trpc_buf, t_u8 num_chan, t_u8 chan) +{ + int i = 0; + int find = 0; + ChanTRPCConfig_t *pentry; + pentry = (ChanTRPCConfig_t *) trpc_buf; + for (i = 0; i < num_chan; i++) { + if (pentry->chan_num == chan) { + find = 1; + break; + } + pentry++; + } + if (find) + return pentry; + else + return NULL; +} + +/** + * @brief get max mod_group in trpbc table + * + * @param trpc_buf trpc table buffer + * @param nun_chan num of chan in trpc table buffer + * @return max mod_group number + */ +t_u8 +get_max_mod_group(t_u8 *trpc_buf, t_u8 num_chan) +{ + t_u8 max_mod_group = 0; + int i, j; + ChanTRPCConfig_t *pentry; + pentry = (ChanTRPCConfig_t *) trpc_buf; + for (i = 0; i < num_chan; i++) { + for (j = 0; j < MAX_MOD_GROUP; j++) { + if (pentry->mod_group[j].mod_group == 0xff) + break; + if (pentry->mod_group[j].mod_group > max_mod_group) + max_mod_group = pentry->mod_group[j].mod_group; + } + pentry++; + } + return max_mod_group; +} + +/** + * @brief get mod_group setting for specifc mod_group + * + * @param pchan_trpc a pointer to channel trpc setting + * @param pmod_group a point to mod_group setting. + * @return NULL or the pointer to specfic mod_group setting. + */ +mod_group_setting * +get_chan_mod_group(ChanTRPCConfig_t * pchan_trpc, + mod_group_setting * pmod_group) +{ + int i; + for (i = 0; i < MAX_MOD_GROUP; i++) { + if (pchan_trpc->mod_group[i].mod_group == 0xff) + break; + if (pmod_group->mod_group == pchan_trpc->mod_group[i].mod_group) { + return &pchan_trpc->mod_group[i]; + } + } + return NULL; +} + +/** + * @brief get the power for specifc mod_group + * + * @param pchan_trpc a pointer to channel trpc setting + * @param pmod_group mod group value + * @return the power of specific mod group. + */ +t_u8 +get_mod_power(ChanTRPCConfig_t * pchan_trpc, t_u8 mod_group) +{ + int i; + for (i = 0; i < MAX_MOD_GROUP; i++) { + if (pchan_trpc->mod_group[i].mod_group == 0xff) + break; + if (pchan_trpc->mod_group[i].mod_group == mod_group) { + return pchan_trpc->mod_group[i].power; + } + } + return 0xff; +} + +/** + * @brief compare to chan_trpc entry + * + * @param psrc_entry pointer to chan_trpc entry in src file + * @param ptarget_entry pointer to the target chan_trpc entry to compare + * @return 0 - match or 1 + */ +int +check_chan_trpc_error(ChanTRPCConfig_t * psrc_entry, + ChanTRPCConfig_t * ptarget_entry, t_u8 min_mod_group, + t_u8 max_mod_group) +{ + int diff = 0; + int i = 0; + mod_group_setting *pmod_group = NULL; + if (psrc_entry->start_freq != ptarget_entry->start_freq) + diff++; + if (psrc_entry->width != ptarget_entry->width) + diff++; + for (i = min_mod_group; i <= max_mod_group; i++) { + if (psrc_entry->mod_group[i].mod_group == 0xff) + break; + pmod_group = + get_chan_mod_group(ptarget_entry, + &psrc_entry->mod_group[i]); + if (!pmod_group) + diff++; + else if (pmod_group->power != psrc_entry->mod_group[i].power) + diff++; + } + if (diff) + return 1; + else + return 0; +} + +/** + * @brief display and compare to chan_trpc entry + * + * @param psrc_entry pointer to chan_trpc entry in src file + * @param ptarget_entry pointer to the target chan_trpc entry to compare + * @return 0 - match or 1 + */ +int +compare_and_display_chan_trpc(ChanTRPCConfig_t * psrc_entry, + ChanTRPCConfig_t * ptarget_entry) +{ + int diff = 0; + int i = 0; + mod_group_setting *pmod_group = NULL; + if (psrc_entry && ptarget_entry) { + if (psrc_entry->start_freq != ptarget_entry->start_freq) + diff++; + if (psrc_entry->width != ptarget_entry->width) + diff++; + for (i = 0; i < MAX_MOD_GROUP; i++) { + if (psrc_entry->mod_group[i].mod_group == 0xff) + break; + pmod_group = + get_chan_mod_group(ptarget_entry, + &psrc_entry->mod_group[i]); + if (pmod_group && + (pmod_group->power == + psrc_entry->mod_group[i].power)) { + printf("ch:%03d startfreq:%04d width:%02d mod:%02d power:%02d %02d PASS\n", (int)psrc_entry->chan_num, (int)psrc_entry->start_freq, (int)psrc_entry->width, (int)psrc_entry->mod_group[i].mod_group, (int)pmod_group->power, (int)psrc_entry->mod_group[i].power); + } else if (pmod_group) { + printf("ch:%03d startfreq:%04d width:%02d mod:%02d power:%02d %02d FAIL\n", (int)psrc_entry->chan_num, (int)psrc_entry->start_freq, (int)psrc_entry->width, (int)psrc_entry->mod_group[i].mod_group, (int)pmod_group->power, (int)psrc_entry->mod_group[i].power); + diff++; + } else { + printf("ch:%03d startfreq:%04d width:%02d mod:%02d power:%02d NOT FOUND\n", (int)psrc_entry->chan_num, (int)psrc_entry->start_freq, (int)psrc_entry->width, (int)psrc_entry->mod_group[i].mod_group, (int)psrc_entry->mod_group[i].power); + diff++; + } + } + } else if (psrc_entry) { + printf("-------------------------------------------------------------------------------------------\n"); + printf("Missing expected channel %d TRPC setting in target file\n", psrc_entry->chan_num); + printf("ch:%03d startfreq:%04d width:%02d Pwr:", + (int)psrc_entry->chan_num, (int)psrc_entry->start_freq, + (int)psrc_entry->width); + for (i = 0; i < MAX_MOD_GROUP; i++) { + if (psrc_entry->mod_group[i].mod_group == 0xff) + break; + if (i == 0) + printf("%d,%d", + psrc_entry->mod_group[i].mod_group, + psrc_entry->mod_group[i].power); + else + printf(",%d,%d", + psrc_entry->mod_group[i].mod_group, + psrc_entry->mod_group[i].power); + } + printf("\n"); + printf("-------------------------------------------------------------------------------------------\n"); + diff++; + } + if (diff) + return 1; + else + return 0; +} + +/** + * @brief get channel list in 2 trpc table + * + * @param target_trpc_buf trpc buf from target file + * @param target_chan_num num of channe in target file + * @param src_trpc_buf trpc buf from src file + * @param src_chan_num num of channel in src file + * @param chan_flag 0- all channel 1--5g only + * @return num of total channel in src trpc buf and target trpc buf +*/ +int +get_trpc_channel_list(t_u8 *target_trpc_buf, t_u8 target_chan_num, + t_u8 *src_trpc_buf, t_u8 src_chan_num, t_u8 *pchan, + t_u8 chan_size, t_u8 chan_flag) +{ + ChanTRPCConfig_t *ptarget_entry = NULL; + ChanTRPCConfig_t *psrc_entry = NULL; + int target_chan_left = target_chan_num; + int src_chan_left = src_chan_num; + int total_chan = 0; + int i = 0; + + memset(pchan, 0, chan_size); + ptarget_entry = (ChanTRPCConfig_t *) target_trpc_buf; + psrc_entry = (ChanTRPCConfig_t *) src_trpc_buf; + + if (chan_flag) { + for (i = 0; i < target_chan_num; i++) { + if (ptarget_entry->chan_num > MAX_BG_CHANNEL) + break; + ptarget_entry++; + target_chan_left--; + } + for (i = 0; i < src_chan_num; i++) { + if (psrc_entry->chan_num > MAX_BG_CHANNEL) + break; + psrc_entry++; + src_chan_left--; + } + if (src_chan_left <= 0) + psrc_entry = NULL; + if (target_chan_left <= 0) + ptarget_entry = NULL; + } + while (1) { + if (!target_chan_left && !src_chan_left) + break; + if (ptarget_entry && psrc_entry) { + if (ptarget_entry->chan_num == psrc_entry->chan_num) { + *pchan = ptarget_entry->chan_num; + pchan++; + total_chan++; + ptarget_entry++; + psrc_entry++; + target_chan_left--; + src_chan_left--; + } else if (ptarget_entry->chan_num < + psrc_entry->chan_num) { + *pchan = ptarget_entry->chan_num; + pchan++; + total_chan++; + ptarget_entry++; + target_chan_left--; + } else { + *pchan = psrc_entry->chan_num; + pchan++; + total_chan++; + psrc_entry++; + src_chan_left--; + } + } else if (ptarget_entry) { + *pchan = ptarget_entry->chan_num; + pchan++; + total_chan++; + ptarget_entry++; + target_chan_left--; + } else if (psrc_entry) { + *pchan = psrc_entry->chan_num; + pchan++; + total_chan++; + psrc_entry++; + src_chan_left--; + } + if (src_chan_left <= 0) + psrc_entry = NULL; + if (target_chan_left <= 0) + ptarget_entry = NULL; + } + return total_chan; +} + +/** + * @brief compare two trpc table's data + * + * @param target_trpc_buf trpc buf from target file + * @param target_chan_num num of channe in target file + * @param src_trpc_buf trpc buf from src file + * @param src_chan_num num of channel in src file + * @param dispaly mode 1: text mode, 2 table mode. + * @return N/A + */ +void +process_trpc_data(t_u8 *target_trpc_buf, t_u8 target_chan_num, + t_u8 *src_trpc_buf, t_u8 src_chan_num, t_u8 display_mode) +{ + int i, j; + t_u32 diff = 0; + t_u16 total_diff = 0; + t_u8 power_target; + t_u8 power_src; + t_u8 max_mod_group_target = 0; + t_u8 max_mod_group_src = 0; + t_u8 total_chan = 0; + t_u8 chan_list[WLAN_IOCTL_USER_SCAN_CHAN_MAX]; + ChanTRPCConfig_t *ptarget_entry = NULL; + ChanTRPCConfig_t *psrc_entry = NULL; + + printf("ModulationGroup:\n"); + printf(" 0: CCK (1,2,5.5,11 Mbps) 1: OFDM (6,9,12,18 Mbps)\n"); + printf(" 2: OFDM (24,36 Mbps) 3: OFDM (48,54 Mbps)\n"); + printf(" 4: HT20 (MCS0,1,2) 5: HT20 (MCS3,4)\n"); + printf(" 6: HT20 (MCS5,6,7) 7: HT40 (MCS0,1,2)\n"); + printf(" 8: HT40 (MCS3,4) 9: HT40 (MCS5,6,7)\n"); + printf("10: HT2_20 (MCS8,9,10) 11: HT2_20 (MCS11,12)\n"); + printf("12: HT2_20 (MCS13,14,15) 13: HT2_40 (MCS8,9,10)\n"); + printf("14: HT2_40 (MCS11,12) 15: HT2_40 (MCS13,14,15)\n"); + printf("16: VHT_QAM256 (MCS8) 17: VHT_40_QAM256 (MCS8,9)\n"); + printf("18: VHT_80_PSK (MCS0,1,2) 19: VHT_80_QAM16 (MCS3,4)\n"); + printf("20: VHT_80_QAM64 (MCS5,6,7) 21: VHT_80_QAM256 (MCS8,9)\n"); + printf("22: VHT2_20_QAM256 (MCS8) 23: VHT2_40_QAM256 (MCS8,9)\n"); + printf("24: VHT2_80_PSK (MCS0,1,2) 25: VHT2_80_QAM16 (MCS3,4)\n"); + printf("26: VHT2_80_QAM64 (MCS5,6,7) 27: VHT2_80_QAM256 (MCS8,9)\n"); + printf("28: HE_20_QAM256 (MCS8,9) 29: HE_20_QAM1024 (MCS10,11)\n"); + printf("30: HE_40_QAM1024 (MCS10,11) 31: HE_80_QAM1024 (MCS10,11)\n"); + printf("32: HE2_20_QAM256 (MCS8,9) 33: HE2_20_QAM1024 (MCS10,11)\n"); + printf("34: HE2_40_QAM1024 (MCS10,11) 35: HE2_80_QAM1024 (MCS10,11)\n"); + printf("\n"); + if (display_mode == 1) { + psrc_entry = (ChanTRPCConfig_t *) src_trpc_buf; + for (i = 0; i < src_chan_num; i++) { + ptarget_entry = + get_trpc_entry(target_trpc_buf, target_chan_num, + psrc_entry->chan_num); + if (ptarget_entry) { + diff += compare_and_display_chan_trpc + (psrc_entry, ptarget_entry); + } else { + diff += compare_and_display_chan_trpc + (psrc_entry, NULL); + } + psrc_entry++; + } + if (diff) + printf("Number of different channel trpc setting:%d in target file\n", diff); + else + printf("PASS\n"); + } else { + printf("Column=ModGroup, Row=Channel, Value=Target,Source\n"); + printf(" CH 00 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15\n"); + ptarget_entry = (ChanTRPCConfig_t *) target_trpc_buf; + total_chan = + get_trpc_channel_list(target_trpc_buf, target_chan_num, + src_trpc_buf, src_chan_num, + chan_list, + WLAN_IOCTL_USER_SCAN_CHAN_MAX, 0); + for (i = 0; i < total_chan; i++) { + ptarget_entry = + get_trpc_entry(target_trpc_buf, target_chan_num, + chan_list[i]); + psrc_entry = + get_trpc_entry(src_trpc_buf, src_chan_num, + chan_list[i]); + diff = 0; + if (psrc_entry && ptarget_entry) + diff = check_chan_trpc_error(psrc_entry, + ptarget_entry, 0, + 15); + else if (psrc_entry) + diff++; + if (diff) + printf("*%03d ", (int)chan_list[i]); + else + printf(" %03d ", (int)chan_list[i]); + for (j = 0; j <= 15; j++) { + if (ptarget_entry) + power_target = + get_mod_power(ptarget_entry, j); + else + power_target = 0xff; + if (psrc_entry) + power_src = + get_mod_power(psrc_entry, j); + else + power_src = 0xff; + if (power_target != 0xff) + printf("%02d", power_target); + else + printf("--"); + if (power_src != 0xff) + printf(",%02d ", power_src); + else + printf(",-- "); + } + if (diff) + total_diff++; + printf("\n"); + } + max_mod_group_target = + get_max_mod_group(target_trpc_buf, target_chan_num); + max_mod_group_src = + get_max_mod_group(src_trpc_buf, src_chan_num); + if (max_mod_group_target > 15 || max_mod_group_src > 15) { + printf(" CH 16 17 18 19 20 21 22 23 24 25 26 27\n"); + ptarget_entry = (ChanTRPCConfig_t *) target_trpc_buf; + total_chan = + get_trpc_channel_list(target_trpc_buf, + target_chan_num, + src_trpc_buf, + src_chan_num, chan_list, + WLAN_IOCTL_USER_SCAN_CHAN_MAX, + 1); + for (i = 0; i < total_chan; i++) { + diff = 0; + ptarget_entry = + get_trpc_entry(target_trpc_buf, + target_chan_num, + chan_list[i]); + psrc_entry = + get_trpc_entry(src_trpc_buf, + src_chan_num, + chan_list[i]); + if (psrc_entry && ptarget_entry) + diff = check_chan_trpc_error(psrc_entry, + ptarget_entry, + 16, 27); + else if (psrc_entry) + diff++; + if (diff) + printf("*%03d ", (int)chan_list[i]); + else + printf(" %03d ", (int)chan_list[i]); + + for (j = 16; j <= 27; j++) { + if (ptarget_entry) + power_target = + get_mod_power + (ptarget_entry, j); + else + power_target = 0xff; + if (psrc_entry) + power_src = + get_mod_power + (psrc_entry, j); + else + power_src = 0xff; + if (power_target != 0xff) + printf("%02d", power_target); + else + printf("--"); + if (power_src != 0xff) + printf(",%02d ", power_src); + else + printf(",-- "); + } + if (diff) + total_diff++; + printf("\n"); + } + } + max_mod_group_target = + get_max_mod_group(target_trpc_buf, target_chan_num); + max_mod_group_src = + get_max_mod_group(src_trpc_buf, src_chan_num); + if (max_mod_group_target > 27 || max_mod_group_src > 27) { + printf(" CH 28 29 30 31 32 33 34 35\n"); + ptarget_entry = (ChanTRPCConfig_t *) target_trpc_buf; + total_chan = + get_trpc_channel_list(target_trpc_buf, + target_chan_num, + src_trpc_buf, + src_chan_num, chan_list, + WLAN_IOCTL_USER_SCAN_CHAN_MAX, + 1); + for (i = 0; i < total_chan; i++) { + diff = 0; + ptarget_entry = + get_trpc_entry(target_trpc_buf, + target_chan_num, + chan_list[i]); + psrc_entry = + get_trpc_entry(src_trpc_buf, + src_chan_num, + chan_list[i]); + if (psrc_entry && ptarget_entry) + diff = check_chan_trpc_error(psrc_entry, + ptarget_entry, + 16, 27); + else if (psrc_entry) + diff++; + if (diff) + printf("*%03d ", (int)chan_list[i]); + else + printf(" %03d ", (int)chan_list[i]); + + for (j = 28; j <= 35; j++) { + if (ptarget_entry) + power_target = + get_mod_power + (ptarget_entry, j); + else + power_target = 0xff; + if (psrc_entry) + power_src = + get_mod_power + (psrc_entry, j); + else + power_src = 0xff; + if (power_target != 0xff) + printf("%02d", power_target); + else + printf("--"); + if (power_src != 0xff) + printf(",%02d ", power_src); + else + printf(",-- "); + } + if (diff) + total_diff++; + printf("\n"); + } + } + if (total_diff) + printf("Number of different channel trpc setting:%d in target file\n", total_diff); + else + printf("PASS\n"); + } + + return; +} + +/** + * @brief Process compare the trpc from 2 bin file + * + * @param argc Number of arguments + * @param argv Pointer to the arguments array + * + * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_FAILURE + */ +static int +process_comparetrpc(int argc, char *argv[]) +{ + FILE *target_fp = NULL; + FILE *src_fp = NULL; + int ret = MLAN_STATUS_SUCCESS; + t_u8 *target_trpc_buf = NULL; + t_u8 *src_trpc_buf = NULL; + t_u8 target_chan_num = WLAN_IOCTL_USER_SCAN_CHAN_MAX; + t_u8 src_chan_num = WLAN_IOCTL_USER_SCAN_CHAN_MAX; + int display_mode = 1; + + if (argc < 5) { + printf("Error: invalid no of arguments\n"); + printf("mlanutl mlanX/uapX comparetrpc target_file src_file 1/2\n"); + ret = MLAN_STATUS_FAILURE; + goto done; + } + if (argc == 6) { + display_mode = a2hex_or_atoi(argv[5]); + if (display_mode != 1 && display_mode != 2) { + printf("Error: invalid display mode\n"); + ret = MLAN_STATUS_FAILURE; + goto done; + } + } + target_fp = fopen(argv[3], "r"); + if (target_fp == NULL) { + perror("target file fopen failed"); + goto done; + } + target_trpc_buf = + (t_u8 *)malloc(sizeof(ChanTRPCConfig_t) * + WLAN_IOCTL_USER_SCAN_CHAN_MAX); + if (!target_trpc_buf) { + printf("ERR:Cannot allocate buffer for target trpc buf!\n"); + goto done; + } + memset(target_trpc_buf, 0, + sizeof(ChanTRPCConfig_t) * WLAN_IOCTL_USER_SCAN_CHAN_MAX); + target_chan_num = + get_trpc_data(target_fp, target_trpc_buf, + WLAN_IOCTL_USER_SCAN_CHAN_MAX, 1); + if (!target_chan_num) { + printf("Invalid target file %s: it should be the raw data file save from get_txpwrlimit command\n", argv[3]); + goto done; + } + src_fp = fopen(argv[4], "r"); + if (src_fp == NULL) { + perror("src file fopen failed"); + goto done; + } + src_trpc_buf = + (t_u8 *)malloc(sizeof(ChanTRPCConfig_t) * + WLAN_IOCTL_USER_SCAN_CHAN_MAX); + if (!src_trpc_buf) { + printf("ERR:Cannot allocate buffer for src trpc buf!\n"); + goto done; + } + memset(src_trpc_buf, 0, + sizeof(ChanTRPCConfig_t) * WLAN_IOCTL_USER_SCAN_CHAN_MAX); + src_chan_num = + get_trpc_data(src_fp, src_trpc_buf, + WLAN_IOCTL_USER_SCAN_CHAN_MAX, 0); + if (!src_chan_num) { + printf("Invalid source file %s: it should be raw data file download to FW during driver init\n", argv[4]); + goto done; + } + printf("Comparing %s to %s\n", argv[3], argv[4]); + process_trpc_data(target_trpc_buf, target_chan_num, src_trpc_buf, + src_chan_num, display_mode); +done: + if (target_fp) + fclose(target_fp); + if (target_trpc_buf) + free(target_trpc_buf); + if (src_fp) + fclose(src_fp); + if (src_trpc_buf) + free(src_trpc_buf); + return ret; +} + +/** + * @brief get source region power data and fill in region power table. + * + * @param fp file handle for region power file + * @param file_size file size; + * @param src_rgpwr_buf power table buffer + + * @return 0 -- success else failure + */ +int +get_src_rgpwr_data(FILE * src_fp, int file_size, + region_chan_pwr_tbl * rgchnpwr_tbl) +{ + t_u8 *tmp_buf = NULL; + int ret = 0; + t_u8 *pdata = NULL; + int left_size = file_size; + mfg_rghdr_t *rghdr = NULL; + mfg_rgdatahdr_t *rgdatahdr = NULL; + int max_chan_bg = 14; + int max_chan_a = 0; + int max_power_bg = 0; + int max_power_a = 0; + int i = 0; + + tmp_buf = (t_u8 *)malloc(file_size); + if (!tmp_buf) { + printf("fail to alloc temp buf, size=%d\n", file_size); + return -EFAULT; + } + if (fread(tmp_buf, sizeof(t_u8), file_size, src_fp) == 0) { + printf("ERR:read source image failed!\n"); + ret = -EFAULT; + goto done; + } + //hexdump("Uncompressed data", tmp_buf, file_size, ' '); + pdata = tmp_buf; + rghdr = (mfg_rghdr_t *) pdata; + if (rghdr->identifier != OTP_IDENTIFIER) { + ret = -EFAULT; + printf("ERR: Invalid identifier in uncompressed file 0x%x\n", + rghdr->identifier); + goto done; + } + rgchnpwr_tbl->ptbaseversion = rghdr->ptbaseversion; + left_size -= sizeof(mfg_rghdr_t); + pdata += sizeof(mfg_rghdr_t); + rgdatahdr = (mfg_rgdatahdr_t *) pdata; + memcpy(&rgchnpwr_tbl->countrycode, &rgdatahdr->countrycode, + sizeof(rgchnpwr_tbl->countrycode)); + rgchnpwr_tbl->environment = rgdatahdr->environment; + rgchnpwr_tbl->regioncode = rgdatahdr->regioncode; + left_size -= sizeof(mfg_rgdatahdr_t); + pdata += sizeof(mfg_rgdatahdr_t); + switch (rghdr->ptbaseversion) { + case PTVER_2X2_AC: + max_chan_a = 39; + max_power_a = 28; + max_power_bg = 16; + break; + case PTVER_1X1_AC: + max_chan_a = 39; + max_power_a = 16; + max_power_bg = 10; + break; + case PTVER_2X2_N: + max_chan_a = 39; + max_power_a = 16; + max_power_bg = 16; + break; + case PTVER_1X1_N: + max_chan_a = 39; + max_power_a = 10; + max_power_bg = 10; + break; + case PTVER_1X1_AC_11P: + max_chan_a = 40; + max_power_a = 16; + max_power_bg = 10; + break; + case PTVER_2X2_AC_2GVHT: + max_chan_a = 39; + max_power_a = 28; + max_power_bg = 24; + break; + case PTVER_1X1_AC_2GVHT: + max_chan_a = 39; + max_power_a = 16; + max_power_bg = 12; + break; + case PTVER_1X1_AC_2GVHT_11P: + max_chan_a = 40; + max_power_a = 16; + max_power_bg = 12; + break; + } + rgchnpwr_tbl->max_chan_bg = max_chan_bg; + rgchnpwr_tbl->max_chan_a = max_chan_a; + rgchnpwr_tbl->max_power_a = max_power_a; + rgchnpwr_tbl->max_power_bg = max_power_bg; + if (left_size < ((max_power_bg + 1) * max_chan_bg)) { + printf("ERR: left size not enough for 2g\n"); + goto done; + } + for (i = 0; i < max_chan_bg; i++) { + rgchnpwr_tbl->bg_pwr_tbl[i].chan_no = *pdata; + pdata++; + memset(rgchnpwr_tbl->bg_pwr_tbl[i].pwr, 0xff, + MAX_MCS_POWER_INDEX); + memcpy(rgchnpwr_tbl->bg_pwr_tbl[i].pwr, pdata, max_power_bg); + pdata += max_power_bg; + } + left_size -= (max_power_bg + 1) * max_chan_bg; + if (left_size < ((max_power_a + 1) * max_chan_a)) { + printf("ERR: left size not enough for 5g\n"); + goto done; + } + for (i = 0; i < max_chan_a; i++) { + rgchnpwr_tbl->a_pwr_tbl[i].chan_no = *pdata; + pdata++; + memset(rgchnpwr_tbl->a_pwr_tbl[i].pwr, 0xff, + MAX_MCS_POWER_INDEX); + memcpy(rgchnpwr_tbl->a_pwr_tbl[i].pwr, pdata, max_power_a); + pdata += max_power_a; + } + left_size -= (max_power_a + 1) * max_chan_a; + if (left_size < max_chan_bg + max_chan_a) { + printf("ERR: left size not enough for chan attr\n"); + goto done; + } + for (i = 0; i < max_chan_bg; i++) { + rgchnpwr_tbl->bg_pwr_tbl[i].chan_attr = *pdata; + pdata++; + } + for (i = 0; i < max_chan_a; i++) { + rgchnpwr_tbl->a_pwr_tbl[i].chan_attr = *pdata; + pdata++; + } + left_size -= max_chan_bg + max_chan_a; + if (left_size) + printf("ERR: left_size=%d\n", left_size); +done: + if (tmp_buf) + free(tmp_buf); + return ret; +} + +/** + * @brief get FW region power table + * + * @param fp file handle for region power file + * @param rgchnpwr_tbl a pointer to regchnpwr tbl + * + * @return 0 -- success else failure + */ +int +get_fw_rgpwr_data(FILE * fp, region_chan_pwr_tbl * rgchnpwr_tbl) +{ + int ln = 0; + int i; + t_u8 *buffer = NULL; + t_u8 *tlv_buf = NULL; + t_u16 size = BUFFER_LENGTH; + int ret = 0; + HostCmd_DS_GEN *hostcmd = NULL; + t_u16 tlv_buf_left = 0; + t_u16 tlv_type, tlv_len; + MrvlIEtypesHeader_t *tlv; + MrvlIEtypes_otp_region_info_t *rginfo_tlv; + MrvlIEtypes_power_table_attr_t *pwr_tbl_attr_tlv; + MrvlIEtypes_chan_attr_t *chan_attr_tlv; + MrvlIEtypes_power_table_t *power_tlv; + t_u8 *pdata = NULL; + chan_power_t *power = NULL; + + buffer = (t_u8 *)malloc(BUFFER_LENGTH); + if (!buffer) { + printf("ERR:Cannot allocate buffer for command!\n"); + goto done; + } + get_hostcmd_raw_data(fp, &ln, buffer, &size); + //hexdump("cmdresp", buffer,size, ' '); + hostcmd = (HostCmd_DS_GEN *)buffer; + hostcmd->command = le16_to_cpu(hostcmd->command); + hostcmd->size = le16_to_cpu(hostcmd->size); + if (hostcmd->command != HostCmd_CMD_CHAN_REGION_CFG) { + printf("ERR: target file don't have the hostcmd id 0x242\n"); + ret = -EFAULT; + goto done; + } + tlv_buf_left = hostcmd->size - S_DS_GEN - sizeof(t_u16); + tlv_buf = buffer + S_DS_GEN + sizeof(t_u16); + while (tlv_buf_left >= sizeof(MrvlIEtypesHeader_t)) { + tlv = (MrvlIEtypesHeader_t *)tlv_buf; + tlv_type = le16_to_cpu(tlv->type); + tlv_len = le16_to_cpu(tlv->len); + switch (tlv_type) { + case TLV_TYPE_POWER_TABLE_ATTR: + pwr_tbl_attr_tlv = + (MrvlIEtypes_power_table_attr_t *) tlv_buf; + rgchnpwr_tbl->max_chan_bg = pwr_tbl_attr_tlv->rows_bg; + rgchnpwr_tbl->max_power_bg = + pwr_tbl_attr_tlv->cols_bg - 1; + rgchnpwr_tbl->max_chan_a = pwr_tbl_attr_tlv->rows_a; + rgchnpwr_tbl->max_power_a = + pwr_tbl_attr_tlv->cols_a - 1; + break; + case TLV_TYPE_REGION_INFO: + rginfo_tlv = (MrvlIEtypes_otp_region_info_t *) tlv_buf; + memcpy(&rgchnpwr_tbl->countrycode, + &rginfo_tlv->countrycode, + sizeof(rgchnpwr_tbl->countrycode)); + rgchnpwr_tbl->regioncode = rginfo_tlv->regioncode; + rgchnpwr_tbl->environment = rginfo_tlv->environment; + break; + case TLV_TYPE_CHAN_ATTR_CFG: + chan_attr_tlv = (MrvlIEtypes_chan_attr_t *) tlv_buf; + if (tlv_len < + ((rgchnpwr_tbl->max_chan_a + + rgchnpwr_tbl->max_chan_bg) * + sizeof(chan_attr_t))) { + printf("ERR: Invalid chan attr tlv\n"); + hexdump("chan attrib tlv", tlv_buf, + tlv_len + sizeof(MrvlIEtypesHeader_t), + ' '); + ret = -EFAULT; + goto done; + } + for (i = 0; i < rgchnpwr_tbl->max_chan_bg; i++) { + if (!chan_attr_tlv->chan_attr[i].chan_no) { + printf("ERR:Invalid chan attr tlv\n"); + hexdump("chan attrib tlv", tlv_buf, + tlv_len + + sizeof(MrvlIEtypesHeader_t), + ' '); + ret = -EFAULT; + goto done; + } + rgchnpwr_tbl->bg_pwr_tbl[i].chan_attr = + chan_attr_tlv->chan_attr[i].chan_attr; + rgchnpwr_tbl->bg_pwr_tbl[i].chan_no = + chan_attr_tlv->chan_attr[i].chan_no; + } + for (i = 0; i < rgchnpwr_tbl->max_chan_a; i++) { + rgchnpwr_tbl->a_pwr_tbl[i].chan_attr = + chan_attr_tlv->chan_attr[i + + rgchnpwr_tbl-> + max_chan_bg]. + chan_attr; + rgchnpwr_tbl->a_pwr_tbl[i].chan_no = + chan_attr_tlv->chan_attr[i + + rgchnpwr_tbl-> + max_chan_bg]. + chan_no; + } + break; + case TLV_TYPE_POWER_TABLE: + power_tlv = (MrvlIEtypes_power_table_t *) tlv_buf; + if (tlv_len < + (rgchnpwr_tbl->max_chan_bg * + (rgchnpwr_tbl->max_power_bg + 1) + + + rgchnpwr_tbl->max_chan_a * + (rgchnpwr_tbl->max_power_a + 1))) { + printf("ERR: Invalid power table tlv\n"); + hexdump("power table tlv", tlv_buf, + tlv_len + sizeof(MrvlIEtypesHeader_t), + ' '); + ret = -EFAULT; + goto done; + } + pdata = (t_u8 *)&power_tlv->chan_power; + for (i = 0; i < rgchnpwr_tbl->max_chan_bg; i++) { + power = (chan_power_t *) pdata; + if (!power->chan_no || + (rgchnpwr_tbl->bg_pwr_tbl[i].chan_no != + power->chan_no)) { + printf("ERR: Invalid power table tlv, channel miss match\n"); + hexdump("power table tlv", tlv_buf, + tlv_len + + sizeof(MrvlIEtypesHeader_t), + ' '); + ret = -EFAULT; + goto done; + } + memset(rgchnpwr_tbl->bg_pwr_tbl[i].pwr, 0xff, + sizeof(rgchnpwr_tbl->bg_pwr_tbl[i].pwr)); + memcpy(rgchnpwr_tbl->bg_pwr_tbl[i].pwr, + power->power, + rgchnpwr_tbl->max_power_bg); + pdata += rgchnpwr_tbl->max_power_bg + 1; + } + for (i = 0; i < rgchnpwr_tbl->max_chan_a; i++) { + power = (chan_power_t *) pdata; + if (rgchnpwr_tbl->a_pwr_tbl[i].chan_no != + power->chan_no) { + printf("ERR: Invalid power table tlv, channel miss match\n"); + hexdump("power table tlv", tlv_buf, + tlv_len + + sizeof(MrvlIEtypesHeader_t), + ' '); + ret = -EFAULT; + goto done; + } + memset(rgchnpwr_tbl->a_pwr_tbl[i].pwr, 0xff, + sizeof(rgchnpwr_tbl->a_pwr_tbl[i].pwr)); + memcpy(rgchnpwr_tbl->a_pwr_tbl[i].pwr, + power->power, rgchnpwr_tbl->max_power_a); + pdata += rgchnpwr_tbl->max_power_a + 1; + } + break; + } + tlv_buf += sizeof(MrvlIEtypesHeader_t) + tlv_len; + tlv_buf_left -= sizeof(MrvlIEtypesHeader_t) + tlv_len; + } +done: + if (buffer) + free(buffer); + return ret; +} + +/** + * @brief display region_chan_pwr_table header + * + * @param tbl pointer to table + * @return void + */ +void +display_tbl_hdr(region_chan_pwr_tbl * tbl) +{ + printf("====================2G_Power_Index_Map=========================================\n"); + printf("Pwr index mapping Pwr index mapping \n"); + printf("===============================================================================\n"); + switch (tbl->ptbaseversion) { + case PTVER_1X1_AC: + case PTVER_1X1_N: + case PTVER_1X1_AC_11P: + printf(" 1 11b (11M - 1M) 2 11g (18M - 6M)\n"); + printf(" 3 11g (36M - 24M) 4 11g (54M - 48M)\n"); + printf(" 5 11n 20 (MCS2 - MCS0, 1x1) 6 11n 20 (MCS4 - MCS3, 1x1)\n"); + printf(" 7 11n 20 (MCS7 - MCS5, 1x1) 8 11n 40 (MCS2 - MCS0, 1x1)\n"); + printf(" 9 11n 40 (MCS4 - MCS3, 1x1) 10 11n 40 (MCS7 - MCS5, 1x1)\n"); + break; + case PTVER_2X2_N: + case PTVER_2X2_AC: + printf(" 1 11b (11M - 1M) 2 11g (18M - 6M)\n"); + printf(" 3 11g (36M - 24M) 4 11g (54M - 48M)\n"); + printf(" 5 11n 20 (MCS2 - MCS0, 1x1) 6 11n 20 (MCS4 - MCS3, 1x1)\n"); + printf(" 7 11n 20 (MCS7 - MCS5, 1x1) 8 11n 20 (MCS10 - MCS8, 2x2)\n"); + printf(" 9 11n 20 (MCS12 - MCS11, 2x2) 10 11n 20 (MCS15 - MCS13, 2x2)\n"); + printf("11 11n 40 (MCS2 - MCS0, 1x1) 12 11n 40 (MCS4 - MCS3, 1x1)\n"); + printf("13 11n 40 (MCS7 - MCS5, 1x1) 14 11n 40 (MCS10 - MCS8, 2x2)\n"); + printf("15 11n 40 (MCS12 - MCS11, 2x2) 16 11n 40 (MCS15 - MCS13, 2x2)\n"); + break; + case PTVER_1X1_AC_2GVHT: + case PTVER_1X1_AC_2GVHT_11P: + printf(" 1 11b (11M - 1M) 2 11g (18M - 6M)\n"); + printf(" 3 11g (36M - 24M) 4 11g (54M - 48M)\n"); + printf(" 5 11n 20 (MCS2 - MCS0, 1x1) 6 11n 20 (MCS4 - MCS3, 1x1)\n"); + printf(" 7 11n 20 (MCS7 - MCS5, 1x1) 8 11n 20 (MCS10 - MCS8, 2x2)\n"); + printf(" 9 11n 20 (MCS12 - MCS11, 2x2) 10 11n 40 (MCS2 - MCS0, 1x1)\n"); + printf(" 11 11n 40 (MCS4 - MCS3, 1x1) 12 11n 40 (MCS7 - MCS5, 1x1)\n"); + break; + case PTVER_2X2_AC_2GVHT: + printf(" 1 11b (11M - 1M) 2 11g (18M - 6M)\n"); + printf(" 3 11g (36M - 24M) 4 11g (54M - 48M)\n"); + printf(" 5 11n 20 (MCS2 - MCS0, 1x1) 6 11n 20 (MCS4 - MCS3, 1x1)\n"); + printf(" 7 11n 20 (MCS7 - MCS5, 1x1) 8 11n 20 (MCS10 - MCS8, 2x2)\n"); + printf(" 9 11n 20 (MCS12 - MCS11, 2x2) 10 11n 20 (MCS15 - MCS13, 2x2)\n"); + printf("11 11ac 20 (mcs8, 1x1) 12 11ac 20 (mcs9-mcs8, 2x2)\n"); + printf("13 11n 40 (MCS2 - MCS0, 1x1) 14 11n 40 (MCS4 - MCS3, 1x1)\n"); + printf("15 11n 40 (MCS7 - MCS5, 1x1) 16 11n 40 (MCS10 - MCS8, 2x2)\n"); + printf("17 11n 40 (MCS12 - MCS11, 2x2) 18 11ac 40 (mcs9-mcs8, 1x1)\n"); + printf("19 11ac 40 (mcs9-mcs8, 2x2) 20 11n 40 (MCS15 - MCS13, 2x2)\n"); + printf("21 11ac 80 (mcs2-mcs0, 1x1) 22 11ac 80 (mcs4 - mcs3, 1x1)\n"); + printf("23 11ac 80 (mcs7 - mcs5, 1x1) 24 11ac 80 (mcs9-8, 1x1)\n"); + break; + } + printf("====================5G_Power_Index_Map=========================================\n"); + printf("Pwr index mapping Pwr index mapping \n"); + printf("===============================================================================\n"); + switch (tbl->ptbaseversion) { + case PTVER_1X1_AC: + case PTVER_1X1_AC_11P: + case PTVER_1X1_AC_2GVHT: + case PTVER_1X1_AC_2GVHT_11P: + printf(" 1 11b (11M - 1M) 2 11a (18M - 6M)\n"); + printf(" 3 11a (36M - 24M) 4 11a (54M - 48M)\n"); + printf(" 5 11n 20 (MCS2 - MCS0, 1x1) 6 11n 20 (MCS4 - MCS3, 1x1)\n"); + printf(" 7 11n 20 (MCS7 - MCS5, 1x1) 8 11ac 20 (mcs8, 1x1)\n"); + printf(" 9 11n 40 (mcs2 - mcs0, 1x1) 10 11n 40 (mcs4 - mcs3, 1x1)\n"); + printf("11 11n 40 (mcs7 - mcs5, 1x1) 12 11ac 40 (mcs9-mcs8, 1x1)\n"); + printf("13 11ac 80 (mcs2-mcs0, 1x1) 14 11ac 80 (mcs4 - mcs3, 1x1)\n"); + printf("15 11ac 80 (mcs7 - mcs5, 1x1) 16 11ac 80 (mcs9-8, 1x1)\n"); + break; + case PTVER_1X1_N: + printf(" 1 11b (11M - 1M) 2 11a (18M - 6M)\n"); + printf(" 3 11a (36M - 24M) 4 11a (54M - 48M)\n"); + printf(" 5 11n 20 (MCS2 - MCS0, 1x1) 6 11n 20 (MCS4 - MCS3, 1x1)\n"); + printf(" 7 11n 20 (MCS7 - MCS5, 1x1) 8 11n 40 (mcs2 - mcs0, 1x1)\n"); + printf(" 9 11n 40 (mcs4 - mcs3, 1x1) 10 11n 40 (mcs7 - mcs5, 1x1)\n"); + break; + case PTVER_2X2_AC_2GVHT: + case PTVER_2X2_AC: + printf(" 1 11b (11M - 1M) 2 11a (18M - 6M)\n"); + printf(" 3 11a (36M - 24M) 4 11a (54M - 48M)\n"); + printf(" 5 11n 20 (MCS2 - MCS0, 1x1) 6 11n 20 (MCS4 - MCS3, 1x1)\n"); + printf(" 7 11n 20 (MCS7 - MCS5, 1x1) 8 11n 20 (mcs10 - mcs8, 2x2)\n"); + printf(" 9 11n 20 (mcs12 - mcs11, 2x2) 10 11n 20 (mcs15 - mcs13, 2x2)\n"); + printf("11 11ac 20 (mcs8, 1x1) 12 11ac 20 (mcs9-mcs8, 2x2)\n"); + printf("13 11n 40 (mcs2 - mcs0, 1x1) 14 11n 40 (mcs4 - mcs3, 1x1)\n"); + printf("15 11n 40 (mcs7 - mcs5, 1x1) 16 11n 40 (mcs10 - mcs8, 2x2)\n"); + printf("17 11n 40 (mcs12 - mcs11, 2x2) 18 11ac 40 (mcs9-mcs8, 1x1) \n"); + printf("19 11ac 40 (mcs9-mcs8, 2x2) 20 11n 40 (mcs15 - mcs13, 2x2)\n"); + printf("21 11ac 80 (mcs2-mcs0, 1x1) 22 11ac 80 (mcs4 - mcs3, 1x1)\n"); + printf("23 11ac 80 (mcs7 - mcs5, 1x1) 24 11ac 80 (mcs9-8, 1x1)\n"); + printf("25 11ac 80 (mcs2-mcs0, 2x2) 26 11ac 80 (mcs4 - mcs3, 2x2)\n"); + printf("27 11ac 80 (mcs7 - mcs5, 2x2) 28 11ac 80 (mcs9-8, 2x2)\n"); + break; + case PTVER_2X2_N: + printf(" 1 11b (11M - 1M) 2 11a (18M - 6M)\n"); + printf(" 3 11a (36M - 24M) 4 11a (54M - 48M)\n"); + printf(" 5 11n 20 (MCS2 - MCS0, 1x1) 6 11n 20 (MCS4 - MCS3, 1x1)\n"); + printf(" 7 11n 20 (MCS7 - MCS5, 1x1) 8 11n 20 (mcs10 - mcs8, 2x2)\n"); + printf(" 9 11n 20 (mcs12 - mcs11, 2x2) 10 11n 20 (mcs15 - mcs13, 2x2)\n"); + printf("11 11n 40 (mcs2 - mcs0, 1x1) 12 11n 40 (mcs4 - mcs3, 1x1)\n"); + printf("13 11n 40 (mcs7 - mcs5, 1x1) 14 11n 40 (mcs10 - mcs8, 2x2)\n"); + printf("15 11n 40 (mcs12 - mcs11, 2x2) 16 11n 40 (mcs15 - mcs13, 2x2) \n"); + break; + } + printf("\n\n"); + return; +} + +/** + * @brief display and compare the channel power table + * + * @param tbl pointer to table + * @param target_tbl pointer to target table + * @return void + */ +void +display_regpwr_tbl(region_chan_pwr_tbl * tbl, region_chan_pwr_tbl * comp_tbl) +{ + int i, j; + if (!comp_tbl) + display_tbl_hdr(tbl); + if (comp_tbl && (tbl->environment != comp_tbl->environment || + tbl->regioncode != comp_tbl->regioncode || + tbl->countrycode[0] != comp_tbl->countrycode[0] || + tbl->countrycode[1] != comp_tbl->countrycode[1])) + printf("* country code is ( %c%c ) region code is ( %d ) environment code is ( %d )\n", tbl->countrycode[0], tbl->countrycode[1], tbl->regioncode, tbl->environment); + else + printf(" country code is ( %c%c ) region code is ( %d ) environment code is ( %d )\n", tbl->countrycode[0], tbl->countrycode[1], tbl->regioncode, tbl->environment); + switch (tbl->max_power_bg) { + case 10: + printf("=========================2G_POWER_TABLE=========================================\n"); + printf("chan_no(Attr), Pindx(dBm) 1 2 3 4 5 6 7 8 9 10 \n"); + printf("================================================================================\n"); + break; + case 12: + printf("=========================2G_POWER_TABLE===================================================\n"); + printf("chan_no(Attr), Pindx(dBm) 1 2 3 4 5 6 7 8 9 10 11 12 \n"); + printf("==========================================================================================\n"); + break; + case 16: + printf("=========================2G_POWER_TABLE=======================================================================\n"); + printf("chan_no(Attr), Pindx(dBm) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 \n"); + printf("==============================================================================================================\n"); + break; + case 24: + printf("=========================5G_POWER_TABLE=========================================================================================================\n"); + printf("chan_no(Attr), Pindx(dBm) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 \n"); + printf("================================================================================================================================================\n"); + break; + } + for (i = 0; i < 14; i++) { + if (comp_tbl && + memcmp(&tbl->bg_pwr_tbl[i], &comp_tbl->bg_pwr_tbl[i], + sizeof(rgchan_pwr_t))) + printf(" *%3d (%02x) ", + tbl->bg_pwr_tbl[i].chan_no, + tbl->bg_pwr_tbl[i].chan_attr); + else + printf(" %3d (%02x) ", + tbl->bg_pwr_tbl[i].chan_no, + tbl->bg_pwr_tbl[i].chan_attr); + for (j = 0; j < tbl->max_power_bg; j++) { + printf("%2d ", tbl->bg_pwr_tbl[i].pwr[j]); + } + printf("\n"); + } + printf(" \n"); + switch (tbl->max_power_a) { + case 10: + printf("=========================5G_POWER_TABLE=========================================\n"); + printf("chan_no(Attr), Pindx(dBm) 1 2 3 4 5 6 7 8 9 10 \n"); + printf("================================================================================\n"); + break; + case 16: + printf("=========================5G_POWER_TABLE=================================================================================\n"); + printf("chan_no(Attr), Pindx(dBm) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 \n"); + printf("========================================================================================================================\n"); + break; + case 28: + printf("=========================5G_POWER_TABLE=============================================================================================================================\n"); + printf("chan_no(Attr), Pindx(dBm) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 \n"); + printf("====================================================================================================================================================================\n"); + break; + } + for (i = 0; i < tbl->max_chan_a; i++) { + if (comp_tbl && + memcmp(&tbl->a_pwr_tbl[i], &comp_tbl->a_pwr_tbl[i], + sizeof(rgchan_pwr_t))) + printf(" *%3d (%02x) ", + tbl->a_pwr_tbl[i].chan_no, + tbl->a_pwr_tbl[i].chan_attr); + else + printf(" %3d (%02x) ", + tbl->a_pwr_tbl[i].chan_no, + tbl->a_pwr_tbl[i].chan_attr); + for (j = 0; j < tbl->max_power_a; j++) { + printf("%2d ", tbl->a_pwr_tbl[i].pwr[j]); + } + printf("\n"); + } + return; +} + +/** + * @brief Process compare the regionpowertable + * + * @param argc Number of arguments + * @param argv Pointer to the arguments array + * + * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_FAILURE + */ +static int +process_compare_rgpwr(int argc, char *argv[]) +{ + + FILE *src_fp = NULL; + FILE *target_fp = NULL; + int ret = MLAN_STATUS_SUCCESS; + struct stat st; + t_u8 *src_rgpwr_buf = NULL; + t_u8 *target_rgpwr_buf = NULL; + + if (argc < 4) { + printf("Error: invalid no of arguments\n"); + printf("mlanutl mlanX/uapX comparergpwr uncompressed_file target_file\n"); + ret = MLAN_STATUS_FAILURE; + goto done; + } + if (argc == 5) { + target_fp = fopen(argv[4], "r"); + if (target_fp == NULL) { + ret = -EFAULT; + perror("target file fopen failed"); + goto done; + } + target_rgpwr_buf = (t_u8 *)malloc(sizeof(region_chan_pwr_tbl)); + if (!target_rgpwr_buf) { + ret = -EFAULT; + printf("ERR:Cannot allocate buffer target_rgpwr_buf!\n"); + goto done; + } + memset(target_rgpwr_buf, 0, sizeof(region_chan_pwr_tbl)); + if (get_fw_rgpwr_data + (target_fp, (region_chan_pwr_tbl *) target_rgpwr_buf)) { + ret = -EFAULT; + printf("ERR:Fail to parse target file\n"); + goto done; + } + } + if (stat(argv[3], &st)) { + printf("cannot stat %s\n", argv[3]); + ret = -EFAULT; + goto done; + } + + src_fp = fopen(argv[3], "r"); + if (src_fp == NULL) { + perror("src file fopen failed"); + goto done; + } + src_rgpwr_buf = (t_u8 *)malloc(sizeof(region_chan_pwr_tbl)); + if (!src_rgpwr_buf) { + ret = -EFAULT; + printf("ERR:Cannot allocate buffer for src_rgpwr_buf!\n"); + goto done; + } + memset(src_rgpwr_buf, 0, sizeof(region_chan_pwr_tbl)); + if (get_src_rgpwr_data + (src_fp, (int)st.st_size, (region_chan_pwr_tbl *) src_rgpwr_buf)) { + printf("ERR: Fail to parse source file!\n"); + goto done; + } + if (src_rgpwr_buf && target_rgpwr_buf) { + if (!memcmp + (src_rgpwr_buf, target_rgpwr_buf, + sizeof(region_chan_pwr_tbl) - 1)) { + printf("PASS\n"); + display_regpwr_tbl((region_chan_pwr_tbl *) + src_rgpwr_buf, NULL); + } else { + printf("FAIL\n"); + printf("SRC Region Channel Power Table:\n"); + display_regpwr_tbl((region_chan_pwr_tbl *) + src_rgpwr_buf, NULL); + printf("==============================================================================\n"); + printf("FW Region Channel Power Table:\n"); + display_regpwr_tbl((region_chan_pwr_tbl *) + target_rgpwr_buf, + (region_chan_pwr_tbl *) + src_rgpwr_buf); + } + } else if (src_rgpwr_buf) { + printf("SRC Region Channel Power Table:\n"); + display_regpwr_tbl((region_chan_pwr_tbl *) src_rgpwr_buf, NULL); + } +done: + if (target_fp) + fclose(target_fp); + if (target_rgpwr_buf) + free(target_rgpwr_buf); + if (src_fp) + fclose(src_fp); + if (src_rgpwr_buf) + free(src_rgpwr_buf); + return ret; +} + +/** + * @brief Enable/Disable amsdu_aggr_ctrl + * + * @param argc Number of arguments + * @param argv Pointer to the arguments array + * + * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_FAILURE + */ +static int +process_11n_amsdu_aggr_ctrl(int argc, char *argv[]) +{ + t_u8 *buffer = NULL; + struct eth_priv_cmd *cmd = NULL; + int ret = 0, data[2]; + struct ifreq ifr; + + /* Check if arguments are valid */ + if ((argc != 3) && (argc != 4)) { + printf("ERR: Invalid arguments\n"); + ret = MLAN_STATUS_FAILURE; + goto done; + } + + /* Initialize buffer */ + buffer = (t_u8 *)malloc(BUFFER_LENGTH); + if (!buffer) { + printf("ERR:Cannot allocate buffer for command!\n"); + ret = MLAN_STATUS_FAILURE; + goto done; + } + + prepare_buffer(buffer, argv[2], (argc - 3), &argv[3]); + + cmd = (struct eth_priv_cmd *)malloc(sizeof(struct eth_priv_cmd)); + if (!cmd) { + printf("ERR:Cannot allocate buffer for command!\n"); + ret = MLAN_STATUS_FAILURE; + goto done; + } + + /* Fill up buffer */ +#ifdef USERSPACE_32BIT_OVER_KERNEL_64BIT + memset(cmd, 0, sizeof(struct eth_priv_cmd)); + memcpy(&cmd->buf, &buffer, sizeof(buffer)); +#else + cmd->buf = buffer; +#endif + cmd->used_len = 0; + cmd->total_len = BUFFER_LENGTH; + + /* Perform IOCTL */ + memset(&ifr, 0, sizeof(struct ifreq)); + strncpy(ifr.ifr_ifrn.ifrn_name, dev_name, strlen(dev_name)); + ifr.ifr_ifru.ifru_data = (void *)cmd; + + if (ioctl(sockfd, MLAN_ETH_PRIV, &ifr)) { + perror("mlanutl"); + fprintf(stderr, "mlanutl: amsduaggrctrl fail\n"); + ret = MLAN_STATUS_FAILURE; + goto done; + } + + memset(data, 0, sizeof(data)); + memcpy(data, buffer, sizeof(data)); + if (data[0] == 1) + printf("Feature is enabled\n"); + if (data[0] == 0) + printf("Feature is disabled\n"); + printf("Current AMSDU buffer size is %d\n", data[1]); + +done: + if (buffer) + free(buffer); + if (cmd) + free(cmd); + + return ret; +} + +/** + * @brief Set/Get Transmit beamforming capabilities + * + * @param argc Number of arguments + * @param argv Pointer to the arguments array + * + * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_FAILURE + */ +static int +process_tx_bf_cap_ioctl(int argc, char *argv[]) +{ + t_u8 *buffer = NULL; + struct eth_priv_cmd *cmd = NULL; + int ret = 0, bf_cap; + struct ifreq ifr; + + /* Check if arguments are valid */ + if ((argc != 3) && (argc != 4)) { + printf("ERR: Invalid arguments\n"); + ret = MLAN_STATUS_FAILURE; + goto done; + } + + /* Initialize buffer */ + buffer = (t_u8 *)malloc(BUFFER_LENGTH); + if (!buffer) { + printf("ERR:Cannot allocate buffer for command!\n"); + ret = MLAN_STATUS_FAILURE; + goto done; + } + + prepare_buffer(buffer, argv[2], (argc - 3), &argv[3]); + + cmd = (struct eth_priv_cmd *)malloc(sizeof(struct eth_priv_cmd)); + if (!cmd) { + printf("ERR:Cannot allocate buffer for command!\n"); + ret = MLAN_STATUS_FAILURE; + goto done; + } + + /* Fill up buffer */ +#ifdef USERSPACE_32BIT_OVER_KERNEL_64BIT + memset(cmd, 0, sizeof(struct eth_priv_cmd)); + memcpy(&cmd->buf, &buffer, sizeof(buffer)); +#else + cmd->buf = buffer; +#endif + cmd->used_len = 0; + cmd->total_len = BUFFER_LENGTH; + + /* Perform IOCTL */ + memset(&ifr, 0, sizeof(struct ifreq)); + strncpy(ifr.ifr_ifrn.ifrn_name, dev_name, strlen(dev_name)); + ifr.ifr_ifru.ifru_data = (void *)cmd; + + if (ioctl(sockfd, MLAN_ETH_PRIV, &ifr)) { + perror("mlanutl"); + fprintf(stderr, "mlanutl: httxbfcap fail\n"); + ret = MLAN_STATUS_FAILURE; + goto done; + } + + memcpy(&bf_cap, buffer, sizeof(int)); + printf("Current TX beamforming capability is 0x%x\n", bf_cap); + +done: + if (buffer) + free(buffer); + if (cmd) + free(cmd); + + return ret; +} + +#ifdef SDIO +/** + * @brief Turn on/off the sdio clock + * + * @param argc Number of arguments + * @param argv Pointer to the arguments array + * + * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_FAILURE + */ +static int +process_sdio_clock_ioctl(int argc, char *argv[]) +{ + t_u8 *buffer = NULL; + struct eth_priv_cmd *cmd = NULL; + int ret = 0, clock_state = 0; + struct ifreq ifr; + + /* Check if arguments are valid */ + if ((argc != 3) && (argc != 4)) { + printf("ERR: Invalid arguments\n"); + ret = MLAN_STATUS_FAILURE; + goto done; + } + + /* Initialize buffer */ + buffer = (t_u8 *)malloc(BUFFER_LENGTH); + if (!buffer) { + printf("ERR:Cannot allocate buffer for command!\n"); + ret = MLAN_STATUS_FAILURE; + goto done; + } + + prepare_buffer(buffer, argv[2], (argc - 3), &argv[3]); + + cmd = (struct eth_priv_cmd *)malloc(sizeof(struct eth_priv_cmd)); + if (!cmd) { + printf("ERR:Cannot allocate buffer for command!\n"); + ret = MLAN_STATUS_FAILURE; + goto done; + } + + /* Fill up buffer */ +#ifdef USERSPACE_32BIT_OVER_KERNEL_64BIT + memset(cmd, 0, sizeof(struct eth_priv_cmd)); + memcpy(&cmd->buf, &buffer, sizeof(buffer)); +#else + cmd->buf = buffer; +#endif + cmd->used_len = 0; + cmd->total_len = BUFFER_LENGTH; + + /* Perform IOCTL */ + memset(&ifr, 0, sizeof(struct ifreq)); + strncpy(ifr.ifr_ifrn.ifrn_name, dev_name, strlen(dev_name)); + ifr.ifr_ifru.ifru_data = (void *)cmd; + + if (ioctl(sockfd, MLAN_ETH_PRIV, &ifr)) { + perror("mlanutl"); + fprintf(stderr, "mlanutl: sdioclock fail\n"); + ret = MLAN_STATUS_FAILURE; + goto done; + } + + if (argc == 3) { + memcpy(&clock_state, buffer, sizeof(clock_state)); + printf("Current SDIO clock state is %d\n", clock_state); + } + +done: + if (buffer) + free(buffer); + if (cmd) + free(cmd); + + return ret; +} +#endif + +#ifdef SDIO +/** + * @brief Set SDIO Multi-point aggregation control parameters + * + * @param argc Number of arguments + * @param argv Pointer to the arguments array + * + * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_FAILURE + */ +static int +process_sdio_mpa_ctrl(int argc, char *argv[]) +{ + t_u8 *buffer = NULL; + struct eth_priv_cmd *cmd = NULL; + int ret = 0, data[6]; + struct ifreq ifr; + + /* Check if arguments are valid */ + if ((argc < 3) && (argc > 9)) { + printf("ERR: Invalid arguments\n"); + ret = MLAN_STATUS_FAILURE; + goto done; + } + + /* Initialize buffer */ + buffer = (t_u8 *)malloc(BUFFER_LENGTH); + if (!buffer) { + printf("ERR:Cannot allocate buffer for command!\n"); + ret = MLAN_STATUS_FAILURE; + goto done; + } + + prepare_buffer(buffer, argv[2], (argc - 3), &argv[3]); + + cmd = (struct eth_priv_cmd *)malloc(sizeof(struct eth_priv_cmd)); + if (!cmd) { + printf("ERR:Cannot allocate buffer for command!\n"); + ret = MLAN_STATUS_FAILURE; + goto done; + } + + /* Fill up buffer */ +#ifdef USERSPACE_32BIT_OVER_KERNEL_64BIT + memset(cmd, 0, sizeof(struct eth_priv_cmd)); + memcpy(&cmd->buf, &buffer, sizeof(buffer)); +#else + cmd->buf = buffer; +#endif + cmd->used_len = 0; + cmd->total_len = BUFFER_LENGTH; + + /* Perform IOCTL */ + memset(&ifr, 0, sizeof(struct ifreq)); + strncpy(ifr.ifr_ifrn.ifrn_name, dev_name, strlen(dev_name)); + ifr.ifr_ifru.ifru_data = (void *)cmd; + + if (ioctl(sockfd, MLAN_ETH_PRIV, &ifr)) { + perror("mlanutl"); + fprintf(stderr, "mlanutl: diaglooptest fail\n"); + ret = MLAN_STATUS_FAILURE; + goto done; + } + + if (argc == 3) { + memset(data, 0, sizeof(data)); + memcpy(data, buffer, sizeof(data)); + printf("Enable MP aggregation for Tx is %d\n", data[0]); + printf("Enable MP aggregation for Rx is %d\n", data[1]); + printf("Tx buffer size is %d\n", data[2]); + printf("Rx buffer size is %d\n", data[3]); + printf("maximum Tx port is %d\n", data[4]); + printf("maximum Rx port is %d\n", data[5]); + } + +done: + if (buffer) + free(buffer); + if (cmd) + free(cmd); + + return ret; +} +#endif + +/** + * @brief Configure sleep parameters + * + * @param argc Number of arguments + * @param argv Pointer to the arguments array + * + * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_FAILURE + */ +static int +process_sleep_params(int argc, char *argv[]) +{ + int ret = 0, data[6]; + t_u8 *buffer = NULL; + struct eth_priv_cmd *cmd = NULL; + struct ifreq ifr; + + /* Check if arguments are valid */ + if ((argc != 3) && (argc != 9)) { + printf("ERR: Invalid arguments\n"); + ret = MLAN_STATUS_FAILURE; + goto done; + } + + /* Initialize buffer */ + buffer = (t_u8 *)malloc(BUFFER_LENGTH); + if (!buffer) { + printf("ERR:Cannot allocate buffer for command!\n"); + ret = MLAN_STATUS_FAILURE; + goto done; + } + + prepare_buffer(buffer, argv[2], (argc - 3), &argv[3]); +/* prepare_buffer(buffer, argv[2], 0, NULL); */ + + cmd = (struct eth_priv_cmd *)malloc(sizeof(struct eth_priv_cmd)); + if (!cmd) { + printf("ERR:Cannot allocate buffer for command!\n"); + ret = MLAN_STATUS_FAILURE; + goto done; + } + + /* Fill up buffer */ +#ifdef USERSPACE_32BIT_OVER_KERNEL_64BIT + memset(cmd, 0, sizeof(struct eth_priv_cmd)); + memcpy(&cmd->buf, &buffer, sizeof(buffer)); +#else + cmd->buf = buffer; +#endif + cmd->used_len = 0; + cmd->total_len = BUFFER_LENGTH; + + /* Perform IOCTL */ + memset(&ifr, 0, sizeof(struct ifreq)); + strncpy(ifr.ifr_ifrn.ifrn_name, dev_name, strlen(dev_name)); + ifr.ifr_ifru.ifru_data = (void *)cmd; + + if (ioctl(sockfd, MLAN_ETH_PRIV, &ifr)) { + perror("mlanutl"); + fprintf(stderr, "mlanutl: sleepparams fail\n"); + ret = MLAN_STATUS_FAILURE; + goto done; + } + memset(data, 0, sizeof(data)); + memcpy(data, buffer, sizeof(data)); + printf("Sleep clock error in ppm is %d\n", data[0]); + printf("Wakeup offset in usec is %d\n", data[1]); + printf("Clock stabilization time in usec is %d\n", data[2]); + printf("Control periodic calibration is %d\n", data[3]); + printf("Control the use of external sleep clock is %d\n", data[4]); + printf("Debug is %d\n", data[5]); + +done: + if (buffer) + free(buffer); + if (cmd) + free(cmd); + + return ret; +} + +/** + * @brief Set/Get cw mode + * + * @param argc Number of arguments + * @param argv Pointer to the arguments array + * + * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_FAILURE + */ +static int +process_cwmode(int argc, char *argv[]) +{ + t_u8 *buffer = NULL, *pos = NULL, *action; + char *data = NULL, *args[100]; + struct eth_priv_cmd *cmd = NULL; + struct ifreq ifr; + cw_mode_ctrl *cwmode = NULL; + FILE *config_file = NULL; + char *line = NULL; + int li = 0; + + /* Initialize buffer */ + buffer = (t_u8 *)malloc(BUFFER_LENGTH); + if (!buffer) { + printf("ERR:Cannot allocate buffer for command!\n"); + return MLAN_STATUS_FAILURE; + } + + memset(buffer, 0, BUFFER_LENGTH); + pos = buffer; + strncpy((char *)pos, CMD_NXP, strlen(CMD_NXP)); + pos += (strlen(CMD_NXP)); + strcpy((char *)pos, argv[2]); + pos += (strlen(argv[2])); + action = pos; + pos++; + + if (argc > 3) { + *action = 1; + config_file = fopen(argv[3], "r"); + if (config_file == NULL) { + perror("CONFIG"); + exit(1); + } + + line = (char *)malloc(MAX_CONFIG_LINE); + if (!line) { + printf("ERR:Cannot allocate memory for line\n"); + exit(1); + } + memset(line, 0, MAX_CONFIG_LINE); + /* Parse file and process */ + while (config_get_line + (line, MAX_CONFIG_LINE, config_file, &li, &data)) { + parse_line(line, args, 100); + + if (strcmp(args[0], "CW_MODE") == 0) + cwmode = (cw_mode_ctrl *) pos; + else { + if (cwmode) { + if (strcmp(args[0], "Mode") == 0) + cwmode->mode = + a2hex_or_atoi(args[1]); + else if (strcmp(args[0], "Channel") == + 0) + cwmode->channel = + a2hex_or_atoi(args[1]); + else if (strcmp(args[0], "Chaninfo") == + 0) + cwmode->chanInfo = + a2hex_or_atoi(args[1]); + else if (strcmp(args[0], "TxPower") == + 0) + cwmode->txPower = + a2hex_or_atoi(args[1]); + else if (strcmp(args[0], "PktLength") == + 0) + cwmode->pktLength = + a2hex_or_atoi(args[1]); + else if (strcmp(args[0], "RateInfo") == + 0) + cwmode->rateInfo = + a2hex_or_atoi(args[1]); + } else { + printf("invalid config file\n"); + printf("Specify the parameters in CW_MODE header as shown below:\n"); + printf("CW_MODE = {\n"); + printf("//\n"); + printf("// specify parameters between CW_MODE header only\n"); + printf("//\n"); + printf("}\n"); + exit(1); + } + } + } + } + cmd = (struct eth_priv_cmd *)malloc(sizeof(struct eth_priv_cmd)); + if (!cmd) { + printf("ERR:Cannot allocate buffer for command!\n"); + free(buffer); + return MLAN_STATUS_FAILURE; + } + + /* Fill up buffer */ + cmd->buf = buffer; + cmd->used_len = 0; + cmd->total_len = BUFFER_LENGTH; + + /* Perform IOCTL */ + memset(&ifr, 0, sizeof(struct ifreq)); + strncpy(ifr.ifr_ifrn.ifrn_name, dev_name, strlen(dev_name)); + ifr.ifr_ifru.ifru_data = (void *)cmd; + + if (ioctl(sockfd, MLAN_ETH_PRIV, &ifr)) { + perror("mlanutl"); + fprintf(stderr, "mlanutl: cwmode fail\n"); + if (cmd) + free(cmd); + if (buffer) + free(buffer); + return MLAN_STATUS_FAILURE; + } + + /* Process result */ + cwmode = (cw_mode_ctrl *) buffer; + printf("CW Mode:\nMode = %d\nChannel = %d\nChanInfo = 0x%x\n" + "TxPower=%d\nRateInfo=0x%x\nPacket Length=%d\n", + cwmode->mode, cwmode->channel, cwmode->chanInfo, + cwmode->txPower, cwmode->rateInfo, cwmode->pktLength); + + if (buffer) + free(buffer); + if (cmd) + free(cmd); + + return MLAN_STATUS_SUCCESS; +} + +/** + * @brief Set/Get DFS Testing settings + * + * @param argc Number of arguments + * @param argv Pointer to the arguments array + * + * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_FAILURE + */ +static int +process_dfs_testing(int argc, char *argv[]) +{ + int ret = 0, data[4]; + t_u8 *buffer = NULL; + struct eth_priv_cmd *cmd = NULL; + struct ifreq ifr; + + /* Check if arguments are valid */ + if ((argc != 3) && (argc != 7)) { + printf("ERR: Invalid arguments\n"); + ret = MLAN_STATUS_FAILURE; + goto done; + } + + /* Initialize buffer */ + buffer = (t_u8 *)malloc(BUFFER_LENGTH); + if (!buffer) { + printf("ERR:Cannot allocate buffer for command!\n"); + ret = MLAN_STATUS_FAILURE; + goto done; + } + + prepare_buffer(buffer, argv[2], (argc - 3), &argv[3]); + + cmd = (struct eth_priv_cmd *)malloc(sizeof(struct eth_priv_cmd)); + if (!cmd) { + printf("ERR:Cannot allocate buffer for command!\n"); + ret = MLAN_STATUS_FAILURE; + goto done; + } + + /* Fill up buffer */ +#ifdef USERSPACE_32BIT_OVER_KERNEL_64BIT + memset(cmd, 0, sizeof(struct eth_priv_cmd)); + memcpy(&cmd->buf, &buffer, sizeof(buffer)); +#else + cmd->buf = buffer; +#endif + cmd->used_len = 0; + cmd->total_len = BUFFER_LENGTH; + + /* Perform IOCTL */ + memset(&ifr, 0, sizeof(struct ifreq)); + strncpy(ifr.ifr_ifrn.ifrn_name, dev_name, strlen(dev_name)); + ifr.ifr_ifru.ifru_data = (void *)cmd; + + if (ioctl(sockfd, MLAN_ETH_PRIV, &ifr)) { + perror("mlanutl"); + fprintf(stderr, "mlanutl: dfstesting fail\n"); + ret = MLAN_STATUS_FAILURE; + goto done; + } + if (argc == 3) { + memset(data, 0, sizeof(data)); + memcpy(data, buffer, sizeof(data)); + printf("User-configured Channel Availability Check in msec is %d\n", data[0]); + printf("User-configured Non-Occupancy Period in sec is %d\n", + data[1]); + printf("No channel change on radar enabled is %d\n", data[2]); + printf("User-configured channel to change to on radar is %d\n", + data[3]); + } + +done: + if (buffer) + free(buffer); + if (cmd) + free(cmd); + + return ret; +} + +/** + * @brief Set/Get CFP table codes + * + * @param argc Number of arguments + * @param argv Pointer to the arguments array + * + * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_FAILURE + */ +static int +process_cfp_code(int argc, char *argv[]) +{ + int ret = 0, data[2]; + t_u8 *buffer = NULL; + struct eth_priv_cmd *cmd = NULL; + struct ifreq ifr; + + /* Check if arguments are valid */ + if ((argc != 3) && (argc != 4) && (argc != 5)) { + printf("ERR: Invalid arguments\n"); + ret = MLAN_STATUS_FAILURE; + goto done; + } + + /* Initialize buffer */ + buffer = (t_u8 *)malloc(BUFFER_LENGTH); + if (!buffer) { + printf("ERR:Cannot allocate buffer for command!\n"); + ret = MLAN_STATUS_FAILURE; + goto done; + } + + prepare_buffer(buffer, argv[2], (argc - 3), &argv[3]); + + cmd = (struct eth_priv_cmd *)malloc(sizeof(struct eth_priv_cmd)); + if (!cmd) { + printf("ERR:Cannot allocate buffer for command!\n"); + ret = MLAN_STATUS_FAILURE; + goto done; + } + + /* Fill up buffer */ +#ifdef USERSPACE_32BIT_OVER_KERNEL_64BIT + memset(cmd, 0, sizeof(struct eth_priv_cmd)); + memcpy(&cmd->buf, &buffer, sizeof(buffer)); +#else + cmd->buf = buffer; +#endif + cmd->used_len = 0; + cmd->total_len = BUFFER_LENGTH; + + /* Perform IOCTL */ + memset(&ifr, 0, sizeof(struct ifreq)); + strncpy(ifr.ifr_ifrn.ifrn_name, dev_name, strlen(dev_name)); + ifr.ifr_ifru.ifru_data = (void *)cmd; + + if (ioctl(sockfd, MLAN_ETH_PRIV, &ifr)) { + perror("mlanutl"); + fprintf(stderr, "mlanutl: cfpcode fail\n"); + ret = MLAN_STATUS_FAILURE; + goto done; + } + if (argc == 3) { + memset(data, 0, sizeof(data)); + memcpy(data, buffer, sizeof(data)); + printf("Code of the CFP table for 2.4GHz is %d\n", data[0]); + printf("Code of the CFP table for 5GHz is %d\n", data[1]); + } + +done: + if (buffer) + free(buffer); + if (cmd) + free(cmd); + + return ret; +} + +/** + * @brief Set/Get Tx/Rx antenna + * + * @param argc Number of arguments + * @param argv Pointer to the arguments array + * + * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_FAILURE + */ +static int +process_set_get_tx_rx_ant(int argc, char *argv[]) +{ + int ret = 0; + int data[3] = { 0 }; + t_u8 *buffer = NULL; + struct eth_priv_cmd *cmd = NULL; + struct ifreq ifr; + + /* Check if arguments are valid */ + if ((argc != 3) && (argc != 4) + && (argc != 5) + ) { + printf("ERR: Invalid arguments\n"); + ret = MLAN_STATUS_FAILURE; + goto done; + } + + /* Initialize buffer */ + buffer = (t_u8 *)malloc(BUFFER_LENGTH); + if (!buffer) { + printf("ERR:Cannot allocate buffer for command!\n"); + ret = MLAN_STATUS_FAILURE; + goto done; + } + + prepare_buffer(buffer, argv[2], (argc - 3), &argv[3]); + + cmd = (struct eth_priv_cmd *)malloc(sizeof(struct eth_priv_cmd)); + if (!cmd) { + printf("ERR:Cannot allocate buffer for command!\n"); + ret = MLAN_STATUS_FAILURE; + goto done; + } + + /* Fill up buffer */ +#ifdef USERSPACE_32BIT_OVER_KERNEL_64BIT + memset(cmd, 0, sizeof(struct eth_priv_cmd)); + memcpy(&cmd->buf, &buffer, sizeof(buffer)); +#else + cmd->buf = buffer; +#endif + cmd->used_len = 0; + cmd->total_len = BUFFER_LENGTH; + + /* Perform IOCTL */ + memset(&ifr, 0, sizeof(struct ifreq)); + strncpy(ifr.ifr_ifrn.ifrn_name, dev_name, strlen(dev_name)); + ifr.ifr_ifru.ifru_data = (void *)cmd; + + if (ioctl(sockfd, MLAN_ETH_PRIV, &ifr)) { + perror("mlanutl"); + fprintf(stderr, "mlanutl: antcfg fail\n"); + ret = MLAN_STATUS_FAILURE; + goto done; + } + if (argc == 3) { + if (cmd->used_len < sizeof(data)) { + memcpy(data, buffer, cmd->used_len); + printf("Mode of Tx path is 0x%x\n", data[0]); + if (cmd->used_len == (sizeof(int) * 2)) + printf("Mode of Rx path is 0x%x\n", data[1]); + } else { + memcpy(data, buffer, sizeof(data)); + printf("Mode of Tx/Rx path is 0x%x\n", data[0]); + /* Evaluate time is valid only when SAD is enabled */ + if (data[0] == 0xffff) { + printf("Evaluate time = %d\n", data[1]); + /* Current antenna value should be 1,2,3. 0 is invalid value */ + if (data[2] > 0) + printf("Current antenna is %d\n", + data[2]); + } + } + } + +done: + if (buffer) + free(buffer); + if (cmd) + free(cmd); + + return ret; +} + +/** + * @brief Get/Set system clock + * + * @param argc Number of arguments + * @param argv Pointer to the arguments array + * + * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_FAILURE + */ +static int +process_sysclock(int argc, char *argv[]) +{ + t_u8 *buffer = NULL; + struct eth_priv_cmd *cmd; + int data[65], i = 0; + struct ifreq ifr; + + /* Initialize buffer */ + buffer = (t_u8 *)malloc(BUFFER_LENGTH); + if (!buffer) { + printf("ERR:Cannot allocate buffer for command!\n"); + return MLAN_STATUS_FAILURE; + } + + prepare_buffer(buffer, argv[2], (argc - 3), &argv[3]); + + cmd = (struct eth_priv_cmd *)malloc(sizeof(struct eth_priv_cmd)); + if (!cmd) { + printf("ERR:Cannot allocate buffer for command!\n"); + free(buffer); + return MLAN_STATUS_FAILURE; + } + + /* Fill up buffer */ +#ifdef USERSPACE_32BIT_OVER_KERNEL_64BIT + memset(cmd, 0, sizeof(struct eth_priv_cmd)); + memcpy(&cmd->buf, &buffer, sizeof(buffer)); +#else + cmd->buf = buffer; +#endif + cmd->used_len = 0; + cmd->total_len = BUFFER_LENGTH; + + /* Perform IOCTL */ + memset(&ifr, 0, sizeof(struct ifreq)); + strncpy(ifr.ifr_ifrn.ifrn_name, dev_name, strlen(dev_name)); + ifr.ifr_ifru.ifru_data = (void *)cmd; + + if (ioctl(sockfd, MLAN_ETH_PRIV, &ifr)) { + perror("mlanutl"); + fprintf(stderr, "mlanutl: sysclock fail\n"); + if (cmd) + free(cmd); + if (buffer) + free(buffer); + return MLAN_STATUS_FAILURE; + } + + /* GET operation */ + if (argc == 3) { + memset(data, 0, sizeof(data)); + memcpy(data, buffer, sizeof(data)); + printf("sysclock = "); + for (i = 1; i <= data[0]; i++) { + printf("%d ", data[i]); + } + printf("\n"); + } + + if (buffer) + free(buffer); + if (cmd) + free(cmd); + + return MLAN_STATUS_SUCCESS; +} + +/** + * @brief Get GTK/PTK + * + * @param argc Number of arguments + * @param argv Pointer to the arguments array + * + * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_FAILURE + */ +static int +process_get_key(int argc, char *argv[]) +{ + t_u8 *buffer = NULL; + struct eth_priv_cmd *cmd; + struct ifreq ifr; + + if (argc != 3) { + printf("ERR: Invalid arguments\n"); + return MLAN_STATUS_FAILURE; + } + /* Initialize buffer */ + buffer = (t_u8 *)malloc(BUFFER_LENGTH); + if (!buffer) { + printf("ERR:Cannot allocate buffer for command!\n"); + return MLAN_STATUS_FAILURE; + } + + prepare_buffer(buffer, argv[2], 0, NULL); + + cmd = (struct eth_priv_cmd *)malloc(sizeof(struct eth_priv_cmd)); + if (!cmd) { + printf("ERR:Cannot allocate buffer for command!\n"); + free(buffer); + return MLAN_STATUS_FAILURE; + } + + /* Fill up buffer */ +#ifdef USERSPACE_32BIT_OVER_KERNEL_64BIT + memset(cmd, 0, sizeof(struct eth_priv_cmd)); + memcpy(&cmd->buf, &buffer, sizeof(buffer)); +#else + cmd->buf = buffer; +#endif + cmd->used_len = 0; + cmd->total_len = BUFFER_LENGTH; + + /* Perform IOCTL */ + memset(&ifr, 0, sizeof(struct ifreq)); + strncpy(ifr.ifr_ifrn.ifrn_name, dev_name, strlen(dev_name)); + ifr.ifr_ifru.ifru_data = (void *)cmd; + + if (ioctl(sockfd, MLAN_ETH_PRIV, &ifr)) { + perror("mlanutl"); + fprintf(stderr, "mlanutl: getkey fail\n"); + if (cmd) + free(cmd); + if (buffer) + free(buffer); + return MLAN_STATUS_FAILURE; + } + + if (cmd->used_len) + printf("Key is %s\n", buffer); + else + printf("Key is not set\n"); + + if (buffer) + free(buffer); + if (cmd) + free(cmd); + + return MLAN_STATUS_SUCCESS; +} + +/** + * @brief Associate to a specific indexed entry in the ScanTable + * + * @param argc Number of arguments + * @param argv Pointer to the arguments array + * + * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_FAILURE + */ +static int +process_associate_ssid_bssid(int argc, char *argv[]) +{ + t_u8 *buffer = NULL; + struct eth_priv_cmd *cmd; + struct ifreq ifr; + + if (argc == 3) { + printf("ERR: Invalid number of arguments\n"); + return MLAN_STATUS_FAILURE; + } + /* Initialize buffer */ + buffer = (t_u8 *)malloc(BUFFER_LENGTH); + if (!buffer) { + printf("ERR:Cannot allocate buffer for command!\n"); + return MLAN_STATUS_FAILURE; + } + + prepare_buffer(buffer, argv[2], (argc - 3), &argv[3]); + + cmd = (struct eth_priv_cmd *)malloc(sizeof(struct eth_priv_cmd)); + if (!cmd) { + printf("ERR:Cannot allocate buffer for command!\n"); + free(buffer); + return MLAN_STATUS_FAILURE; + } + + /* Fill up buffer */ +#ifdef USERSPACE_32BIT_OVER_KERNEL_64BIT + memset(cmd, 0, sizeof(struct eth_priv_cmd)); + memcpy(&cmd->buf, &buffer, sizeof(buffer)); +#else + cmd->buf = buffer; +#endif + cmd->used_len = 0; + cmd->total_len = BUFFER_LENGTH; + + /* Perform IOCTL */ + memset(&ifr, 0, sizeof(struct ifreq)); + strncpy(ifr.ifr_ifrn.ifrn_name, dev_name, strlen(dev_name)); + ifr.ifr_ifru.ifru_data = (void *)cmd; + + if (ioctl(sockfd, MLAN_ETH_PRIV, &ifr)) { + perror("mlanutl"); + fprintf(stderr, "mlanutl: associate fail\n"); + if (cmd) + free(cmd); + if (buffer) + free(buffer); + return MLAN_STATUS_FAILURE; + } + + if (buffer) + free(buffer); + if (cmd) + free(cmd); + + return MLAN_STATUS_SUCCESS; +} + +/** + * @brief Set/Get Transmit beamforming configuration + * + * @param argc Number of arguments + * @param argv Pointer to the arguments array + * + * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_FAILURE + */ +static int +process_tx_bf_cfg(int argc, char *argv[]) +{ + t_u8 *buffer = NULL; + char *param = NULL; + struct eth_priv_cmd *cmd = NULL; + struct ifreq ifr; + t_u32 param_cnt = 0; + int status = MLAN_STATUS_SUCCESS; + int bf_action; + bf_global_cfg *bf_cfg = NULL; + + if (argc == 3) { + printf("ERR: Invalid number of arguments\n"); + return MLAN_STATUS_FAILURE; + } + /* Initialize buffer */ + buffer = (t_u8 *)malloc(BUFFER_LENGTH); + if (!buffer) { + printf("ERR:Cannot allocate buffer for command!\n"); + return MLAN_STATUS_FAILURE; + } + + prepare_buffer(buffer, argv[2], (argc - 3), &argv[3]); + + cmd = (struct eth_priv_cmd *)malloc(sizeof(struct eth_priv_cmd)); + if (!cmd) { + printf("ERR:Cannot allocate buffer for command!\n"); + status = MLAN_STATUS_FAILURE; + goto exit; + } + + /* Fill up buffer */ +#ifdef USERSPACE_32BIT_OVER_KERNEL_64BIT + memset(cmd, 0, sizeof(struct eth_priv_cmd)); + memcpy(&cmd->buf, &buffer, sizeof(buffer)); +#else + cmd->buf = buffer; +#endif + cmd->used_len = 0; + cmd->total_len = BUFFER_LENGTH; + + /* Perform IOCTL */ + memset(&ifr, 0, sizeof(struct ifreq)); + strncpy(ifr.ifr_ifrn.ifrn_name, dev_name, strlen(dev_name)); + ifr.ifr_ifru.ifru_data = (void *)cmd; + + if (ioctl(sockfd, MLAN_ETH_PRIV, &ifr)) { + perror("mlanutl"); + fprintf(stderr, "mlanutl: httxbfcfg fail\n"); + status = MLAN_STATUS_FAILURE; + goto exit; + } + + param = argv[3]; + param_cnt = strlen(param); + if (param_cnt == 1) { + /* The first byte represents the beamforming action */ + bf_action = atoi(argv[3]); + switch (bf_action) { + case BF_GLOBAL_CONFIGURATION: + bf_cfg = (bf_global_cfg *) buffer; + printf("Action: BF Configuration (%d) \n", bf_action); + printf("Enable: %d\n", bf_cfg->bf_enbl); + printf("Sounding Enable: %d\n", + bf_cfg->sounding_enbl); + printf("Feedback Type: %d\n", bf_cfg->fb_type); + printf("SNR Threshold: %d\n", + bf_cfg->snr_threshold); + printf("Sounding Interval: %d\n", + bf_cfg->sounding_interval); + printf("BF Mode: %d\n", bf_cfg->bf_mode); + break; + default: + break; + } + } + +exit: + if (buffer) + free(buffer); + if (cmd) + free(cmd); + + return status; +} + +/** + * @brief Control WPS Session Enable/Disable + * + * @param argc Number of arguments + * @param argv Pointer to the arguments array + * + * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_FAILURE + */ +static int +process_wps_cfg(int argc, char *argv[]) +{ + t_u8 *buffer = NULL; + struct eth_priv_cmd *cmd; + struct ifreq ifr; + + if (argc < 3 && argc > 4) { + printf("ERR: Invalid number of arguments\n"); + return MLAN_STATUS_FAILURE; + } + /* Initialize buffer */ + buffer = (t_u8 *)malloc(BUFFER_LENGTH); + if (!buffer) { + printf("ERR:Cannot allocate buffer for command!\n"); + return MLAN_STATUS_FAILURE; + } + + prepare_buffer(buffer, argv[2], (argc - 3), &argv[3]); + + cmd = (struct eth_priv_cmd *)malloc(sizeof(struct eth_priv_cmd)); + if (!cmd) { + printf("ERR:Cannot allocate buffer for command!\n"); + free(buffer); + return MLAN_STATUS_FAILURE; + } + + /* Fill up buffer */ +#ifdef USERSPACE_32BIT_OVER_KERNEL_64BIT + memset(cmd, 0, sizeof(struct eth_priv_cmd)); + memcpy(&cmd->buf, &buffer, sizeof(buffer)); +#else + cmd->buf = buffer; +#endif + cmd->used_len = 0; + cmd->total_len = BUFFER_LENGTH; + + /* Perform IOCTL */ + memset(&ifr, 0, sizeof(struct ifreq)); + strncpy(ifr.ifr_ifrn.ifrn_name, dev_name, strlen(dev_name)); + ifr.ifr_ifru.ifru_data = (void *)cmd; + + if (ioctl(sockfd, MLAN_ETH_PRIV, &ifr)) { + perror("mlanutl"); + fprintf(stderr, "mlanutl: wpssession fail\n"); + if (cmd) + free(cmd); + if (buffer) + free(buffer); + return MLAN_STATUS_FAILURE; + } + printf("%s\n", buffer); + + if (buffer) + free(buffer); + if (cmd) + free(cmd); + + return MLAN_STATUS_SUCCESS; +} + +/** + * @brief Set/Get Port Control mode + * + * @param argc Number of arguments + * @param argv Pointer to the arguments array + * + * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_FAILURE + */ +static int +process_port_ctrl(int argc, char *argv[]) +{ + t_u8 *buffer = NULL; + struct eth_priv_cmd *cmd; + struct ifreq ifr; + int port_ctrl = 0; + + if (argc < 3 && argc > 4) { + printf("ERR: Invalid number of arguments\n"); + return MLAN_STATUS_FAILURE; + } + /* Initialize buffer */ + buffer = (t_u8 *)malloc(BUFFER_LENGTH); + if (!buffer) { + printf("ERR:Cannot allocate buffer for command!\n"); + return MLAN_STATUS_FAILURE; + } + + prepare_buffer(buffer, argv[2], (argc - 3), &argv[3]); + + cmd = (struct eth_priv_cmd *)malloc(sizeof(struct eth_priv_cmd)); + if (!cmd) { + printf("ERR:Cannot allocate buffer for command!\n"); + free(buffer); + return MLAN_STATUS_FAILURE; + } + + /* Fill up buffer */ +#ifdef USERSPACE_32BIT_OVER_KERNEL_64BIT + memset(cmd, 0, sizeof(struct eth_priv_cmd)); + memcpy(&cmd->buf, &buffer, sizeof(buffer)); +#else + cmd->buf = buffer; +#endif + cmd->used_len = 0; + cmd->total_len = BUFFER_LENGTH; + + /* Perform IOCTL */ + memset(&ifr, 0, sizeof(struct ifreq)); + strncpy(ifr.ifr_ifrn.ifrn_name, dev_name, strlen(dev_name)); + ifr.ifr_ifru.ifru_data = (void *)cmd; + + if (ioctl(sockfd, MLAN_ETH_PRIV, &ifr)) { + perror("mlanutl"); + fprintf(stderr, "mlanutl: port_ctrl fail\n"); + if (cmd) + free(cmd); + if (buffer) + free(buffer); + return MLAN_STATUS_FAILURE; + } + if (argc == 3) { + port_ctrl = (int)*buffer; + if (port_ctrl == 1) + printf("port_ctrl is Enabled\n"); + else + printf("port_ctrl is Disabled\n"); + } + + if (buffer) + free(buffer); + if (cmd) + free(cmd); + + return MLAN_STATUS_SUCCESS; +} + +/** + * @brief Private IOCTL entry to get the By-passed TX packet from upper layer + * + * @param argc Number of arguments + * @param argv Pointer to the arguments array + * + * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_FAILURE + */ +static int +process_bypassed_packet(int argc, char *argv[]) +{ + t_u8 *buffer = NULL; + struct eth_priv_cmd *cmd; + struct ifreq ifr; + + /* Initialize buffer */ + buffer = (t_u8 *)malloc(BUFFER_LENGTH); + if (!buffer) { + printf("ERR:Cannot allocate buffer for command!\n"); + return MLAN_STATUS_FAILURE; + } + + prepare_buffer(buffer, argv[2], (argc - 3), &argv[3]); + + cmd = (struct eth_priv_cmd *)malloc(sizeof(struct eth_priv_cmd)); + if (!cmd) { + printf("ERR:Cannot allocate buffer for command!\n"); + free(buffer); + return MLAN_STATUS_FAILURE; + } + + /* Fill up buffer */ +#ifdef USERSPACE_32BIT_OVER_KERNEL_64BIT + memset(cmd, 0, sizeof(struct eth_priv_cmd)); + memcpy(&cmd->buf, &buffer, sizeof(buffer)); +#else + cmd->buf = buffer; +#endif + cmd->used_len = 0; + cmd->total_len = BUFFER_LENGTH; + + /* Perform IOCTL */ + memset(&ifr, 0, sizeof(struct ifreq)); + strncpy(ifr.ifr_ifrn.ifrn_name, dev_name, strlen(dev_name)); + ifr.ifr_ifru.ifru_data = (void *)cmd; + + if (ioctl(sockfd, MLAN_ETH_PRIV, &ifr)) { + perror("mlanutl"); + fprintf(stderr, "mlanutl: pb_bypass fail\n"); + if (cmd) + free(cmd); + if (buffer) + free(buffer); + return MLAN_STATUS_FAILURE; + } + + if (buffer) + free(buffer); + if (cmd) + free(cmd); + + return MLAN_STATUS_SUCCESS; +} + +/* #ifdef FW_WAKEUP_METHOD */ +/** + * @brief Set/Get module configuration + * + * @param argc Number of arguments + * @param argv Pointer to the arguments array + * + * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_FAILURE + */ +static int +process_fw_wakeup_method(int argc, char *argv[]) +{ + t_u8 *buffer = NULL; + struct eth_priv_cmd *cmd; + struct ifreq ifr; + int fw_wakeup_method = 0; + int gpio_pin = 0; + + if (argc < 3 || argc > 5) { + printf("ERR: Invalid number of arguments\n"); + return MLAN_STATUS_FAILURE; + } + /* Initialize buffer */ + buffer = (t_u8 *)malloc(BUFFER_LENGTH); + if (!buffer) { + printf("ERR:Cannot allocate buffer for command!\n"); + return MLAN_STATUS_FAILURE; + } + + prepare_buffer(buffer, argv[2], (argc - 3), &argv[3]); + + cmd = (struct eth_priv_cmd *)malloc(sizeof(struct eth_priv_cmd)); + if (!cmd) { + printf("ERR:Cannot allocate buffer for command!\n"); + free(buffer); + return MLAN_STATUS_FAILURE; + } + + /* Fill up buffer */ +#ifdef USERSPACE_32BIT_OVER_KERNEL_64BIT + memset(cmd, 0, sizeof(struct eth_priv_cmd)); + memcpy(&cmd->buf, &buffer, sizeof(buffer)); +#else + cmd->buf = buffer; +#endif + cmd->used_len = 0; + cmd->total_len = BUFFER_LENGTH; + + /* Perform IOCTL */ + memset(&ifr, 0, sizeof(struct ifreq)); + strncpy(ifr.ifr_ifrn.ifrn_name, dev_name, strlen(dev_name)); + ifr.ifr_ifru.ifru_data = (void *)cmd; + + if (ioctl(sockfd, MLAN_ETH_PRIV, &ifr)) { + perror("mlanutl"); + fprintf(stderr, "mlanutl: fwwakeupmethod fail\n"); + if (cmd) + free(cmd); + if (buffer) + free(buffer); + return MLAN_STATUS_FAILURE; + } + if (argc == 3) { + fw_wakeup_method = (int)*buffer; + gpio_pin = (int)*(buffer + 4); + if (fw_wakeup_method == 1) + printf("FW wakeup method is interface\n"); + else if (fw_wakeup_method == 2) + printf("FW wakeup method is gpio, GPIO Pin is %d\n", + gpio_pin); + } + + if (buffer) + free(buffer); + if (cmd) + free(cmd); + + return MLAN_STATUS_SUCCESS; +} + +/* #endif */ + +#ifdef SDIO +/** + * @brief SD comand53 read/write + * + * @param argc number of arguments + * @param argv A pointer to arguments array + * @return MLAN_STATUS_SUCCESS--success, otherwise--fail + */ +int +process_sdcmd53rw(int argc, char *argv[]) +{ + int ret = MLAN_STATUS_SUCCESS; + int cmd_header_len = 0; + struct eth_priv_cmd *cmd; + struct ifreq ifr; + t_u8 *buffer = NULL; + t_u8 *pos = NULL; + int addr, mode, blklen, blknum, i = 0, rw; + t_u16 cmd_len = 0; + + if (argc < 8) { + fprintf(stderr, "Invalid number of parameters!\n"); + return MLAN_STATUS_FAILURE; + } + /* Initialize buffer */ + buffer = (t_u8 *)malloc(BUFFER_LENGTH); + if (!buffer) { + printf("ERR:Cannot allocate buffer for command!\n"); + return MLAN_STATUS_FAILURE; + } + prepare_buffer(buffer, argv[2], 0, NULL); + + cmd_header_len = strlen(CMD_NXP) + strlen(argv[2]); + + pos = buffer + cmd_header_len + sizeof(cmd_len); + + if (argc == 8) { + rw = pos[0] = 0; /* CMD53 read */ + } else { + rw = pos[0] = 1; /* CMD53 write */ + } + pos[1] = atoval(argv[3]); /* func (0/1/2) */ + addr = atoval(argv[4]); /* address */ + pos[2] = addr & 0xff; + pos[3] = (addr >> 8) & 0xff; + pos[4] = (addr >> 16) & 0xff; + pos[5] = (addr >> 24) & 0xff; + mode = atoval(argv[5]); /* byte mode/block mode (0/1) */ + pos[6] = (t_u8)mode; + blklen = atoval(argv[6]); /* block size */ + pos[7] = blklen & 0xff; + pos[8] = (blklen >> 8) & 0xff; + blknum = atoval(argv[7]); /* block number or byte number */ + pos[9] = blknum & 0xff; + pos[10] = (blknum >> 8) & 0xff; + if (pos[0]) { + for (i = 0; i < (argc - 8); i++) + pos[11 + i] = atoval(argv[8 + i]); + } + cmd_len = 11 + i; + memcpy(buffer + cmd_header_len, &cmd_len, sizeof(cmd_len)); + + cmd = (struct eth_priv_cmd *)malloc(sizeof(struct eth_priv_cmd)); + if (!cmd) { + printf("ERR:Cannot allocate buffer for command!\n"); + ret = MLAN_STATUS_FAILURE; + goto done; + } + + /* Fill up buffer */ +#ifdef USERSPACE_32BIT_OVER_KERNEL_64BIT + memset(cmd, 0, sizeof(struct eth_priv_cmd)); + memcpy(&cmd->buf, &buffer, sizeof(buffer)); +#else + cmd->buf = buffer; +#endif + cmd->used_len = 0; + cmd->total_len = BUFFER_LENGTH; + + /* Perform IOCTL */ + memset(&ifr, 0, sizeof(struct ifreq)); + strncpy(ifr.ifr_ifrn.ifrn_name, dev_name, strlen(dev_name)); + ifr.ifr_ifru.ifru_data = (void *)cmd; + + if (ioctl(sockfd, MLAN_ETH_PRIV, &ifr)) { + perror("mlanutl"); + fprintf(stderr, "mlanutl: sdcmd53rw fail\n"); + ret = MLAN_STATUS_FAILURE; + goto done; + } + + if (mode) { + fprintf(stderr, "CMD53rw blklen = %d, blknum = %d\n", blklen, + blknum); + } else { + blklen = 1; + fprintf(stderr, "CMD53rw bytelen = %d\n", blknum); + } + if (!rw) + hexdump("CMD53 data", buffer, blklen * blknum, ' '); + +done: + if (buffer) + free(buffer); + if (cmd) + free(cmd); + + return ret; +} +#endif + +#ifdef WIFI_DIRECT_SUPPORT +/** + * @brief Set/Get P2P NoA (Notice of Absence) Or OPP-PS parameters + * + * @param argc Number of arguments + * @param argv Pointer to the arguments array + * + * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_FAILURE + */ +static int +process_cfg_noa_opp_ps(int argc, char *argv[]) +{ + t_u8 *buffer = NULL; + struct eth_priv_cmd *cmd; + struct ifreq ifr; + mlan_ds_wifi_direct_config *cfg; + + if (argc < 3 || argc > 8) { + printf("ERR: Invalid number of arguments\n"); + return MLAN_STATUS_FAILURE; + } + + /* Initialize buffer */ + buffer = (t_u8 *)malloc(BUFFER_LENGTH); + if (!buffer) { + printf("ERR:Cannot allocate buffer for command!\n"); + return MLAN_STATUS_FAILURE; + } + + prepare_buffer(buffer, argv[2], (argc - 3), &argv[3]); + + cmd = (struct eth_priv_cmd *)malloc(sizeof(struct eth_priv_cmd)); + if (!cmd) { + printf("ERR:Cannot allocate buffer for command!\n"); + free(buffer); + return MLAN_STATUS_FAILURE; + } + + /* Fill up buffer */ +#ifdef USERSPACE_32BIT_OVER_KERNEL_64BIT + memset(cmd, 0, sizeof(struct eth_priv_cmd)); + memcpy(&cmd->buf, &buffer, sizeof(buffer)); +#else + cmd->buf = buffer; +#endif + cmd->used_len = 0; + cmd->total_len = BUFFER_LENGTH; + + /* Perform IOCTL */ + memset(&ifr, 0, sizeof(struct ifreq)); + strncpy(ifr.ifr_ifrn.ifrn_name, dev_name, strlen(dev_name)); + ifr.ifr_ifru.ifru_data = (void *)cmd; + + if (ioctl(sockfd, MLAN_ETH_PRIV, &ifr)) { + perror("mlanutl"); + fprintf(stderr, "mlanutl: noa_cfg fail\n"); + if (cmd) + free(cmd); + if (buffer) + free(buffer); + return MLAN_STATUS_FAILURE; + } + if (argc == 3) { + cfg = (mlan_ds_wifi_direct_config *)buffer; + if (!cfg) { + printf("Err : Could not get P2P noa configuration\n"); + if (cmd) + free(cmd); + if (buffer) + free(buffer); + return MLAN_STATUS_FAILURE; + } + + if (cfg->flags & WIFI_DIRECT_NOA) { + printf("noa_enable : %d\n", cfg->noa_enable); + printf("index : %d\n", cfg->index); + printf("noa_count : %d\n", cfg->noa_count); + printf("noa_duration : %d\n", cfg->noa_duration); + printf("noa_interval : %d\n", cfg->noa_interval); + } + if (cfg->flags & WIFI_DIRECT_OPP_PS) { + printf("opp_ps_enable : %d\n", cfg->opp_ps_enable); + printf("ct_window : %d\n", cfg->ct_window); + } + } + + if (buffer) + free(buffer); + if (cmd) + free(cmd); + + return MLAN_STATUS_SUCCESS; +} +#endif + +/** + * @brief Issue a dscp map command + * + * @param argc number of arguments + * @param argv A pointer to arguments array + * + * @return MLAN_STATUS_SUCCESS--success, otherwise--fail + */ +static int +process_dscpmap(int argc, char *argv[]) +{ + int ret = 0; + t_u8 *buffer = NULL; + struct eth_priv_cmd *cmd = NULL; + struct ifreq ifr; + unsigned int dscp, tid, idx; + t_u8 dscp_map[64]; + + buffer = (t_u8 *)malloc(BUFFER_LENGTH); + if (buffer == NULL) { + fprintf(stderr, "Cannot alloc memory\n"); + ret = ENOMEM; + goto done; + } + memset(buffer, 0, BUFFER_LENGTH); + + cmd = (struct eth_priv_cmd *)malloc(sizeof(struct eth_priv_cmd)); + if (!cmd) { + printf("ERR:Cannot allocate buffer for command!\n"); + ret = ENOMEM; + goto done; + } + + /* buffer = MRVL_CMD */ + strncpy((char *)buffer, CMD_NXP, strlen(CMD_NXP)); + strncpy((char *)buffer + strlen(CMD_NXP), argv[2], strlen(argv[2])); + + /* Fill up buffer */ +#ifdef USERSPACE_32BIT_OVER_KERNEL_64BIT + memset(cmd, 0, sizeof(struct eth_priv_cmd)); + memcpy(&cmd->buf, &buffer, sizeof(buffer)); +#else + cmd->buf = buffer; +#endif + cmd->used_len = 0; + cmd->total_len = BUFFER_LENGTH; + + /* Perform IOCTL */ + memset(&ifr, 0, sizeof(struct ifreq)); + strncpy(ifr.ifr_ifrn.ifrn_name, dev_name, strlen(dev_name)); + ifr.ifr_ifru.ifru_data = (void *)cmd; + + if (ioctl(sockfd, MLAN_ETH_PRIV, &ifr)) { + perror("ioctl[dscpmap]"); + printf("ERR:Command sending failed!\n"); + ret = -EFAULT; + goto done; + } + memcpy(dscp_map, buffer, sizeof(dscp_map)); + + if ((argc == 4) && (strcmp(argv[3], "reset") == 0)) { + memset(dscp_map, 0xff, sizeof(dscp_map)); + } else if (argc == (3 + sizeof(dscp_map))) { + /* Update the entire dscp table */ + for (idx = 3; idx < (3 + sizeof(dscp_map)); idx++) { + tid = a2hex_or_atoi(argv[idx]); + + if (tid < 8) { + dscp_map[idx - 3] = tid; + } + } + } else if (argc > 3 && argc <= (3 + sizeof(dscp_map))) { + /* Update any dscp entries provided on the command line */ + for (idx = 3; idx < argc; idx++) { + if ((sscanf(argv[idx], "%x=%x", &dscp, &tid) == 2) + && (dscp < sizeof(dscp_map)) + && (tid < 8)) { + dscp_map[dscp] = tid; + } + } + } else if (argc != 3) { + printf("Invalid number of arguments\n"); + ret = MLAN_STATUS_FAILURE; + goto done; + } + + memset(buffer, 0, BUFFER_LENGTH); + /* buffer = MRVL_CMD */ + strncpy((char *)buffer, CMD_NXP, strlen(CMD_NXP)); + strncpy((char *)buffer + strlen(CMD_NXP), argv[2], strlen(argv[2])); + if (argc > 3) + memcpy(buffer + strlen(CMD_NXP) + strlen(argv[2]), + dscp_map, sizeof(dscp_map)); +#ifdef USERSPACE_32BIT_OVER_KERNEL_64BIT + memset(cmd, 0, sizeof(struct eth_priv_cmd)); + memcpy(&cmd->buf, &buffer, sizeof(buffer)); +#else + cmd->buf = buffer; +#endif + cmd->used_len = 0; + cmd->total_len = BUFFER_LENGTH; + + /* Perform IOCTL */ + memset(&ifr, 0, sizeof(struct ifreq)); + strncpy(ifr.ifr_ifrn.ifrn_name, dev_name, strlen(dev_name)); + ifr.ifr_ifru.ifru_data = (void *)cmd; + + if (ioctl(sockfd, MLAN_ETH_PRIV, &ifr)) { + perror("ioctl[dscpmap]"); + printf("ERR:Command sending failed!\n"); + ret = -EFAULT; + goto done; + } + + /* Display the active dscp -> TID mapping table */ + if (cmd->used_len) { + printf("DscpMap:\n"); + hexdump(NULL, buffer, cmd->used_len, ' '); + } + +done: + if (buffer) + free(buffer); + if (cmd) + free(cmd); + return ret; +} + +/** + * @brief Set/Get DF repeater mode parameters + * + * @param argc number of arguments + * @param argv A pointer to arguments array + * + * @return MLAN_STATUS_SUCCESS--success, otherwise--fail + */ +static int +process_dfs_repeater(int argc, char *argv[]) +{ + int ret = 0; + t_u8 *buffer = NULL; + struct eth_priv_cmd *cmd = NULL; + struct ifreq ifr; + dfs_repeater *dfs_rptr = NULL; + + if (argc < 3 && argc > 4) { + printf("ERR: Invalid number of arguments\n"); + return MLAN_STATUS_FAILURE; + } + + /* Initialize buffer */ + buffer = (t_u8 *)malloc(BUFFER_LENGTH); + if (!buffer) { + printf("ERR:Cannot allocate buffer for command!\n"); + return MLAN_STATUS_FAILURE; + } + + prepare_buffer(buffer, argv[2], (argc - 3), &argv[3]); + + cmd = (struct eth_priv_cmd *)malloc(sizeof(struct eth_priv_cmd)); + if (!cmd) { + printf("ERR:Cannot allocate buffer for command!\n"); + free(buffer); + return MLAN_STATUS_FAILURE; + } + + /* Fill up buffer */ +#ifdef USERSPACE_32BIT_OVER_KERNEL_64BIT + memset(cmd, 0, sizeof(struct eth_priv_cmd)); + memcpy(&cmd->buf, &buffer, sizeof(buffer)); +#else + cmd->buf = buffer; +#endif + cmd->used_len = 0; + cmd->total_len = BUFFER_LENGTH; + + /* Perform IOCTL */ + memset(&ifr, 0, sizeof(struct ifreq)); + strncpy(ifr.ifr_ifrn.ifrn_name, dev_name, strlen(dev_name)); + ifr.ifr_ifru.ifru_data = (void *)cmd; + + if (ioctl(sockfd, MLAN_ETH_PRIV, &ifr)) { + perror("mlanutl"); + fprintf(stderr, "mlanutl: %s fail\n", __func__); + ret = MLAN_STATUS_FAILURE; + goto done; + } + if (argc == 3) { + dfs_rptr = (dfs_repeater *) buffer; + printf("DFS repeater mode: %s\n", + (dfs_rptr->mode) ? "On" : "Off"); + } + +done: + if (buffer) + free(buffer); + if (cmd) + free(cmd); + + return ret; +} + +#ifdef WIFI_DIRECT_SUPPORT +/** + * @brief Set/Get miracast configuration parameters + * + * @param argc number of arguments + * @param argv A pointer to arguments array + * + * @return MLAN_STATUS_SUCCESS--success, otherwise--fail + */ +static int +process_miracastcfg(int argc, char *argv[]) +{ + int ret = MLAN_STATUS_SUCCESS; + int data[3]; + t_u8 *buffer = NULL; + struct eth_priv_cmd *cmd = NULL; + struct ifreq ifr; + + if (argc < 3 && argc > 6) { + fprintf(stderr, "mlanutl: Invalid number of arguments\n"); + ret = MLAN_STATUS_FAILURE; + goto done; + } + + /* Initialize buffer */ + buffer = (t_u8 *)malloc(BUFFER_LENGTH); + if (!buffer) { + fprintf(stderr, "mlanutl: Cannot allocate memory\n"); + ret = MLAN_STATUS_FAILURE; + goto done; + } + + prepare_buffer(buffer, argv[2], (argc - 3), &argv[3]); + + cmd = (struct eth_priv_cmd *)malloc(sizeof(struct eth_priv_cmd)); + if (!cmd) { + fprintf(stderr, + "mlanutl: Cannot allocate buffer for command\n"); + ret = MLAN_STATUS_FAILURE; + goto done; + } + + /* Fill up buffer */ +#ifdef USERSPACE_32BIT_OVER_KERNEL_64BIT + memset(cmd, 0, sizeof(struct eth_priv_cmd)); + memcpy(&cmd->buf, &buffer, sizeof(buffer)); +#else + cmd->buf = buffer; +#endif + cmd->used_len = 0; + cmd->total_len = BUFFER_LENGTH; + + /* Perform IOCTL */ + memset(&ifr, 0, sizeof(struct ifreq)); + strncpy(ifr.ifr_ifrn.ifrn_name, dev_name, strlen(dev_name)); + ifr.ifr_ifru.ifru_data = (void *)cmd; + + if (ioctl(sockfd, MLAN_ETH_PRIV, &ifr)) { + perror("mlanutl"); + fprintf(stderr, "mlanutl: miracastcfg fail\n"); + ret = MLAN_STATUS_FAILURE; + goto done; + } + + memset(data, 0, sizeof(data)); + /* Process result */ + memcpy(data, buffer, sizeof(data)); + if (argc == 3) { + /* GET operation */ + printf("Miracast Configuration:\n"); + printf(" Mode: %d\n", data[0]); + printf(" Scan time: %d\n", data[1]); + printf(" Scan channel gap: %d\n", data[2]); + } + +done: + if (buffer) + free(buffer); + if (cmd) + free(cmd); + + return ret; +} +#endif /* WIFI_DIRECT_SUPPORT */ + +/** + * @brief Set/get control to coex RX window size + * + * @param argc Number of arguments + * @param argv Pointer to the arguments array + * + * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_FAILURE + */ +static int +process_coex_rx_winsize(int argc, char *argv[]) +{ + int ret = 0; + int coex_rx_winsize = 0; + t_u8 *buffer = NULL; + struct eth_priv_cmd *cmd = NULL; + struct ifreq ifr; + + /* Check if arguments are valid */ + if ((argc != 3) && (argc != 4)) { + printf("ERR: Invalid arguments\n"); + ret = MLAN_STATUS_FAILURE; + goto done; + } + + /* Initialize buffer */ + buffer = (t_u8 *)malloc(BUFFER_LENGTH); + if (!buffer) { + printf("ERR: Cannot allocate buffer for command!\n"); + ret = MLAN_STATUS_FAILURE; + goto done; + } + + prepare_buffer(buffer, argv[2], (argc - 3), &argv[3]); + + cmd = (struct eth_priv_cmd *)malloc(sizeof(struct eth_priv_cmd)); + if (!cmd) { + printf("ERR: Cannot allocate buffer for command!\n"); + ret = MLAN_STATUS_FAILURE; + goto done; + } + + /* Fill up buffer */ +#ifdef USERSPACE_32BIT_OVER_KERNEL_64BIT + memset(cmd, 0, sizeof(struct eth_priv_cmd)); + memcpy(&cmd->buf, &buffer, sizeof(buffer)); +#else + cmd->buf = buffer; +#endif + cmd->used_len = 0; + cmd->total_len = BUFFER_LENGTH; + + /* Perform IOCTL */ + memset(&ifr, 0, sizeof(struct ifreq)); + strncpy(ifr.ifr_ifrn.ifrn_name, dev_name, strlen(dev_name)); + ifr.ifr_ifru.ifru_data = (void *)cmd; + + if (ioctl(sockfd, MLAN_ETH_PRIV, &ifr)) { + perror("mlanutl"); + fprintf(stderr, "mlanutl: coex_rx_winsize fail\n"); + ret = MLAN_STATUS_FAILURE; + goto done; + } + if (argc == 3) { + memcpy(&coex_rx_winsize, buffer, sizeof(coex_rx_winsize)); + printf("COEX RX winsize is %s\n", + coex_rx_winsize ? "enabled" : "disabled"); + } + +done: + if (buffer) + free(buffer); + if (cmd) + free(cmd); + + return ret; +} + +#ifdef PCIE +/** + * @brief Read/Write PCIE register + * + * @param argc Number of arguments + * @param argv Pointer to the arguments array + * + * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_FAILURE + */ +static int +process_pcie_reg_rw(int argc, char *argv[]) +{ + int ret = 0, data[2]; + t_u8 *buffer = NULL; + struct eth_priv_cmd *cmd = NULL; + struct ifreq ifr; + + /* Check if arguments are valid */ + if ((argc != 4) && (argc != 5)) { + printf("ERR: Invalid arguments\n"); + ret = MLAN_STATUS_FAILURE; + goto done; + } + + /* Initialize buffer */ + buffer = (t_u8 *)malloc(BUFFER_LENGTH); + if (!buffer) { + printf("ERR:Cannot allocate buffer for command!\n"); + ret = MLAN_STATUS_FAILURE; + goto done; + } + + prepare_buffer(buffer, argv[2], (argc - 3), &argv[3]); + + cmd = (struct eth_priv_cmd *)malloc(sizeof(struct eth_priv_cmd)); + if (!cmd) { + printf("ERR:Cannot allocate buffer for command!\n"); + ret = MLAN_STATUS_FAILURE; + goto done; + } + + /* Fill up buffer */ +#ifdef USERSPACE_32BIT_OVER_KERNEL_64BIT + memset(cmd, 0, sizeof(struct eth_priv_cmd)); + memcpy(&cmd->buf, &buffer, sizeof(buffer)); +#else + cmd->buf = buffer; +#endif + cmd->used_len = 0; + cmd->total_len = BUFFER_LENGTH; + + /* Perform IOCTL */ + memset(&ifr, 0, sizeof(struct ifreq)); + strncpy(ifr.ifr_ifrn.ifrn_name, dev_name, strlen(dev_name)); + ifr.ifr_ifru.ifru_data = (void *)cmd; + + if (ioctl(sockfd, MLAN_ETH_PRIV, &ifr)) { + perror("mlanutl"); + fprintf(stderr, "mlanutl: pcieregrw fail\n"); + ret = MLAN_STATUS_FAILURE; + goto done; + } + if (argc == 4) { + memset(data, 0, sizeof(data)); + memcpy(data, buffer, sizeof(data)); + printf("Offset of PCIE register is %#x\n", data[0]); + printf("Value at the register is %#x\n", data[1]); + } + +done: + if (buffer) + free(buffer); + if (cmd) + free(cmd); + + return ret; +} + +/** + * @brief Read/Write PCIE register/memory from BAR0 + * + * @param argc Number of arguments + * @param argv Pointer to the arguments array + * + * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_FAILURE + */ +static int +process_pcie_bar0_reg_rw(int argc, char *argv[]) +{ + int ret = 0, data[2]; + t_u8 *buffer = NULL; + struct eth_priv_cmd *cmd = NULL; + struct ifreq ifr; + + /* Check if arguments are valid */ + if ((argc != 4) && (argc != 5)) { + printf("ERR: Invalid arguments\n"); + ret = MLAN_STATUS_FAILURE; + goto done; + } + + /* Initialize buffer */ + buffer = (t_u8 *)malloc(BUFFER_LENGTH); + if (!buffer) { + printf("ERR:Cannot allocate buffer for command!\n"); + ret = MLAN_STATUS_FAILURE; + goto done; + } + + prepare_buffer(buffer, argv[2], (argc - 3), &argv[3]); + + cmd = (struct eth_priv_cmd *)malloc(sizeof(struct eth_priv_cmd)); + if (!cmd) { + printf("ERR:Cannot allocate buffer for command!\n"); + ret = MLAN_STATUS_FAILURE; + goto done; + } + + /* Fill up buffer */ +#ifdef USERSPACE_32BIT_OVER_KERNEL_64BIT + memset(cmd, 0, sizeof(struct eth_priv_cmd)); + memcpy(&cmd->buf, &buffer, sizeof(buffer)); +#else + cmd->buf = buffer; +#endif + cmd->used_len = 0; + cmd->total_len = BUFFER_LENGTH; + + /* Perform IOCTL */ + memset(&ifr, 0, sizeof(struct ifreq)); + strncpy(ifr.ifr_ifrn.ifrn_name, dev_name, strlen(dev_name)); + ifr.ifr_ifru.ifru_data = (void *)cmd; + + if (ioctl(sockfd, MLAN_ETH_PRIV, &ifr)) { + perror("mlanutl"); + fprintf(stderr, "mlanutl: pcieregrw fail\n"); + ret = MLAN_STATUS_FAILURE; + goto done; + } + if (argc == 4) { + memset(data, 0, sizeof(data)); + memcpy(data, buffer, sizeof(data)); + printf("Offset of PCIE register is %#x\n", data[0]); + printf("Value at the register is %#x\n", data[1]); + } + +done: + if (buffer) + free(buffer); + if (cmd) + free(cmd); + + return ret; +} +#endif + +/** + * @brief get SOC sensor temperature. + * + * @param argc Number of arguments + * @param argv Pointer to the arguments array + * + * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_FAILURE + */ +static int +process_get_sensor_temp(int argc, char *argv[]) +{ + int ret = 0; + t_u32 temp = 0; + t_u8 *buffer = NULL; + struct eth_priv_cmd *cmd = NULL; + struct ifreq ifr; + + /* Initialize buffer */ + buffer = (t_u8 *)malloc(BUFFER_LENGTH); + if (!buffer) { + printf("ERR:Cannot allocate buffer for command!\n"); + ret = MLAN_STATUS_FAILURE; + goto done; + } + memset(buffer, 0, BUFFER_LENGTH); + + /* Sanity tests */ + if (argc != 3) { + printf("Error: invalid no of arguments\n"); + printf("mlanutl mlanX get_sensor_temp\n"); + ret = MLAN_STATUS_FAILURE; + goto done; + } + + prepare_buffer(buffer, argv[2], 0, NULL); + + cmd = (struct eth_priv_cmd *)malloc(sizeof(struct eth_priv_cmd)); + if (!cmd) { + printf("ERR:Cannot allocate buffer for command!\n"); + ret = MLAN_STATUS_FAILURE; + goto done; + } + + /* Fill up buffer */ +#ifdef USERSPACE_32BIT_OVER_KERNEL_64BIT + memset(cmd, 0, sizeof(struct eth_priv_cmd)); + memcpy(&cmd->buf, &buffer, sizeof(buffer)); +#else + cmd->buf = buffer; +#endif + cmd->used_len = 0; + cmd->total_len = BUFFER_LENGTH; + + /* Perform IOCTL */ + memset(&ifr, 0, sizeof(struct ifreq)); + strncpy(ifr.ifr_ifrn.ifrn_name, dev_name, strlen(dev_name)); + ifr.ifr_ifru.ifru_data = (void *)cmd; + + if (ioctl(sockfd, MLAN_ETH_PRIV, &ifr)) { + perror("mlanutl"); + fprintf(stderr, "mlanutl: temp_sensor fail\n"); + ret = MLAN_STATUS_FAILURE; + goto done; + } + + /* Process result */ + memcpy(&temp, buffer, sizeof(t_u32)); + printf("SOC temperature is %u C \n", temp); + +done: + if (buffer) + free(buffer); + if (cmd) + free(cmd); + + return ret; +} + +/** + * @brief Get channel report values + * + * @param chanNum Number of channels + * @param startFreq Start Frequency + * @param duration Duration + * @param pAnpi Pointer to the anpi value + * @param pLoadPercent Pointer to the LoadPercent value + * @param chanWidth Channel width + * + * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_FAILURE + */ +static int +chanrpt_getValues(t_u8 chanNum, t_u16 startFreq, + t_u32 duration, t_s16 *pAnpi, t_u8 *pLoadPercent, + t_u8 chanWidth) +{ + int ret = MLAN_STATUS_SUCCESS; + struct ifreq ifr; + t_u8 *buffer = NULL, *pos = NULL; + t_u32 cmd_len = 0, cmd_header_len; + struct eth_priv_cmd *cmd = NULL; + t_u8 *pByte; + int eventLen = 0; + MrvlIEtypes_Data_t *pTlvHdr; + HostCmd_DS_GEN *hostcmd; + HostCmd_DS_CHAN_RPT_RSP *pChanRptRsp = NULL; + HostCmd_DS_CHAN_RPT_REQ *pChanRptReq = NULL; + t_u8 *pChanRptEvent = NULL; + MrvlIEtypes_ChanRptChanLoad_t *pLoadRpt = NULL; + MrvlIEtypes_ChanRptNoiseHist_t *pNoiseRpt = NULL; + + cmd_header_len = strlen(CMD_NXP) + strlen(HOSTCMD); + + buffer = (t_u8 *)malloc(BUFFER_LENGTH); + if (buffer == NULL) { + fprintf(stderr, "Cannot alloc memory\n"); + ret = ENOMEM; + goto done; + } + memset(buffer, 0, BUFFER_LENGTH); + + cmd = (struct eth_priv_cmd *)malloc(sizeof(struct eth_priv_cmd)); + if (!cmd) { + printf("ERR:Cannot allocate buffer for command!\n"); + ret = ENOMEM; + goto done; + } + + /* Fill up buffer */ +#ifdef USERSPACE_32BIT_OVER_KERNEL_64BIT + memset(cmd, 0, sizeof(struct eth_priv_cmd)); + memcpy(&cmd->buf, &buffer, sizeof(buffer)); +#else + cmd->buf = buffer; +#endif + cmd->used_len = 0; + cmd->total_len = BUFFER_LENGTH; + + /* buffer = MRVL_CMD */ + strncpy((char *)buffer, CMD_NXP, strlen(CMD_NXP)); + strncpy((char *)buffer + strlen(CMD_NXP), HOSTCMD, strlen(HOSTCMD)); + + /* buffer = MRVL_CMD */ + hostcmd = (HostCmd_DS_GEN *)(buffer + cmd_header_len + sizeof(t_u32)); + + /* Point after host command header */ + pos = (t_u8 *)hostcmd + S_DS_GEN; + + cmd_len = S_DS_GEN + sizeof(HostCmd_DS_CHAN_RPT_REQ); + + hostcmd->command = cpu_to_le16(HostCmd_CMD_CHAN_REPORT_REQUEST); + hostcmd->size = cpu_to_le16(cmd_len); + hostcmd->seq_num = 0; + hostcmd->result = 0; + + pChanRptReq = (HostCmd_DS_CHAN_RPT_REQ *)pos; + + memset((void *)pChanRptReq, 0x00, sizeof(HostCmd_DS_CHAN_RPT_REQ)); + + pChanRptReq->chanDesc.chanNum = chanNum; + pChanRptReq->chanDesc.startFreq = cpu_to_le16(startFreq); + pChanRptReq->chanDesc.chanWidth = chanWidth; + pChanRptReq->millisecDwellTime = duration; + + /* Put buffer length */ + memcpy(buffer + cmd_header_len, &cmd_len, sizeof(t_u32)); + + /* Initialize the ifr structure */ + memset(&ifr, 0, sizeof(ifr)); + strncpy(ifr.ifr_ifrn.ifrn_name, dev_name, strlen(dev_name)); + ifr.ifr_ifru.ifru_data = (void *)cmd; + /* Perform ioctl */ + if (ioctl(sockfd, MLAN_ETH_PRIV, &ifr)) { + perror("ioctl[chanrpt hostcmd]"); + printf("ERR:Command sending failed!\n"); + ret = -EFAULT; + goto done; + } + + eventLen = NL_MAX_PAYLOAD; + pChanRptEvent = (t_u8 *)malloc(NL_MAX_PAYLOAD); + + if (!pChanRptEvent) { + printf("ERR:Could not allocate buffer!\n"); + ret = MLAN_STATUS_FAILURE; + goto done; + } + + ret = wait_event(EVENT_CHANNEL_REPORT_RDY, pChanRptEvent, &eventLen); + + if (ret || !pChanRptEvent || !eventLen) { + printf("ERR: wait_event failed!\n"); + ret = -EFAULT; + goto done; + } + + pChanRptRsp = (HostCmd_DS_CHAN_RPT_RSP *)(pChanRptEvent + EVENT_ID_LEN); + eventLen -= EVENT_ID_LEN; + + /* TSF is a t_u64, some formatted printing libs have + * trouble printing long longs, so cast and dump as bytes + */ + pByte = (t_u8 *)&pChanRptRsp->startTsf; + + pByte = pChanRptRsp->tlvBuffer; + + eventLen -= sizeof(pChanRptRsp->commandResult); + eventLen -= sizeof(pChanRptRsp->startTsf); + eventLen -= sizeof(pChanRptRsp->duration); + + pByte = pChanRptRsp->tlvBuffer; + + while ((unsigned int)eventLen >= sizeof(pTlvHdr->header)) { + pTlvHdr = (MrvlIEtypes_Data_t *)pByte; + pTlvHdr->header.len = le16_to_cpu(pTlvHdr->header.len); + + switch (le16_to_cpu(pTlvHdr->header.type)) { + case TLV_TYPE_CHANRPT_CHAN_LOAD: + pLoadRpt = (MrvlIEtypes_ChanRptChanLoad_t *)pTlvHdr; + *pLoadPercent = (pLoadRpt->ccaBusyFraction * 100) / 255; + break; + + case TLV_TYPE_CHANRPT_NOISE_HIST: + pNoiseRpt = (MrvlIEtypes_ChanRptNoiseHist_t *)pTlvHdr; + *pAnpi = pNoiseRpt->anpi; + break; + + default: + break; + } + + pByte += (pTlvHdr->header.len + sizeof(pTlvHdr->header)); + eventLen -= (pTlvHdr->header.len + sizeof(pTlvHdr->header)); + eventLen = (eventLen > 0) ? eventLen : 0; + } + +done: + if (buffer) + free(buffer); + if (cmd) + free(cmd); + if (pChanRptEvent) + free(pChanRptEvent); + return ret; +} + +/** + * @brief Print x Axis + * + * @param pChanRpt Pointer to the chan report + * @param numChans Number of channels + * + * @return void + */ +static void +chanrpt_print_xAxis(ChanRptInfo_t * pChanRpt, int numChans) +{ + int idx; + + printf(" `-"); + + for (idx = 0; idx < numChans; idx++) { + printf("----"); + } + + printf("\n "); + + for (idx = 0; idx < numChans; idx++) { + printf("%03d ", (pChanRpt + idx)->chanNum); + } + + printf("\n"); +} + +/** + * @brief Print anpi + * + * @param pChanRpt Pointer to the chan report + * @param numChans Number of channels + * + * @return void + */ +static void +chanrpt_print_anpi(ChanRptInfo_t * pChanRpt, int numChans) +{ + int dumpIdx; + int yAxis; + int yPrint; + + printf("\n"); + printf(" Average Noise Power Indicator\n"); + printf(" -----------------------------\n"); + + yPrint = 0; + for (yAxis = -55; yAxis >= -95; yAxis -= 2) { + if (yPrint % 2 == 1) { + printf("%2d| ", yAxis); + } else { + printf(" | "); + } + + yPrint++; + + for (dumpIdx = 0; dumpIdx < numChans; dumpIdx++) { + if ((pChanRpt + dumpIdx)->anpi >= yAxis) { + printf("### "); + } else if ((pChanRpt + dumpIdx)->anpi >= yAxis - 2) { + printf("%3d ", (pChanRpt + dumpIdx)->anpi); + } else { + printf(" "); + } + } + + printf("\n"); + } + + chanrpt_print_xAxis(pChanRpt, numChans); +} + +/** + * @brief Print chan load + * + * @param pChanRpt Pointer to the chan report + * @param numChans Number of channels + * + * @return void + */ +static void +chanrpt_print_chanLoad(ChanRptInfo_t * pChanRpt, int numChans) +{ + int dumpIdx; + int yAxis; + int yPrint; + + printf("\n"); + printf(" Channel Load\n"); + printf(" ------------\n"); + + yPrint = 0; + for (yAxis = 100; yAxis >= 0; yAxis -= 5) { + if (yPrint % 2 == 1) { + printf("%2d%%| ", yAxis); + } else { + printf(" | "); + } + + yPrint++; + + for (dumpIdx = 0; dumpIdx < numChans; dumpIdx++) { + if ((pChanRpt + dumpIdx)->chanLoad >= yAxis) { + printf("### "); + } else if ((pChanRpt + dumpIdx)->chanLoad >= yAxis - 5) { + printf("%2d%% ", + (pChanRpt + dumpIdx)->chanLoad); + } else { + printf(" "); + } + } + + printf("\n"); + } + chanrpt_print_xAxis(pChanRpt, numChans); +} + +/** + * @brief Get chanrpt values and print graph + * + * @param void + * + * @return void + */ +static void +chanrpt_graph(void) +{ + int idx; + ChanRptInfo_t chanRpt[14]; + + memset(chanRpt, 0x00, sizeof(chanRpt)); + for (idx = 0; (unsigned int)idx < NELEMENTS(chanRpt); idx++) { + chanRpt[idx].chanNum = idx + 1; + chanrpt_getValues(idx + 1, + 0, + 100, + &chanRpt[idx].anpi, &chanRpt[idx].chanLoad, + 0); + } + + chanrpt_print_anpi(chanRpt, NELEMENTS(chanRpt)); + chanrpt_print_chanLoad(chanRpt, NELEMENTS(chanRpt)); +} + +/** + * @brief Loops to get chanrpt values and print graph, at end print 1 average graph + * + * @param loopOnLoad Print Load graph loop on + * @param loopOnAnpi Print anpi graph loop on + * @param loops Loops + * + * @return void + */ +static void +chanrpt_graph_loop(boolean loopOnLoad, boolean loopOnAnpi, int loops) +{ + int idx; + int loopsLeft; + ChanRptInfo_t chanRpt[14]; + ChanRptInfo_t chanRptAvg[14]; + + memset(chanRpt, 0x00, sizeof(chanRpt)); + memset(chanRptAvg, 0x00, sizeof(chanRptAvg)); + for (idx = 0; (unsigned int)idx < NELEMENTS(chanRpt); idx++) { + chanRpt[idx].chanNum = idx + 1; + chanrpt_getValues(idx + 1, + 0, + 100, + &chanRpt[idx].anpi, &chanRpt[idx].chanLoad, + 0); + } + + idx = 0; + loopsLeft = loops; + + while (loopsLeft) { + chanRpt[idx].chanNum = idx + 1; + chanrpt_getValues(idx + 1, + 0, + 75, + &chanRpt[idx].anpi, &chanRpt[idx].chanLoad, + 0); + + chanRptAvg[idx].chanNum = idx + 1; + chanRptAvg[idx].anpi + = (chanRptAvg[idx].anpi * (loops - loopsLeft) + + chanRpt[idx].anpi) / (loops - loopsLeft + 1); + + chanRptAvg[idx].chanLoad + = (chanRptAvg[idx].chanLoad * (loops - loopsLeft) + + chanRpt[idx].chanLoad) / (loops - loopsLeft + 1); + + idx = (idx + 1) % NELEMENTS(chanRpt); + + if (idx == 0) { + if (loopOnAnpi) { + chanrpt_print_anpi(chanRpt, NELEMENTS(chanRpt)); + } + + if (loopOnLoad) { + chanrpt_print_chanLoad(chanRpt, + NELEMENTS(chanRpt)); + } + + loopsLeft--; + } + } + + if (loopOnAnpi) { + chanrpt_print_anpi(chanRptAvg, NELEMENTS(chanRptAvg)); + } + + if (loopOnLoad) { + chanrpt_print_chanLoad(chanRptAvg, NELEMENTS(chanRptAvg)); + } +} + +/** + * @brief Issue a changraph command + * + * @param argc number of arguments + * @param argv A pointer to arguments array + * + * @return MLAN_STATUS_SUCCESS--success, otherwise--fail + */ +static int +process_chan_graph(int argc, char *argv[]) +{ + if (argc == 3) { + chanrpt_graph(); + } else if (argc == 5) { + t_u8 input = atoi(argv[4]); + + if (input <= 100) { + if (strcmp(argv[3], "load") == 0) { + chanrpt_graph_loop(TRUE, FALSE, input); + } else if (strcmp(argv[3], "anpi") == 0) { + chanrpt_graph_loop(FALSE, TRUE, input); + } else if (strcmp(argv[3], "anpiload") == 0) { + chanrpt_graph_loop(TRUE, TRUE, input); + } else { + printf("\nchangraph syntax:" + " changraph \n The value of should be <= 100\n"); + } + } else { + printf("\nchangraph syntax:" + " changraph \n The value of should be <= 100\n"); + } + } + + return MLAN_STATUS_SUCCESS; +} + +/** + * @brief Process extended channel switch(ECSA) + * @param argc Number of arguments + * @param argv A pointer to arguments array + * @return MLAN_STATUS_SUCCESS--success, otherwise--fail + */ +static int +process_extend_channel_switch(int argc, char *argv[]) +{ + t_u8 *buffer = NULL; + struct eth_priv_cmd *cmd = NULL; + struct ifreq ifr; + + /* Initialize buffer */ + buffer = (t_u8 *)malloc(BUFFER_LENGTH); + if (!buffer) { + printf("ERR:Cannot allocate buffer for command!\n"); + return MLAN_STATUS_FAILURE; + } + + prepare_buffer(buffer, argv[2], (argc - 3), &argv[3]); + + cmd = (struct eth_priv_cmd *)malloc(sizeof(struct eth_priv_cmd)); + if (!cmd) { + printf("ERR:Cannot allocate buffer for command!\n"); + free(buffer); + return MLAN_STATUS_FAILURE; + } + + /* Fill up buffer */ +#ifdef USERSPACE_32BIT_OVER_KERNEL_64BIT + memset(cmd, 0, sizeof(struct eth_priv_cmd)); + memcpy(&cmd->buf, &buffer, sizeof(buffer)); +#else + cmd->buf = buffer; +#endif + cmd->used_len = 0; + cmd->total_len = BUFFER_LENGTH; + + /* Perform IOCTL */ + memset(&ifr, 0, sizeof(struct ifreq)); + strncpy(ifr.ifr_ifrn.ifrn_name, dev_name, strlen(dev_name)); + ifr.ifr_ifru.ifru_data = (void *)cmd; + + if (ioctl(sockfd, MLAN_ETH_PRIV, &ifr)) { + perror("mlanutl"); + fprintf(stderr, "mlanutl: extended channel switch fail\n"); + if (cmd) + free(cmd); + if (buffer) + free(buffer); + return MLAN_STATUS_FAILURE; + } + + if (buffer) + free(buffer); + if (cmd) + free(cmd); + return MLAN_STATUS_SUCCESS; +} + +/** + * @brief Get/Set per packet Txctl and Rxinfo configuration + * + * @param argc Number of arguments + * @param argv Pointer to the arguments array + * + * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_FAILURE + */ +static int +process_per_pkt_cfg(int argc, char *argv[]) +{ + int ret = MLAN_STATUS_SUCCESS, i, j; + t_u8 *buffer = NULL; + struct eth_priv_cmd *cmd = NULL; + MrvlIEtypes_per_pkt_cfg_t *per_pkt_cfg = NULL; + struct ifreq ifr; + t_u8 *pos = NULL; + + /* Sanity tests */ + if (argc != 3 && argc != 4 && argc < 6) { + printf("Error: invalid no of arguments\n"); + printf("mlanutl mlanX perpktcfg [tx_rx_control] [type_num] [ether_type1 ...] [tx_rx_control] [type_num] [ether_type1 ...]\n"); + ret = MLAN_STATUS_FAILURE; + goto done; + } + + /* Initialize buffer */ + buffer = (t_u8 *)malloc(BUFFER_LENGTH); + if (!buffer) { + printf("ERR:Cannot allocate buffer for command!\n"); + ret = MLAN_STATUS_FAILURE; + goto done; + } + + memset(buffer, 0, BUFFER_LENGTH); + + /* Flag it for our use */ + pos = buffer; + strncpy((char *)pos, CMD_NXP, strlen(CMD_NXP)); + pos += (strlen(CMD_NXP)); + /* Insert command */ + strncpy((char *)pos, argv[2], strlen(argv[2])); + pos += (strlen(argv[2])); + + if (argc == 3) { + *pos = ACTION_GET; + } else { + *pos = ACTION_SET; + pos++; + i = 3; + while (i < argc) { + per_pkt_cfg = (MrvlIEtypes_per_pkt_cfg_t *) pos; + per_pkt_cfg->header.type = TLV_TYPE_PER_PKT_CFG; + if (a2hex_or_atoi(argv[i]) <= MAX_TXRX_CTRL) { + per_pkt_cfg->tx_rx_control = + (t_u8)a2hex_or_atoi(argv[i++]); + per_pkt_cfg->header.len += sizeof(t_u8); + if (per_pkt_cfg->tx_rx_control == 0) + break; + else if (i >= argc) { + printf("Error: invalid arguments, type_num is needed when tx_rx_control != 0.\n"); + ret = MLAN_STATUS_FAILURE; + goto done; + } + } else { + printf("Error: invalid arguments, tx_rx_control <=3\n"); + ret = MLAN_STATUS_FAILURE; + goto done; + } + + if (a2hex_or_atoi(argv[i]) <= MAX_NUM_ETHER_TYPE && + a2hex_or_atoi(argv[i]) > 0) + per_pkt_cfg->proto_type_num = + a2hex_or_atoi(argv[i++]); + else { + printf("Error: invalid arguments, type_num <=8\n"); + ret = MLAN_STATUS_FAILURE; + goto done; + } + + for (j = 0; j < per_pkt_cfg->proto_type_num; j++) { + if (i < argc) + per_pkt_cfg->ether_type[j] = + (t_u16)a2hex_or_atoi(argv[i++]); + else { + printf("Error: invalid arguments, number of ether type less than type_num \n"); + ret = MLAN_STATUS_FAILURE; + goto done; + } + } + per_pkt_cfg->header.len = + sizeof(MrvlIEtypes_per_pkt_cfg_t) + + per_pkt_cfg->proto_type_num * sizeof(t_u16) - + sizeof(MrvlIEtypesHeader_t); + pos += per_pkt_cfg->header.len + + sizeof(MrvlIEtypesHeader_t); + } + } + + cmd = (struct eth_priv_cmd *)malloc(sizeof(struct eth_priv_cmd)); + if (!cmd) { + printf("ERR:Cannot allocate buffer for command!\n"); + ret = MLAN_STATUS_FAILURE; + goto done; + } + + /* Fill up buffer */ +#ifdef USERSPACE_32BIT_OVER_KERNEL_64BIT + memset(cmd, 0, sizeof(struct eth_priv_cmd)); + memcpy(&cmd->buf, &buffer, sizeof(buffer)); +#else + cmd->buf = buffer; +#endif + cmd->used_len = 0; + cmd->total_len = BUFFER_LENGTH; + + /* Perform IOCTL */ + memset(&ifr, 0, sizeof(struct ifreq)); + strncpy(ifr.ifr_ifrn.ifrn_name, dev_name, strlen(dev_name)); + ifr.ifr_ifru.ifru_data = (void *)cmd; + + if (ioctl(sockfd, MLAN_ETH_PRIV, &ifr)) { + perror("mlanutl"); + fprintf(stderr, "mlanutl: perpktcfg fail\n"); + ret = MLAN_STATUS_FAILURE; + goto done; + } + + /* Process Get result */ + pos = buffer + (strlen(CMD_NXP)) + strlen(argv[2]); + if (*pos == ACTION_GET) { + per_pkt_cfg = (MrvlIEtypes_per_pkt_cfg_t *)++ pos; + while (per_pkt_cfg->header.type == TLV_TYPE_PER_PKT_CFG) { + if (per_pkt_cfg->tx_rx_control & TX_PKT_CTRL) { + printf("The ethernet type of per packet Txctrl:\n"); + for (j = 0; j < per_pkt_cfg->proto_type_num; + j++) { + printf("0x%04x ", + per_pkt_cfg->ether_type[j]); + } + printf("\n"); + } else if (per_pkt_cfg->tx_rx_control & RX_PKT_INFO) { + printf("The ethernet type of per packet Rxinfo:\n"); + for (j = 0; j < per_pkt_cfg->proto_type_num; + j++) { + printf("0x%04x ", + per_pkt_cfg->ether_type[j]); + } + printf("\n"); + } + pos += per_pkt_cfg->header.len + + sizeof(MrvlIEtypesHeader_t); + per_pkt_cfg = (MrvlIEtypes_per_pkt_cfg_t *) pos; + } + } else if (argc == 4) { + printf("Disable per packet control!\n"); + } else { + printf("Successfully do the TXctl/Rxinfo per packet configuration!\n"); + } +done: + if (buffer) + free(buffer); + if (cmd) + free(cmd); + return ret; +} + +/** + * @brief enable auto_arp 1->enable 0->disable + * + * @param argc Number of arguments + * @param argv Pointer to the arguments array + * + * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_FAILURE + */ +static int +process_auto_arp(int argc, char *argv[]) +{ + int ret = 0, status; + t_u8 *buffer = NULL; + struct eth_priv_cmd *cmd = NULL; + struct ifreq ifr; + + /* Initialize buffer */ + buffer = (t_u8 *)malloc(BUFFER_LENGTH); + if (!buffer) { + printf("ERR:Cannot allocate buffer for command!\n"); + ret = MLAN_STATUS_FAILURE; + goto done; + } + memset(buffer, 0, BUFFER_LENGTH); + + /* Sanity tests */ + if (argc != 3 && argc != 4) { + printf("Error: invalid no of arguments\n"); + printf("mlanutl mlanX auto_arp [0/1]\n"); + ret = MLAN_STATUS_FAILURE; + goto done; + } + + prepare_buffer(buffer, argv[2], argc - 3, &argv[3]); + + cmd = (struct eth_priv_cmd *)malloc(sizeof(struct eth_priv_cmd)); + if (!cmd) { + printf("ERR:Cannot allocate buffer for command!\n"); + ret = MLAN_STATUS_FAILURE; + goto done; + } + + /* Fill up buffer */ +#ifdef USERSPACE_32BIT_OVER_KERNEL_64BIT + memset(cmd, 0, sizeof(struct eth_priv_cmd)); + memcpy(&cmd->buf, &buffer, sizeof(buffer)); +#else + cmd->buf = buffer; +#endif + cmd->used_len = 0; + cmd->total_len = BUFFER_LENGTH; + + /* Perform IOCTL */ + memset(&ifr, 0, sizeof(struct ifreq)); + strncpy(ifr.ifr_ifrn.ifrn_name, dev_name, strlen(dev_name)); + ifr.ifr_ifru.ifru_data = (void *)cmd; + + if (ioctl(sockfd, MLAN_ETH_PRIV, &ifr)) { + perror("mlanutl"); + fprintf(stderr, "mlanutl: auto_arp fail\n"); + ret = MLAN_STATUS_FAILURE; + goto done; + } + + /* Process Get result */ + if (argc == 3) { + memcpy(&status, buffer, sizeof(status)); + if (status == 0) { + printf("Auto ARP is Disabled\n"); + } else if (status == 1) { + printf("Auto ARP is Enabled\n"); + } + } + +done: + if (buffer) + free(buffer); + if (cmd) + free(cmd); + return ret; +} + +/** + * @brief Creates a tx/rx histogram statistic request and send to driver + * + * @param argc Number of arguments + * @param argv Pointer to the arguments array + * + * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_FAILURE + */ +static int +process_txrxhistogram(int argc, char *argv[]) +{ + t_u8 *buffer = NULL; + struct eth_priv_cmd *cmd = NULL; + int ret = MLAN_STATUS_SUCCESS, i; + struct ifreq ifr; + tx_rx_histogram *tx_rx_info; + tx_pkt_ht_rate_info *tx_ht_info; + tx_pkt_vht_rate_info *tx_vht_info; + tx_pkt_he_rate_info *tx_he_info; + tx_pkt_rate_info *tx_info; + rx_pkt_ht_rate_info *rx_ht_info; + rx_pkt_vht_rate_info *rx_vht_info; + rx_pkt_he_rate_info *rx_he_info; + rx_pkt_rate_info *rx_info; + t_u16 size = 0; + t_u8 *pos = NULL; + + /* Initialize buffer */ + buffer = (t_u8 *)malloc(BUFFER_LENGTH); + if (!buffer) { + printf("ERR:Cannot allocate buffer for command!\n"); + ret = MLAN_STATUS_FAILURE; + goto done; + } + memset(buffer, 0, BUFFER_LENGTH); + + /* Sanity tests */ + if (argc != 5 && argc != 4) { + printf("Error: invalid no of arguments\n"); + printf("mlanutl mlanX/uapX txrxhistogram [action: 0/1/2] [tx_rx_statics: 1/2/3]\n"); + ret = MLAN_STATUS_FAILURE; + goto done; + } + + /* Insert command */ + strncpy((char *)buffer, argv[2], strlen(argv[2])); + tx_rx_info = (tx_rx_histogram *) (buffer + strlen(argv[2])); + tx_rx_info->enable = (t_u8)a2hex_or_atoi(argv[3]); + if (argc == 5 && tx_rx_info->enable == GET_TX_RX_HISTOGRAM) + tx_rx_info->action = (t_u8)a2hex_or_atoi(argv[4]); + + cmd = (struct eth_priv_cmd *)malloc(sizeof(struct eth_priv_cmd)); + if (!cmd) { + printf("ERR:Cannot allocate buffer for command!\n"); + ret = MLAN_STATUS_FAILURE; + goto done; + } + + /* Fill up buffer */ +#ifdef USERSPACE_32BIT_OVER_KERNEL_64BIT + memset(cmd, 0, sizeof(struct eth_priv_cmd)); + memcpy(&cmd->buf, &buffer, sizeof(buffer)); +#else + cmd->buf = buffer; +#endif + cmd->used_len = 0; + cmd->total_len = BUFFER_LENGTH; + + /* Perform IOCTL */ + memset(&ifr, 0, sizeof(struct ifreq)); + strncpy(ifr.ifr_ifrn.ifrn_name, dev_name, strlen(dev_name)); + ifr.ifr_ifru.ifru_data = (void *)cmd; + + if (ioctl(sockfd, MLAN_ETH_PRIV, &ifr)) { + perror("mlanutl"); + fprintf(stderr, "mlanutl: get tx/rx histogram fail\n");; + ret = MLAN_STATUS_FAILURE; + goto done; + } + + /* Process result */ + pos = buffer + strlen(argv[2]) + 2 * sizeof(t_u8); + memcpy(&size, pos, sizeof(size)); + pos += sizeof(size); + if (tx_rx_info->enable & GET_TX_RX_HISTOGRAM) { + if (tx_rx_info->action & FLAG_TX_HISTOGRAM) { + printf("The TX histogram statistic:\n"); + printf("============================================\n"); + tx_ht_info = (tx_pkt_ht_rate_info *) pos; + for (i = 0; i < 16; i++) { + printf("htmcs_txcnt[%d] = %u\n", i, + tx_ht_info->htmcs_txcnt[i]); + printf("htsgi_txcnt[%d] = %u\n", i, + tx_ht_info->htsgi_txcnt[i]); + printf("htstbcrate_txcnt[%d] = %u\n", i, + tx_ht_info->htstbcrate_txcnt[i]); + } + pos += sizeof(tx_pkt_ht_rate_info); + tx_vht_info = (tx_pkt_vht_rate_info *) pos; + for (i = 0; i < 10; i++) { + printf("vhtmcs_txcnt[%d] = %u\n", i, + tx_vht_info->vhtmcs_txcnt[i]); + printf("vhtsgi_txcnt[%d] = %u\n", i, + tx_vht_info->vhtsgi_txcnt[i]); + printf("vhtstbcrate_txcnt[%d] = %u\n", i, + tx_vht_info->vhtstbcrate_txcnt[i]); + } + pos += sizeof(tx_pkt_vht_rate_info); + if (size == + (sizeof(tx_pkt_ht_rate_info) + + sizeof(tx_pkt_vht_rate_info) + + sizeof(tx_pkt_he_rate_info) + + sizeof(tx_pkt_rate_info)) + || size == + (sizeof(tx_pkt_ht_rate_info) + + sizeof(tx_pkt_vht_rate_info) + + sizeof(tx_pkt_he_rate_info) + + sizeof(tx_pkt_rate_info) + + sizeof(rx_pkt_ht_rate_info) + + sizeof(rx_pkt_vht_rate_info) + + sizeof(rx_pkt_he_rate_info) + + sizeof(rx_pkt_rate_info))) { + tx_he_info = (tx_pkt_he_rate_info *) pos; + for (i = 0; i < 12; i++) { + printf("hemcs_txcnt[%d] = %u\n", i, + tx_he_info->hemcs_txcnt[i]); + printf("hestbcrate_txcnt[%d] = %u\n", i, + tx_he_info->hestbcrate_txcnt[i]); + } + pos += sizeof(tx_pkt_he_rate_info); + } + tx_info = (tx_pkt_rate_info *) pos; + for (i = 0; i < 2; i++) + printf("nss_txcnt[%d] = %u\n", i, + tx_info->nss_txcnt[i]); + for (i = 0; i < 3; i++) + printf("bandwidth_txcnt[%d] = %u\n", i, + tx_info->bandwidth_txcnt[i]); + for (i = 0; i < 4; i++) + printf("preamble_txcnt[%d] = %u\n", i, + tx_info->preamble_txcnt[i]); + printf("ldpc_txcnt = %u\n", + tx_info->ldpc_txcnt); + printf("rts_txcnt = %u\n", + tx_info->rts_txcnt); + printf("ack_RSSI = %d\n\n", + tx_info->ack_RSSI); + pos += sizeof(tx_pkt_rate_info); + } + + if (tx_rx_info->action & FLAG_RX_HISTOGRAM) { + printf("The RX histogram statistic:\n"); + printf("============================================\n"); + rx_ht_info = (rx_pkt_ht_rate_info *) pos; + for (i = 0; i < 16; i++) { + printf("htmcs_rxcnt[%d] = %u\n", i, + rx_ht_info->htmcs_rxcnt[i]); + printf("htsgi_rxcnt[%d] = %u\n", i, + rx_ht_info->htsgi_rxcnt[i]); + printf("htstbcrate_rxcnt[%d] = %u\n", i, + rx_ht_info->htstbcrate_rxcnt[i]); + } + pos += sizeof(rx_pkt_ht_rate_info); + rx_vht_info = (rx_pkt_vht_rate_info *) pos; + for (i = 0; i < 10; i++) { + printf("vhtmcs_rxcnt[%d] = %u\n", i, + rx_vht_info->vhtmcs_rxcnt[i]); + printf("vhtsgi_rxcnt[%d] = %u\n", i, + rx_vht_info->vhtsgi_rxcnt[i]); + printf("vhtstbcrate_rxcnt[%d] = %u\n", i, + rx_vht_info->vhtstbcrate_rxcnt[i]); + } + pos += sizeof(rx_pkt_vht_rate_info); + if (size == + (sizeof(rx_pkt_ht_rate_info) + + sizeof(rx_pkt_vht_rate_info) + + sizeof(rx_pkt_he_rate_info) + + sizeof(rx_pkt_rate_info)) + || size == + (sizeof(tx_pkt_ht_rate_info) + + sizeof(tx_pkt_vht_rate_info) + + sizeof(tx_pkt_he_rate_info) + + sizeof(tx_pkt_rate_info) + + sizeof(rx_pkt_ht_rate_info) + + sizeof(rx_pkt_vht_rate_info) + + sizeof(rx_pkt_he_rate_info) + + sizeof(rx_pkt_rate_info))) { + rx_he_info = (rx_pkt_he_rate_info *) pos; + for (i = 0; i < 12; i++) { + printf("hemcs_txcnt[%d] = %u\n", i, + rx_he_info->hemcs_rxcnt[i]); + printf("hestbcrate_txcnt[%d] = %u\n", i, + rx_he_info->hestbcrate_rxcnt[i]); + } + pos += sizeof(rx_pkt_he_rate_info); + } + rx_info = (rx_pkt_rate_info *) pos; + for (i = 0; i < 2; i++) + printf("nss_rxcnt[%d] = %u\n", i, + rx_info->nss_rxcnt[i]); + printf("nsts_rxcnt = %u\n", + rx_info->nsts_rxcnt); + for (i = 0; i < 3; i++) + printf("bandwidth_rxcnt[%d] = %u\n", i, + rx_info->bandwidth_rxcnt[i]); + for (i = 0; i < 6; i++) + printf("preamble_rxcnt[%d] = %u\n", i, + rx_info->preamble_rxcnt[i]); + for (i = 0; i < 2; i++) + printf("ldpc_txbfcnt[%d] = %u\n", i, + rx_info->ldpc_txbfcnt[i]); + for (i = 0; i < 2; i++) + printf("rssi_value[%d] = %d\n", i, + rx_info->rssi_value[i]); + for (i = 0; i < 4; i++) + printf("rssi_chain0[%d] = %d\n", i, + rx_info->rssi_chain0[i]); + for (i = 0; i < 4; i++) + printf("rssi_chain1[%d] = %d\n", i, + rx_info->rssi_chain1[i]); + printf("\n"); + } + } else if (tx_rx_info->enable & ENABLE_TX_RX_HISTOGRAM) + printf("Enable the TX and RX histogram statistic\n"); + else + printf("Disable the TX and RX histogram statistic\n"); + +done: + if (buffer) + free(buffer); + if (cmd) + free(cmd); + + return ret; +} + +/** + * @brief Set/Get out band independent reset + * + * @param argc Number of arguments + * @param argv Pointer to the arguments array + * + * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_FAILURE + */ +static int +process_ind_rst_cfg(int argc, char *argv[]) +{ + int ret = 0; + int data[3] = { 0 }; + t_u8 *buffer = NULL; + struct eth_priv_cmd *cmd = NULL; + struct ifreq ifr; + + /* Check if arguments are valid */ + if ((argc < 3) || (argc > 5)) { + printf("ERR: Invalid arguments\n"); + printf("usage: mlanutl indrstcfg [gpio_pin]\n"); + ret = MLAN_STATUS_FAILURE; + goto done; + } + if (((argc == 4) || (argc == 5)) && + ((atoi(argv[3]) < 0) || (atoi(argv[3]) > 2))) { + printf("ERR: Mode must be 0, 1 or 2\n"); + return MLAN_STATUS_FAILURE; + } + + /* Initialize buffer */ + buffer = (t_u8 *)malloc(BUFFER_LENGTH); + if (!buffer) { + printf("ERR:Cannot allocate buffer for command!\n"); + ret = MLAN_STATUS_FAILURE; + goto done; + } + + prepare_buffer(buffer, argv[2], (argc - 3), &argv[3]); + + cmd = (struct eth_priv_cmd *)malloc(sizeof(struct eth_priv_cmd)); + if (!cmd) { + printf("ERR:Cannot allocate buffer for command!\n"); + ret = MLAN_STATUS_FAILURE; + goto done; + } + + /* Fill up buffer */ +#ifdef USERSPACE_32BIT_OVER_KERNEL_64BIT + memset(cmd, 0, sizeof(struct eth_priv_cmd)); + memcpy(&cmd->buf, &buffer, sizeof(buffer)); +#else + cmd->buf = buffer; +#endif + cmd->used_len = 0; + cmd->total_len = BUFFER_LENGTH; + + /* Perform IOCTL */ + memset(&ifr, 0, sizeof(struct ifreq)); + strncpy(ifr.ifr_ifrn.ifrn_name, dev_name, strlen(dev_name)); + ifr.ifr_ifru.ifru_data = (void *)cmd; + + if (ioctl(sockfd, MLAN_ETH_PRIV, &ifr)) { + perror("mlanutl"); + fprintf(stderr, "mlanutl: indrstcfg fail\n"); + ret = MLAN_STATUS_FAILURE; + goto done; + } + if (argc == 3) { + memcpy(data, buffer, sizeof(data)); + /* Display the result */ + printf("Independent Reset Mode = %s\n", + (data[0] == + 0) ? "disabled" : ((data[0] == + 1) ? "Out Band" : "In Band")); + if (data[0] == 1) + printf("GPIO Pin = %d\n", data[1]); + } + +done: + if (buffer) + free(buffer); + if (cmd) + free(cmd); + + return ret; +} + +static void +send_dot11_packet(char *ifName, char *file_name) +{ + t_u8 sendbuf[BUF_SIZ], buff[BUF_SIZ]; + char *args[100], *pos, mac_addr[20]; + struct ether_header *eh = (struct ether_header *)sendbuf; + int data_len = 0, tx_len = 0; + dot11_txcontrol *txc; + struct sockaddr_ll socket_address; + wsmp_header *header; + t_u8 mac[ETH_ALEN]; + FILE *config_file = NULL; + char *line = NULL; + int li = 0, arg_num = 0, ret = 0, i = 0; + int protocol = 0; + int sockfd; + struct ifreq if_idx; + struct ifreq if_mac; + + memset(buff, 0, sizeof(buff)); + memset(mac, 0, sizeof(mac)); + memset(mac_addr, 0, sizeof(mac_addr)); + + /* Construct the Ethernet header */ + memset(sendbuf, 0, BUF_SIZ); + txc = (dot11_txcontrol *) (sendbuf + sizeof(struct ether_header)); + config_file = fopen(file_name, "r"); + if (config_file == NULL) { + perror("CONFIG"); + exit(1); + } + + line = (char *)malloc(MAX_CONFIG_LINE); + if (!line) { + printf("ERR:Cannot allocate memory for line\n"); + exit(1); + } + memset(line, 0, MAX_CONFIG_LINE); + + /* Parse file and process */ + while (config_get_line(line, MAX_CONFIG_LINE, config_file, &li, &pos)) { + arg_num = parse_line(line, args, 100); + + if (strcmp(args[0], "Datarate") == 0) { + txc->tx_datarate = ((t_u16)A2HEXDECIMAL(args[1])); + printf("datarate(in 0.5Mbps) = %d\n", txc->tx_datarate); + } else if (strcmp(args[0], "Channel") == 0) { + txc->tx_channel = atoi(args[1]); + printf("channel = %d\n", txc->tx_channel); + } else if (strcmp(args[0], "Bandwidth") == 0) { + txc->tx_Bw = (t_u8)A2HEXDECIMAL(args[1]); + printf("Bandwidth = %d\n", txc->tx_Bw); + } else if (strcmp(args[0], "Power") == 0) { + txc->tx_power = (t_u8)A2HEXDECIMAL(args[1]); + printf("powerlevel = %d\n", txc->tx_power); + } else if (strcmp(args[0], "Priority") == 0) { + txc->pkt_priority = atoi(args[1]); + printf("Pkt_priority = %d\n", txc->pkt_priority); + } else if (strcmp(args[0], "Retry_limit") == 0) { + txc->retry_limit = atoi(args[1]); + printf("Retry_limit = %d\n", txc->retry_limit); + } else if (strncmp(args[0], "Addr", 4) == 0) { + + strncpy(mac_addr, args[1], sizeof(mac_addr) - 1); + ret = mac2raw(mac_addr, mac); + printf("destination MAC : %s\n", mac_addr); + if (ret != MLAN_STATUS_SUCCESS) { + printf("%s Address \n", + ret == + MLAN_STATUS_FAILURE ? "Invalid MAC" : ret + == + MAC_BROADCAST ? "Broadcast" : + "Multicast"); + } + } else if (strcmp(args[0], "Data") == 0) { + for (i = 0; i < arg_num - 1; i++) { + buff[i] = (t_u8)A2HEXDECIMAL(args[i + 1]); + } + } else if (strcmp(args[0], "Protocol") == 0) { + protocol = A2HEXDECIMAL(args[1]); + printf("protocol = %x\n", protocol); + } + data_len = arg_num - 1; + } + + /* Open RAW socket to send/recv on */ + if ((sockfd = socket(AF_PACKET, SOCK_RAW, htons(protocol))) == -1) { + perror("socket"); + } + + /* Get the index of the interface to send on */ + memset(&if_idx, 0, sizeof(struct ifreq)); + strncpy(if_idx.ifr_name, ifName, IFNAMSIZ - 1); + if (ioctl(sockfd, SIOCGIFINDEX, &if_idx) < 0) + perror("SIOCGIFINDEX"); + + /*get mac address of the interface */ + memset(&if_mac, 0, sizeof(struct ifreq)); + strncpy(if_mac.ifr_name, ifName, IFNAMSIZ - 1); + if (ioctl(sockfd, SIOCGIFHWADDR, &if_mac) < 0) + perror("SIOCGIFHWADDR"); + + memcpy(eh->ether_shost, (u_int8_t *) & if_mac.ifr_hwaddr.sa_data, + MLAN_MAC_ADDR_LENGTH); + + /* destination mac address */ + for (i = 0; i < MLAN_MAC_ADDR_LENGTH; i++) { + eh->ether_dhost[i] = (uint8_t) mac[i]; + } + /* Ethertype field */ + eh->ether_type = htons(protocol); + tx_len += sizeof(struct ether_header); + /*Add the length of tx header */ + tx_len += sizeof(dot11_txcontrol); + + if (protocol == ETH_P_WSMP) { + header = (wsmp_header *) (sendbuf + tx_len); + header->version = 2; + header->sec_type = 5; + header->chan = txc->tx_channel; + header->rate = txc->tx_datarate / 2; + header->tx_pow = txc->tx_power; + header->app_class = 14; + header->acm_len = 0; + header->len = data_len; + tx_len += sizeof(wsmp_header); + } + memcpy(sendbuf + tx_len, buff, data_len); + + tx_len += data_len; + + /* Index of the network device */ + socket_address.sll_ifindex = if_idx.ifr_ifindex; + /* Address length */ + socket_address.sll_halen = ETH_ALEN; + memcpy(&socket_address.sll_addr, (uint8_t *) mac, MLAN_MAC_ADDR_LENGTH); + if (sendto(sockfd, sendbuf, tx_len, 0, + (struct sockaddr *)&socket_address, + sizeof(struct sockaddr_ll)) < 0) + perror("Send failed\n"); + else + printf("packet sent\n"); + + close(sockfd); + fclose(config_file); +} + +static void +receive_dot11_packet(char *ifName, int protocol, int verbose) +{ + int sockopt = 0, i, j, prev_channel = 0; + t_u8 buf[BUF_SIZ]; + ssize_t numbytes; + struct ether_header *eh = (struct ether_header *)buf; + dot11_rxcontrol *rxctrl; + int sockfd = 0; + struct ifreq if_idx; + struct ifreq if_mac; + + /* Open RAW socket to recv on */ + if ((sockfd = socket(AF_PACKET, SOCK_RAW, htons(protocol))) == -1) { + perror("socket"); + } + /* Get the index of the interface to send on */ + memset(&if_idx, 0, sizeof(struct ifreq)); + strncpy(if_idx.ifr_name, ifName, IFNAMSIZ - 1); + if (ioctl(sockfd, SIOCGIFINDEX, &if_idx) < 0) + perror("SIOCGIFINDEX"); + + /*get mac address of the interface */ + memset(&if_mac, 0, sizeof(struct ifreq)); + strncpy(if_mac.ifr_name, ifName, IFNAMSIZ - 1); + if (ioctl(sockfd, SIOCGIFHWADDR, &if_mac) < 0) + perror("SIOCGIFHWADDR"); + + /* Allow the socket to be reused - incase connection is closed prematurely */ + if (setsockopt + (sockfd, SOL_SOCKET, SO_REUSEADDR, &sockopt, + sizeof sockopt) == -1) { + perror("setsockopt"); + close(sockfd); + exit(EXIT_FAILURE); + } + + /* Bind to device */ + if (setsockopt + (sockfd, SOL_SOCKET, SO_BINDTODEVICE, ifName, IFNAMSIZ - 1) == -1) { + perror("SO_BINDTODEVICE"); + close(sockfd); + exit(EXIT_FAILURE); + } + + printf("protocol type : %x\n", protocol); + printf("waiting to receive data...\n"); + rxctrl = (dot11_rxcontrol *) (buf + sizeof(struct ether_header)); + while (1) { + numbytes = recvfrom(sockfd, buf, BUF_SIZ, 0, NULL, NULL); + if (verbose == 1) { + printf("\nReceived data from peer - "); + for (i = 0; i < MLAN_MAC_ADDR_LENGTH; i++) { + printf("%02x", eh->ether_shost[i]); + if (i < (MLAN_MAC_ADDR_LENGTH - 1)) + printf(":"); + } + printf("\n"); + printf("\nchannel = %d\ndata rate = %d\n" + "antenna = %d\nRSSI = %d\n", + rxctrl->rx_channel, + rxctrl->rx_datarate, + rxctrl->rx_antenna, rxctrl->rx_RSSI); + + i = sizeof(struct ether_header) + + sizeof(dot11_rxcontrol); + + if (protocol == ETH_P_WSMP) { + j = i; + printf("WSMP header : \n"); + for (; i < j + sizeof(wsmp_header); i++) + printf("%02x ", buf[i]); + printf("\n"); + } + printf("Data:\n"); + + for (; i < numbytes; i++) + printf("%02x ", buf[i]); + printf("\n"); + } else { + if (rxctrl->rx_channel != prev_channel) { + printf("channel %d : ", rxctrl->rx_channel); + for (i = 0; i < MLAN_MAC_ADDR_LENGTH; i++) + printf("%x ", eh->ether_shost[i]); + printf("\n"); + prev_channel = rxctrl->rx_channel; + } else + printf("*"); + fflush(stdout); + } + } +} + +/** + * @brief process request to send/recv WSMP packets + * + * @param argc Number of arguments + * @param argv Pointer to the arguments array + * + * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_FAILURE + * */ +static int +process_dot11_txrx(int argc, char *argv[]) +{ + int ret = MLAN_STATUS_SUCCESS; + char ifName[IFNAMSIZ], file_name[100]; + int receive_protocol, verbose = 0; + + memset(ifName, 0, sizeof(ifName)); + memset(file_name, 0, sizeof(file_name)); + if (argc != 5 && argc != 6) { + fprintf(stderr, "Invalid no. of arguments\n"); + fprintf(stderr, + "Usage : ./mlanutil dot11_txrx \n" + "./mlanutil dot11_txrx send \n" + "./mlanutil dot11_txrx recv [v]\n"); + ret = MLAN_STATUS_FAILURE; + goto done; + } + + /*copy interface name */ + strncpy(ifName, argv[1], sizeof(ifName) - 1); + + if (!strcmp(argv[3], "send")) { + strncpy(file_name, argv[4], sizeof(file_name) - 1); + if (argc == 5) + send_dot11_packet(ifName, file_name); + else { + fprintf(stderr, "Usage: " + "./mlanutil dot11_txrx send \n"); + ret = MLAN_STATUS_FAILURE; + goto done; + } + } else if (!strcmp(argv[3], "recv")) { + receive_protocol = A2HEXDECIMAL(argv[4]); + if (argc == 6 && strcmp(argv[5], "v") == 0) + verbose = 1; + receive_dot11_packet(ifName, receive_protocol, verbose); + } else { + fprintf(stderr, "Invalid option after dot11_txrx\n"); + fprintf(stderr, + "Usage : ./mlanutil dot11_txrx [options]\n" + "./mlanutil dot11_txrx send " + "./mlanutil dot11_txrx recv [v]\n"); + } + +done: + return ret; +} + +/** + * @brief Issue a tsf command + * + * @param argc number of arguments + * @param argv A pointer to arguments array + * + * @return MLAN_STATUS_SUCCESS--success, otherwise--fail + */ +int +process_tsf(int argc, char *argv[]) +{ + int ret = MLAN_STATUS_SUCCESS; + int x; + struct ifreq ifr; + t_u8 *buffer = NULL, *pos = NULL; + t_u32 cmd_len = 0, cmd_header_len; + struct eth_priv_cmd *cmd = NULL; + HostCmd_DS_GEN *hostcmd; + + cmd_header_len = strlen(CMD_NXP) + strlen(HOSTCMD); + + buffer = (t_u8 *)malloc(BUFFER_LENGTH); + if (buffer == NULL) { + fprintf(stderr, "Cannot alloc memory\n"); + ret = ENOMEM; + goto done; + } + memset(buffer, 0, BUFFER_LENGTH); + + cmd = (struct eth_priv_cmd *)malloc(sizeof(struct eth_priv_cmd)); + if (!cmd) { + printf("ERR:Cannot allocate buffer for command!\n"); + ret = ENOMEM; + goto done; + } + + /* Fill up buffer */ +#ifdef USERSPACE_32BIT_OVER_KERNEL_64BIT + memset(cmd, 0, sizeof(struct eth_priv_cmd)); + memcpy(&cmd->buf, &buffer, sizeof(buffer)); +#else + cmd->buf = buffer; +#endif + cmd->used_len = 0; + cmd->total_len = BUFFER_LENGTH; + + /* buffer = MRVL_CMD */ + strncpy((char *)buffer, CMD_NXP, strlen(CMD_NXP)); + strncpy((char *)buffer + strlen(CMD_NXP), HOSTCMD, strlen(HOSTCMD)); + + /* buffer = MRVL_CMD */ + hostcmd = (HostCmd_DS_GEN *)(buffer + cmd_header_len + sizeof(t_u32)); + + /* Point after host command header */ + pos = (t_u8 *)hostcmd + S_DS_GEN; + + cmd_len = S_DS_GEN + sizeof(t_u64); + + hostcmd->command = cpu_to_le16(HostCmd_CMD_GET_TSF); + hostcmd->size = cpu_to_le16(cmd_len); + hostcmd->seq_num = 0; + hostcmd->result = 0; + + /* Put buffer length */ + memcpy(buffer + cmd_header_len, &cmd_len, sizeof(t_u32)); + + /* Initialize the ifr structure */ + memset(&ifr, 0, sizeof(ifr)); + strncpy(ifr.ifr_ifrn.ifrn_name, dev_name, strlen(dev_name)); + ifr.ifr_ifru.ifru_data = (void *)cmd; + /* Perform ioctl */ + if (ioctl(sockfd, MLAN_ETH_PRIV, &ifr)) { + perror("ioctl[hostcmd]"); + printf("ERR:Command sending failed!\n"); + ret = -EFAULT; + goto done; + } + + printf("TSF="); + + for (x = 7; x >= 0; x--) { + printf("%02x", pos[x]); + } + + puts("\n"); + +done: + if (buffer) + free(buffer); + if (cmd) + free(cmd); + return ret; +} + +/** + * @brief Process dynamic bandwidth set/get + * @param argc Number of arguments + * @param argv A pointer to arguments array + * @return MLAN_STATUS_SUCCESS--success, otherwise--fail + */ +static int +process_dyn_bw(int argc, char *argv[]) +{ + t_u8 *buffer = NULL; + struct eth_priv_cmd *cmd = NULL; + struct ifreq ifr; + int dyn_bw = 0; + + /* Check arguments */ + if (argc < 3 || argc > 4) { + printf("ERR:Incorrect number of arguments!\n"); + printf("Syntax: ./mlanutl mlanX dyn_bw \n"); + return MLAN_STATUS_FAILURE; + } + + /* Initialize buffer */ + buffer = (t_u8 *)malloc(BUFFER_LENGTH); + if (!buffer) { + printf("ERR:Cannot allocate buffer for command!\n"); + return MLAN_STATUS_FAILURE; + } + + prepare_buffer(buffer, argv[2], (argc - 3), &argv[3]); + + cmd = (struct eth_priv_cmd *)malloc(sizeof(struct eth_priv_cmd)); + if (!cmd) { + printf("ERR:Cannot allocate buffer for command!\n"); + free(buffer); + return MLAN_STATUS_FAILURE; + } + + /* Fill up buffer */ +#ifdef USERSPACE_32BIT_OVER_KERNEL_64BIT + memset(cmd, 0, sizeof(struct eth_priv_cmd)); + memcpy(&cmd->buf, &buffer, sizeof(buffer)); +#else + cmd->buf = buffer; +#endif + cmd->used_len = 0; + cmd->total_len = BUFFER_LENGTH; + + /* Perform IOCTL */ + memset(&ifr, 0, sizeof(struct ifreq)); + strncpy(ifr.ifr_ifrn.ifrn_name, dev_name, strlen(dev_name)); + ifr.ifr_ifru.ifru_data = (void *)cmd; + + if (ioctl(sockfd, MLAN_ETH_PRIV, &ifr)) { + perror("mlanutl"); + fprintf(stderr, "mlanutl: dyn_bw fail\n"); + if (cmd) + free(cmd); + if (buffer) + free(buffer); + return MLAN_STATUS_FAILURE; + } + + /* Process result */ + dyn_bw = *(int *)buffer; + printf("Dynamic bandwidth: 0x%02x\n", dyn_bw); + + if (buffer) + free(buffer); + if (cmd) + free(cmd); + + return MLAN_STATUS_SUCCESS; +} + +/** + * @brief Process set/get deauth control when uap move to another channel + * @param argc Number of arguments + * @param argv A pointer to arguments array + * @return MLAN_STATUS_SUCCESS--success, otherwise--fail + */ +static int +process_ctrldeauth(int argc, char *argv[]) +{ + t_u8 *buffer = NULL; + struct eth_priv_cmd *cmd = NULL; + struct ifreq ifr; + + /* Initialize buffer */ + buffer = (t_u8 *)malloc(BUFFER_LENGTH); + if (!buffer) { + printf("ERR:Cannot allocate buffer for command!\n"); + return MLAN_STATUS_FAILURE; + } + + prepare_buffer(buffer, argv[2], (argc - 3), &argv[3]); + + cmd = (struct eth_priv_cmd *)malloc(sizeof(struct eth_priv_cmd)); + if (!cmd) { + printf("ERR:Cannot allocate buffer for command!\n"); + free(buffer); + return MLAN_STATUS_FAILURE; + } + + /* Fill up buffer */ +#ifdef USERSPACE_32BIT_OVER_KERNEL_64BIT + memset(cmd, 0, sizeof(struct eth_priv_cmd)); + memcpy(&cmd->buf, &buffer, sizeof(buffer)); +#else + cmd->buf = buffer; +#endif + cmd->used_len = 0; + cmd->total_len = BUFFER_LENGTH; + + /* Perform IOCTL */ + memset(&ifr, 0, sizeof(struct ifreq)); + strncpy(ifr.ifr_ifrn.ifrn_name, dev_name, strlen(dev_name)); + ifr.ifr_ifru.ifru_data = (void *)cmd; + + if (ioctl(sockfd, MLAN_ETH_PRIV, &ifr)) { + perror("mlanutl"); + fprintf(stderr, "mlanutl: deauthctrl fail\n"); + if (cmd) + free(cmd); + if (buffer) + free(buffer); + return MLAN_STATUS_FAILURE; + } + + /* Process result */ + printf("Deauth control: "); + if (buffer[0]) + printf("enabled.\n"); + else + printf("disabled.\n"); + + if (buffer) + free(buffer); + if (cmd) + free(cmd); + + return MLAN_STATUS_SUCCESS; +} + +/** + * @brief Process boot sleep configure command + * @param argc number of arguments + * @param argv A pointer to arguments array + * @return MLAN_STATUS_SUCCESS--success, otherwise--fail + */ +static int +process_bootsleep(int argc, char *argv[]) +{ + t_u8 *buffer = NULL; + struct eth_priv_cmd *cmd = NULL; + struct ifreq ifr; + + /* Check arguments */ + if (argc != 3 && argc != 4) { + printf("ERR:Incorrect number of arguments!\n"); + printf("Syntax: ./mlanutl mlanX bootsleep <1/0>\n"); + return MLAN_STATUS_FAILURE; + } + + /* Initialize buffer */ + buffer = (t_u8 *)malloc(BUFFER_LENGTH); + if (!buffer) { + printf("ERR:Cannot allocate buffer for command!\n"); + return MLAN_STATUS_FAILURE; + } + + prepare_buffer(buffer, argv[2], (argc - 3), &argv[3]); + + cmd = (struct eth_priv_cmd *)malloc(sizeof(struct eth_priv_cmd)); + if (!cmd) { + printf("ERR:Cannot allocate buffer for command!\n"); + free(buffer); + return MLAN_STATUS_FAILURE; + } + +/* Fill up buffer */ +#ifdef USERSPACE_32BIT_OVER_KERNEL_64BIT + memset(cmd, 0, sizeof(struct eth_priv_cmd)); + memcpy(&cmd->buf, &buffer, sizeof(buffer)); +#else + cmd->buf = buffer; +#endif + cmd->used_len = 0; + cmd->total_len = BUFFER_LENGTH; + + /* Perform IOCTL */ + memset(&ifr, 0, sizeof(struct ifreq)); + strncpy(ifr.ifr_ifrn.ifrn_name, dev_name, strlen(dev_name)); + ifr.ifr_ifru.ifru_data = (void *)cmd; + + if (ioctl(sockfd, MLAN_ETH_PRIV, &ifr)) { + perror("mlanutl"); + fprintf(stderr, "mlanutl: bootsleep fail\n"); + if (cmd) + free(cmd); + if (buffer) + free(buffer); + return MLAN_STATUS_FAILURE; + } + + /* Process Get result */ + if (argc == 3) { + printf("boot sleep status: %u\n", *(t_u16 *)buffer); + } + + if (buffer) + free(buffer); + if (cmd) + free(cmd); + + return MLAN_STATUS_SUCCESS; +} + +/** + * @brief Process static rx abort config set/get + * @param argc Number of arguments + * @param argv A pointer to arguments array + * @return MLAN_STATUS_SUCCESS--success, otherwise--fail + */ +static int +process_rx_abort_cfg(int argc, char *argv[]) +{ + t_u8 *buffer = NULL; + struct eth_priv_cmd *cmd = NULL; + struct ifreq ifr; + rx_abort_cfg_para data; + int rssi = 0; + + /* Check arguments */ + if (argc < 3 || (argc > 5)) { + printf("ERR:Incorrect number of arguments!\n"); + return MLAN_STATUS_FAILURE; + } + + /* Initialize buffer */ + buffer = (t_u8 *)malloc(BUFFER_LENGTH); + if (!buffer) { + printf("ERR:Cannot allocate buffer for command!\n"); + return MLAN_STATUS_FAILURE; + } + + prepare_buffer(buffer, argv[2], (argc - 3), &argv[3]); + + cmd = (struct eth_priv_cmd *)malloc(sizeof(struct eth_priv_cmd)); + if (!cmd) { + printf("ERR:Cannot allocate buffer for command!\n"); + free(buffer); + return MLAN_STATUS_FAILURE; + } + + /* Fill up buffer */ +#ifdef USERSPACE_32BIT_OVER_KERNEL_64BIT + memset(cmd, 0, sizeof(struct eth_priv_cmd)); + memcpy(&cmd->buf, &buffer, sizeof(buffer)); +#else + cmd->buf = buffer; +#endif + cmd->used_len = 0; + cmd->total_len = BUFFER_LENGTH; + + /* Perform IOCTL */ + memset(&ifr, 0, sizeof(struct ifreq)); + strncpy(ifr.ifr_ifrn.ifrn_name, dev_name, strlen(dev_name)); + ifr.ifr_ifru.ifru_data = (void *)cmd; + + if (ioctl(sockfd, MLAN_ETH_PRIV, &ifr)) { + perror("mlanutl"); + fprintf(stderr, "mlanutl: rx_abort_cfg fail\n"); + if (cmd) + free(cmd); + if (buffer) + free(buffer); + return MLAN_STATUS_FAILURE; + } + + /* Process result */ + memset((void *)&data, 0, sizeof(data)); + memcpy((void *)&data, buffer, sizeof(data)); + + printf("Static Rx Abort %s\n", + (data.enable == 1) ? "enabled" : "disabled"); + + if (data.enable) { + /* on some platforms, t_s8 is same as unsigned char */ + rssi = (int)(data.rssi_threshold); + if (rssi > 0x7f) + rssi = -(256 - rssi); + printf("RSSI Threshold : %s%ddBm\n", ((rssi > 0) ? "-" : ""), + rssi); + } + printf("\n"); + + if (buffer) + free(buffer); + if (cmd) + free(cmd); + + return MLAN_STATUS_SUCCESS; +} + +/** + * @brief Process dynamic rx abort config set/get + * @param argc Number of arguments + * @param argv A pointer to arguments array + * @return MLAN_STATUS_SUCCESS--success, otherwise--fail + */ +static int +process_rx_abort_cfg_ext(int argc, char *argv[]) +{ + t_u8 *buffer = NULL; + struct eth_priv_cmd *cmd = NULL; + struct ifreq ifr; + rx_abort_cfg_ext_para data; + int rssi; + + /* Check arguments */ + if (argc < 3 || (argc > 6)) { + printf("ERR:Incorrect number of arguments!\n"); + return MLAN_STATUS_FAILURE; + } + + /* Initialize buffer */ + buffer = (t_u8 *)malloc(BUFFER_LENGTH); + if (!buffer) { + printf("ERR:Cannot allocate buffer for command!\n"); + return MLAN_STATUS_FAILURE; + } + + prepare_buffer(buffer, argv[2], (argc - 3), &argv[3]); + + cmd = (struct eth_priv_cmd *)malloc(sizeof(struct eth_priv_cmd)); + if (!cmd) { + printf("ERR:Cannot allocate buffer for command!\n"); + free(buffer); + return MLAN_STATUS_FAILURE; + } + + /* Fill up buffer */ +#ifdef USERSPACE_32BIT_OVER_KERNEL_64BIT + memset(cmd, 0, sizeof(struct eth_priv_cmd)); + memcpy(&cmd->buf, &buffer, sizeof(buffer)); +#else + cmd->buf = buffer; +#endif + cmd->used_len = 0; + cmd->total_len = BUFFER_LENGTH; + + /* Perform IOCTL */ + memset(&ifr, 0, sizeof(struct ifreq)); + strncpy(ifr.ifr_ifrn.ifrn_name, dev_name, strlen(dev_name)); + ifr.ifr_ifru.ifru_data = (void *)cmd; + + if (ioctl(sockfd, MLAN_ETH_PRIV, &ifr)) { + perror("mlanutl"); + fprintf(stderr, "mlanutl: rx_abort_cfg_ext fail\n"); + if (cmd) + free(cmd); + if (buffer) + free(buffer); + return MLAN_STATUS_FAILURE; + } + + /* Process result */ + memset((void *)&data, 0, sizeof(data)); + memcpy((void *)&data, buffer, sizeof(data)); + + printf("Dynamic Rx Abort %s\n", + (data.enable == 1) ? "enabled" : "disabled"); + + if (data.enable) { + /* on some platforms, t_s8 is same as unsigned char */ + rssi = (int)(data.rssi_margin); + if (rssi > 0x7f) + rssi = -(256 - rssi); + printf("RSSI Margin : %s%ddBm\n", ((rssi > 0) ? "-" : ""), + rssi); + + rssi = (int)(data.ceil_rssi_threshold); + if (rssi > 0x7f) + rssi = -(256 - rssi); + printf("Ceil RSSI Threshold : %s%ddBm\n", + ((rssi > 0) ? "-" : ""), rssi); + } + printf("\n"); + if (buffer) + free(buffer); + if (cmd) + free(cmd); + + return MLAN_STATUS_SUCCESS; +} + +/** + * @brief Process tx ampdu protection mode set/get + * @param argc Number of arguments + * @param argv A pointer to arguments array + * @return MLAN_STATUS_SUCCESS--success, otherwise--fail + */ +static int +process_tx_ampdu_prot_mode(int argc, char *argv[]) +{ + t_u8 *buffer = NULL; + struct eth_priv_cmd *cmd = NULL; + struct ifreq ifr; + tx_ampdu_prot_mode_para data; + + /* Check arguments */ + if (argc < 3 || (argc > 4)) { + printf("ERR:Incorrect number of arguments!\n"); + return MLAN_STATUS_FAILURE; + } + + /* Initialize buffer */ + buffer = (t_u8 *)malloc(BUFFER_LENGTH); + if (!buffer) { + printf("ERR:Cannot allocate buffer for command!\n"); + return MLAN_STATUS_FAILURE; + } + + prepare_buffer(buffer, argv[2], (argc - 3), &argv[3]); + + cmd = (struct eth_priv_cmd *)malloc(sizeof(struct eth_priv_cmd)); + if (!cmd) { + printf("ERR:Cannot allocate buffer for command!\n"); + free(buffer); + return MLAN_STATUS_FAILURE; + } + + /* Fill up buffer */ +#ifdef USERSPACE_32BIT_OVER_KERNEL_64BIT + memset(cmd, 0, sizeof(struct eth_priv_cmd)); + memcpy(&cmd->buf, &buffer, sizeof(buffer)); +#else + cmd->buf = buffer; +#endif + cmd->used_len = 0; + cmd->total_len = BUFFER_LENGTH; + + /* Perform IOCTL */ + memset(&ifr, 0, sizeof(struct ifreq)); + strncpy(ifr.ifr_ifrn.ifrn_name, dev_name, strlen(dev_name)); + ifr.ifr_ifru.ifru_data = (void *)cmd; + + if (ioctl(sockfd, MLAN_ETH_PRIV, &ifr)) { + perror("mlanutl"); + fprintf(stderr, "mlanutl: tx_ampdu_prot_mode fail\n"); + if (cmd) + free(cmd); + if (buffer) + free(buffer); + return MLAN_STATUS_FAILURE; + } + + /* Process result */ + memset((void *)&data, 0, sizeof(data)); + memcpy((void *)&data, buffer, sizeof(data)); + + printf("Tx AMPDU protection mode: "); + if (data.mode == TX_AMPDU_RTS_CTS) + printf("RTS/CTS\n"); + else if (data.mode == TX_AMPDU_CTS_2_SELF) + printf("CTS-2-SELF\n"); + else if (data.mode == TX_AMPDU_DYNAMIC_RTS_CTS) + printf("DYNAMIC RTS/CTS\n"); + else + printf("Disabled\n"); + printf("\n"); + + if (buffer) + free(buffer); + if (cmd) + free(cmd); + + return MLAN_STATUS_SUCCESS; +} + +/** + * @brief Process rate adapt config set/get + * @param argc Number of arguments + * @param argv A pointer to arguments array + * @return MLAN_STATUS_SUCCESS--success, otherwise--fail + */ +static int +process_rate_adapt_cfg(int argc, char *argv[]) +{ + t_u8 *buffer = NULL; + struct eth_priv_cmd *cmd = NULL; + struct ifreq ifr; + rate_adapt_cfg_para data; + + /* Check arguments */ + if ((argc < 3) || (argc > 4 && argc != 7)) { + printf("ERR:Incorrect number of arguments!\n"); + return MLAN_STATUS_FAILURE; + } + + /* Initialize buffer */ + buffer = (t_u8 *)malloc(BUFFER_LENGTH); + if (!buffer) { + printf("ERR:Cannot allocate buffer for command!\n"); + return MLAN_STATUS_FAILURE; + } + + prepare_buffer(buffer, argv[2], (argc - 3), &argv[3]); + + cmd = (struct eth_priv_cmd *)malloc(sizeof(struct eth_priv_cmd)); + if (!cmd) { + printf("ERR:Cannot allocate buffer for command!\n"); + free(buffer); + return MLAN_STATUS_FAILURE; + } + + /* Fill up buffer */ +#ifdef USERSPACE_32BIT_OVER_KERNEL_64BIT + memset(cmd, 0, sizeof(struct eth_priv_cmd)); + memcpy(&cmd->buf, &buffer, sizeof(buffer)); +#else + cmd->buf = buffer; +#endif + cmd->used_len = 0; + cmd->total_len = BUFFER_LENGTH; + + /* Perform IOCTL */ + memset(&ifr, 0, sizeof(struct ifreq)); + strncpy(ifr.ifr_ifrn.ifrn_name, dev_name, strlen(dev_name)); + ifr.ifr_ifru.ifru_data = (void *)cmd; + + if (ioctl(sockfd, MLAN_ETH_PRIV, &ifr)) { + perror("mlanutl"); + fprintf(stderr, "mlanutl: rate_adapt_cfg fail\n"); + if (cmd) + free(cmd); + if (buffer) + free(buffer); + return MLAN_STATUS_FAILURE; + } + + /* Process result */ + memset((void *)&data, 0, sizeof(data)); + memcpy((void *)&data, buffer, sizeof(data)); + + printf("Rate Adapt Cfg:\n"); + + if (data.sr_rateadapt == 0) + printf(" Legacy RateAdapt Enabled\n"); + else { + printf(" SR RateAdapt Enabled\n"); + if ((data.ra_low_thresh & data.ra_high_thresh) == 0xff) + printf("Dynamic rate adaptation mode based on noise level active\n"); + else { + printf("Aggregated data Tx success rate static thresholds:\n"); + printf(" Low : %u\n", data.ra_low_thresh); + printf(" High : %u\n", data.ra_high_thresh); + } + printf("Eval Timer interval : %u i.e. %ums\n", + data.ra_interval, 10 * data.ra_interval); + printf("(in multiples of 10)\n\n"); + } + + if (buffer) + free(buffer); + if (cmd) + free(cmd); + + return MLAN_STATUS_SUCCESS; +} + +/** + * @brief Process cck desense config set/get + * @param argc Number of arguments + * @param argv A pointer to arguments array + * @return MLAN_STATUS_SUCCESS--success, otherwise--fail + */ +static int +process_cck_desense_cfg(int argc, char *argv[]) +{ + t_u8 *buffer = NULL; + struct eth_priv_cmd *cmd = NULL; + struct ifreq ifr; + cck_desense_cfg_para data; + int rssi; + + /* Check arguments */ + if (argc < 3 || argc > 8) { + printf("ERR:Incorrect number of arguments!\n"); + return MLAN_STATUS_FAILURE; + } + + /* Initialize buffer */ + buffer = (t_u8 *)malloc(BUFFER_LENGTH); + if (!buffer) { + printf("ERR:Cannot allocate buffer for command!\n"); + return MLAN_STATUS_FAILURE; + } + + prepare_buffer(buffer, argv[2], (argc - 3), &argv[3]); + + cmd = (struct eth_priv_cmd *)malloc(sizeof(struct eth_priv_cmd)); + if (!cmd) { + printf("ERR:Cannot allocate buffer for command!\n"); + free(buffer); + return MLAN_STATUS_FAILURE; + } + + /* Fill up buffer */ +#ifdef USERSPACE_32BIT_OVER_KERNEL_64BIT + memset(cmd, 0, sizeof(struct eth_priv_cmd)); + memcpy(&cmd->buf, &buffer, sizeof(buffer)); +#else + cmd->buf = buffer; +#endif + cmd->used_len = 0; + cmd->total_len = BUFFER_LENGTH; + + /* Perform IOCTL */ + memset(&ifr, 0, sizeof(struct ifreq)); + strncpy(ifr.ifr_ifrn.ifrn_name, dev_name, strlen(dev_name)); + ifr.ifr_ifru.ifru_data = (void *)cmd; + + if (ioctl(sockfd, MLAN_ETH_PRIV, &ifr)) { + perror("mlanutl"); + fprintf(stderr, "mlanutl: cck_desense_cfg fail\n"); + if (cmd) + free(cmd); + if (buffer) + free(buffer); + return MLAN_STATUS_FAILURE; + } + + /* Process result */ + memset((void *)&data, 0, sizeof(data)); + memcpy((void *)&data, buffer, sizeof(data)); + + printf("CCK Desense %s\n", (data.mode) ? "enabled" : "disabled"); + + if (data.mode != CCK_DESENSE_MODE_DISABLED) { + printf("Mode: %s\n", + (data.mode == CCK_DESENSE_MODE_DYNAMIC) ? + "Dynamic" : "Dynamic Enhanced"); + /* on some platforms, t_s8 is same as unsigned char */ + rssi = (int)(data.margin); + if (rssi > 0x7f) + rssi = -(256 - rssi); + printf("Margin : %s%ddBm\n", ((rssi > 0) ? "-" : ""), rssi); + + rssi = (int)(data.ceil_thresh); + if (rssi > 0x7f) + rssi = -(256 - rssi); + printf("Ceil RSSI Threshold : %s%ddBm\n", + ((rssi > 0) ? "-" : ""), rssi); + } + if (data.mode == CCK_DESENSE_MODE_DYN_ENH) { + printf("Num ON intervals : %d\n", data.num_on_intervals); + printf("Num OFF intervals : %d\n", data.num_off_intervals); + } + printf("\n"); + + if (buffer) + free(buffer); + if (cmd) + free(cmd); + + return MLAN_STATUS_SUCCESS; +} + +/** + * @brief Process low power mode config set/get + * @param argc Number of arguments + * @param argv A pointer to arguments array + * @return MLAN_STATUS_SUCCESS--success, otherwise--fail + */ +static int +process_lpm(int argc, char *argv[]) +{ + t_u8 *buffer = NULL; + struct eth_priv_cmd *cmd; + struct ifreq ifr; + t_u16 lpm = 0; + + /* Check arguments */ + if (argc < 3 || argc > 4) { + printf("ERR:Incorrect number of arguments!\n"); + return MLAN_STATUS_FAILURE; + } + + /* Initialize buffer */ + buffer = (t_u8 *)malloc(BUFFER_LENGTH); + if (!buffer) { + printf("ERR:Cannot allocate buffer for command!\n"); + return MLAN_STATUS_FAILURE; + } + + prepare_buffer(buffer, argv[2], (argc - 3), &argv[3]); + + cmd = (struct eth_priv_cmd *)malloc(sizeof(struct eth_priv_cmd)); + if (!cmd) { + printf("ERR:Cannot allocate buffer for command!\n"); + free(buffer); + return MLAN_STATUS_FAILURE; + } + + /* Fill up buffer */ +#ifdef USERSPACE_32BIT_OVER_KERNEL_64BIT + memset(cmd, 0, sizeof(struct eth_priv_cmd)); + memcpy(&cmd->buf, &buffer, sizeof(buffer)); +#else + cmd->buf = buffer; +#endif + cmd->used_len = 0; + cmd->total_len = BUFFER_LENGTH; + + /* Perform IOCTL */ + memset(&ifr, 0, sizeof(struct ifreq)); + strncpy(ifr.ifr_ifrn.ifrn_name, dev_name, strlen(dev_name)); + ifr.ifr_ifru.ifru_data = (void *)cmd; + + if (ioctl(sockfd, MLAN_ETH_PRIV, &ifr)) { + perror("mlanutl"); + fprintf(stderr, "mlanutl: lpm fail\n"); + if (cmd) + free(cmd); + if (buffer) + free(buffer); + return MLAN_STATUS_FAILURE; + } + + if (argc == 3) { + /* GET operation */ + lpm = *(t_u16 *)buffer; + printf("low power mode is %d\n", lpm); + } + + if (buffer) + free(buffer); + if (cmd) + free(cmd); + + return MLAN_STATUS_SUCCESS; +} + +/** + * @brief Process twt_setup + * @param argc number of arguments + * @param argv a pointer to arguments array + * @return MLAN_STATUS_SUCCESS--success, otherwise--fail + */ +static int +process_twt_setup(int argc, char *argv[]) +{ + twt_setup *param_buf = NULL; + char *line = NULL; + FILE *config_file = NULL; + int li = 0, ret = MLAN_STATUS_SUCCESS, cmd_found = 0, cmd_header_len = + 0; + char *args[30], *pos = NULL; + t_u8 *buffer = NULL; + struct eth_priv_cmd *cmd = NULL; + struct ifreq ifr; + + /* Check arguments */ + if (argc != 4) { + printf("ERR:Incorrect number of arguments.\n"); + printf("Syntax: ./mlanutl mlanX twt_setup \n"); + return MLAN_STATUS_FAILURE; + } + + buffer = (t_u8 *)malloc(BUFFER_LENGTH); + if (!buffer) { + printf("ERR:Cannot allocate memory!\n"); + ret = MLAN_STATUS_FAILURE; + goto done; + } + + cmd_header_len = strlen(CMD_NXP) + strlen(argv[2]); + prepare_buffer(buffer, argv[2], 0, NULL); + cmd = (struct eth_priv_cmd *)malloc(sizeof(struct eth_priv_cmd)); + if (!cmd) { + printf("ERR: Cannot allocate buffer for command!\n"); + ret = MLAN_STATUS_FAILURE; + goto done; + } + + /* Fill up buffer */ +#ifdef USERSPACE_32BIT_OVER_KERNEL_64BIT + memset(cmd, 0, sizeof(struct eth_priv_cmd)); + memcpy(&cmd->buf, &buffer, sizeof(buffer)); +#else + cmd->buf = buffer; +#endif + cmd->used_len = cmd_header_len; + cmd->total_len = BUFFER_LENGTH; + + param_buf = (twt_setup *) ((t_u8 *)buffer + cmd_header_len); + + /* Check if file exists */ + config_file = fopen(argv[3], "r"); + if (config_file == NULL) { + printf("\nERR:Could not open Config file.\n"); + ret = MLAN_STATUS_FAILURE; + goto done; + } + line = (char *)malloc(MAX_CONFIG_LINE); + if (!line) { + printf("ERR:Cannot allocate memory for line\n"); + ret = MLAN_STATUS_FAILURE; + goto done; + } + memset(line, 0, MAX_CONFIG_LINE); + + /* Parse file and process */ + while (config_get_line(line, MAX_CONFIG_LINE, config_file, &li, &pos)) { + parse_line(line, args, 30); + if (!cmd_found && strncmp(args[0], argv[2], strlen(args[0]))) + continue; + + cmd_found = 1; + + if (strcmp(args[0], "Implicit") == 0) { + param_buf->implicit = (t_u8)A2HEXDECIMAL(args[1]); + } else if (strcmp(args[0], "Announced") == 0) { + param_buf->announced = (t_u8)A2HEXDECIMAL(args[1]); + } else if (strcmp(args[0], "TriggerEnabled") == 0) { + param_buf->triggerEn = (t_u8)A2HEXDECIMAL(args[1]); + } else if (strcmp(args[0], "TWTInformationDisabled") == 0) { + param_buf->twtInfoDisabled = + (t_u8)A2HEXDECIMAL(args[1]); + } else if (strcmp(args[0], "NegotiationType") == 0) { + param_buf->negotiationType = + (t_u8)A2HEXDECIMAL(args[1]); + } else if (strcmp(args[0], "TWTWakeupDuration") == 0) { + param_buf->twtWakeupDuration = + (t_u8)A2HEXDECIMAL(args[1]); + } else if (strcmp(args[0], "FlowIdentifier") == 0) { + param_buf->flowIdentifier = (t_u8)A2HEXDECIMAL(args[1]); + } else if (strcmp(args[0], "HardConstraint") == 0) { + param_buf->hardConstraint = (t_u8)A2HEXDECIMAL(args[1]); + } else if (strcmp(args[0], "TWTExponent") == 0) { + param_buf->twtExponent = (t_u8)A2HEXDECIMAL(args[1]); + } else if (strcmp(args[0], "TWTMantissa") == 0) { + param_buf->twtMantissa = (t_u16)A2HEXDECIMAL(args[1]); + } else if (strcmp(args[0], "}") == 0 && cmd_found) { + break; + } + } + + if (!cmd_found) { + printf("Command %s not found in the config file!\n" + "Syntax: ./mlanutl mlanX twt_setup \n", + (char *)argv[2]); + ret = MLAN_STATUS_FAILURE; + goto done; + } + + cmd->used_len = cmd_header_len + sizeof(twt_setup); + + /* Initialize the ifr structure */ + memset(&ifr, 0, sizeof(ifr)); + + strncpy(ifr.ifr_ifrn.ifrn_name, dev_name, strlen(dev_name)); + ifr.ifr_ifru.ifru_data = (void *)cmd; + + if (ioctl(sockfd, MLAN_ETH_PRIV, &ifr)) { + perror("mlanutl: twt_setup"); + fprintf(stderr, "mlanutl:twt_setup failed\n"); + ret = MLAN_STATUS_FAILURE; + goto done; + } + +done: + if (line) + free(line); + if (config_file) + fclose(config_file); + if (cmd) + free(cmd); + if (buffer) + free(buffer); + return ret; +} + +/** + * @brief Process twt_teardown + * @param argc number of arguments + * @param argv A pointer to arguments array + * @return MLAN_STATUS_SUCCESS--success, otherwise--fail + */ +static int +process_twt_teardown(int argc, char *argv[]) +{ + twt_teardown *param_buf = NULL; + char *line = NULL; + FILE *config_file = NULL; + int li = 0, ret = MLAN_STATUS_SUCCESS, cmd_found = 0, cmd_header_len = + 0; + char *args[30], *pos = NULL; + t_u8 *buffer = NULL; + struct eth_priv_cmd *cmd = NULL; + struct ifreq ifr; + + /* Check arguments */ + if (argc != 4) { + printf("ERR:Incorrect number of arguments.\n"); + printf("Syntax: ./mlanutl mlanX twt_teardown \n"); + return MLAN_STATUS_FAILURE; + } + + buffer = (t_u8 *)malloc(BUFFER_LENGTH); + if (!buffer) { + printf("ERR:Cannot allocate memory!\n"); + ret = MLAN_STATUS_FAILURE; + goto done; + } + + cmd_header_len = strlen(CMD_NXP) + strlen(argv[2]); + prepare_buffer(buffer, argv[2], 0, NULL); + cmd = (struct eth_priv_cmd *)malloc(sizeof(struct eth_priv_cmd)); + if (!cmd) { + printf("ERR: Cannot allocate buffer for command!\n"); + ret = MLAN_STATUS_FAILURE; + goto done; + } + + /* Fill up buffer */ +#ifdef USERSPACE_32BIT_OVER_KERNEL_64BIT + memset(cmd, 0, sizeof(struct eth_priv_cmd)); + memcpy(&cmd->buf, &buffer, sizeof(buffer)); +#else + cmd->buf = buffer; +#endif + cmd->used_len = cmd_header_len; + cmd->total_len = BUFFER_LENGTH; + + param_buf = (twt_teardown *) ((t_u8 *)buffer + cmd_header_len); + + /* Check if file exists */ + config_file = fopen(argv[3], "r"); + if (config_file == NULL) { + printf("\nERR:Could not open Config file.\n"); + ret = MLAN_STATUS_FAILURE; + goto done; + } + + line = (char *)malloc(MAX_CONFIG_LINE); + if (!line) { + printf("ERR:Cannot allocate memory for line\n"); + ret = MLAN_STATUS_FAILURE; + goto done; + } + memset(line, 0, MAX_CONFIG_LINE); + + /* Parse file and process */ + while (config_get_line(line, MAX_CONFIG_LINE, config_file, &li, &pos)) { + parse_line(line, args, 30); + if (!cmd_found && strncmp(args[0], argv[2], strlen(args[0]))) + continue; + + cmd_found = 1; + + if (strcmp(args[0], "FlowIdentifier") == 0) { + param_buf->flowIdentifier = (t_u8)A2HEXDECIMAL(args[1]); + } else if (strcmp(args[0], "NegotiationType") == 0) { + param_buf->negotiationType = + (t_u8)A2HEXDECIMAL(args[1]); + } else if (strcmp(args[0], "TearDownAllTWT") == 0) { + param_buf->teardownAllTWT = (t_u8)A2HEXDECIMAL(args[1]); + } else if (strcmp(args[0], "}") == 0 && cmd_found) { + break; + } + } + + if (!cmd_found) { + printf("Command %s not found in the config file!\n" + "Syntax: ./mlanutl mlanX twt_teardown \n", + (char *)argv[2]); + ret = MLAN_STATUS_FAILURE; + goto done; + } + + cmd->used_len = cmd_header_len + sizeof(twt_teardown); + + /* Initialize the ifr structure */ + memset(&ifr, 0, sizeof(ifr)); + + strncpy(ifr.ifr_ifrn.ifrn_name, dev_name, strlen(dev_name)); + ifr.ifr_ifru.ifru_data = (void *)cmd; + + if (ioctl(sockfd, MLAN_ETH_PRIV, &ifr)) { + perror("mlanutl: twt_teardown"); + fprintf(stderr, "mlanutl:twt_teardown failed\n"); + ret = MLAN_STATUS_FAILURE; + goto done; + } + +done: + if (line) + free(line); + if (config_file) + fclose(config_file); + if (cmd) + free(cmd); + if (buffer) + free(buffer); + return ret; +} + +/******************************************************** + Global Functions +********************************************************/ + +/** + * @brief Entry function for mlanutl + * @param argc Number of arguments + * @param argv A pointer to arguments array + * @return MLAN_STATUS_SUCCESS--success, otherwise--fail + */ +int +main(int argc, char *argv[]) +{ + int ret = MLAN_STATUS_SUCCESS; + + if ((argc == 2) && (strcmp(argv[1], "-v") == 0)) { + fprintf(stdout, "NXP mlanutl version %s\n", MLANUTL_VER); + exit(0); + } + if (argc < 3) { + fprintf(stderr, "Invalid number of parameters!\n"); + display_usage(); + exit(1); + } + + strncpy(dev_name, argv[1], IFNAMSIZ - 1); + + /* + * Create a socket + */ + sockfd = socket(AF_INET, SOCK_STREAM, 0); + if (sockfd < 0) { + fprintf(stderr, "mlanutl: Cannot open socket.\n"); + exit(1); + } + + ret = process_command(argc, argv); + + if (ret == MLAN_STATUS_NOTFOUND) { + ret = process_generic(argc, argv); + + if (ret) { + fprintf(stderr, "Invalid command specified!\n"); + display_usage(); + ret = 1; + } + } + + close(sockfd); + return ret; +} diff --git a/mxm_wifiex/wlan_src/mapp/mlanutl/mlanutl.h b/mxm_wifiex/wlan_src/mapp/mlanutl/mlanutl.h new file mode 100644 index 0000000..4a22a5b --- /dev/null +++ b/mxm_wifiex/wlan_src/mapp/mlanutl/mlanutl.h @@ -0,0 +1,2891 @@ +/** @file mlanutl.h + * + * @brief This file contains definitions for application + * + * + * Copyright 2014-2020 NXP + * + * NXP CONFIDENTIAL + * The source code contained or described herein and all documents related to + * the source code (Materials) are owned by NXP, its + * suppliers and/or its licensors. Title to the Materials remains with NXP, + * its suppliers and/or its licensors. The Materials contain + * trade secrets and proprietary and confidential information of NXP, its + * suppliers and/or its licensors. The Materials are protected by worldwide copyright + * and trade secret laws and treaty provisions. No part of the Materials may be + * used, copied, reproduced, modified, published, uploaded, posted, + * transmitted, distributed, or disclosed in any way without NXP's prior + * express written permission. + * + * No license under any patent, copyright, trade secret or other intellectual + * property right is granted to or conferred upon you by disclosure or delivery + * of the Materials, either expressly, by implication, inducement, estoppel or + * otherwise. Any license under such intellectual property rights must be + * express and approved by NXP in writing. + * + */ +/************************************************************************ +Change log: + 11/26/2008: initial version +************************************************************************/ +#ifndef _MLANUTL_H_ +#define _MLANUTL_H_ + +/** Include header files */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +/** Type definition: boolean */ +typedef enum { FALSE, TRUE } boolean; + +/** 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))) + +/** Convert to correct endian format */ +#ifdef BIG_ENDIAN_SUPPORT +/** CPU to little-endian convert for 16-bit */ +#define cpu_to_le16(x) swap_byte_16(x) +/** CPU to little-endian convert for 32-bit */ +#define cpu_to_le32(x) swap_byte_32(x) +/** Little-endian to CPU convert for 16-bit */ +#define le16_to_cpu(x) swap_byte_16(x) +/** Little-endian to CPU convert for 32-bit */ +#define le32_to_cpu(x) swap_byte_32(x) +#else +/** Do nothing */ +#define cpu_to_le16(x) (x) +/** Do nothing */ +#define cpu_to_le32(x) (x) +/** Do nothing */ +#define le16_to_cpu(x) (x) +/** Do nothing */ +#define le32_to_cpu(x) (x) +#endif + +/** TLV header */ +#define TLVHEADER /** Tag */ \ + t_u16 tag; \ + /** Length */ \ + t_u16 length + +/** Length of TLV header */ +#define TLVHEADER_LEN 4 + +/** Character, 1 byte */ +typedef signed char t_s8; +/** Unsigned character, 1 byte */ +typedef unsigned char t_u8; + +/** Short integer */ +typedef signed short t_s16; +/** Unsigned short integer */ +typedef unsigned short t_u16; + +/** Integer */ +typedef signed int t_s32; +/** Unsigned integer */ +typedef unsigned int t_u32; + +/** Long long integer */ +typedef signed long long t_s64; +/** Unsigned long long integer */ +typedef unsigned long long t_u64; + +/** Void pointer (4-bytes) */ +typedef void t_void; + +/** The attribute pack used for structure packing */ +#ifndef __ATTRIB_PACK__ +#define __ATTRIB_PACK__ __attribute__((packed)) +#endif + +/** Success */ +#define MLAN_STATUS_SUCCESS (0) +/** Failure */ +#define MLAN_STATUS_FAILURE (-1) +/** Not found */ +#define MLAN_STATUS_NOTFOUND (1) + +/** IOCTL number */ +#define MLAN_ETH_PRIV (SIOCDEVPRIVATE + 14) + +/** Command buffer max length */ +#define BUFFER_LENGTH (3 * 1024) + +/** Find number of elements */ +#define NELEMENTS(x) (sizeof(x)/sizeof(x[0])) + +/** BIT value */ +#define MBIT(x) (((t_u32)1) << (x)) + +#ifndef MIN +/** Find minimum value */ +#define MIN(a, b) ((a) < (b) ? (a) : (b)) +#endif /* MIN */ + +/** Length of ethernet address */ +#ifndef ETH_ALEN +#define ETH_ALEN 6 +#endif + +/** Action field value : get */ +#define ACTION_GET 0 +/** Action field value : set */ +#define ACTION_SET 1 + +/** Channel usability flags */ +#define NXP_CHANNEL_DISABLED MBIT(7) +#define NXP_CHANNEL_NOHT160 MBIT(4) +#define NXP_CHANNEL_NOHT80 MBIT(3) +#define NXP_CHANNEL_NOHT40 MBIT(2) +#define NXP_CHANNEL_DFS MBIT(1) +#define NXP_CHANNEL_PASSIVE MBIT(0) + +char mod_conv_bg_1x1[10][35] = { "CCK (1,2,5.5,11 Mbps)", + "OFDM_PSK (6,9,12,18 Mbps)", + "OFDM_QAM16 (24,36 Mbps)", + "OFDM_QAM64 (48,54 Mbps)", + "HT_20_PSK (MCS 0,1,2)", + "HT_20_QAM16 (MCS 3,4)", + "HT_20_QAM64 (MCS 5,6,7)", + "HT_40_PSK (MCS 0,1,2)", + "HT_40_QAM16 (MCS 3,4)", + "HT_40_QAM64 (MCS 5,6,7)" +}; + +char mod_conv_a_1x1[6][35] = { "VHT_20_QAM256 (MCS 8)", + "VHT_40_QAM256 (MCS 8,9)", + "VHT_80_PSK (MCS 0,1,2)", + "VHT_80_QAM16 (MCS 3,4)", + "VHT_80_QAM64 (MCS 5,6,7)", + "VHT_80_QAM256 (MCS 8,9)" +}; + +char mod_conv_bg_2x2[6][35] = { "HT2_20_PSK (MCS 8,9,10)", + "HT2_20_QAM16 (MCS 11,12)", + "HT2_20_QAM64 (MCS 13,14,15)", + "HT2_40_PSK (MCS 8,9,10)", + "HT2_40_QAM16 (MCS 11,12)", + "HT2_40_QAM64 (MCS 13,14,15)" +}; + +char mod_conv_a_2x2[6][35] = { "VHT2_20_QAM256 (MCS 8)", + "VHT2_40_QAM256 (MCS 8,9)", + "VHT2_80_PSK (MCS 0,1,2)", + "VHT2_80_QAM16 (MCS 3,4)", + "VHT2_80_QAM64 (MCS 5,6,7)", + "VHT2_80_QAM256 (MCS 8,9)" +}; + +/** Socket */ +extern t_s32 sockfd; + +/** Device name */ +extern char dev_name[IFNAMSIZ + 1]; + +#define HOSTCMD "hostcmd" + +/** NXP private command identifier */ +#define CMD_NXP "MRVL_CMD" + +struct command_node { + char *name; + int (*handler) (int, char **); +}; + +/** Private command structure */ +#ifdef USERSPACE_32BIT_OVER_KERNEL_64BIT +struct eth_priv_cmd { + /** Command buffer pointer */ + t_u64 buf; + /** buffer updated by driver */ + int used_len; + /** buffer sent by application */ + int total_len; +} __ATTRIB_PACK__; +#else +struct eth_priv_cmd { + /** Command buffer */ + t_u8 *buf; + /** Used length */ + int used_len; + /** Total length */ + int total_len; +}; +#endif + +#if defined(STA_SUPPORT) +struct eth_priv_pmfcfg { + /* Management Frame Protection Capability */ + t_u8 mfpc; + /* Management Frame Protection Required */ + t_u8 mfpr; +}; +#endif + +struct eth_priv_htcapinfo { + t_u32 ht_cap_info_bg; + t_u32 ht_cap_info_a; +}; + +#define MAX_NUM_MAC 2 + +struct dmcsChanStatus_t { + /** Channel number */ + t_u8 channel; + /** Number of ap on this channel */ + t_u8 ap_count; + /** Number of station on this channel */ + t_u8 sta_count; +}; + +struct dmcsStatus_t { + /** Radio ID */ + t_u8 radio_id; + /** Running mode */ + t_u8 running_mode; + /** Current channel status */ + struct dmcsChanStatus_t chan_status[2]; +}; + +/** data structure for cmd dmcs */ +struct eth_priv_dmcs_status { + /** Current mapping policy */ + t_u8 mapping_policy; + /** radio status of DMCS */ + struct dmcsStatus_t radio_status[MAX_NUM_MAC]; +}; + +struct eth_priv_addba { + t_u32 time_out; + t_u32 tx_win_size; + t_u32 rx_win_size; + t_u32 tx_amsdu; + t_u32 rx_amsdu; +}; + +/** data_structure for cmd vhtcfg */ +struct eth_priv_vhtcfg { + /** Band (1: 2.4G, 2: 5 G, 3: both 2.4G and 5G) */ + t_u32 band; + /** TxRx (1: Tx, 2: Rx, 3: both Tx and Rx) */ + t_u32 txrx; + /** BW CFG (0: 11N CFG, 1: vhtcap) */ + t_u32 bwcfg; + /** VHT capabilities. */ + t_u32 vht_cap_info; + /** VHT Tx mcs */ + t_u32 vht_tx_mcs; + /** VHT Rx mcs */ + t_u32 vht_rx_mcs; + /** VHT rx max rate */ + t_u16 vht_rx_max_rate; + /** VHT max tx rate */ + t_u16 vht_tx_max_rate; +}; + +/** data_structure for cmd opermodecfg */ +struct eth_priv_opermodecfg { + /** channel width: 1-20MHz, 2-40MHz, 3-80MHz, 4-160MHz or 80+80MHz */ + t_u8 bw; + /** Rx NSS */ + t_u8 nss; +}; + +/** data structure for cmd getdatarate */ +struct eth_priv_data_rate { + /** Tx data rate */ + t_u32 tx_data_rate; + /** Rx data rate */ + t_u32 rx_data_rate; + + /** Tx channel bandwidth */ + t_u32 tx_bw; + /** Tx guard interval */ + t_u32 tx_gi; + /** Rx channel bandwidth */ + t_u32 rx_bw; + /** Rx guard interval */ + t_u32 rx_gi; + /** MCS index */ + t_u32 tx_mcs_index; + t_u32 rx_mcs_index; + /** NSS */ + t_u32 tx_nss; + t_u32 rx_nss; + /* LG rate: 0, HT rate: 1, VHT rate: 2 */ + t_u32 tx_rate_format; + t_u32 rx_rate_format; +}; + +/** data structure for cmd bandcfg */ +struct eth_priv_bandcfg { + /** Infra band */ + t_u32 config_bands; + /** Ad-hoc start band */ + t_u32 adhoc_start_band; + /** Ad-hoc start channel */ + t_u32 adhoc_channel; + /** fw supported band */ + t_u32 fw_bands; +}; + +/** data structure for cmd txratecfg */ +struct eth_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; + /** Rate rate */ + t_u32 rate; + /** NSS */ + t_u32 nss; + /** Rate Setting */ + t_u16 rate_setting; +}; + +/** data structure for cmd getlog */ +struct eth_priv_get_log { + /** 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]; + /** beacon recv count */ + t_u32 bcn_rcv_cnt; + /** beacon miss count */ + t_u32 bcn_miss_cnt; + /** Tx frag count */ + t_u32 tx_frag_cnt; + /** Qos Tx frag count */ + t_u32 qos_tx_frag_cnt[8]; + /** Qos failed count */ + t_u32 qos_failed_cnt[8]; + /** Qos retry count */ + t_u32 qos_retry_cnt[8]; + /** Qos multi retry count */ + t_u32 qos_multi_retry_cnt[8]; + /** Qos frame dup count */ + t_u32 qos_frm_dup_cnt[8]; + /** Qos rts success count */ + t_u32 qos_rts_suc_cnt[8]; + /** Qos rts failure count */ + t_u32 qos_rts_failure_cnt[8]; + /** Qos ack failure count */ + t_u32 qos_ack_failure_cnt[8]; + /** Qos Rx frag count */ + t_u32 qos_rx_frag_cnt[8]; + /** Qos Tx frame count */ + t_u32 qos_tx_frm_cnt[8]; + /** Qos discarded frame count */ + t_u32 qos_discarded_frm_cnt[8]; + /** Qos mpdus Rx count */ + t_u32 qos_mpdus_rx_cnt[8]; + /** Qos retry rx count */ + t_u32 qos_retries_rx_cnt[8]; + /** CMACICV errors count */ + t_u32 cmacicv_errors; + /** CMAC replays count */ + t_u32 cmac_replays; + /** mgmt CCMP replays count */ + t_u32 mgmt_ccmp_replays; + /** TKIP ICV errors count */ + t_u32 tkipicv_errors; + /** TKIP replays count */ + t_u32 tkip_replays; + /** CCMP decrypt errors count */ + t_u32 ccmp_decrypt_errors; + /** CCMP replays count */ + t_u32 ccmp_replays; + /** Tx amsdu count */ + t_u32 tx_amsdu_cnt; + /** failed amsdu count */ + t_u32 failed_amsdu_cnt; + /** retry amsdu count */ + t_u32 retry_amsdu_cnt; + /** multi-retry amsdu count */ + t_u32 multi_retry_amsdu_cnt; + /** Tx octets in amsdu count */ + t_u64 tx_octets_in_amsdu_cnt; + /** amsdu ack failure count */ + t_u32 amsdu_ack_failure_cnt; + /** Rx amsdu count */ + t_u32 rx_amsdu_cnt; + /** Rx octets in amsdu count */ + t_u64 rx_octets_in_amsdu_cnt; + /** Tx ampdu count */ + t_u32 tx_ampdu_cnt; + /** tx mpdus in ampdu count */ + t_u32 tx_mpdus_in_ampdu_cnt; + /** tx octets in ampdu count */ + t_u64 tx_octets_in_ampdu_cnt; + /** ampdu Rx count */ + t_u32 ampdu_rx_cnt; + /** mpdu in Rx ampdu count */ + t_u32 mpdu_in_rx_ampdu_cnt; + /** Rx octets ampdu count */ + t_u64 rx_octets_in_ampdu_cnt; + /** ampdu delimiter CRC error count */ + t_u32 ampdu_delimiter_crc_error_cnt; +}; + +struct eth_priv_esuppmode_cfg { + /* RSN mode */ + t_u16 rsn_mode; + /* Pairwise cipher */ + t_u8 pairwise_cipher; + /* Group cipher */ + t_u8 group_cipher; +}; + +/** MLAN MAC Address Length */ +#define MLAN_MAC_ADDR_LENGTH 6 +#ifdef UAP_SUPPORT +/** Max clients supported by AP */ +#define MAX_AP_CLIENTS 64 +/** associated station info */ +struct ap_client_info { + /** STA MAC address */ + t_u8 mac_address[MLAN_MAC_ADDR_LENGTH]; + /** Power Mgmt status */ + t_u8 power_mgmt_status; + /** RSSI */ + t_s8 rssi; +}; + +/** Type definition of eth_priv_getstalist */ +struct eth_priv_getstalist { + /** station count */ + t_u16 sta_count; + /** station list */ + struct ap_client_info client_info[MAX_AP_CLIENTS]; +}; +#endif + +#define COUNTRY_CODE_LEN 3 +/** Type definition of eth_priv_countrycode for CMD_COUNTRYCODE */ +struct eth_priv_countrycode { + /** Country Code */ + t_u8 country_code[COUNTRY_CODE_LEN]; +}; + +/** Type definition of mlan_ds_hs_cfg for MLAN_OID_PM_CFG_HS_CFG */ +struct eth_priv_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; + /** Host sleep wake interval */ + t_u32 hs_wake_interval; + /** Parameter type*/ + t_u8 param_type_ind; + /** Indication GPIO pin number */ + t_u32 ind_gpio; + /** Level on ind_GPIO pin for normal wakeup source */ + t_u32 level; + /** Parameter type*/ + t_u8 param_type_ext; + /** Force ignore events*/ + t_u32 event_force_ignore; + /** Events use ext gap to wake up host*/ + t_u32 event_use_ext_gap; + /** Ext gap*/ + t_u8 ext_gap; + /** GPIO wave level*/ + t_u8 gpio_wave; +}; + +typedef struct _eth_priv_mgmt_frame_wakeup { + /** action - bitmap + ** On matching rx'd pkt and filter during NON_HOSTSLEEP mode: + ** Action[1]=0 Discard + ** Action[1]=1 Allow + ** Note that default action on non-match is "Allow". + ** + ** On matching rx'd pkt and filter during HOSTSLEEP mode: + ** Action[1:0]=00 Discard and Not Wake host + ** Action[1:0]=01 Discard and Wake host + ** Action[1:0]=10 Invalid + ** Note that default action on non-match is "Discard and Not Wake host". + **/ + t_u32 action; + /** Frame type(p2p, tdls...) + ** type=0: invalid + ** type=1: p2p + ** type=0xff: management frames(assoc res/rsp,probe req/rsp,...) + ** type=others: reserved + **/ + t_u32 type; + /** Frame mask according to each type + ** When type=1 for p2p, frame-mask have following define: + ** Bit Frame + ** 0 GO Negotiation Request + ** 1 GO Negotiation Response + ** 2 GO Negotiation Confirmation + ** 3 P2P Invitation Request + ** 4 P2P Invitation Response + ** 5 Device Discoverability Request + ** 6 Device Discoverability Response + ** 7 Provision Discovery Request + ** 8 Provision Discovery Response + ** 9 Notice of Absence + ** 10 P2P Presence Request + ** 11 P2P Presence Response + ** 12 GO Discoverability Request + ** 13-31 Reserved + ** + ** When type=others, frame-mask is reserved. + **/ + t_u32 frame_mask; +} eth_priv_mgmt_frame_wakeup; + +/** Type definition of eth_priv_scan_time_params */ +struct eth_priv_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; +}; + +/** Type definition of eth_priv_scan_cfg */ +struct eth_priv_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 */ + struct eth_priv_scan_time_params scan_time; + /** First passive scan then active scan */ + t_u8 passive_to_active_scan; + /** Extended Scan */ + t_u32 ext_scan; + /* Time gap between two scan channels in milliseconds */ + t_u32 scan_chan_gap; +}; + +enum _mlan_rate_format { + MLAN_RATE_FORMAT_LG = 0, + MLAN_RATE_FORMAT_HT, + MLAN_RATE_FORMAT_VHT, + MLAN_RATE_FORMAT_AUTO = 0xFF, +}; + +/** HT channel bandwidth */ +typedef enum _mlan_ht_bw { + MLAN_HT_BW20, + MLAN_HT_BW40, +/** VHT channel bandwidth */ + MLAN_VHT_BW80, + MLAN_VHT_BW160, +} mlan_ht_bw; +/** Type definition of mlan_power group info */ +struct eth_priv_power_group { + /** rate format (LG rate: 0; HT rate: 1; VHT rate: 2; no auto ctrl: 0xFF) */ + t_u32 rate_format; + /** bandwidth (LG: 20 MHz; HT: 20/40 MHz; VHT: 80/160/80+80 MHz) */ + t_u8 bandwidth; + /** NSS */ + t_u32 nss; + /** LG: first rate index; HT/VHT: first MCS */ + t_u8 first_rate_ind; + /** LG: last rate index; HT/VHT: last MCS */ + t_u8 last_rate_ind; + /** minmum tx power (dBm) */ + t_s8 power_min; + /** maximum tx power (dBm) */ + t_s8 power_max; + /** tx power step (dB) */ + t_s8 power_step; +}; + +/** max of power groups */ +#define MAX_POWER_GROUP 64 +/** Type definition of mlan_power_cfg_ext */ +struct eth_priv_power_cfg_ext { + /** number of power_groups */ + t_u32 num_pwr_grp; + /** array of power groups */ + struct eth_priv_power_group power_group[MAX_POWER_GROUP]; +}; + +/** Type definition of eth_priv_ds_ps_cfg */ +struct eth_priv_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; + /** 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; +}; + +#ifdef STA_SUPPORT + +/** Maximum length of SSID */ +#define MRVDRV_MAX_SSID_LENGTH 32 + +/** Maximum length of SSID list */ +#define MRVDRV_MAX_SSID_LIST_LENGTH 10 + +/** Maximum length of BSSID list */ +#define MAX_BSSID_FILTER_LIST 5 + +/** Bssid structure */ +typedef struct { + /* bssid */ + t_u8 bssid[ETH_ALEN]; +} __ATTRIB_PACK__ wlan_ioctl_user_scan_bssid; + +/** Maximum number of channels that can be sent in a setuserscan ioctl */ +#define WLAN_IOCTL_USER_SCAN_CHAN_MAX 50 + +/** Maximum channel scratch */ +#define MAX_CHAN_SCRATCH 100 + +/** Maximum channel number for b/g band */ +#define MAX_CHAN_BG_BAND 14 + +/** Maximum number of probes to send on each channel */ +#define MAX_PROBES 5 + +/** Scan all the channels in specified band */ +#define BAND_SPECIFIED 0x80 + +/** Maximum size of IEEE Information Elements */ +#define IEEE_MAX_IE_SIZE 256 + +/** Maximum number of TID */ +#define MAX_NUM_TID 8 + +/** Type enumeration of WMM AC_QUEUES */ +typedef enum _mlan_wmm_ac_e { + WMM_AC_BK, + WMM_AC_BE, + WMM_AC_VI, + WMM_AC_VO +} __ATTRIB_PACK__ mlan_wmm_ac_e; + +/** Enumeration for scan mode */ +enum { + 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_UNCHANGED = 0, + MLAN_SCAN_TYPE_ACTIVE, + MLAN_SCAN_TYPE_PASSIVE +}; + +/** Enumeration for passive to active scan */ +enum _mlan_pass_to_act_scan { + MLAN_PASS_TO_ACT_SCAN_UNCHANGED = 0, + MLAN_PASS_TO_ACT_SCAN_EN, + MLAN_PASS_TO_ACT_SCAN_DIS +}; + +/** IEEE Type definitions */ +typedef 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, + + COUNTRY_INFO = 7, + + 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, + + VHT_CAPABILITY = 191, + VHT_OPERATION = 192, + EXT_BSS_LOAD = 193, + BW_CHANNEL_SWITCH = 194, + VHT_TX_POWER_ENV = 195, + EXT_POWER_CONSTR = 196, + AID_INFO = 197, + QUIET_CHAN = 198, + OPER_MODE_NTF = 199, + + 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, +} __ATTRIB_PACK__ IEEEtypes_ElementId_e; + +/** Capability Bit Map*/ +#ifdef BIG_ENDIAN_SUPPORT +typedef 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; +} __ATTRIB_PACK__ IEEEtypes_CapInfo_t, *pIEEEtypes_CapInfo_t; +#else +typedef 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; +} __ATTRIB_PACK__ IEEEtypes_CapInfo_t, *pIEEEtypes_CapInfo_t; +#endif /* BIG_ENDIAN_SUPPORT */ + +/** IEEE IE header */ +typedef struct _IEEEtypes_Header_t { + /** Element ID */ + t_u8 element_id; + /** Length */ + t_u8 len; +} __ATTRIB_PACK__ IEEEtypes_Header_t, *pIEEEtypes_Header_t; + +/** IEEE IE header */ +#define IEEE_HEADER_LEN sizeof(IEEEtypes_Header_t) + +/** Vendor specific IE header */ +typedef 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; +} __ATTRIB_PACK__ IEEEtypes_VendorHeader_t, *pIEEEtypes_VendorHeader_t; + +/** Vendor specific IE */ +typedef 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)]; +} __ATTRIB_PACK__ IEEEtypes_VendorSpecific_t, *pIEEEtypes_VendorSpecific_t; + +/** IEEE IE */ +typedef 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)]; +} __ATTRIB_PACK__ IEEEtypes_Generic_t, *pIEEEtypes_Generic_t; + +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; + /** Channel Load (max = 100) */ + t_u8 chan_load; + /** TSF value from the firmware at packet reception */ + t_u64 network_tsf; +} wlan_get_scan_table_fixed; + +/** + * 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[1]; */ +} wlan_ioctl_get_scan_table_entry; + +/** + * Structure to store BSS info (probe resp or beacon) & IEEE IE info for each + * BSS returned in WLAN_GET_SCAN_RESP IOCTL + */ +typedef struct _wlan_ioctl_get_bss_info { + /** + * Length of the BSS Information (probe resp or beacon) that + * follows after the fixed_field + */ + t_u32 bss_info_length; + + /** + * Probe response or beacon scanned for the BSS. + * + * Field layout: + */ + /** TSF 8 octets */ + t_u8 tsf[8]; + /** Beacon Interval 2 octets */ + t_u16 beacon_interval; + /** Capability Info 2 octets */ + IEEEtypes_CapInfo_t cap_info; + + /** + * IEEE Infomation Elements; variable number & length per 802.11 spec + */ + /** SSID */ + char ssid[MRVDRV_MAX_SSID_LENGTH + 1]; + /** SSID Length */ + t_u32 ssid_len; + /** WMM Capability */ + char wmm_cap; + /** WPS Capability */ + char wps_cap; + /** Privacy Capability - WEP/WPA/RSN */ + char priv_cap; + /** HT (11N) Capability */ + char ht_cap; + /** VHT (11AC) Capability */ + char vht_cap[2]; + /* 802.11k Capability */ + char dot11k_cap; + /** 802.11r Capability */ + char dot11r_cap; +} wlan_ioctl_get_bss_info; + +/** + * Structure to save of scan table info for each BSS returned + * in WLAN_GET_SCAN_RESP IOCTL + */ +struct wlan_ioctl_get_scan_list { + /** fixed info */ + wlan_ioctl_get_scan_table_entry fixed_buf; + /** variable info - BSS info (probe resp or beacon) & IEEE IE info */ + wlan_ioctl_get_bss_info bss_info_buf; + /** pointer to next node in list */ + struct wlan_ioctl_get_scan_list *next; + /** pointer to previous node in list */ + struct wlan_ioctl_get_scan_list *prev; +}; + +/** + * 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; + +enum ieee80211_channel_flags { + IEEE80211_CHAN_DISABLED = 1 << 0, + IEEE80211_CHAN_NO_IR = 1 << 1, + /* hole at 1<<2 */ + IEEE80211_CHAN_RADAR = 1 << 3, + IEEE80211_CHAN_NO_HT40PLUS = 1 << 4, + IEEE80211_CHAN_NO_HT40MINUS = 1 << 5, + IEEE80211_CHAN_NO_OFDM = 1 << 6, + IEEE80211_CHAN_NO_80MHZ = 1 << 7, + IEEE80211_CHAN_NO_160MHZ = 1 << 8, + IEEE80211_CHAN_INDOOR_ONLY = 1 << 9, + IEEE80211_CHAN_IR_CONCURRENT = 1 << 10, + IEEE80211_CHAN_NO_20MHZ = 1 << 11, + IEEE80211_CHAN_NO_10MHZ = 1 << 12, +}; + +typedef struct { + /** center freq */ + t_u16 center_freq; + /** chan num */ + t_u16 hw_value; + /** chan flags */ + t_u32 flags; + /** max power */ + int max_power; + /** dfs state */ + t_u8 dfs_state; +} __ATTRIB_PACK__ wlan_ieee80211_chan; + +typedef struct { + /** num of chan */ + t_u8 num_chan; + /** chan_list */ + wlan_ieee80211_chan chan_list[]; +} __ATTRIB_PACK__ wlan_ieee80211_chan_list; + +typedef struct { + t_u8 chan_number; + /**< Channel Number to scan */ + t_u8 radio_type; + /**< Radio type: 'B/G' Band = 0, 'A' Band = 1 */ + t_u8 scan_type;/**< Scan type: Active = 1, Passive = 2 */ + t_u8 reserved;/**< Reserved */ + t_u32 scan_time; + /**< Scan duration in milliseconds; if 0 default used */ +} __ATTRIB_PACK__ wlan_ioctl_user_scan_chan; + +typedef struct { + char ssid[MRVDRV_MAX_SSID_LENGTH + 1]; + /**< SSID */ + t_u8 max_len; /**< Maximum length of SSID */ +} __ATTRIB_PACK__ wlan_ioctl_user_scan_ssid; + +typedef struct { + + /** Flag set to keep the previous scan table intact */ + t_u8 keep_previous_scan; /* Do not erase the existing scan results */ + + /** BSS mode to be sent in the firmware command */ + t_u8 bss_mode; + + /** Configure the number of probe requests for active chan scans */ + t_u8 num_probes; + + /** Reserved */ + t_u8 reserved; + + /** BSSID filter sent in the firmware command to limit the results */ + t_u8 specific_bssid[ETH_ALEN]; + + /** SSID filter list used in the to limit the scan results */ + wlan_ioctl_user_scan_ssid ssid_list[MRVDRV_MAX_SSID_LIST_LENGTH]; + + /** Variable number (fixed maximum) of channels to scan up */ + wlan_ioctl_user_scan_chan chan_list[WLAN_IOCTL_USER_SCAN_CHAN_MAX]; + + /** Gap between two scans */ + t_u16 scan_chan_gap; + /** scan type: 0 legacy, 1: enhance scan*/ + t_u8 ext_scan_type; + /** flag to filer only probe response */ + t_u8 proberesp_only; + t_u8 random_mac[MLAN_MAC_ADDR_LENGTH]; + /** Number of BSSIDs in bssid_list*/ + t_u8 bssid_num; + /** List of BSSIDs to be filterd*/ + wlan_ioctl_user_scan_bssid bssid_list[MAX_BSSID_FILTER_LIST]; +} __ATTRIB_PACK__ wlan_ioctl_user_scan_cfg; + +/** Max Ie length */ +#define MAX_IE_SIZE 256 + +/** custom IE */ +typedef 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[]; +} __ATTRIB_PACK__ custom_ie; + +/** Convert character to integer */ +#define CHAR2INT(x) (((x) >= 'A') ? ((x) - 'A' + 10) : ((x) - '0')) + +/** + * Hex or Decimal to Integer + * @param num string to convert into decimal or hex + */ +#define A2HEXDECIMAL(num) \ + (strncasecmp("0x", (num), 2) ? (unsigned int) strtoll((num), NULL, 0) : a2hex((num))) + +/** Convert TLV header from little endian format to CPU format */ +#define endian_convert_tlv_header_in(x) \ + { \ + (x)->tag = le16_to_cpu((x)->tag); \ + (x)->length = le16_to_cpu((x)->length); \ + } + +/** Convert TLV header to little endian format from CPU format */ +#define endian_convert_tlv_header_out(x) \ + { \ + (x)->tag = cpu_to_le16((x)->tag); \ + (x)->length = cpu_to_le16((x)->length); \ + } +/** Max IE index to FW */ +#define MAX_MGMT_IE_INDEX_TO_FW 4 +/** Max IE index per BSS */ +#define MAX_MGMT_IE_INDEX 16 + +/** Private command ID to pass custom IE list */ +#define CUSTOM_IE_CFG (SIOCDEVPRIVATE + 13) +/* TLV Definitions */ + +/** Maximum IE buffer length */ +#define MAX_IE_BUFFER_LEN 256 + +/** TLV: Management IE list */ +#define MRVL_MGMT_IE_LIST_TLV_ID (PROPRIETARY_TLV_BASE_ID + 0x69) /* 0x0169 */ + +/** TLV: Max Management IE */ +#define MRVL_MAX_MGMT_IE_TLV_ID (PROPRIETARY_TLV_BASE_ID + 0xaa) /* 0x01aa */ + +/** custom IE info */ +typedef struct _custom_ie_info { + /** size of buffer */ + t_u16 buf_size; + /** no of buffers of buf_size */ + t_u16 buf_count; +} __ATTRIB_PACK__ custom_ie_info; + +/** TLV buffer : Max Mgmt IE */ +typedef 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[]; +} __ATTRIB_PACK__ tlvbuf_max_mgmt_ie; + +/** TLV buffer : custom IE */ +typedef struct _eth_priv_ds_misc_custom_ie { + /** Type */ + t_u16 type; + /** Length */ + t_u16 len; + /** IE data */ + custom_ie ie_data[]; +} __ATTRIB_PACK__ eth_priv_ds_misc_custom_ie; + +/*-----------------------------------------------------------------*/ +/** 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 = 5, +}; + +/** Type definition of mlan_ds_reg_rw for MLAN_OID_REG_RW */ +struct eth_priv_ds_reg_rw { + /** Register type */ + t_u32 type; + /** Offset */ + t_u32 offset; + /** Value */ + t_u32 value; +}; + +/** Maximum EEPROM data */ +#define MAX_EEPROM_DATA 256 + +/** Type definition of mlan_ds_read_eeprom for MLAN_OID_EEPROM_RD */ +struct eth_priv_ds_read_eeprom { + /** Multiples of 4 */ + t_u16 offset; + /** Number of bytes */ + t_u16 byte_count; + /** Value */ + t_u8 value[MAX_EEPROM_DATA]; +}; + +/** Type definition of mlan_ds_mem_rw for MLAN_OID_MEM_RW */ +struct eth_priv_ds_mem_rw { + /** Address */ + t_u32 addr; + /** Value */ + t_u32 value; +}; + +/** Type definition of mlan_ds_reg_mem for MLAN_IOCTL_REG_MEM */ +struct eth_priv_ds_reg_mem { + /** Sub-command */ + t_u32 sub_command; + /** Register memory access parameter */ + union { + /** Register access for MLAN_OID_REG_RW */ + struct eth_priv_ds_reg_rw reg_rw; + /** EEPROM access for MLAN_OID_EEPROM_RD */ + struct eth_priv_ds_read_eeprom rd_eeprom; + /** Memory access for MLAN_OID_MEM_RW */ + struct eth_priv_ds_mem_rw mem_rw; + } param; +}; + +/** Data structure of WMM QoS information */ +typedef 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 */ +} __ATTRIB_PACK__ IEEEtypes_WmmQosInfo_t; + +/** Max channel value for BG band */ +#define MAX_BG_CHANNEL 14 + +/** 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 + +/** Maximum number of User Priorities */ +#define MAX_USER_PRIORITIES 8 + +/** Extra IE bytes allocated in messages for appended IEs after a TSPEC */ +#define WMM_ADDTS_EXTRA_IE_BYTES 256 + +/** + * @brief Enumeration for the command result from an ADDTS or DELTS command + */ +typedef enum { + TSPEC_RESULT_SUCCESS = 0, + TSPEC_RESULT_EXEC_FAILURE = 1, + TSPEC_RESULT_TIMEOUT = 2, + TSPEC_RESULT_DATA_INVALID = 3, +} __ATTRIB_PACK__ mlan_wmm_tspec_result_e; + +/** + * @brief Enumeration for the action field in the Queue configure command + */ +typedef enum { + WMM_QUEUE_CONFIG_ACTION_GET = 0, + WMM_QUEUE_CONFIG_ACTION_SET = 1, + WMM_QUEUE_CONFIG_ACTION_DEFAULT = 2, + + WMM_QUEUE_CONFIG_ACTION_MAX +} __ATTRIB_PACK__ mlan_wmm_queue_config_action_e; + +/** + * @brief Enumeration for the action field in the queue stats command + */ +typedef enum { + WMM_STATS_ACTION_START = 0, + WMM_STATS_ACTION_STOP = 1, + WMM_STATS_ACTION_GET_CLR = 2, + WMM_STATS_ACTION_SET_CFG = 3, /* Not currently used */ + WMM_STATS_ACTION_GET_CFG = 4, /* Not currently used */ + + WMM_STATS_ACTION_MAX +} __ATTRIB_PACK__ mlan_wmm_stats_action_e; + +/** Data structure of WMM Aci/Aifsn */ +typedef 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 +} __ATTRIB_PACK__ IEEEtypes_WmmAciAifsn_t, *pIEEEtypes_WmmAciAifsn_t; + +/** Data structure of WMM ECW */ +typedef 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 +} __ATTRIB_PACK__ IEEEtypes_WmmEcw_t, *pIEEEtypes_WmmEcw_t; + +/** Data structure of WMM AC parameters */ +typedef struct _IEEEtypes_WmmAcParameters_t { + IEEEtypes_WmmAciAifsn_t aci_aifsn; /**< AciAifSn */ + IEEEtypes_WmmEcw_t ecw; /**< Ecw */ + t_u16 tx_op_limit; /**< Tx op limit */ +} __ATTRIB_PACK__ IEEEtypes_WmmAcParameters_t, *pIEEEtypes_WmmAcParameters_t; + +/** Data structure of WMM Info IE */ +typedef 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; + +} __ATTRIB_PACK__ IEEEtypes_WmmInfo_t, *pIEEEtypes_WmmInfo_t; + +/** Data structure of WMM parameter IE */ +typedef 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]; + +} __ATTRIB_PACK__ IEEEtypes_WmmParameter_t, *pIEEEtypes_WmmParameter_t; + +/** + * @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 wlan_wmm_addts_req_ioctl + */ +typedef struct { + mlan_wmm_tspec_result_e commandResult; + /**< Firmware execution result */ + + t_u32 timeout_ms; /**< Timeout value in milliseconds */ + t_u8 ieeeStatusCode; /**< IEEE status code */ + + t_u32 ieDataLen; + t_u8 ieData[WMM_TSPEC_SIZE + /**< TSPEC to send in the ADDTS */ + + WMM_ADDTS_EXTRA_IE_BYTES]; + /**< ADDTS 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 wlan_wmm_delts_req_ioctl + */ +typedef struct { + mlan_wmm_tspec_result_e commandResult; + /**< Firmware execution result */ + t_u8 ieeeReasonCode; /**< IEEE reason code sent, unused for WMM */ + + t_u32 ieDataLen; + t_u8 ieData[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. + * + * - msduLifetimeExpiry is ignored if set to 0 on a set command + * + * @sa wlan_wmm_queue_config_ioctl + */ +typedef struct { + mlan_wmm_queue_config_action_e action; + /**< Set, Get, or Default */ + mlan_wmm_ac_e accessCategory; /**< WMM_AC_BK(0) to WMM_AC_VO(3) */ + t_u16 msduLifetimeExpiry; /**< lifetime expiry in TUs */ + t_u8 supportedRates[10]; /**< Not supported yet */ +} wlan_ioctl_wmm_queue_config_t; + +/** Number of bins in the histogram for the HostCmd_DS_WMM_QUEUE_STATS */ +#define WMM_STATS_PKTS_HIST_BINS 7 + +/** + * @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 wlan_wmm_queue_stats_ioctl + */ +typedef struct { + mlan_wmm_stats_action_e action; + /**< Start, Stop, or Get */ + t_u8 userPriority; + /**< User Priority (0 to 7) */ + t_u16 pktCount; /**< Number of successful packets transmitted */ + t_u16 pktLoss; /**< Packets lost; not included in pktCount */ + t_u32 avgQueueDelay; + /**< Average Queue delay in microseconds */ + t_u32 avgTxDelay;/**< Average Transmission delay in microseconds */ + t_u16 usedTime; /**< Calculated used time - units of 32 microsec */ + t_u16 policedTime; + /**< Calculated 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 delayHistogram[WMM_STATS_PKTS_HIST_BINS]; +} wlan_ioctl_wmm_queue_stats_t; + +/** + * @brief IOCTL and command sub structure for a Traffic stream status. + */ +typedef struct { + t_u8 tid; /**< TSID: Range: 0->7 */ + t_u8 valid; /**< TSID specified is valid */ + t_u8 accessCategory;/**< AC TSID is active on */ + t_u8 userPriority; /**< UP specified for the TSID */ + + t_u8 psb; /**< Power save mode for TSID: 0 (legacy), 1 (UAPSD) */ + t_u8 flowDir; /**< Upstream (0), Downlink(1), Bidirectional(3) */ + t_u16 mediumTime; /**< Medium time granted for the TSID */ +} __ATTRIB_PACK__ HostCmd_DS_WMM_TS_STATUS, + wlan_ioctl_wmm_ts_status_t, wlan_cmd_wmm_ts_status_t; + +/** + * @brief IOCTL sub structure for a specific WMM AC Status + */ +typedef struct { + /** WMM Acm */ + t_u8 wmmAcm; + /** Flow required flag */ + t_u8 flowRequired; + /** Flow created flag */ + t_u8 flowCreated; + /** Disabled flag */ + t_u8 disabled; + /** delivery enabled */ + t_u8 deliveryEnabled; + /** trigger enabled */ + t_u8 triggerEnabled; +} 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 wlan_wmm_queue_status_ioctl + */ +typedef struct { + /** WMM AC queue status */ + wlan_ioctl_wmm_queue_status_ac_t acStatus[MAX_AC_QUEUES]; +} wlan_ioctl_wmm_queue_status_t; +#endif /* STA_SUPPORT */ + +/** 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 : Clear */ +#define HostCmd_ACT_GEN_CLEAR 0x0004 +/** General purpose action : Remove */ +#define HostCmd_ACT_GEN_REMOVE 0x0004 + +/** TLV type ID definition */ +#define PROPRIETARY_TLV_BASE_ID 0x0100 + +/** MrvlIEtypesHeader_t */ +typedef struct MrvlIEtypesHeader { + /** Header type */ + t_u16 type; + /** Header length */ + t_u16 len; +} __ATTRIB_PACK__ MrvlIEtypesHeader_t; + +/** MrvlIEtypes_Data_t */ +typedef struct MrvlIEtypes_Data_t { + /** Header */ + MrvlIEtypesHeader_t header; + /** Data */ + t_u8 data[1]; +} __ATTRIB_PACK__ MrvlIEtypes_Data_t; + +/** HostCmd_DS_802_11_SUBSCRIBE_EVENT */ +typedef struct MAPP_HostCmd_DS_802_11_SUBSCRIBE_EVENT { + /** Action */ + t_u16 action; + /** Events */ + t_u16 events; +} __ATTRIB_PACK__ HostCmd_DS_802_11_SUBSCRIBE_EVENT; + +/** MrvlIEtypes_RssiParamSet_t */ +typedef struct MrvlIEtypes_RssiThreshold { + /** Header */ + MrvlIEtypesHeader_t header; + /** RSSI value */ + t_u8 RSSI_value; + /** RSSI frequency */ + t_u8 RSSI_freq; +} __ATTRIB_PACK__ MrvlIEtypes_RssiThreshold_t; + +/** MrvlIEtypes_SnrThreshold_t */ +typedef struct MrvlIEtypes_SnrThreshold { + /** Header */ + MrvlIEtypesHeader_t header; + /** SNR value */ + t_u8 SNR_value; + /** SNR frequency */ + t_u8 SNR_freq; +} __ATTRIB_PACK__ MrvlIEtypes_SnrThreshold_t; + +/** MrvlIEtypes_FailureCount_t */ +typedef struct MrvlIEtypes_FailureCount { + /** Header */ + MrvlIEtypesHeader_t header; + /** Failure value */ + t_u8 fail_value; + /** Failure frequency */ + t_u8 fail_freq; +} __ATTRIB_PACK__ MrvlIEtypes_FailureCount_t; + +/** MrvlIEtypes_BeaconsMissed_t */ +typedef struct MrvlIEtypes_BeaconsMissed { + /** Header */ + MrvlIEtypesHeader_t header; + /** Number of beacons missed */ + t_u8 beacon_missed; + /** Reserved */ + t_u8 reserved; +} __ATTRIB_PACK__ MrvlIEtypes_BeaconsMissed_t; + +/** MrvlIEtypes_LinkQuality_t */ +typedef struct MrvlIEtypes_LinkQuality { + /** Header */ + MrvlIEtypesHeader_t header; + /** Link SNR threshold */ + t_u16 link_SNR_thrs; + /** Link SNR frequency */ + t_u16 link_SNR_freq; + /** Minimum rate value */ + t_u16 min_rate_val; + /** Minimum rate frequency */ + t_u16 min_rate_freq; + /** Tx latency value */ + t_u32 tx_latency_val; + /** Tx latency threshold */ + t_u32 tx_latency_thrs; +} __ATTRIB_PACK__ MrvlIEtypes_LinkQuality_t; + +/** Host Command ID : 802.11 subscribe event */ +#define HostCmd_CMD_802_11_SUBSCRIBE_EVENT 0x0075 + +/** 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 : 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 :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 */ + +/** MrvlIEtypes_PreBeaconLost_t */ +typedef struct MrvlIEtypes_PreBeaconLost { + /** Header */ + MrvlIEtypesHeader_t header; + /** Pre-Beacon Lost */ + t_u8 pre_beacon_lost; + /** Reserved */ + t_u8 reserved; +} __ATTRIB_PACK__ MrvlIEtypes_PreBeaconLost_t; + +/** TLV type: Pre-Beacon Lost */ +#define TLV_TYPE_PRE_BEACON_LOST (PROPRIETARY_TLV_BASE_ID + 0x49) /* 0x0149 */ + +/** TLV type : Extended capabilities */ +#define TLV_TYPE_EXTCAP 0x007f + +/** AutoTx_MacFrame_t */ +typedef struct AutoTx_MacFrame { + t_u16 interval; /**< in seconds */ + t_u8 priority; /**< User Priority: 0~7, ignored if non-WMM */ + t_u8 reserved; /**< set to 0 */ + t_u16 frame_len; /**< Length of MAC frame payload */ + t_u8 dest_mac_addr[MLAN_MAC_ADDR_LENGTH]; /**< Destination MAC address */ + t_u8 src_mac_addr[MLAN_MAC_ADDR_LENGTH]; /**< Source MAC address */ + t_u8 payload[]; /**< Payload */ +} __ATTRIB_PACK__ AutoTx_MacFrame_t; + +/** MrvlIEtypes_AutoTx_t */ +typedef struct MrvlIEtypes_AutoTx { + MrvlIEtypesHeader_t header; /**< Header */ + AutoTx_MacFrame_t auto_tx_mac_frame; /**< Auto Tx MAC frame */ +} __ATTRIB_PACK__ MrvlIEtypes_AutoTx_t; + +/** HostCmd_DS_802_11_AUTO_TX */ +typedef struct MAPP_HostCmd_DS_802_11_AUTO_TX { + /** Action */ + t_u16 action; /* 0 = ACT_GET; 1 = ACT_SET; */ + MrvlIEtypes_AutoTx_t auto_tx; /**< Auto Tx */ +} __ATTRIB_PACK__ HostCmd_DS_802_11_AUTO_TX; + +/** Host Command ID : 802.11 auto Tx */ +#define HostCmd_CMD_802_11_AUTO_TX 0x0082 + +/** TLV type : Auto Tx */ +#define TLV_TYPE_AUTO_TX (PROPRIETARY_TLV_BASE_ID + 0x18) /* 0x0118 */ + +/** HostCmd_DS_802_11_CFG_DATA */ +typedef struct MAPP_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; + +/** Host Command ID : Configuration data */ +#define HostCmd_CMD_CFG_DATA 0x008f + +/** mlan_ioctl_11h_tpc_resp */ +typedef struct { + int status_code; + /**< Firmware command result status code */ + int tx_power;/**< Reported TX Power from the TPC Report */ + int link_margin; + /**< Reported Link margin from the TPC Report */ + int rssi; /**< RSSI of the received TPC Report frame */ +} __ATTRIB_PACK__ mlan_ioctl_11h_tpc_resp; + +/** Host Command ID : 802.11 TPC adapt req */ +#define HostCmd_CMD_802_11_TPC_ADAPT_REQ 0x0060 + +/** HostCmd_DS_802_11_CRYPTO */ +typedef struct MAPP_HostCmd_DS_802_11_CRYPTO { + t_u16 encdec; /**< Decrypt=0, Encrypt=1 */ + t_u16 algorithm; /**< RC4=1 AES=2 , AES_KEY_WRAP=3 */ + t_u16 key_IV_length;/**< Length of Key IV (bytes) */ + t_u8 keyIV[32]; /**< Key IV */ + t_u16 key_length; /**< Length of Key (bytes) */ + t_u8 key[32]; /**< Key */ + MrvlIEtypes_Data_t data; + /**< Plain text if encdec=Encrypt, Ciphertext data if encdec=Decrypt*/ +} __ATTRIB_PACK__ HostCmd_DS_802_11_CRYPTO; + +/** HostCmd_DS_802_11_CRYPTO_AES_CCM */ +typedef struct MAPP_HostCmd_DS_802_11_CRYPTO_AES_CCM { + t_u16 encdec; /**< Decrypt=0, Encrypt=1 */ + t_u16 algorithm; /**< AES_CCM=4 */ + t_u16 key_length; /**< Length of Key (bytes) */ + t_u8 key[32]; /**< Key */ + t_u16 nonce_length;/**< Length of Nonce (bytes) */ + t_u8 nonce[14]; /**< Nonce */ + t_u16 AAD_length; /**< Length of AAD (bytes) */ + t_u8 AAD[32]; /**< AAD */ + MrvlIEtypes_Data_t data; + /**< Plain text if encdec=Encrypt, Ciphertext data if encdec=Decrypt*/ +} __ATTRIB_PACK__ HostCmd_DS_802_11_CRYPTO_AES_CCM; + +/** HostCmd_DS_802_11_CRYPTO_WAPI */ +typedef struct MAPP_HostCmd_DS_802_11_CRYPTO_WAPI { + t_u16 encdec; /**< Decrypt=0, Encrypt=1 */ + t_u16 algorithm; /**< WAPI =5 */ + t_u16 key_length; /**< Length of Key (bytes) */ + t_u8 key[32]; /**< Key */ + t_u16 nonce_length;/**< Length of Nonce (bytes) */ + t_u8 nonce[16]; /**< Nonce */ + t_u16 AAD_length; /**< Length of AAD (bytes) */ + t_u8 AAD[48]; /**< AAD */ + t_u16 data_length; /**< Length of data (bytes) */ +} __ATTRIB_PACK__ HostCmd_DS_802_11_CRYPTO_WAPI; +/** WAPI cipher test */ +#define CIPHER_TEST_WAPI (5) +/** AES CCM cipher test */ +#define CIPHER_TEST_AES_CCM (4) +/** GCMP cipher test */ +#define CIPHER_TEST_GCMP (6) +/** Host Command ID : 802.11 crypto */ +#define HostCmd_CMD_802_11_CRYPTO 0x0078 +/** Get the current TSF */ +#define HostCmd_CMD_GET_TSF 0x0080 + +/** Read/Write Mac register */ +#define HostCmd_CMD_MAC_REG_ACCESS 0x0019 +/** Read/Write BBP register */ +#define HostCmd_CMD_BBP_REG_ACCESS 0x001a +/** Read/Write RF register */ +#define HostCmd_CMD_RF_REG_ACCESS 0x001b + +/** Host Command ID : CAU register access */ +#define HostCmd_CMD_CAU_REG_ACCESS 0x00ed + +/** Host Command ID : Memory access */ +#define HostCmd_CMD_MEM_ACCESS 0x0086 + +/** channel band */ +enum { + BAND_2GHZ = 0, + BAND_5GHZ = 1, + BAND_4GHZ = 2, +}; + +/** channel offset */ +enum { + SEC_CHAN_NONE = 0, + SEC_CHAN_ABOVE = 1, + SEC_CHAN_5MHZ = 2, + SEC_CHAN_BELOW = 3 +}; + +/** channel bandwidth */ +enum { + CHAN_BW_20MHZ = 0, + CHAN_BW_10MHZ, + CHAN_BW_40MHZ, + CHAN_BW_80MHZ, +}; + +/** scan mode */ +enum { + SCAN_MODE_MANUAL = 0, + SCAN_MODE_ACS, + SCAN_MODE_USER, +}; + +/** Band_Config_t */ +typedef struct _Band_Config_t { +#ifdef BIG_ENDIAN_SUPPORT + /** Channel Selection Mode - (00)=manual, (01)=ACS, (02)=user*/ + t_u8 scanMode:2; + /** Secondary Channel Offset - (00)=None, (01)=Above, (11)=Below */ + t_u8 chan2Offset:2; + /** Channel Width - (00)=20MHz, (10)=40MHz, (11)=80MHz */ + t_u8 chanWidth:2; + /** Band Info - (00)=2.4GHz, (01)=5GHz */ + t_u8 chanBand:2; +#else + /** Band Info - (00)=2.4GHz, (01)=5GHz */ + t_u8 chanBand:2; + /** Channel Width - (00)=20MHz, (10)=40MHz, (11)=80MHz */ + t_u8 chanWidth:2; + /** Secondary Channel Offset - (00)=None, (01)=Above, (11)=Below */ + t_u8 chan2Offset:2; + /** Channel Selection Mode - (00)=manual, (01)=ACS, (02)=Adoption mode*/ + t_u8 scanMode:2; +#endif +} __ATTRIB_PACK__ Band_Config_t; + +/** Failure */ +#define MLAN_EVENT_FAILURE -1 + +/** Netlink protocol number */ +#define NETLINK_NXP (MAX_LINKS - 1) +/** Netlink maximum payload size */ +#define NL_MAX_PAYLOAD 1024 +/** Netlink multicast group number */ +#define NL_MULTICAST_GROUP 1 +/** Default wait time in seconds for events */ +#define UAP_RECV_WAIT_DEFAULT 10 +/** Maximum number of devices */ +#define MAX_NO_OF_DEVICES 4 + +/* Event buffer */ +typedef struct _evt_buf { + /** Flag to check if event data is present in the buffer or not */ + int flag; + /** Event length */ + int length; + /** Event data */ + t_u8 buffer[NL_MAX_PAYLOAD]; +} __ATTRIB_PACK__ evt_buf; + +/** Event header */ +typedef struct _event_header { + /** Event ID */ + t_u32 event_id; + /** Event data */ + t_u8 event_data[]; +} __ATTRIB_PACK__ event_header; + +/** Event ID length */ +#define EVENT_ID_LEN 4 + +/** Event definition: Radar Detected by card */ +#define EVENT_CHANNEL_REPORT_RDY 0x00000054 + +/** Host Command ID : Channel report request */ +#define HostCmd_CMD_CHAN_REPORT_REQUEST 0x00dd +/** TLV type : Chan Load */ +#define TLV_TYPE_CHANRPT_CHAN_LOAD (PROPRIETARY_TLV_BASE_ID + 0x59) /* 0x0159 */ +/** TLV type : Noise Historgram */ +#define TLV_TYPE_CHANRPT_NOISE_HIST (PROPRIETARY_TLV_BASE_ID + 0x5a) /* 0x015a */ + +typedef struct { + t_u16 startFreq; + t_u8 chanWidth; + t_u8 chanNum; + +} __ATTRIB_PACK__ MrvlChannelDesc_t; + +typedef struct { + MrvlChannelDesc_t chanDesc; + /**< Channel band, number */ + t_u32 millisecDwellTime; /**< Channel dwell time in milliseconds */ +} __ATTRIB_PACK__ HostCmd_DS_CHAN_RPT_REQ; + +typedef struct { + + t_u32 commandResult; + /**< Rpt request command result (0 == SUCCESS) */ + t_u64 startTsf; /**< TSF Measurement started */ + t_u32 duration; /**< Duration of measurement in microsecs */ + + t_u8 tlvBuffer[1]; + /**< TLV Buffer */ +} __ATTRIB_PACK__ HostCmd_DS_CHAN_RPT_RSP; + +typedef struct { + MrvlIEtypesHeader_t Header; /**< Header */ + + t_u8 ccaBusyFraction; /**< Parts per 255 channel was busy */ +} __ATTRIB_PACK__ MrvlIEtypes_ChanRptChanLoad_t; + +typedef struct { + MrvlIEtypesHeader_t header; /**< Header */ + + t_s16 anpi; /**< ANPI calculated from the histogram */ + /** RPI histogram bins. The number of bins utilized is variable and must + be calculated by the header length */ + t_u8 rpiDensities[11]; +} __ATTRIB_PACK__ MrvlIEtypes_ChanRptNoiseHist_t; + +/** Maximum length of lines in configuration file */ +#define MAX_CONFIG_LINE 1024 +/** MAC BROADCAST */ +#define MAC_BROADCAST 0x1FF +/** MAC MULTICAST */ +#define MAC_MULTICAST 0x1FE + +/** HostCmd_DS_REG */ +typedef struct MAPP_HostCmd_DS_REG { + /** Read or write */ + t_u16 action; + /** Register offset */ + t_u16 offset; + /** Value */ + t_u32 value; +} __ATTRIB_PACK__ HostCmd_DS_REG; + +/** HostCmd_DS_MEM */ +typedef struct MAPP_HostCmd_DS_MEM { + /** Read or write */ + t_u16 action; + /** Reserved */ + t_u16 reserved; + /** Address */ + t_u32 addr; + /** Value */ + t_u32 value; +} __ATTRIB_PACK__ HostCmd_DS_MEM; + +typedef struct _HostCmd_DS_MEF_CFG { + /** Criteria */ + t_u32 Criteria; + /** Number of entries */ + t_u16 NumEntries; +} __ATTRIB_PACK__ HostCmd_DS_MEF_CFG; + +typedef struct _MEF_CFG_DATA { + /** Size */ + t_u16 size; + /** Data */ + HostCmd_DS_MEF_CFG data; +} __ATTRIB_PACK__ MEF_CFG_DATA; + +/** HostCmd_DS_GEN */ +typedef struct MAPP_HostCmd_DS_GEN { + /** Command */ + t_u16 command; + /** Size */ + t_u16 size; + /** Sequence number */ + t_u16 seq_num; + /** Result */ + t_u16 result; +} __ATTRIB_PACK__ HostCmd_DS_GEN; + +/** Size of HostCmd_DS_GEN */ +#define S_DS_GEN sizeof(HostCmd_DS_GEN) + +/** Type definition of aggr_ctrl */ +typedef struct _aggr_ctrl { + /** Enable */ + t_u16 enable; + /** Aggregation alignment */ + t_u16 aggr_align; + /** Aggregation max packet/size */ + t_u16 aggr_max_size; + /** Aggregation max packet number */ + t_u16 aggr_max_num; + /** Aggrgation timeout, in microseconds */ + t_u16 aggr_tmo; +} aggr_ctrl; + +/** Type definition of mlan_ds_misc_aggr_ctrl for MLAN_OID_MISC_AGGR_CTRL */ +typedef struct _aggr_ctrl_params { + /** Tx aggregation control */ + aggr_ctrl tx; +} aggr_ctrl_params; + +typedef struct _usb_aggr_ctrl { + /** Enable */ + t_u16 enable; + /** Aggregation mode */ + t_u16 aggr_mode; + /** Aggregation alignment */ + t_u16 aggr_align; + /** Aggregation max packet/size */ + t_u16 aggr_max; + /** Aggrgation timeout, in microseconds */ + t_u16 aggr_tmo; +} usb_aggr_ctrl; + +/** Type definition of mlan_ds_misc_usb_aggr_ctrl for MLAN_OID_MISC_USB_AGGR_CTRL */ +typedef struct _aggr_params { + /** Tx aggregation control */ + usb_aggr_ctrl tx_aggr_ctrl; + /** Rx deaggregation control */ + usb_aggr_ctrl rx_deaggr_ctrl; +} aggr_params; + +/** pkt_header */ +typedef struct _pkt_header { + /** pkt_len */ + t_u32 pkt_len; + /** pkt_type */ + t_u32 TxPktType; + /** tx control */ + t_u32 TxControl; +} pkt_header; + +/** eth_priv_802_11_header packet from FW with length */ +typedef struct _eth_priv_mgmt_frame_tx { + /** Packet Length */ + t_u16 frm_len; + /** Frame Control */ + t_u16 frm_ctl; + /** Duration ID */ + t_u16 duration_id; + /** Address1 */ + t_u8 addr1[ETH_ALEN]; + /** Address2 */ + t_u8 addr2[ETH_ALEN]; + /** Address3 */ + t_u8 addr3[ETH_ALEN]; + /** Sequence Control */ + t_u16 seq_ctl; + /** Address4 */ + t_u8 addr4[ETH_ALEN]; + /** Frame payload */ + t_u8 payload[]; +} __ATTRIB_PACK__ eth_priv_mgmt_frame_tx; + +/** frame tx ioctl number */ +#define FRAME_TX_IOCTL (SIOCDEVPRIVATE + 12) + +typedef struct { + t_u32 timeSinceLastQuery_ms; /**< Duration of stats collection */ + + t_u16 bcnCnt; /**< Number of beacons received */ + t_u16 bcnMiss; /**< Estimate of beacons missed */ + t_s16 bcnRssiAvg; /**< Avg beacon RSSI */ + t_s16 bcnSnrAvg; /**< Avg beacon SNR */ + + t_u32 rxPkts; /**< Number of packets received */ + t_s16 rxRssiAvg; /**< Avg received packet RSSI */ + t_s16 rxSnrAvg; /**< Avg received packet SNR */ + + t_u32 txPkts; /**< Number of packets transmitted */ + t_u32 txAttempts; /**< Number of attempts made */ + t_u32 txFailures; /**< Number of pkts that failed */ + t_u8 txInitRate; /**< Current rate adaptation TX rateid */ + t_u8 reserved[3]; /**< Reserved */ + + t_u16 txQueuePktCnt[MAX_AC_QUEUES]; + /**< Number of packets per AC */ + t_u32 txQueueDelay[MAX_AC_QUEUES]; + /**< Averge queue delay per AC*/ +} __ATTRIB_PACK__ HostCmd_DS_LINK_STATS_SUMMARY; + +#define HostCmd_CMD_LINK_STATS_SUMMARY 0x00d3 + +/** Type enumeration of WMM AC_QUEUES */ +typedef enum _wmm_ac { + AC_BE, + AC_BK, + AC_VI, + AC_VO, +} wmm_ac; + +/** Data structure of Host command WMM_PARAM_CFG */ +typedef struct _HostCmd_DS_WMM_PARAM_CONFIG { + /** action */ + t_u16 action; + /** AC Parameters Record WMM_AC_BE, WMM_AC_BK, WMM_AC_VI, WMM_AC_VO */ + IEEEtypes_WmmAcParameters_t ac_params[MAX_AC_QUEUES]; +} __ATTRIB_PACK__ HostCmd_DS_WMM_PARAM_CONFIG; + +/** Host Command ID : Configure ADHOC_OVER_IP parameters */ +#define HostCmd_CMD_WMM_PARAM_CONFIG 0x023a + +#ifdef WIFI_DIRECT_SUPPORT +/** flag for NOA */ +#define WIFI_DIRECT_NOA 1 +/** flag for OPP_PS */ +#define WIFI_DIRECT_OPP_PS 2 +/** Type definition of mlan_ds_wifi_direct_config for MLAN_OID_MISC_WIFI_DIRECT_CONFIG */ +typedef struct _mlan_ds_wifi_direct_config { + /** flags for NOA/OPP_PS */ + t_u8 flags; + /** NoA enable/disable */ + t_u8 noa_enable; + /** index */ + t_u16 index; + /** NoA count */ + t_u8 noa_count; + /** NoA duration */ + t_u32 noa_duration; + /** NoA interval */ + t_u32 noa_interval; + /** opp ps enable/disable */ + t_u8 opp_ps_enable; + /** CT window value */ + t_u8 ct_window; +} mlan_ds_wifi_direct_config; +#endif + +/** DFS repeater mode configuration */ +typedef struct _dfs_repeater { + /** Enable DFS repeater mode */ + t_u16 action; + /** 1 on and 0 off */ + t_u16 mode; +} dfs_repeater; + +#ifdef RX_PACKET_COALESCE +/** RX packet coalesce tlv */ +typedef struct _tlvbuf_rx_pkt_coal_t { + /** threshold for rx packets */ + t_u32 rx_pkt_count; + /** timeout for rx coalescing timer */ + t_u16 delay; +} tlvbuf_rx_pkt_coal_t; +#endif + +/** Maximum SSID length */ +#define MAX_SSID_LENGTH 32 +/** Maximum SSID length */ +#define MIN_SSID_LENGTH 1 +/** Maximum WPA passphrase length */ +#define MAX_WPA_PASSPHRASE_LENGTH 64 +/** Minimum WPA passphrase length */ +#define MIN_WPA_PASSPHRASE_LENGTH 8 + +/** channel statictics */ +typedef struct _chan_statistics_t { + /** channle number */ + t_u8 chan_num; + /** band info */ + Band_Config_t bandcfg; + /** flags */ + t_u8 flags; + /** noise */ + t_s8 noise; + /** total network */ + t_u16 total_networks; + /** scan duration */ + t_u16 cca_scan_duration; + /** busy duration */ + t_u16 cca_busy_duration; + /** min rss */ + t_u8 min_rss; + /** max rss */ + t_u8 max_rss; +} __ATTRIB_PACK__ chan_statistics_t; + +typedef struct _chan_stats { + /** Number of records in the chan_stats */ + t_u32 num_in_chan_stats; + /** channel statistics */ + chan_statistics_t stats[]; +} chan_stats; + +/** cloud keep alive parameters */ +typedef struct _cloud_keep_alive { + /** id */ + t_u8 mkeep_alive_id; + /** enable/disable of this id */ + t_u8 enable; + /** enable/disable reset*/ + t_u8 reset; + /** Reserved */ + t_u8 reserved; + /** Destination MAC address */ + t_u8 dst_mac[ETH_ALEN]; + /** Source MAC address */ + t_u8 src_mac[ETH_ALEN]; + /** packet send period */ + t_u32 sendInterval; + /** packet retry interval */ + t_u32 retryInterval; + /** packet retry count */ + t_u8 retryCount; + /** packet length */ + t_u8 pkt_len; + /** packet content */ + t_u8 pkt[255]; +} __ATTRIB_PACK__ cloud_keep_alive; + +#define TLV_TYPE_PER_PKT_CFG 0x0001 +#define MAX_NUM_ETHER_TYPE 8 +#define MAX_TXRX_CTRL 3 +#define TX_PKT_CTRL MBIT(0) +#define RX_PKT_INFO MBIT(1) +/** PER_PKT_CFG_TLV for per-packet configuration */ +typedef struct _MrvlIEtypes_per_pkt_cfg_t { + /** Header */ + MrvlIEtypesHeader_t header; + /** Tx/Rx per-packet control */ + t_u8 tx_rx_control; + /** Number of ethernet types in ether_type array */ + t_u8 proto_type_num; + /** Array of ether_type for per-packet control */ + t_u16 ether_type[]; +} MrvlIEtypes_per_pkt_cfg_t; + +#define FLAG_TX_HISTOGRAM 0x01 +#define FLAG_RX_HISTOGRAM 0x02 +#define DISABLE_TX_RX_HISTOGRAM 0x00 +#define ENABLE_TX_RX_HISTOGRAM 0x01 +#define GET_TX_RX_HISTOGRAM 0x02 +/** TX histiogram ht statistic parameters */ +typedef struct _tx_pkt_ht_rate_info { + /** tx packet counter of MCS0~MCS15 */ + t_u32 htmcs_txcnt[16]; + /** tx packet's short GI counter of MCS0~MCS15 */ + t_u32 htsgi_txcnt[16]; + /** tx STBC packet counter of MCS0~MCS15 */ + t_u32 htstbcrate_txcnt[16]; +} tx_pkt_ht_rate_info; +/** TX histiogram vht statistic parameters */ +typedef struct _tx_pkt_vht_rate_info { + /** tx packet counter of MCS0~MCS9 */ + t_u32 vhtmcs_txcnt[10]; + /** tx packet's short GI counter of MCS0~MCS9 */ + t_u32 vhtsgi_txcnt[10]; + /** tx STBC packet counter of MCS0~MCS9 */ + t_u32 vhtstbcrate_txcnt[10]; +} tx_pkt_vht_rate_info; +/** TX histiogram he statistic parameters */ +typedef struct _tx_pkt_he_rate_info { + /** tx packet counter of MCS0~MCS11 */ + t_u32 hemcs_txcnt[12]; + /** tx STBC packet counter of MCS0~MCS11 */ + t_u32 hestbcrate_txcnt[12]; +} tx_pkt_he_rate_info; +/** TX histogram statistic parameters*/ +typedef struct _tx_pkt_rate_info { + /** tx packet counter of every NSS, NSS=1,2 */ + t_u32 nss_txcnt[2]; + /** tx packet counter of every bandwith */ + t_u32 bandwidth_txcnt[3]; + /** different preamble tx packet counter */ + t_u32 preamble_txcnt[4]; + /** tx packet counter of using LDPC coding */ + t_u32 ldpc_txcnt; + /** transmitted RTS counter */ + t_u32 rts_txcnt; + /** RSSI of ack */ + t_s32 ack_RSSI; +} tx_pkt_rate_info; +/** RX histiogram ht statistic parameters */ +typedef struct _rx_pkt_ht_rate_info { + /** Rx packet counter of MCS0~MCS15 */ + t_u32 htmcs_rxcnt[16]; + /** Rx packet's short GI counter of MCS0~MCS15 */ + t_u32 htsgi_rxcnt[16]; + /** Rx STBC packet counter of MCS0~MCS15 */ + t_u32 htstbcrate_rxcnt[16]; +} rx_pkt_ht_rate_info; +/** RX histiogram vht statistic parameters */ +typedef struct _rx_pkt_vht_rate_info { + /** Rx packet counter of MCS0~MCS9 */ + t_u32 vhtmcs_rxcnt[10]; + /** Rx packet's short GI counter of MCS0~MCS9 */ + t_u32 vhtsgi_rxcnt[10]; + /** Rx STBC packet counter of MCS0~MCS9 */ + t_u32 vhtstbcrate_rxcnt[10]; +} rx_pkt_vht_rate_info; +/** RX histiogram he statistic parameters */ +typedef struct _rx_pkt_he_rate_info { + /** Rx packet counter of MCS0~MCS11 */ + t_u32 hemcs_rxcnt[12]; + /** Rx STBC packet counter of MCS0~MCS11 */ + t_u32 hestbcrate_rxcnt[12]; +} rx_pkt_he_rate_info; +/** RX histogram statistic parameters*/ +typedef struct _rx_pkt_rate_info { + /** Rx packet counter of every NSS, NSS=1,2 */ + t_u32 nss_rxcnt[2]; + /** Received packet counter which using STBC */ + t_u32 nsts_rxcnt; + /** Rx packet counter of every bandwith */ + t_u32 bandwidth_rxcnt[3]; + /** Different preamble Rx packet counter */ + t_u32 preamble_rxcnt[6]; + /** VHT SIGA2 LDPC bit*/ + t_u32 ldpc_txbfcnt[2]; + /** Average RSSI */ + t_s32 rssi_value[2]; + /** RSSI value of path A */ + t_s32 rssi_chain0[4]; + /** RSSI value of path B */ + t_s32 rssi_chain1[4]; +} rx_pkt_rate_info; +/** TX and RX histogram statistic parameters*/ +typedef struct _tx_rx_histogram { + /** Enable or disable get tx/rx histogram statistic */ + t_u8 enable; + /** Choose to get TX, RX or both histogram statistic */ + t_u8 action; +} __ATTRIB_PACK__ tx_rx_histogram; + +/** max mod group */ +#define MAX_MOD_GROUP 35 + +/** modulation setting */ +typedef struct _mod_group_setting { + /** modulation group */ + t_u8 mod_group; + /** power */ + t_u8 power; +} __ATTRIB_PACK__ mod_group_setting; + +/** chan trpc config */ +typedef struct _ChanTRPCConfig_t { + /** start freq */ + t_u16 start_freq; + /* channel width */ + t_u8 width; + /** channel number */ + t_u8 chan_num; + mod_group_setting mod_group[MAX_MOD_GROUP]; +} __ATTRIB_PACK__ ChanTRPCConfig_t; + +/** MrvlIETypes_ChanTRPCConfig_t */ +typedef struct _MrvlIETypes_ChanTRPCConfig_t { + /** Header */ + MrvlIEtypesHeader_t header; + /** start freq */ + t_u16 start_freq; + /* channel width */ + t_u8 width; + /** channel number */ + t_u8 chan_num; + /** mode groups */ + mod_group_setting mod_group[]; +} __ATTRIB_PACK__ MrvlIETypes_ChanTRPCConfig_t; + +/*This command gets/sets the Transmit Rate-based Power Control (TRPC) channel configuration.*/ +#define HostCmd_CHANNEL_TRPC_CONFIG 0x00fb + +/** TLV OF CHAN_TRPC_CONFIG */ +#define TLV_TYPE_CHAN_TRPC_CONFIG (PROPRIETARY_TLV_BASE_ID + 137) + +/** mlan_ds_misc_chan_trpc_cfg */ +typedef struct _mlan_ds_misc_chan_trpc_cfg { + /** sub_band */ + t_u16 sub_band; + /** length */ + t_u16 length; + /** trpc buf */ + t_u8 trpc_buf[BUFFER_LENGTH]; +} __ATTRIB_PACK__ mlan_ds_misc_chan_trpc_cfg; + +/** command ID for CHAN_REGION */ +#define HostCmd_CMD_CHAN_REGION_CFG 0x0242 +#define TLV_TYPE_CHAN_ATTR_CFG (PROPRIETARY_TLV_BASE_ID + 237) //0x1ed +#define TLV_TYPE_REGION_INFO (PROPRIETARY_TLV_BASE_ID + 238) //0x1ee +#define TLV_TYPE_POWER_TABLE (PROPRIETARY_TLV_BASE_ID + 262) //0x206 +#define TLV_TYPE_POWER_TABLE_ATTR (PROPRIETARY_TLV_BASE_ID + 317) //0x23d + +/** MrvlIEtypes_otp_region_info_t */ +typedef struct MrvlIEtypes_otp_region_info { + /** Header */ + MrvlIEtypesHeader_t header; + /** country code */ + t_u8 countrycode[2]; + /** region code */ + t_u8 regioncode; + /** environment */ + t_u8 environment; + /** force_reg */ + t_u16 force_reg:1; + /** reserviced */ + t_u16 reserved:15; +} __ATTRIB_PACK__ MrvlIEtypes_otp_region_info_t; + +/** MrvlIEtypes_otp_region_info_t */ +typedef struct MrvlIEtypes_power_table_attr { + MrvlIEtypesHeader_t header; + /** rows bg = num of channel in 2g */ + t_u8 rows_bg; + /** cols_bg = num of 2g power modules + 1 */ + t_u8 cols_bg; + /** rows a = num of channel in 5g */ + t_u8 rows_a; + /** cols a = num of 5g power modules + 1 */ + t_u8 cols_a; +} __ATTRIB_PACK__ MrvlIEtypes_power_table_attr_t; + +typedef struct { + /** chan number */ + t_u8 chan_no; + /** chan attr */ + t_u8 chan_attr; +} __ATTRIB_PACK__ chan_attr_t; + +/** MrvlIEtypes_chan_attr_t */ +typedef struct MrvlIEtypes_chan_attr { + MrvlIEtypesHeader_t header; + chan_attr_t chan_attr[]; +} __ATTRIB_PACK__ MrvlIEtypes_chan_attr_t; + +typedef struct { + /** chan number */ + t_u8 chan_no; + /** power modules */ + t_u8 power[]; +} __ATTRIB_PACK__ chan_power_t; + +/** MrvlIEtypes_power_tbl_t */ +typedef struct MrvlIEtypes_power_tbl { + MrvlIEtypesHeader_t header; + chan_power_t chan_power[]; +} __ATTRIB_PACK__ MrvlIEtypes_power_table_t; + +typedef enum { + PTVER_2X2_AC = 0, + PTVER_1X1_AC = 1, + PTVER_2X2_N = 2, + PTVER_1X1_N = 3, + PTVER_1X1_AC_11P = 5, + PTVER_2X2_AC_2GVHT = 6, + PTVER_1X1_AC_2GVHT = 7, + PTVER_1X1_AC_2GVHT_11P = 8, +} __ATTRIB_PACK__ ptver_type_e; + +/** mlan_ds_misc_chan_chnrgpwr_cfg */ +typedef struct _mlan_ds_misc_chnrgpwr_cfg { + /** length */ + t_u16 length; + /** chnrgpwr buf */ + t_u8 chnrgpwr_buf[BUFFER_LENGTH]; +} __ATTRIB_PACK__ mlan_ds_misc_chnrgpwr_cfg; + +#define OTP_IDENTIFIER 0x8888 +/* mfg_rghdr_t*/ +typedef struct { + /* identifier, show always 0x8888 */ + t_u16 identifier; + /** version */ + t_u8 version; + /** num of entry */ + t_u8 numberofentries; + /** ptbase version */ + t_u8 ptbaseversion; + /** reserved */ + t_u8 reserved; + /** CRC */ + t_u32 crc; +} __ATTRIB_PACK__ mfg_rghdr_t; + +/* mfg_rgdatahdr_t */ +typedef struct { + /** country code */ + t_u8 countrycode[2]; + /** enviroment */ + t_u8 environment; + /** region code */ + t_u8 regioncode; + /** compressmethod */ + t_u16 compressmethod; + /** length */ + t_u16 length; + /** compressed table */ + t_u8 compressedtable; +} __ATTRIB_PACK__ mfg_rgdatahdr_t; + +#define MAX_MCS_POWER_INDEX 28 +#define MAX_BG_CHAN 14 +#define MAX_A_CHAN 40 + +typedef struct { + /** chan number */ + t_u8 chan_no; + /** power value */ + t_u8 pwr[MAX_MCS_POWER_INDEX]; + /** chan attr */ + t_u8 chan_attr; +} __ATTRIB_PACK__ rgchan_pwr_t; + +/** region_chan_pwr_tbl*/ +typedef struct { + /** country code */ + t_u8 countrycode[2]; + /** enviromnent */ + t_u8 environment; + /** region code */ + t_u8 regioncode; + /** 2g pwr tbl */ + rgchan_pwr_t bg_pwr_tbl[MAX_BG_CHAN]; + /** 5g pwr tbl */ + rgchan_pwr_t a_pwr_tbl[MAX_A_CHAN]; + /** max chan number in 5g */ + int max_chan_bg; + /** max power modules in 2g */ + int max_power_bg; + int max_chan_a; + /** max power modules in 5g */ + int max_power_a; + /** ptbase version for display */ + t_u8 ptbaseversion; +} __ATTRIB_PACK__ region_chan_pwr_tbl; + +#define ETH_P_WSMP 0x88dc +#define BUF_SIZ 1024 +typedef struct { + t_u8 version; + t_u8 sec_type; + t_u8 chan; + t_u8 rate; + t_u8 tx_pow; + t_u8 app_class; + t_u8 acm_len; + t_u16 len; +} __ATTRIB_PACK__ wsmp_header; + +typedef struct { + t_u16 rx_datarate; //Data rate + t_u8 rx_channel; //Channel number + t_u8 rx_antenna; //received antenna + t_s8 rx_RSSI; //RSSI info + t_u8 reserved[3]; //Reserved fields +} __ATTRIB_PACK__ dot11_rxcontrol; + +typedef struct { + t_u16 tx_datarate; //Data rate in unit of 0.5Mbps + t_u8 tx_channel; //Channel number to transmit the frame + t_u8 tx_Bw; //Bandwidth to transmit the frame + t_u8 tx_power; //Power to be used for transmission + t_u8 pkt_priority; //Priority of the packet to be transmitted + t_u8 retry_limit; //tx retry limit + t_u8 reserved[1]; //Reserved fields +} __ATTRIB_PACK__ dot11_txcontrol; + +/* CW_MODE_CTRL structure*/ +typedef struct { + t_u8 mode; + t_u8 channel; + t_u8 chanInfo; + t_u16 txPower; + t_u16 pktLength; + t_u32 rateInfo; +} __ATTRIB_PACK__ cw_mode_ctrl; + +#if defined(PCIE) +/* ssu_params_cfg */ +typedef struct _ssu_params_cfg { + /* ssu mode */ + t_u8 ssu_mode; + /* 0-3; # of FFT samples to skip */ + t_u32 nskip; + /* 0-3: # of FFT samples selected to dump */ + t_u32 nsel; + /* 0-3: Down sample ADC input for buffering */ + t_u32 adcdownsample; + /* 0-1: Mask out ADC Data from spectral packet */ + t_u32 mask_adc_pkt; + /* 0-1: Enable 16-Bit FFT output data precision in spectral packet */ + t_u32 out_16bits; + /* 0-1: Enable power spectrum in dB for spectral packe */ + t_u32 spec_pwr_enable; + /* 0-1: Enable spectral packet rate reduction in DB output format */ + t_u32 rate_deduction; + /* 0-7: Number of spectral packets over which spectral data is to be averaged. */ + t_u32 n_pkt_avg; +} __ATTRIB_PACK__ ssu_params_cfg; +#endif + +/** 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 +/** TX Sounding*/ +#define TX_SOUNDING_CFG 0x05 + +/** bf global cfg args */ +typedef struct _bf_global_cfg { + /** 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; +} bf_global_cfg; + +/** trigger sounding args */ +typedef struct _trigger_sound { + /** Peer MAC address */ + t_u8 peer_mac[MLAN_MAC_ADDR_LENGTH]; + /** Status */ + t_u8 status; +} trigger_sound; + +/** bf periodicity args */ +typedef struct _bf_periodicity_cfg { + /** Peer MAC address */ + t_u8 peer_mac[MLAN_MAC_ADDR_LENGTH]; + /** Current Tx BF Interval in milliseconds */ + t_u16 interval; + /** Status */ + t_u8 status; +} bf_periodicity_cfg; + +/** tx bf peer args */ +typedef struct _tx_bf_peer_cfg { + /** 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; +} tx_bf_peer_cfg; + +/** SNR threshold args */ +typedef struct _snr_thr_cfg { + /** Peer MAC address */ + t_u8 peer_mac[MLAN_MAC_ADDR_LENGTH]; + /** SNR for peer */ + t_u8 snr; +} snr_thr_cfg; + +/** Type definition of mlan_ds_11ax_he_capa for MLAN_OID_11AX_HE_CFG */ +typedef struct _mlan_ds_11ax_he_capa { + /** tlv id of he capability */ + t_u16 id; + /** length of the payload */ + t_u16 len; + /** extension id */ + t_u8 ext_id; + /** he mac capability info */ + t_u8 he_mac_cap[6]; + /** he phy capability info */ + t_u8 he_phy_cap[11]; + /** he txrx mcs support for 80MHz */ + t_u8 he_txrx_mcs_support[4]; + /** val for txrx mcs 160Mhz or 80+80, and PPE thresholds */ + t_u8 val[28]; +} __ATTRIB_PACK__ mlan_ds_11ax_he_capa, *pmlan_ds_11ax_he_capa; + +/** Type definition of mlan_ds_11ax_he_cfg for MLAN_OID_11AX_HE_CFG */ +typedef struct _mlan_ds_11ax_he_cfg { + /** band, BIT0:2.4G, BIT1:5G*/ + t_u8 band; + /** mlan_ds_11ax_he_capa */ + mlan_ds_11ax_he_capa he_cap; +} __ATTRIB_PACK__ mlan_ds_11ax_he_cfg, *pmlan_ds_11ax_he_cfg; + +#define MLAN_11AXCMD_CFG_ID_SR_OBSS_PD_OFFSET 1 +#define MLAN_11AXCMD_CFG_ID_SR_ENABLE 2 +#define MLAN_11AXCMD_CFG_ID_BEAM_CHANGE 3 +#define MLAN_11AXCMD_CFG_ID_HTC_ENABLE 4 + +#define MLAN_11AXCMD_SR_SUBID 0x102 +#define MLAN_11AXCMD_BEAM_SUBID 0x103 +#define MLAN_11AXCMD_HTC_SUBID 0x104 + +#define MRVL_DOT11AX_ENABLE_SR_TLV_ID (PROPRIETARY_TLV_BASE_ID + 322) +#define MRVL_DOT11AX_OBSS_PD_OFFSET_TLV_ID (PROPRIETARY_TLV_BASE_ID + 323) + +#ifndef MLAN_ACT_GET +#define MLAN_ACT_GET 2 +#endif + +/** Type definition of mlan_11axcmdcfg_obss_pd_offset for MLAN_OID_11AX_CMD_CFG */ +typedef struct _mlan_11axcmdcfg_obss_pd_offset { + /** */ + t_u8 offset[2]; +} __ATTRIB_PACK__ mlan_11axcmdcfg_obss_pd_offset; + +/** Type definition of mlan_11axcmdcfg_sr_control for MLAN_OID_11AX_CMD_CFG */ +typedef struct _mlan_11axcmdcfg_sr_control { + /** 1 enable, 0 disable */ + t_u8 control; +} __ATTRIB_PACK__ mlan_11axcmdcfg_sr_control; + +/** Type definition of mlan_ds_11ax_sr_cmd for MLAN_OID_11AX_CMD_CFG */ +typedef struct _mlan_ds_11ax_sr_cmd { + /** type*/ + t_u16 type; + /** length of TLV */ + t_u16 len; + /** value */ + union { + mlan_11axcmdcfg_obss_pd_offset obss_pd_offset; + mlan_11axcmdcfg_sr_control sr_control; + } param; +} __ATTRIB_PACK__ mlan_ds_11ax_sr_cmd, *pmlan_ds_11ax_sr_cmd; + +/** Type definition of mlan_ds_11ax_beam_cmd for MLAN_OID_11AX_CMD_CFG */ +typedef struct _mlan_ds_11ax_beam_cmd { + /** command value: 1 is disable, 0 is enable*/ + t_u8 value; +} mlan_ds_11ax_beam_cmd, *pmlan_ds_11ax_beam_cmd; + +/** Type definition of mlan_ds_11ax_htc_cmd for MLAN_OID_11AX_CMD_CFG */ +typedef struct _mlan_ds_11ax_htc_cmd { + /** command value: 1 is enable, 0 is disable*/ + t_u8 value; +} mlan_ds_11ax_htc_cmd, *pmlan_ds_11ax_htc_cmd; + +/** Type definition of mlan_ds_11ax_cmd_cfg for MLAN_OID_11AX_CMD_CFG */ +typedef struct _mlan_ds_11ax_cmd_cfg { + /** Sub-command */ + t_u32 sub_command; + /** Sub-id */ + t_u32 sub_id; + /** 802.11n configuration parameter */ + union { + /** SR configuration for MLAN_11AXCMD_SR_SUBID */ + mlan_ds_11ax_sr_cmd sr_cfg; + /** Beam configuration for MLAN_11AXCMD_BEAM_SUBID */ + mlan_ds_11ax_beam_cmd beam_cfg; + /** HTC configuration for MLAN_11AXCMD_HTC_SUBID */ + mlan_ds_11ax_htc_cmd htc_cfg; + } param; +} mlan_ds_11ax_cmd_cfg, *pmlan_ds_11ax_cmd_cfg; + +/** TWT setup parameters */ +typedef struct _twt_setup { + /** Implicit, 0: TWT session is explicit, 1: Session is implicit */ + t_u8 implicit; + /** Announced, 0: Unannounced, 1: Announced TWT */ + t_u8 announced; + /** Trigger Enabled, 0: Non-Trigger enabled, 1: Trigger enabled TWT */ + t_u8 triggerEn; + /** TWT Information Disabled, 0: TWT info enabled, 1: TWT info disabled */ + t_u8 twtInfoDisabled; + /** Negotiation Type, 0: Future Individual TWT SP start time, 1: Next Wake TBTT time */ + t_u8 negotiationType; + /** TWT Wakeup Duration, time after which the TWT requesting STA can transition to doze state */ + t_u8 twtWakeupDuration; + /** Flow Identifier. Range: [0-7]*/ + t_u8 flowIdentifier; + /** Hard Constraint, 0: FW can tweak the TWT setup parameters if it is rejected by AP. + ** 1: Firmware should not tweak any parameters. */ + t_u8 hardConstraint; + /** TWT Exponent, Range: [0-63] */ + t_u8 twtExponent; + /** TWT Mantissa Range: [0-sizeof(UINT16)] */ + t_u16 twtMantissa; +} __ATTRIB_PACK__ twt_setup; + +/** TWT tear down parameters */ +typedef struct _twt_teardown { + /** TWT Flow Identifier. Range: [0-7] */ + t_u8 flowIdentifier; + /** Negotiation Type. 0: Future Individual TWT SP start time, 1: Next Wake TBTT time */ + t_u8 negotiationType; + /** Tear down all TWT. 1: To teardown all TWT, 0 otherwise */ + t_u8 teardownAllTWT; +} __ATTRIB_PACK__ twt_teardown; + +/** rx_abort_cfg parameters */ +typedef struct _rx_abort_cfg_para { + /** enable/disable Rx abort */ + int enable; + /** rx weak rssi pkt threshold */ + int rssi_threshold; +} rx_abort_cfg_para; +/** rx_abort_cfg_ext parameters */ +typedef struct _rx_abort_cfg_ext_para { + /** enable/disable Rx abort */ + int enable; + /** rssi margin */ + int rssi_margin; + /** ceil rssi threshold */ + int ceil_rssi_threshold; +} rx_abort_cfg_ext_para; + +#define TX_AMPDU_RTS_CTS 0 +#define TX_AMPDU_CTS_2_SELF 1 +#define TX_AMPDU_DISABLE_PROTECTION 2 +#define TX_AMPDU_DYNAMIC_RTS_CTS 3 + +/** tx_ampdu_prot_mode parameters */ +typedef struct _tx_ampdu_prot_mode_para { + /** set prot mode */ + int mode; +} tx_ampdu_prot_mode_para; + +/** rate adapt cfg parameters */ +typedef struct _rate_adapt_cfg_para { + /** SR(Success Rate) rateadapt */ + int sr_rateadapt; + /** set low threshold */ + int ra_low_thresh; + /** set high threshold */ + int ra_high_thresh; + /** set timer interval */ + int ra_interval; +} rate_adapt_cfg_para; + +#define CCK_DESENSE_MODE_DISABLED 0 +#define CCK_DESENSE_MODE_DYNAMIC 1 +#define CCK_DESENSE_MODE_DYN_ENH 2 +/** cck_desense_cfg parameters */ +typedef struct _cck_desense_cfg_para { + /** cck desense mode: 0:disable 1:normal 2:dynamic */ + int mode; + /** specify rssi margin */ + int margin; + /** specify ceil rssi threshold */ + int ceil_thresh; + /** cck desense "on" interval count */ + int num_on_intervals; + /** cck desense "off" interval count */ + int num_off_intervals; +} cck_desense_cfg_para; + +typedef enum _dfs_state { + /** Channel can be used, CAC (Channel Availability Check) must be done before using it */ + DFS_USEABLE = 0, + /** Channel is not available, radar was detected */ + DFS_UNAVAILABLE = 1, + /** Channel is Available, CAC is done and is free of radar */ + DFS_AVAILABLE = 2, +} dfs_state; + +#endif /* _MLANUTL_H_ */ diff --git a/mxm_wifiex/wlan_src/mapp/mlanutl/timestamp.c b/mxm_wifiex/wlan_src/mapp/mlanutl/timestamp.c new file mode 100644 index 0000000..8f87a6d --- /dev/null +++ b/mxm_wifiex/wlan_src/mapp/mlanutl/timestamp.c @@ -0,0 +1,420 @@ +/** @file timestamp.c + * + * @brief Functions for timestamping feature + * + * + * + * Copyright 2014-2020 NXP + * + * NXP CONFIDENTIAL + * The source code contained or described herein and all documents related to + * the source code (Materials) are owned by NXP, its + * suppliers and/or its licensors. Title to the Materials remains with NXP, + * its suppliers and/or its licensors. The Materials contain + * trade secrets and proprietary and confidential information of NXP, its + * suppliers and/or its licensors. The Materials are protected by worldwide copyright + * and trade secret laws and treaty provisions. No part of the Materials may be + * used, copied, reproduced, modified, published, uploaded, posted, + * transmitted, distributed, or disclosed in any way without NXP's prior + * express written permission. + * + * No license under any patent, copyright, trade secret or other intellectual + * property right is granted to or conferred upon you by disclosure or delivery + * of the Materials, either expressly, by implication, inducement, estoppel or + * otherwise. Any license under such intellectual property rights must be + * express and approved by NXP in writing. + * + */ + +#include "timestamp.h" +#include "time.h" + +/* GLobal Declarations */ +struct timespec send_time; +struct interface_data inter; + +/** + *@brief Receive Timestamps + * + *@param argc Number of arguments + *@param argv Pointer to the arguments array + * + * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_FAILURE + **/ +void +receive_timestamp(int argc, char *argv[]) +{ + int sockfd; + int sockopt; + char ifName[IFNAMSIZ]; + struct ifreq if_ip; /* get ip addr */ + int so_timestamping_flags = 0; + int siocgstamp = 0; + int siocgstampns = 0; + struct timeval now; + int res; + struct ifreq if_idx; + struct ifreq if_mac; + fd_set readfs, errorfs; + + /* Get interface name */ + if (argc > 2) + strcpy(ifName, argv[1]); + else { + fprintf(stderr, + "invalid no. of arguments to receive_timestamp \n"); + exit(1); + } + + /* Header structures */ + so_timestamping_flags |= SOF_TIMESTAMPING_SOFTWARE; + so_timestamping_flags |= SOF_TIMESTAMPING_RAW_HARDWARE; + memset(&if_ip, 0, sizeof(struct ifreq)); + + /* Open PF_PACKET socket, listening for EtherType ETHER_TYPE */ + if ((sockfd = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_802_EX1))) == -1) { + perror("listener: socket"); + } + + /* Get the index of the interface to receive on */ + memset(&if_idx, 0, sizeof(struct ifreq)); + strncpy(if_idx.ifr_name, ifName, IFNAMSIZ - 1); + if (ioctl(sockfd, SIOCGIFINDEX, &if_idx) < 0) + perror("SIOCGIFINDEX"); + + /* Get the MAC address of the interface to receive on */ + memset(&if_mac, 0, sizeof(struct ifreq)); + strncpy(if_mac.ifr_name, ifName, IFNAMSIZ - 1); + if (ioctl(sockfd, SIOCGIFHWADDR, &if_mac) < 0) + perror("SIOCGIFHWADDR"); + + /* Allow the socket to be reused - incase connection is closed prematurely */ + if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &sockopt, + sizeof sockopt) == -1) { + perror("setsockopt"); + close(sockfd); + exit(1); + } + + /* Bind to device */ + if (setsockopt(sockfd, SOL_SOCKET, SO_BINDTODEVICE, + ifName, IFNAMSIZ - 1) == -1) { + perror("SO_BINDTODEVICE"); + close(sockfd); + exit(1); + } + + if (so_timestamping_flags && + setsockopt(sockfd, SOL_SOCKET, SO_TIMESTAMPING, + &so_timestamping_flags, + sizeof(so_timestamping_flags)) < 0) + perror("setsockopt SO_TIMESTAMPING"); + + while (1) { + FD_ZERO(&readfs); + FD_ZERO(&errorfs); + FD_SET(sockfd, &readfs); + FD_SET(sockfd, &errorfs); + gettimeofday(&now, NULL); + res = select(sockfd + 1, &readfs, 0, &errorfs, NULL); + if (res > 0) { + recvpacket(sockfd, 0, siocgstamp, siocgstampns); + } + } +} + +/** + *@brief Send Timestamps + * + *@param argc Number of arguments + *@param argv Pointer to the arguments array + * + *@return MLAN_STATUS_SUCCESS/MLAN_STATUS_FAILURE + **/ +int +send_timestamp(int argc, char *argv[]) +{ + int sockfd; + struct ifreq if_idx; + struct ifreq if_mac; + int tx_len = 0, i; + char sendbuf[BUF_SIZ]; + char buff[BUF_SIZ]; + struct ether_header *eh = (struct ether_header *)sendbuf; + struct sockaddr_ll socket_address; + char ifName[IFNAMSIZ], ip[50]; + struct timeval delta; + fd_set readfs, errorfs; + int res, siocgstamp = 1, siocgstampns = 1; + int so_timestamping_flags = SOF_TIMESTAMPING_TX_HARDWARE; + struct ifreq hwtstamp; + struct hwtstamp_config hwconfig; + + so_timestamping_flags |= SOF_TIMESTAMPING_RAW_HARDWARE; + so_timestamping_flags |= SOF_TIMESTAMPING_TX_HARDWARE; + so_timestamping_flags |= SOF_TIMESTAMPING_SYS_HARDWARE; + + /* Get interface name */ + if (argc > 4) { + strcpy(ifName, argv[1]); + strcpy(ip, argv[4]); + } else { + fprintf(stderr, "invalid no. of args for send_timestamp\n"); + exit(1); + } + + /* Open RAW socket to send on */ + if ((sockfd = socket(PF_PACKET, SOCK_RAW, ETH_P_802_EX1)) == -1) { + perror("socket"); + } + + memset(&hwtstamp, 0, sizeof(hwtstamp)); + strncpy(hwtstamp.ifr_name, ifName, sizeof(hwtstamp.ifr_name)); + hwtstamp.ifr_data = (void *)&hwconfig; + memset(&hwconfig, 0, sizeof(hwconfig)); + + hwconfig.tx_type = + (so_timestamping_flags & SOF_TIMESTAMPING_TX_HARDWARE) ? + HWTSTAMP_TX_ON : HWTSTAMP_TX_OFF; + + hwconfig.rx_filter = + (so_timestamping_flags & SOF_TIMESTAMPING_RX_HARDWARE) ? + HWTSTAMP_FILTER_PTP_V1_L4_SYNC : HWTSTAMP_FILTER_NONE; + + /* Get the index of the interface to send on */ + memset(&if_idx, 0, sizeof(struct ifreq)); + strncpy(if_idx.ifr_name, ifName, IFNAMSIZ - 1); + if (ioctl(sockfd, SIOCGIFINDEX, &if_idx) < 0) + perror("SIOCGIFINDEX"); + + /* Get the MAC address of the interface to send on */ + memset(&if_mac, 0, sizeof(struct ifreq)); + strncpy(if_mac.ifr_name, ifName, IFNAMSIZ - 1); + if (ioctl(sockfd, SIOCGIFHWADDR, &if_mac) < 0) + perror("SIOCGIFHWADDR"); + + if (so_timestamping_flags && + setsockopt(sockfd, SOL_SOCKET, SO_TIMESTAMPING, + &so_timestamping_flags, + sizeof(so_timestamping_flags)) < 0) + perror("setsockopt SO_TIMESTAMPING"); + + if (setsockopt(sockfd, SOL_SOCKET, SO_BINDTODEVICE, + ifName, IFNAMSIZ - 1) == -1) { + perror("bind"); + exit(1); + } + + /* Construct the Ethernet header */ + memset(sendbuf, 0, BUF_SIZ); + + /* Ethernet header */ + memcpy(eh->ether_shost, (u_int8_t *) & if_mac.ifr_hwaddr.sa_data, + MLAN_MAC_ADDR_LENGTH); + + eh->ether_type = htons(ETH_P_802_EX1); + + tx_len += sizeof(struct ether_header); + + get_mac(ifName, ip); + for (i = 0; i < MLAN_MAC_ADDR_LENGTH; i++) { + eh->ether_dhost[i] = (uint8_t) inter.mac[i]; + } + /* Index of the network device */ + socket_address.sll_ifindex = if_idx.ifr_ifindex; + + /* Address length */ + socket_address.sll_halen = ETH_ALEN; + memcpy(&socket_address.sll_addr, (uint8_t *) & inter.mac, + MLAN_MAC_ADDR_LENGTH); + + clock_gettime(CLOCK_REALTIME, &send_time); + sprintf(buff, "%lld.%lld", (long long)send_time.tv_sec, + (long long)send_time.tv_nsec); + strcpy((sendbuf + tx_len), buff); + + /* Send packet */ + res = sendto(sockfd, sendbuf, tx_len + strlen(buff), 0, + (struct sockaddr *)&socket_address, + sizeof(struct sockaddr_ll)); + if (res < 0) + perror("Send "); + + fprintf(stdout, "Application time : %lld.%09lld (sent)\n", + (long long)send_time.tv_sec, (long long)send_time.tv_nsec); + + delta.tv_sec = 5; + delta.tv_usec = 0; + + FD_ZERO(&readfs); + FD_ZERO(&errorfs); + FD_SET(sockfd, &readfs); + FD_SET(sockfd, &errorfs); + + res = select(sockfd + 1, &readfs, 0, &errorfs, &delta); + if (res > 0) { + recvpacket(sockfd, MSG_ERRQUEUE, siocgstamp, siocgstampns); + } + return MLAN_STATUS_SUCCESS; +} + +/** + *@brief get destination mac address + * + *@param ifc interface from which packet has to be sent + *@param ip IP Address of destination + * + *@return N/A + **/ +void +get_mac(char *ifc, char *ip) +{ + char ipAddr[20]; + char hwAddr[20]; + char device[10], temp[3], in[50]; + int i = 0, j = 0, k = 0, res = 0, retry = 0; + FILE *arpCache = fopen("/proc/net/arp", "r"); + if (!arpCache) { + fprintf(stderr, + "Arp Cache: Failed to open file \"/proc/net/arp\""); + } + + /* Ignore the first line, which contains the header */ + char header[ARP_FILE_BUFFER_LEN]; + +retry_again: + + if (!fgets(header, sizeof(header), arpCache)) + fprintf(stderr, "error getting mac from proc files"); + while (3 == fscanf(arpCache, ARP_FORMAT, ipAddr, hwAddr, device)) { + if ((!strcmp(ipAddr, ip)) && (!strcmp(ifc, device))) { + printf("Sending Packet to Peer : %s\n", hwAddr); + strcpy(inter.ip, ipAddr); + strcpy(inter.interface, device); + while (hwAddr[i] != '\0') { + if (hwAddr[i] == ':') { + inter.mac[j++] = strtol(temp, NULL, 16); + i++; + k = 0; + } else + temp[k++] = hwAddr[i++]; + } + inter.mac[j] = strtol(temp, NULL, 16); + res = 1; + } + } + if (res != 1 && retry == 0) { + sprintf(in, "ping -c 2 %s > /dev/null", ip); + system(in); + retry = 1; + rewind(arpCache); + goto retry_again; + } else if (res != 1 && retry == 1) { + printf("cannot find mac address for the specified ip\n"); + fclose(arpCache); + exit(1); + } + fclose(arpCache); +} + +/* + *@brief Receive Sync Packets + * + *@param sock socket from which packet must be recieved + *@param recvmsg_flags flags for recvmsg + *@param siocgstamp timestamp flag + *@param siocgstampns timestamp flag for nano secs + * + *@return N/A + **/ +void +recvpacket(int sock, int recvmsg_flags, int siocgstamp, int siocgstampns) +{ + unsigned char data[256]; + struct msghdr msg; + struct iovec entry; + struct sockaddr_in from_addr; + struct { + struct cmsghdr cm; + char control[512]; + } control; + int res, i; + + memset(&msg, 0, sizeof(msg)); + msg.msg_iov = &entry; + msg.msg_iovlen = 1; + entry.iov_base = data; + entry.iov_len = sizeof(data); + msg.msg_name = (caddr_t) & from_addr; + msg.msg_namelen = sizeof(from_addr); + msg.msg_control = &control; + msg.msg_controllen = sizeof(control); + + res = recvmsg(sock, &msg, recvmsg_flags | MSG_DONTWAIT); + if (res < 0) { + fprintf(stderr, "%s %s: %s\n", + "recvmsg", + (recvmsg_flags & MSG_ERRQUEUE) ? "error" : "regular", + strerror(errno)); + } else { + if (!(recvmsg_flags & MSG_ERRQUEUE)) { + printf("Received Packet from Peer : "); + for (i = 6; i < 12; i++) + printf("%02x:", data[i]); + printf("\n"); + } + printpacket(&msg, res, sock, recvmsg_flags, siocgstamp, + siocgstampns); + } +} + +/** + * @brief Prints Sent/Received Sync packets + * + * @param msg msghdr structure variable + * @param res result of recvmsg call + * @param sock socket variable + * @param recvmsg_flags flags for receive message + * @param siocgstamp timestamp flag + * @param siocgstampns timestamp flag for nano secs + * + * @return N/A + **/ +void +printpacket(struct msghdr *msg, int res, + int sock, int recvmsg_flags, int siocgstamp, int siocgstampns) +{ + struct cmsghdr *cmsg; + struct timespec now; + struct timespec *stamp; + clock_gettime(CLOCK_REALTIME, &now); + if (!(recvmsg_flags & MSG_ERRQUEUE)) { + printf("Application time : %ld.%09ld (received)\n", + (long)now.tv_sec, (long)now.tv_nsec); + } + + for (cmsg = CMSG_FIRSTHDR(msg); cmsg; cmsg = CMSG_NXTHDR(msg, cmsg)) { + if (cmsg->cmsg_level == SOL_SOCKET && + cmsg->cmsg_type == SO_TIMESTAMPING) { + stamp = (struct timespec *)CMSG_DATA(cmsg); + stamp++; + /* skip deprecated HW transformed */ + stamp++; + fprintf(stdout, "HW time : %ld.%09ld\n", + (long)stamp->tv_sec, (long)stamp->tv_nsec); + if (!(recvmsg_flags & MSG_ERRQUEUE)) + fprintf(stdout, "Delta in nsecs= %lld\n", + ((long long)(now.tv_sec - + stamp->tv_sec) * + 1000000000L + now.tv_nsec) - + (stamp->tv_nsec)); + else + fprintf(stdout, "Delta in nsecs= %lld", + ((long long)(stamp->tv_sec - + send_time.tv_sec) * + 1000000000L + (stamp->tv_nsec) - + send_time.tv_nsec)); + } + } + fprintf(stdout, "\n"); +} diff --git a/mxm_wifiex/wlan_src/mapp/mlanutl/timestamp.h b/mxm_wifiex/wlan_src/mapp/mlanutl/timestamp.h new file mode 100644 index 0000000..1a94c07 --- /dev/null +++ b/mxm_wifiex/wlan_src/mapp/mlanutl/timestamp.h @@ -0,0 +1,60 @@ +/** @file timestamp.h +* +* @brief This file contains definitions used for timestamp feature +* + * + * Copyright 2014-2020 NXP + * + * NXP CONFIDENTIAL + * The source code contained or described herein and all documents related to + * the source code (Materials) are owned by NXP, its + * suppliers and/or its licensors. Title to the Materials remains with NXP, + * its suppliers and/or its licensors. The Materials contain + * trade secrets and proprietary and confidential information of NXP, its + * suppliers and/or its licensors. The Materials are protected by worldwide copyright + * and trade secret laws and treaty provisions. No part of the Materials may be + * used, copied, reproduced, modified, published, uploaded, posted, + * transmitted, distributed, or disclosed in any way without NXP's prior + * express written permission. + * + * No license under any patent, copyright, trade secret or other intellectual + * property right is granted to or conferred upon you by disclosure or delivery + * of the Materials, either expressly, by implication, inducement, estoppel or + * otherwise. Any license under such intellectual property rights must be + * express and approved by NXP in writing. + * + */ + +#ifndef _TIMESTAMP_H_ +#define _TIMESTAMP_H_ + +#include "mlanutl.h" +#include +#include +#include + +#define BUF_SIZ 1024 +#define ARP_FORMAT "%s %*s %*s %s %*s %s" +#define ARP_FILE_BUFFER_LEN (1024) + +struct interface_data { + char ip[20]; + int mac[20]; + char interface[20]; +}; + +/** + * 802.1 Local Experimental 1. + */ +#ifndef ETH_P_802_EX1 +#define ETH_P_802_EX1 0x88B5 +#endif + +void receive_timestamp(int argc, char *argv[]); +int send_timestamp(int argc, char *argv[]); +void get_mac(char *ifc, char *ip); +void recvpacket(int sock, int recvmsg_flags, int siocgstamp, int siocgstampns); +void printpacket(struct msghdr *msg, int res, int sock, + int recvmsg_flags, int siocgstamp, int siocgstampns); + +#endif //_TIMESTAMP_H_ diff --git a/mxm_wifiex/wlan_src/mapp/uaputl/Makefile b/mxm_wifiex/wlan_src/mapp/uaputl/Makefile new file mode 100644 index 0000000..0f04379 --- /dev/null +++ b/mxm_wifiex/wlan_src/mapp/uaputl/Makefile @@ -0,0 +1,54 @@ +# File : uaputl/Makefile +# +# Copyright 2014-2020 NXP + +# Path to the top directory of the wlan distribution +PATH_TO_TOP = ../.. + +# Determine how we should copy things to the install directory +ABSPATH := $(filter /%, $(INSTALLDIR)) +RELPATH := $(filter-out /%, $(INSTALLDIR)) +INSTALLPATH := $(ABSPATH) +ifeq ($(strip $(INSTALLPATH)),) +INSTALLPATH := $(PATH_TO_TOP)/$(RELPATH) +endif + +# Override CFLAGS for application sources, remove __ kernel namespace defines +CFLAGS := $(filter-out -D__%, $(ccflags-y)) +# remove KERNEL include dir +CFLAGS := $(filter-out -I$(KERNELDIR)%, $(CFLAGS)) + + +#CFLAGS += -DAP22 -fshort-enums +CFLAGS += -Wall +#ECHO = @ +LIBS = -lrt + + +.PHONY: default tags all + +OBJECTS = uaputl.o uapcmd.o uaphostcmd.o +HEADERS = uaputl.h uapcmd.h + +TARGET = uaputl.exe + +build default: $(TARGET) + @cp -f $(TARGET) $(INSTALLPATH) + @cp -rf config $(INSTALLPATH) + + +all : tags default + +$(TARGET): $(OBJECTS) $(HEADERS) + $(ECHO)$(CC) $(LIBS) -o $@ $(OBJECTS) + +%.o: %.c $(HEADERS) + $(ECHO)$(CC) $(CFLAGS) -c -o $@ $< + +tags: + ctags -R -f tags.txt + +distclean clean: + $(ECHO)$(RM) $(OBJECTS) $(TARGET) + $(ECHO)$(RM) tags.txt + diff --git a/mxm_wifiex/wlan_src/mapp/uaputl/config/80211d_domain.conf b/mxm_wifiex/wlan_src/mapp/uaputl/config/80211d_domain.conf new file mode 100644 index 0000000..bb14e86 --- /dev/null +++ b/mxm_wifiex/wlan_src/mapp/uaputl/config/80211d_domain.conf @@ -0,0 +1,45 @@ +/* Domain and country mapping are in this section */ +/* Domain name followed by supported countries */ + +COUNTRY: DOMAIN_CODE_FCC AE AM AN AR AZ BH BL BN BR CL CN CR CS DZ EC EG GE HN HK ID IL IR JM JO KP KW KZ LB LK MA MO NP OM PE PG PH PK PT QA SA SG SV SY TH TT TN UY YE ZA ZW VN +COUNTRY: DOMAIN_CODE_FCC1 US UZ CA CO DO GT MX PA PR TW NZ BO BZ VE +COUNTRY: DOMAIN_CODE_MKK JP +COUNTRY: DOMAIN_CODE_ETSI AL AD AT AU BY BE BA BG HR CY CZ DK EE FI FR MK DE GB GR HU IS IE IT KR LV LI LT LU MT MD MC ME NL NO PL RO RU SM RS SI SK ES SE CH TR UA UK +COUNTRY: DOMAIN_CODE_IN IN +COUNTRY: DOMAIN_CODE_MY MY + + +/* Domain specific sub-band information */ +/* Domain name followed by set of triplets separated by comma */ +/* 1st number in triplet is First channel, */ +/* 2nd number in triplet is Number of channels followed from the First channel */ +/* 3rd number in triplet is Max-TX-power in dbm */ + +DOMAIN: DOMAIN_CODE_FCC 1 13 20 +DOMAIN: DOMAIN_CODE_FCC1 1 11 30 +DOMAIN: DOMAIN_CODE_ETSI 1 13 20 +DOMAIN: DOMAIN_CODE_MKK 1 14 23 +DOMAIN: DOMAIN_CODE_IN 1 11 30 +DOMAIN: DOMAIN_CODE_MY 1 13 20 +DOMAIN: DOMAIN_CODE_TEST 1 1 20, 2 1 16, 3 6 30, 11 1 10 +DOMAIN: DOMAIN_CODE_TEST1 1 11 30, 36 1 17, 40 1 17, 44 1 17, 48 1 17, 52 1 24, 56 1 24, 60 1 24, 64 1 24, 149 1 23, 153 1 23, 157 1 23, 161 1 23, 165 1 23, +DOMAIN: DOMAIN_CODE_END + +/* + * Information for channels in A Band. + */ + +*** 5GHz *** + +DOMAIN: DOMAIN_CODE_FCC 36 1 20, 40 1 20, 44 1 20, 48 1 20, 52 1 20, 56 1 20, 60 1 20, 64 1 20, 100 1 20, 104 1 20, 108 1 20, 112 1 20, 116 1 20, 120 1 20, 124 1 20, 128 1 20, 132 1 20, 136 1 20, 140 1 20, 144 1 20, 149 1 20, 153 1 20, 157 1 20, 161 1 20, 165 1 20, +DOMAIN: DOMAIN_CODE_FCC1 36 1 30, 40 1 30, 44 1 30, 48 1 30, 52 1 30, 56 1 30, 60 1 30, 64 1 30, 100 1 30, 104 1 30, 108 1 30, 112 1 30, 116 1 30, 120 1 30, 124 1 30, 128 1 30, 132 1 30, 136 1 30, 140 1 30, 144 1 30, 149 1 30, 153 1 30, 157 1 30, 161 1 30, 165 1 30, + +DOMAIN: DOMAIN_CODE_MKK 8 1 24, 12 1 24, 16 1 24, 36 1 23, 40 1 23, 44 1 23, 48 1 23, 52 1 23, 56 1 23, 60 1 23, 64 1 23, 100 1 23, 104 1 23, 108 1 23, 112 1 23, 116 1 23, 120 1 23, 124 1 23, 128 1 23, 132 1 23, 136 1 23, 140 1 23, + +DOMAIN: DOMAIN_CODE_ETSI 36 1 20, 40 1 20, 44 1 20, 48 1 20, 52 1 20, 56 1 20, 60 1 20, 64 1 20, 100 1 20, 104 1 20, 108 1 20, 112 1 20, 116 1 20, 120 1 20, 124 1 20, 128 1 20, 132 1 20, 136 1 20, 140 1 20, 149 1 20, 153 1 20, 157 1 20, 161 1 20, 165 1 20, + +DOMAIN: DOMAIN_CODE_IN 36 1 30, 40 1 30, 44 1 30, 48 1 30, 52 1 30, 56 1 30, 60 1 30, 64 1 30, 149 1 30, 153 1 30, 157 1 30, 161 1 30, 165 1 30, + +DOMAIN: DOMAIN_CODE_MY 36 1 20, 40 1 20, 44 1 20, 48 1 20, 52 1 20, 56 1 20, 60 1 20, 64 1 20, 149 1 20, 153 1 20, 157 1 20, 161 1 20, 165 1 20, + +DOMAIN: DOMAIN_CODE_5G_END diff --git a/mxm_wifiex/wlan_src/mapp/uaputl/config/embedded_dhcp.conf b/mxm_wifiex/wlan_src/mapp/uaputl/config/embedded_dhcp.conf new file mode 100644 index 0000000..4417c5b --- /dev/null +++ b/mxm_wifiex/wlan_src/mapp/uaputl/config/embedded_dhcp.conf @@ -0,0 +1,9 @@ +# File : embedded_dhcp.conf + +dhcp_config={ + HostIPAddr=192.168.10.1 + StartIPAddr=192.168.10.10 + SubMask=255.255.255.0 + LeaseTime=10000 + LimitCount=5 +} diff --git a/mxm_wifiex/wlan_src/mapp/uaputl/config/sample_cal_data_bg_8688.conf b/mxm_wifiex/wlan_src/mapp/uaputl/config/sample_cal_data_bg_8688.conf new file mode 100644 index 0000000..e37f674 --- /dev/null +++ b/mxm_wifiex/wlan_src/mapp/uaputl/config/sample_cal_data_bg_8688.conf @@ -0,0 +1,42 @@ +01 00 0c 00 58 02 +00 40 68 0c 00 00 00 40 00 00 00 00 00 11 00 00 +00 11 00 10 00 00 00 00 00 00 00 00 00 00 00 00 +10 12 00 10 10 86 40 89 01 03 02 00 01 02 05 00 +01 03 05 00 17 17 00 05 00 00 00 00 00 00 00 00 +00 30 1f 11 00 00 00 70 00 00 00 00 13 00 1e 01 +00 1e 5e 15 29 5e 15 13 5c 1d 0d 0b 1d 0d 0b 29 +0d 0b 29 5c 0b 29 5c 1d 00 5c 1d 0d 00 00 00 00 +00 5c c0 0e 00 00 00 cc 00 5f 00 00 07 01 04 00 +00 00 0e 0d 00 00 00 00 00 00 00 00 00 00 00 ff +00 00 00 01 00 00 00 00 00 00 00 ff 00 00 00 01 +00 00 00 00 00 00 00 ff 00 00 00 01 00 00 00 00 +00 00 00 ff 00 00 00 01 00 00 00 00 06 3c 06 3d +00 00 00 00 00 00 00 00 00 00 00 00 +00 5c dc 25 00 00 01 28 00 6f 00 00 07 01 04 00 +00 00 0e 0d 00 00 00 00 00 00 00 00 00 08 00 07 +00 00 00 09 00 00 00 00 00 08 00 07 00 00 00 09 +00 00 00 00 00 08 00 07 00 00 00 09 00 00 00 00 +00 08 00 07 00 00 00 09 00 00 00 00 06 3c 06 3d +00 00 00 00 00 00 00 00 00 00 00 00 +00 14 9f 1f 00 00 01 3c 03 00 00 00 00 f1 0a f1 +00 fb 0d fb +00 20 dd 28 00 00 01 5c 08 86 00 88 ff 06 b1 05 +24 24 3c 42 00 00 24 18 a4 24 bc bc 3d 00 a0 8f +00 14 00 2a 00 00 01 70 00 00 30 00 01 05 1b 00 +00 00 00 01 +00 74 2c 10 00 00 01 e4 00 00 00 00 09 6a 09 b0 +0b 12 00 6c 04 0a 00 6c 03 03 00 6c 03 03 00 6c +3f ff ff 00 3f ff ff 01 3f ff ff 02 3f ff ff 03 +15 00 00 04 17 00 00 05 19 00 00 06 1b 00 00 07 +1d 00 00 08 1f 00 00 09 21 00 00 0a 23 00 00 0b +25 00 00 0c 28 00 00 0d 2a 00 00 0e 2d 00 00 0f +2f 00 00 10 32 00 00 11 34 00 00 12 3f ff ff 13 +3f ff ff 14 +00 74 84 10 ff ff ff ff 01 00 00 00 09 b0 09 ba +0a 0f 00 6c 04 09 00 6c 03 03 00 6c 03 03 00 6c +3f ff ff 00 3f ff ff 01 3f ff ff 02 3f ff ff 03 +15 00 00 04 17 00 00 05 1a 00 00 06 1c 00 00 07 +1f 00 00 08 21 00 00 09 23 00 00 0a 26 00 00 0b +2a 00 00 0c 2d 00 00 0d 31 00 00 0e 34 00 00 0f +3f ff ff 10 3f ff ff 11 3f ff ff 12 3f ff ff 13 +3f ff ff 14 diff --git a/mxm_wifiex/wlan_src/mapp/uaputl/config/uapcoex.conf b/mxm_wifiex/wlan_src/mapp/uaputl/config/uapcoex.conf new file mode 100644 index 0000000..40912f7 --- /dev/null +++ b/mxm_wifiex/wlan_src/mapp/uaputl/config/uapcoex.conf @@ -0,0 +1,22 @@ +# File : uapcoex.conf + +coex_config={ + common_config={ + bitmap=0x0 # bit 0: override CTS2RTS protection + APBTCoex=0 # enabled or not + } + sco_config={ + protectionFromQTime0=1000 + protectionFromQTime1=600 + protectionFromQTime2=0 + protectionFromQTime3=0 + scoProtectionFromRate=9 + aclFrequency=20 + } + acl_config={ + enabled=1 + btTime=40 + wlanTime=60 + aclProtectionFromRate=1 + } +} diff --git a/mxm_wifiex/wlan_src/mapp/uaputl/config/uaputl.conf b/mxm_wifiex/wlan_src/mapp/uaputl/config/uaputl.conf new file mode 100644 index 0000000..8c807a5 --- /dev/null +++ b/mxm_wifiex/wlan_src/mapp/uaputl/config/uaputl.conf @@ -0,0 +1,151 @@ +# File : uaputl.conf + + +ap_config={ + SSID="NXP Micro AP" # SSID of Micro AP, use '\' as an escape character before '"' character in SSID + BeaconPeriod=100 # Beacon period in TU + Channel=6 # Radio Channel 6 +# Channel=0,1 # auto channel select (MCS mode) +# Channel=6,2 # primary channel 6, secondary channel above. +# Channel=6,4 # primary channel 6, secondary channel below + ChanList=1,6,11 # Scan channel list +# AP_MAC=00:34:22:77:46:41 # MAC address of AP + Band=0 # 0 for 2.4GHz band + # 1 for 5GHz band + Rate=0x82,0x84,0x8b,0x96,0x0C,0x12,0x18,0x24,0x30,0x48,0x60,0x6c + # Set of data rate that a station + # in the BSS may use + # (in unit of 500 kilobit/s) + TxPowerLevel=13 # Transmit power level in dBm + BroadcastSSID=1 # Broadcast SSID feature + # 1: Enable 0:Disable + RTSThreshold=2347 # RTS threshold value + FragThreshold=2346 # Fragmentation threshold value + DTIMPeriod=1 # DTIM period in beacon periods + MCBCdataRate=0 # MCBC rate to use for packet transmission + # 0:auto + # >0 fix rate (in unit of 500 kilobit/s) +# TxBeaconRate=0 # Beacon rate to use for Beacon transmission + # 0:auto + # >0 fix rate (in unit of 500 kilobit/s) + PktFwdCtl=1 # Packet forwarding control + # 0: forward all packets to the host + # 1: firmware handles intr-BSS packets + StaAgeoutTimer=1800 # Inactive client station age out timer value + # in units of 100ms + PSStaAgeoutTimer=400 # Inactive client PS station age out timer value + # in units of 100ms + MaxStaNum=10 # Max number of stations allowed to connect + Retrylimit=7 # Retry limit to use for packet transmissions + AuthMode=0 # 0:Open authentication + # 1:shared key authentication + # 3: WPA3 SAE + Protocol=1 # protocol to use + # 1: No security 2: Static WEP + # 8: WPA 32: WPA2 40:WPA2 Mixed Mode + # 64: WPA3 SAE + RSNReplayProtection=0 # RSN replay protection 0: disabled, 1: enabled + PairwiseUpdateTimeout=100 #Pairwise Handshake update timeout: 100ms + PairwiseHandshakeRetries=3 #Pairwise Handshake retries: 3 + GroupwiseUpdateTimeout=100 #Groupwise Handshake update timeout: 100ms + GroupwiseHandshakeRetries=3 #Groupwise Handshake retries: 3 + +# **** WEP security setting****** +# KeyIndex=0 # Index of WEP key to use (0 to 3) +# Sample Key configurations are +# Key_0="55555" +# Key_1=1234567890 +# Key_2="1234567890123" +# Key_3=12345678901234567890123456 + +# **** Pairwise Cipher setting****** +# Configure both of the following for Protocol=40 +# PwkCipherWPA=4 # Pairwise cipher type + # 4: TKIP 8: AES CCMP + # 12: AES CCMP + TKIP +# PwkCipherWPA2=8 # Pairwise cipher type + # 4: TKIP 8: AES CCMP + # 12: AES CCMP + TKIP + +# **** Group Cipher setting****** + +# GwkCipher=4 # group cipher type + # 4: TKIP 8: AES CCMP + +# PSK="1234567890" # WPA/WPA2 passphrase + GroupRekeyTime= 86400 # Group key re-key interval, in second. + # 0 mean never re-key + + Enable11n=1 # 1 to enable, 0 to disable + HTCapInfo=0x111c # HTCapInfo + # Bit 15-13: Reserved set to 0 + # Bit 12: DSS/CCK mode in 40MHz enable/disable + # Bit 11-10: Reserved set to 0 + # Bit 9-8: Reserved set to 0x01 + # Bit 7: Reserved set to 0 + # Bit 6: Short GI in 40 Mhz enable/disable + # Bit 5: Short GI in 20 Mhz enable/disable + # Bit 4: Green field enable/disble + # Bit 3-2: Reserved set to 1 + # Bit 1: 20/40 Mhz enable disable. + # Bit 0: Reserved set to 0 + AMPDU=0x03 # AMPDU + # Bit 7-5: Reserved set to 0 + # Bit 4-2: Minimum MPDU Start spacing + # Set to 0 for no restriction + # Set to 1 for 1/4 us + # Set to 2 for 1/2 us + # Set to 3 for 1 us + # Set to 4 for 2 us + # Set to 5 for 4 us + # Set to 6 for 8 us + # Set to 7 for 16 us + # Bit 1-0: Max A-MPDU length + HT_MCS_MAP=0x0000ffff # Bit 7-0: MCS_SET_0 + # Bit 15-8:MCS_SET_1 +# Enable2040Coex=1 #Enable 20/40 coex feature + + #802.11D specific configuration + 11d_enable=0 # 0-disable 1-enable +# country=US # country information +# PreambleType=2 #0 to set auto, 1 to set short, 2 to set long preamble +} + + + +ap_mac_filter={ + FilterMode=0 # Mode of filter table + # 0: filter table is disabled + # 1: allow MAC address in the filter table to associate + # 2: block MAC address in the filter table + Count=0 # Number of entries in filter table,up to 16 +#Sample mac settings are +# mac_1=00:50:23:45:76:22 # mac address +# mac_2=00:34:22:77:46:34 # mac address +} + +# Wmm param setting +Wmm_parameters={ + Qos_info=0x80 + AC_BE + Aifsn=1 + Ecw_max=1 + Ecw_min=1 + Tx_op=1 + AC_BK + Aifsn=2 + Ecw_max=2 + Ecw_min=2 + Tx_op=2 + AC_VI + Aifsn=3 + Ecw_max=3 + Ecw_min=3 + Tx_op=3 + AC_VO + Aifsn=4 + Ecw_max=4 + Ecw_min=4 + Tx_op=4 +} + diff --git a/mxm_wifiex/wlan_src/mapp/uaputl/config/uaputl_wifidirect.conf b/mxm_wifiex/wlan_src/mapp/uaputl/config/uaputl_wifidirect.conf new file mode 100644 index 0000000..fa1017c --- /dev/null +++ b/mxm_wifiex/wlan_src/mapp/uaputl/config/uaputl_wifidirect.conf @@ -0,0 +1,80 @@ +# File : uaputl_wifidirect.conf + + +ap_config={ + SSID="DIRECT-" # SSID for WifiDirect + BeaconPeriod=100 # Beacon period in TU + Channel=6 # Radio Channel 6 +# Channel=0,1 # auto channel select (MCS mode) +# Channel=6,2 # primary channel 6, secondary channel above. +# Channel=6,4 # primary channel 6, secondary channel below + ChanList=1,6,11 # Scan channel list +# AP_MAC=00:34:22:77:46:41 # MAC address of AP + Rate=0x8C,0x12,0x18,0x24,0x30,0x48,0x60,0x6c + # Set of data rate that a station + # in the BSS may use + # (in unit of 500 kilobit/s) + TxPowerLevel=13 # Transmit power level in dBm + BroadcastSSID=1 # Broadcast SSID feature + # 1: Enable 0:Disable + RTSThreshold=2347 # RTS threshold value + FragThreshold=2346 # Fragmentation threshold value + DTIMPeriod=1 # DTIM period in beacon periods + MCBCdataRate=0 # MCBC rate to use for packet transmission + # 0:auto + # >0 fix rate (in unit of 500 kilobit/s) + PktFwdCtl=1 # Packet forwarding control + # 0: forward all packets to the host + # 1: firmware handles intr-BSS packets + StaAgeoutTimer=1800 # Inactive client station age out timer value + # in units of 100ms + PSStaAgeoutTimer=400 # Inactive client PS station age out timer value + # in units of 100ms + MaxStaNum=7 # Max number of stations allowed to connect + Retrylimit=7 # Retry limit to use for packet transmissions + AuthMode=0 # 0:Open authentication + # 1:shared key authentication + Protocol=32 # protocol to use + # 1: No security 2: Static WEP + # 8: WPA 32: WPA2 40:WPA2 Mixed Mode + RSNReplayProtection=0 # RSN replay protection 0: disabled, 1: enabled + PairwiseUpdateTimeout=2000 #Pairwise Handshake update timeout: 2000ms + PairwiseHandshakeRetries=3 #Pairwise Handshake retries: 3 + GroupwiseUpdateTimeout=2000 #Groupwise Handshake update timeout: 2000ms + GroupwiseHandshakeRetries=3 #Groupwise Handshake retries: 3 + + PwkCipherWPA2=8 # Pairwise cipher type + GwkCipher=8 # group cipher type + PSK="1234567890" # WPA/WPA2 passphrase + + GroupRekeyTime= 86400 # Group key re-key interval, in second. + # 0 mean never re-key + + Enable11n=1 # 1 to enable, 0 to disable + HTCapInfo=0x111c # HTCapInfo + # Bit 15-13: Reserved set to 0 + # Bit 12: DSS/CCK mode in 40MHz enable/disable + # Bit 11-10: Reserved set to 0 + # Bit 9-8: Reserved set to 0x01 + # Bit 7: Reserved set to 0 + # Bit 6: Short GI in 40 Mhz enable/disable + # Bit 5: Short GI in 20 Mhz enable/disable + # Bit 4: Green field enable/disble + # Bit 3-2: Reserved set to 1 + # Bit 1: 20/40 Mhz enable disable. + # Bit 0: Reserved set to 0 + AMPDU=0x03 # AMPDU + # Bit 7-5: Reserved set to 0 + # Bit 4-2: Minimum MPDU Start spacing + # Set to 0 for no restriction + # Set to 1 for 1/4 us + # Set to 2 for 1/2 us + # Set to 3 for 1 us + # Set to 4 for 2 us + # Set to 5 for 4 us + # Set to 6 for 8 us + # Set to 7 for 16 us + # Bit 1-0: Max A-MPDU length + #802.11D specific configuration + 11d_enable=0 # 0-disable 1-enable +} diff --git a/mxm_wifiex/wlan_src/mapp/uaputl/uapcmd.c b/mxm_wifiex/wlan_src/mapp/uaputl/uapcmd.c new file mode 100644 index 0000000..949adf5 --- /dev/null +++ b/mxm_wifiex/wlan_src/mapp/uaputl/uapcmd.c @@ -0,0 +1,7563 @@ +/** @file uapcmd.c + * + * @brief This file contains the handling of command. + * + * + * Copyright 2014-2020 NXP + * + * NXP CONFIDENTIAL + * The source code contained or described herein and all documents related to + * the source code (Materials) are owned by NXP, its + * suppliers and/or its licensors. Title to the Materials remains with NXP, + * its suppliers and/or its licensors. The Materials contain + * trade secrets and proprietary and confidential information of NXP, its + * suppliers and/or its licensors. The Materials are protected by worldwide copyright + * and trade secret laws and treaty provisions. No part of the Materials may be + * used, copied, reproduced, modified, published, uploaded, posted, + * transmitted, distributed, or disclosed in any way without NXP's prior + * express written permission. + * + * No license under any patent, copyright, trade secret or other intellectual + * property right is granted to or conferred upon you by disclosure or delivery + * of the Materials, either expressly, by implication, inducement, estoppel or + * otherwise. Any license under such intellectual property rights must be + * express and approved by NXP in writing. + * + */ +/**************************************************************************** +Change log: + 03/01/08: Initial creation +****************************************************************************/ + +/**************************************************************************** + Header files +****************************************************************************/ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "uaputl.h" +#include "uapcmd.h" + +extern struct option cmd_options[]; +/**************************************************************************** + Local functions +****************************************************************************/ +/** + * @brief Show usage information for the sys_cfg_ap_mac_address + * command + * + * $return N/A + */ +void +print_sys_cfg_ap_mac_address_usage(void) +{ + printf("\nUsage : sys_cfg_ap_mac_address [AP_MAC_ADDRESS]\n"); + printf("\nIf AP_MAC_ADDRESS is provided, a 'set' is performed, else a 'get' is performed.\n"); + return; +} + +/** + * @brief Show usage information for the sys_cfg_ssid command + * + * $return N/A + */ +void +print_sys_cfg_ssid_usage(void) +{ + printf("\nUsage : sys_cfg_ssid [SSID]\n"); + printf("\nIf SSID is provided, a 'set' is performed, else a 'get' is performed.\n"); + return; +} + +/** + * @brief Show usage information for the sys_cfg_beacon_period + * command + * + * $return N/A + */ +void +print_sys_cfg_beacon_period_usage(void) +{ + printf("\nUsage : sys_cfg_beacon_period [BEACON_PERIOD]\n"); + printf("\nIf BEACON_PERIOD is provided, a 'set' is performed, else a 'get' is performed.\n"); + return; +} + +/** + * @brief Show usage information for the sys_cfg_dtim_period + * command + * + * $return N/A + */ +void +print_sys_cfg_dtim_period_usage(void) +{ + printf("\nUsage : sys_cfg_dtim_period [DTIM_PERIOD]\n"); + printf("\nIf DTIM_PERIOD is provided, a 'set' is performed, else a 'get' is performed.\n"); + return; +} + +/** + * @brief Show usage information for the bss_status + * command + * + * $return N/A + */ +void +print_sys_cfg_bss_status_usage(void) +{ + printf("\nUsage : sys_cfg_bss_status\n"); + return; +} + +/** + * @brief Show usage information for the sys_cfg_channel + * command + * + * $return N/A + */ +void +print_sys_cfg_channel_usage(void) +{ + printf("\nUsage : sys_cfg_channel [CHANNEL] [MODE]\n"); + printf("\nIf CHANNEL is provided, a 'set' is performed, else a 'get' is performed."); + printf("\n MODE: band config mode "); + printf("\n Bit 0: ACS mode enable/disable"); + printf("\n Bit 1: secondary channel is above primary channel"); + printf("\n Bit 2: secondary channel is below primary channel"); + printf("\n"); + return; +} + +/** + * @brief Show usage information for the sys_cfg_channel + * command + * + * $return N/A + */ +void +print_sys_cfg_channel_ext_usage(void) +{ + printf("\nUsage : sys_cfg_channel_ext [CHANNEL] [BAND] [MODE]\n"); + printf("\nIf CHANNEL is provided, a 'set' is performed, else a 'get' is performed."); + printf("\n BAND:"); + printf("\n 0 : 2.4GHz operation"); + printf("\n 1 : 5GHz operation"); + printf("\n MODE: band config mode "); + printf("\n Bit 0: ACS mode enable/disable"); + printf("\n Bit 1: secondary channel is above primary channel"); + printf("\n Bit 2: secondary channel is below primary channel"); + printf("\n"); + return; +} + +/** + * @brief Show usage information for the sys_cfg_scan_channels + * command + * + * $return N/A + */ +void +print_sys_cfg_scan_channels_usage(void) +{ + printf("\nUsage : sys_cfg_scan_channels [CHANNEL[.BAND]]\n"); + printf("\nIf CHANNELS and BANDS are provided, a 'set' is performed, else a 'get' is performed.\n"); + printf("\n BAND : band of operation"); + printf("\n 0 : 2.4GHZ"); + printf("\n 1 : 5GHZ\n"); + return; +} + +/** + * @brief Show usage information for the sys_cfg_rates_ext command + * + * $return N/A + */ +void +print_sys_cfg_rates_ext_usage(void) +{ + printf("\nUsage : sys_cfg_rates_ext [rates RATES] [mbrate RATE]\n"); + printf("\nIf 'Rate' provided, a 'set' is performed else a 'get' is performed"); + printf("\nRATES is provided as a set of data rates, in unit of 500 kilobits"); + printf("\nA rate with MSB bit is basic rate, i.e 0x82 is basic rate.\n"); + printf("\nFollowing is the list of supported rates in units of 500 Kbps:"); + printf("\nDecimal: (2, 4, 11, 22, 12, 18, 24, 36, 48, 72, 96, 108)"); + printf("\nHex: (0x02, 0x04, 0x0b, 0x16, 0x0C, 0x12, 0x18, 0x24, 0x30, 0x48, 0x60, 0x6c)"); + printf("\nBasic rates: (0x82, 0x84, 0x8b, 0x96, 0x8C, 0x92, 0x98, 0xA4, 0xB0, 0xC8, 0xE0, 0xEc)\n"); + printf("\nRates 2, 4, 11 and 22 (in units of 500 Kbps) must be present in either of basic or"); + printf("\nnon-basic rates. If OFDM rates are enabled then 12, 24 and 48 (in units of 500 Kbps)"); + printf("\nmust be present in either basic or non-basic rates"); + printf("\nEach rate must be separated by a space."); + printf("\nrates followed by RATES for setting operational rates."); + printf("\nmbrate followed by RATE for setting multicast and broadcast rate."); + return; +} + +/** + * @brief Show usage information for the sys_cfg_rates command + * + * $return N/A + */ +void +print_sys_cfg_rates_usage(void) +{ + printf("\nUsage : sys_cfg_rates [RATES]\n"); + printf("\n[RATES] is set of data rates in unit of 500 kbps and each rate can be"); + printf("\nentered in hexadecimal or decimal format. Rates must be separated by"); + printf("\nspace. Duplicate Rate fields are not allowed"); + printf("\nA rate with MSB bit is basic rate, i.e 0x82 is basic rate."); + printf("\nFollowing is the list of supported rates in units of 500 Kbps:"); + printf("\nDecimal: (2, 4, 11, 22, 12, 18, 24, 36, 48, 72, 96, 108)"); + printf("\nHex: (0x02, 0x04, 0x0b, 0x16, 0x0C, 0x12, 0x18, 0x24, 0x30, 0x48, 0x60, 0x6c)"); + printf("\nBasic rates: (0x82, 0x84, 0x8b, 0x96, 0x8C, 0x92, 0x98, 0xA4, 0xB0, 0xC8, 0xE0, 0xEc)\n"); + return; +} + +/** + * @brief Show usage information for the sys_cfg_tx_power + * command + * + * $return N/A + */ +void +print_sys_cfg_tx_power_usage(void) +{ + printf("\nUsage : sys_cfg_tx_power [TX_POWER]\n"); + printf("\nIf TX_POWER is provided, a 'set' is performed, else a 'get' is performed."); + printf("\nTX_POWER is represented in dBm.\n"); + return; +} + +/** + * @brief Show usage information for the sys_cfg_bcast_ssid_ctl + * command + * + * $return N/A + */ +void +print_sys_cfg_bcast_ssid_ctl_usage(void) +{ + printf("\nUsage : sys_cfg_bcast_ssid_ctl [0|1]\n"); + printf("\nOptions: 0 - Disable SSID broadcast,send empty SSID (length=0) in beacon"); + printf("\n 1 - Enable SSID broadcast"); + printf("\n 2 - Disable SSID broadcast, clear SSID (ACSII 0) in beacon, but keep the original length"); + printf("\n empty - Get current SSID broadcast setting\n"); + return; +} + +/** + * @brief Show usage information for the sys_cfg_rsn_replay_prot + * command + * + * $return N/A + */ +void +print_sys_cfg_rsn_replay_prot_usage(void) +{ + printf("\nUsage : sys_cfg_rsn_replay_prot [0|1]\n"); + printf("\nOptions: 0 - Disable RSN replay protection"); + printf("\n 1 - Enable RSN replay protection"); + printf("\n empty - Get current RSN replay protection setting\n"); + return; +} + +/** + * @brief Show usage information for the sys_cfg_preamble_ctl + * command + * + * $return N/A + */ +void +print_sys_cfg_preamble_ctl_usage(void) +{ + printf("\nUsage : sys_cfg_preamble_ctl\n"); + printf("\nOptions: 0 - Auto/Default"); + printf("\n 1 - Short Preamble"); + printf("\n 2 - Long Preamble\n"); + return; +} + +/** + * @brief Show usage information for the sys_cfg_antenna_ctl + * command + * + * $return N/A + */ +void +print_sys_cfg_antenna_ctl_usage(void) +{ + printf("\nUsage : sys_cfg_antenna_ctl [MODE]\n"); + printf("\nOptions: ANTENNA : 0 - Rx antenna"); + printf("\n 1 - Tx antenna"); + printf("\n MODE : 0 - Antenna A"); + printf("\n 1 - Antenna B"); + printf("\n empty - Get current antenna settings\n"); + return; +} + +/** + * @brief Show usage information for the sys_cfg_rts_threshold + * command + * + * $return N/A + */ +void +print_sys_cfg_rts_threshold_usage(void) +{ + printf("\nUsage : sys_cfg_rts_threshold [RTS_THRESHOLD]\n"); + printf("\nIf RTS_THRESHOLD is provided, a 'set' is performed, else a 'get' is performed.\n"); + return; +} + +/** + * @brief Show usage information for the sys_cfg_frag_threshold + * command + * + * $return N/A + */ +void +print_sys_cfg_frag_threshold_usage(void) +{ + printf("\nUsage : sys_cfg_frag_threshold [FRAG_THRESHOLD]\n"); + printf("\nIf FRAG_THRESHOLD is provided, a 'set' is performed, else a 'get' is performed."); + printf("\nFragment threshold should between 256 and 2346.\n"); + return; +} + +/** + * @brief Show usage information for the sys_cfg_tx_beacon_rate + * command + * + * $return N/A + */ +void +print_sys_cfg_tx_beacon_rates_usage(void) +{ + printf("\nUsage : sys_cfg_tx_beacon_rate [TX_DATA_RATE]\n"); + printf("\nOptions: 0 - Auto rate"); + printf("\n >0 - Set specified beacon rate"); + printf("\n empty - Get current beacon rate"); + printf("\nFollowing is the list of supported rates in units of 500 Kbps"); + printf("\nDecimal: (2, 4, 11, 22, 12, 18, 24, 36, 48, 72, 96, 108)"); + printf("\nHex: (0x02, 0x04, 0x0b, 0x16, 0x0C, 0x12, 0x18, 0x24, 0x30, 0x48, 0x60, 0x6c)"); + printf("\nOnly zero or rates currently configured are allowed.\n"); + return; +} + +/** + * @brief Show usage information for the sys_cfg_mcbc_data_rate + * command + * + * $return N/A + */ +void +print_sys_cfg_mcbc_data_rates_usage(void) +{ + printf("\nUsage : sys_cfg_mcbc_data_rate [MCBC_DATA_RATE]\n"); + printf("\nOptions: 0 - Auto rate"); + printf("\n >0 - Set specified MCBC data rate"); + printf("\n empty - Get current MCBC data rate"); + printf("\nFollowing is the list of supported rates in units of 500 Kbps"); + printf("\nDecimal: (2, 4, 11, 22, 12, 18, 24, 36, 48, 72, 96, 108)"); + printf("\nHex: (0x02, 0x04, 0x0b, 0x16, 0x0C, 0x12, 0x18, 0x24, 0x30, 0x48, 0x60, 0x6c)"); + printf("\nOnly zero or one of the basic rates currently configured are allowed.\n"); + return; +} + +/** + * @brief Show usage information for the sys_cfg_auth command + * + * $return N/A + */ +void +print_sys_cfg_auth_usage(void) +{ + printf("\nUsage : sys_cfg_auth [AUTHMODE]\n"); + printf("\nOptions: AUTHMODE : 0 - Open authentication"); + printf("\n 1 - Shared key authentication"); + printf("\n 255 - Auto (Open and Shared key) authentication"); + printf("\n empty - Get current authenticaton mode\n"); + return; +} + +/** + * @brief Show usage information for the sys_cfg_pkt_fwd_ctl command + * + * $return N/A + */ +void +print_sys_cfg_pkt_fwd_ctl_usage(void) +{ + printf("\nUsage : sys_cfg_pkt_fwd_ctl [PKT_FWD_CTRL]\n"); + printf("\nPKT_FWD_CTRL: bit 0 -- Packet forwarding handled by Host (0) or Firmware (1)"); + printf("\n bit 1 -- Intra-BSS broadcast packets are allowed (0) or denied (1)"); + printf("\n bit 2 -- Intra-BSS unicast packets are allowed (0) or denied (1)"); + printf("\n bit 3 -- Inter-BSS unicast packets are allowed (0) or denied (1)"); + printf("\n empty - Get current packet forwarding setting\n"); + return; +} + +/** + * @brief Show usage information for the sys_cfg_sta_ageout_timer + * command + * + * $return N/A + */ +void +print_sys_cfg_sta_ageout_timer_usage(void) +{ + printf("\nUsage : sys_cfg_sta_ageout_timer [STA_AGEOUT_TIMER]\n"); + printf("\nIf STA_AGEOUT_TIMER is provided, a 'set' is performed, else a 'get' is performed."); + printf("\nSTA_AGEOUT_TIMER is represented in units of 100 ms."); + printf("\nValue of 0 will mean that stations will never be aged out."); + printf("\nThe value should be between 100 and 864000.\n"); + return; +} + +/** + * @brief Show usage information for the sys_cfg_ps_sta_ageout_timer + * command + * + * $return N/A + */ +void +print_sys_cfg_ps_sta_ageout_timer_usage(void) +{ + printf("\nUsage : sys_cfg_ps_sta_ageout_timer [PS_STA_AGEOUT_TIMER]\n"); + printf("\nIf PS_STA_AGEOUT_TIMER is provided, a 'set' is performed, else a 'get' is performed."); + printf("\nPS_STA_AGEOUT_TIMER is represented in units of 100 ms."); + printf("\nValue of 0 will mean that stations will never be aged out."); + printf("\nThe value should be between 100 and 864000.\n"); + return; +} + +/** + * @brief Show usage information for the sys_cfg_protocol command + * + * $return N/A + */ +void +print_sys_cfg_protocol_usage(void) +{ + printf("\nUsage : sys_cfg_protocol [PROTOCOL] [AKM_SUITE]\n"); + printf("\nOptions: PROTOCOL: 1 - No RSN"); + printf("\n 2 - WEP Static"); + printf("\n 8 - WPA"); + printf("\n 32 - WPA2"); + printf("\n 40 - WPA2 Mixed"); + printf("\n 256 - WPA3 SAE"); + printf("\n empty - Get current protocol"); + printf("\n AKM_SUITE: bit 0 - KEY_MGMT_EAP"); + printf("\n bit 1 - KEY_MGMT_PSK"); + printf("\n bit 2 - KEY_MGMT_NONE"); + printf("\n bit 8 - KEY_MGMT_PSK_SHA256"); + printf("\n bit 10 - KEY_MGMT_WPA3_SAE"); + printf("\n"); + return; +} + +/** + * @brief Show usage information for the sys_cfg_wep_key + * command + * + * $return N/A + */ +void +print_sys_cfg_wep_key_usage(void) +{ + printf("\nUsage : sys_cfg_wep_key "); + printf("[INDEX_0 IS_DEFAULT KEY_0] [INDEX_1 IS_DEFAULT KEY_1] [INDEX_2 IS_DEFAULT KEY_2] [INDEX_3 IS_DEFAULT KEY_3]\n"); + printf("[Index_0] [Index_1] [Index_2] [Index_3]\n"); + printf("\nOptions: INDEX_* : 0 - KeyIndex is 0"); + printf("\n 1 - KeyIndex is 1"); + printf("\n 2 - KeyIndex is 2"); + printf("\n 3 - KeyIndex is 3"); + printf("\n IS_DEFAULT : 0 - KeyIndex is not the default"); + printf("\n 1 - KeyIndex is the default transmit key"); + printf("\n KEY_* : Key value"); + printf("\n Index_*: 0 - Get key 0 setting"); + printf("\n 1 - Get key 1 setting"); + printf("\n 2 - Get key 2 setting"); + printf("\n 3 - Get key 3 setting"); + printf("\n empty - Get current WEP key settings\n"); + return; +} + +/** + * @brief Show usage information for the sys_cfg_cipher + * command + * + * $return N/A + */ +void +print_sys_cfg_cipher_usage(void) +{ + printf("\nUsage : sys_cfg_cipher [PAIRWISE_CIPHER GROUP_CIPHER]\n"); + printf("\nOptions: PAIRWISE_CIPHER: 0 - NONE"); + printf("\n 4 - TKIP"); + printf("\n 8 - AES CCMP"); + printf("\n 12 - AES CCMP + TKIP"); + printf("\n GROUP_CIPHER : 0 - NONE"); + printf("\n 4 - TKIP"); + printf("\n 8 - AES CCMP"); + printf("\n empty - Get current cipher settings\n"); + return; +} + +/** + * @brief Show usage information for the sys_cfg_pwk_cipher + * command + * + * $return N/A + */ +void +print_sys_cfg_pwk_cipher_usage(void) +{ + printf("\nUsage : sys_cfg_pwk_cipher [] [PAIRWISE_CIPHER]\n"); + printf("\nOptions: PROTOCOL :"); + printf("\n 8 - WPA"); + printf("\n 32 - WPA2"); + printf("\n PAIRWISE_CIPHER : "); + printf("\n 4 - TKIP"); + printf("\n 8 - AES CCMP"); + printf("\n 12 - AES CCMP + TKIP"); + printf("\n WPA/TKIP cannot be used when uAP operates in 802.11n mode.\n"); + printf("\n If only PROTOCOL is given, pairwise cipher for that protocol is displayed\n"); + printf("\n empty - Get current protocol and pairwise cipher settings\n"); + return; +} + +/** + * @brief Show usage information for the sys_cfg_gwk_cipher + * command + * + * $return N/A + */ +void +print_sys_cfg_gwk_cipher_usage(void) +{ + printf("\nUsage : sys_cfg_gwk_cipher [GROUP_CIPHER]\n"); + printf("\n GROUP_CIPHER :"); + printf("\n 4 - TKIP"); + printf("\n 8 - AES CCMP"); + printf("\n empty - Get current group cipher settings\n"); + return; +} + +/** + * @brief Show usage information for the sys_cfg_group_rekey_timer command + * + * $return N/A + */ +void +print_sys_cfg_group_rekey_timer_usage(void) +{ + printf("\nUsage : sys_cfg_group_rekey_timer [GROUP_REKEY_TIMER]\n"); + printf("\nOptions: GROUP_REKEY_TIME is represented in seconds"); + printf("\n empty - Get current group re-key time\n"); + return; +} + +/** + * @brief Show usage information for the sys_cfg_wpa_passphrase + * command + * + * $return N/A + */ +void +print_sys_cfg_wpa_passphrase_usage(void) +{ + printf("\nUsage : sys_cfg_wpa_passphrase [PASSPHRASE]\n"); + printf("\nIf PASSPHRASE is provided, a 'set' is performed, else a 'get' is performed.\n"); + return; +} + +/** + * @brief Show usage information for the sys_cfg_wpa3_sae_password + * command + * + * $return N/A + */ +void +print_sys_cfg_wpa3_sae_password_usage(void) +{ + printf("\nUsage : sys_cfg_wpa3_sae_password [PASSWORD]\n"); + printf("\nIf PASSWORD is provided, a 'set' is performed, else a 'get' is performed.\n"); + return; +} + +/** + * @brief Show usage information for the sta_filter_table command + * + * $return N/A + */ +void +print_sta_filter_table_usage(void) +{ + printf("\nUsage : sta_filter_table \n"); + printf("\nOptions: FILTERMODE : 0 - Disable filter table"); + printf("\n 1 - allow MAC addresses specified in the allowed list"); + printf("\n 2 - block MAC addresses specified in the banned list"); + printf("\n MACADDRESS_LIST is the list of MAC addresses to be acted upon. Each"); + printf("\n MAC address must be separated with a space. Maximum of"); + printf("\n 16 MAC addresses are supported."); + printf("\n empty - Get current mac filter settings\n"); + return; +} + +/** + * @brief Show usage information for the sys_cfg_max_sta_num command + * + * $return N/A + */ +void +print_sys_cfg_max_sta_num_usage(void) +{ + printf("\nUsage : sys_cfg_max_sta_num [STA_NUM]\n"); + printf("\nIf STA_NUM is provided, a 'set' is performed, else a 'get' is performed.\n"); + return; +} + +/** + * @brief Show usage information for the sys_cfg_retry_limit command + * + * $return N/A + */ +void +print_sys_cfg_retry_limit_usage(void) +{ + printf("\nUsage : sys_cfg_retry_limit [RETRY_LIMIT]\n"); + printf("\nIf RETRY_LIMIT is provided, a 'set' is performed, else a 'get' is performed."); + printf("\nRETRY_LIMIT should be greater than or equal to zero and less than or equal to 14\n"); + return; +} + +/** + * @brief Show usage information for the sys_cfg_sticky_tim_config command + * + * $return N/A + */ +void +print_sys_cfg_sticky_tim_config_usage(void) +{ + printf("\nUsage : sys_cfg_sticky_tim_config [ENABLE] [ ]\n"); + printf("\nOptions: ENABLE 0 - disable"); + printf("\n 1 - enable"); + printf("\n 2 - enable with previous values of DURATION and STICKY_BITMASK"); + printf("\n DURATION: duration for sticky TIM"); + printf("\n STICKY_BITMASK: Bitmask for sticky TIM configuartion"); + printf("\n empty - Get current sticky TIM configuration\n"); + return; +} + +/** + * @brief Show usage information for the sys_cfg_sticky_tim_mac_addr command + * + * $return N/A + */ +void +print_sys_cfg_sticky_tim_sta_mac_addr_usage(void) +{ + printf("\nUsage : sys_cfg_sticky_tim_sta_mac_addr [CONTROL] [STA_MAC_ADDRESS]\n"); + printf("\nOptions: CONTROL: sticky TIM config for given station"); + printf("\n STA_MAC_ADDRESS: station MAC address"); + printf("\n if only STA_MAC_ADDRESS is given - Get sticky TIM configuration for that station\n"); + printf("\n empty - Get current sticky TIM configuration for all associated stations\n"); + return; +} + +/** + * @brief Show usage information for the sys_cfg_2040_coex command + * + * $return N/A + */ +void +print_sys_cfg_2040_coex_usage(void) +{ + printf("\nUsage : sys_cfg_2040_coex [ENABLE]\n"); + printf("\nOptions: ENABLE 0 - disable"); + printf("\n 1 - enable"); + printf("\n empty - Get current 20/40 BSS coexistence configuration\n"); + return; +} + +/** + * @brief Show usage information for the sys_cfg_eapol_pwk_hsk command + * + * $return N/A + */ +void +print_sys_cfg_eapol_pwk_hsk_usage(void) +{ + printf("\nUsage : sys_cfg_eapol_pwk_hsk [ ]\n"); + printf("\nIf TIMEOUT and number of RETRIES are both provided, a 'set' is performed."); + printf("\nIf no parameter is provided,a 'get' is performed."); + printf("\nTIMEOUT and number of RETRIES should be greater than or equal to zero\n"); + return; +} + +/** + * @brief Show usage information for the sys_cfg_eapol_gwk_hsk command + * + * $return N/A + */ +void +print_sys_cfg_eapol_gwk_hsk_usage(void) +{ + printf("\nUsage : sys_cfg_eapol_gwk_hsk [ ]\n"); + printf("\nIf TIMEOUT and number of RETRIES are both provided, a 'set' is performed."); + printf("\nIf no parameter is provided,a 'get' is performed."); + printf("\nTIMEOUT and number of RETRIES should be greater than or equal to zero\n"); + return; +} + +/** + * @brief Show usage information for the cfg_data command + * + * $return N/A + */ +void +print_cfg_data_usage(void) +{ + printf("\nUsage : cfg_data [*.conf]\n"); + printf("\n type : 2 -- cal data"); + printf("\n *.conf : file contain configuration data"); + printf("\n empty - get current configuration data\n"); + return; +} + +/** + * @brief Get configured operational rates. + * + * @param rates Operational rates allowed are + * stored at this pointer + * @return Number of basic rates allowed. + * -1 if a failure + */ +int +get_sys_cfg_rates(t_u8 *rates) +{ + apcmdbuf_sys_configure *cmd_buf = NULL; + tlvbuf_rates *tlv = NULL; + t_u8 *buffer = NULL; + t_u16 cmd_len; + int ret = UAP_FAILURE; + int i = 0; + int rate_cnt = 0; + /* Initialize the command length */ + cmd_len = + sizeof(apcmdbuf_sys_configure) + sizeof(tlvbuf_rates) + + MAX_DATA_RATES; + /* Initialize the command buffer */ + buffer = (t_u8 *)malloc(cmd_len); + if (!buffer) { + printf("ERR:Cannot allocate buffer for command!\n"); + return -1; + } + memset(buffer, 0, cmd_len); + + /* Locate headers */ + cmd_buf = (apcmdbuf_sys_configure *)buffer; + tlv = (tlvbuf_rates *)(buffer + sizeof(apcmdbuf_sys_configure)); + + /* Fill the command buffer */ + cmd_buf->cmd_code = APCMD_SYS_CONFIGURE; + cmd_buf->size = cmd_len; + cmd_buf->seq_num = 0; + cmd_buf->result = 0; + tlv->tag = MRVL_RATES_TLV_ID; + cmd_buf->action = ACTION_GET; + tlv->length = MAX_DATA_RATES; + + endian_convert_tlv_header_out(tlv); + /* Send the command */ + ret = uap_ioctl((t_u8 *)cmd_buf, &cmd_len, cmd_len); + endian_convert_tlv_header_in(tlv); + /* Process response */ + if (ret == UAP_SUCCESS) { + /* Verify response */ + if ((cmd_buf->cmd_code != + (APCMD_SYS_CONFIGURE | APCMD_RESP_CHECK)) || + (tlv->tag != MRVL_RATES_TLV_ID)) { + printf("ERR:Corrupted response! cmd_code=%x, Tlv->tag=%x\n", cmd_buf->cmd_code, tlv->tag); + free(buffer); + return -1; + } + + /* Copy response */ + if (cmd_buf->result == CMD_SUCCESS) { + for (i = 0; i < tlv->length; i++) { + if (tlv->operational_rates[i] != 0) { + rates[rate_cnt++] = + tlv->operational_rates[i]; + } + } + } else { + printf("ERR:Could not get operational rates!\n"); + } + } else { + printf("ERR:Command sending failed!\n"); + } + if (buffer) + free(buffer); + return rate_cnt; +} + +/** + * @brief Check rate is valid or not. + * + * @param rate Rate for check + * + * @return UAP_SUCCESS or UAP_FAILURE + */ +int +is_tx_rate_valid(t_u8 rate) +{ + int rate_cnt = 0; + int i; + t_u8 rates[MAX_DATA_RATES]; + + rate_cnt = get_sys_cfg_rates((t_u8 *)&rates); + if (rate_cnt > 0) { + for (i = 0; i < rate_cnt; i++) { + if (rate == (rates[i] & ~BASIC_RATE_SET_BIT)) { + return UAP_SUCCESS; + } + } + } + return UAP_FAILURE; +} + +/** + * @brief Check mcbc rate is valid or not. + * + * @param rate Rate for check + * + * @return UAP_SUCCESS or UAP_FAILURE + */ +int +is_mcbc_rate_valid(t_u8 rate) +{ + int rate_cnt = 0; + int i; + t_u8 rates[MAX_DATA_RATES]; + + rate_cnt = get_sys_cfg_rates((t_u8 *)&rates); + if (rate_cnt > 0) { + for (i = 0; i < rate_cnt; i++) { + if (rates[i] & BASIC_RATE_SET_BIT) { + if (rate == (rates[i] & ~BASIC_RATE_SET_BIT)) { + return UAP_SUCCESS; + } + } + } + } + return UAP_FAILURE; +} + +/**************************************************************************** + Global functions +****************************************************************************/ +/** + * @brief Creates a sys_cfg request for AP MAC address + * and sends to the driver + * + * Usage: "sys_cfg_ap_mac_address [AP_MAC_ADDRESS]" + * if AP_MAC_ADDRESS is provided, a 'set' is performed, + * else a 'get' is performed. + * + * @param argc Number of arguments + * @param argv Pointer to the arguments + * @return UAP_SUCCESS/UAP_FAILURE + */ +int +apcmd_sys_cfg_ap_mac_address(int argc, char *argv[]) +{ + apcmdbuf_sys_configure *cmd_buf = NULL; + tlvbuf_ap_mac_address *tlv = NULL; + t_u8 *buffer = NULL; + t_u16 cmd_len = 0; + t_u16 buf_len = MRVDRV_SIZE_OF_CMD_BUFFER; + int ret = UAP_SUCCESS; + int opt; + + while ((opt = getopt_long(argc, argv, "+", cmd_options, NULL)) != -1) { + switch (opt) { + default: + print_sys_cfg_ap_mac_address_usage(); + return UAP_SUCCESS; + } + } + argc -= optind; + argv += optind; + + /* Check arguments */ + if (argc > 1) { + printf("ERR:Too many arguments.\n"); + print_sys_cfg_ap_mac_address_usage(); + return UAP_FAILURE; + } + + /* Initialize the command length */ + cmd_len = + sizeof(apcmdbuf_sys_configure) + sizeof(tlvbuf_ap_mac_address); + + /* Initialize the command buffer */ + buffer = (t_u8 *)malloc(buf_len); + if (!buffer) { + printf("ERR:Cannot allocate buffer for command!\n"); + return UAP_FAILURE; + } + memset(buffer, 0, buf_len); + + /* Locate headers */ + cmd_buf = (apcmdbuf_sys_configure *)buffer; + tlv = (tlvbuf_ap_mac_address *)(buffer + + sizeof(apcmdbuf_sys_configure)); + + /* Fill the command buffer */ + cmd_buf->cmd_code = APCMD_SYS_CONFIGURE; + cmd_buf->size = cmd_len; + cmd_buf->seq_num = 0; + cmd_buf->result = 0; + tlv->tag = MRVL_AP_MAC_ADDRESS_TLV_ID; + tlv->length = ETH_ALEN; + if (argc == 0) { + cmd_buf->action = ACTION_GET; + } else { + cmd_buf->action = ACTION_SET; + if ((ret = mac2raw(argv[0], tlv->ap_mac_addr)) != UAP_SUCCESS) { + printf("ERR: %s Address \n", + ret == UAP_FAILURE ? "Invalid MAC" : ret == + UAP_RET_MAC_BROADCAST ? "Broadcast" : + "Multicast"); + free(buffer); + return UAP_FAILURE; + } + } + endian_convert_tlv_header_out(tlv); + + /* Send the command */ + ret = uap_ioctl((t_u8 *)cmd_buf, &cmd_len, buf_len); + endian_convert_tlv_header_in(tlv); + /* Process response */ + if (ret == UAP_SUCCESS) { + /* Verify response */ + if ((cmd_buf->cmd_code != + (APCMD_SYS_CONFIGURE | APCMD_RESP_CHECK)) || + (tlv->tag != MRVL_AP_MAC_ADDRESS_TLV_ID)) { + printf("ERR:Corrupted response! cmd_code=%x, Tlv->tag=%x\n", cmd_buf->cmd_code, tlv->tag); + free(buffer); + return UAP_FAILURE; + } + + /* Print response */ + if (cmd_buf->result == CMD_SUCCESS) { + if (argc == 0) { + printf("AP MAC address = "); + print_mac(tlv->ap_mac_addr); + printf("\n"); + } else { + printf("AP MAC address setting successful\n"); + } + } else { + if (argc == 0) { + printf("ERR:Could not get AP MAC address!\n"); + } else { + printf("ERR:Could not set AP MAC address!\n"); + } + ret = UAP_FAILURE; + } + } else { + printf("ERR:Command sending failed!\n"); + } + + if (buffer) + free(buffer); + return ret; +} + +/** + * @brief Creates a sys_cfg request for SSID + * and sends to the driver + * + * Usage: "sys_cfg_ssid [SSID]" + * if SSID is provided, a 'set' is performed + * else a 'get' is performed + * + * @param argc Number of arguments + * @param argv Pointer to the arguments + * @return UAP_SUCCESS/UAP_FAILURE + */ +int +apcmd_sys_cfg_ssid(int argc, char *argv[]) +{ + apcmdbuf_sys_configure *cmd_buf = NULL; + tlvbuf_ssid *tlv = NULL; + t_u8 *buffer = NULL; + t_u16 cmd_len = 0; + t_u16 buf_len = MRVDRV_SIZE_OF_CMD_BUFFER; + int ret = UAP_SUCCESS; + t_u8 ssid[33]; + + argc--; + argv++; + + /* Check arguments */ + if (argc > 1) { + printf("ERR:Too many arguments.\n"); + print_sys_cfg_ssid_usage(); + return UAP_FAILURE; + } + + if (argc == 0) { + /* Initialize the command length */ + cmd_len = + sizeof(apcmdbuf_sys_configure) + sizeof(tlvbuf_ssid) + + MAX_SSID_LENGTH; + } else { + if (strlen(argv[0]) > MAX_SSID_LENGTH) { + printf("ERR:SSID too long.\n"); + return UAP_FAILURE; + } + /* Initialize the command length */ + if (argv[0][1] == '"') { + argv[0]++; + } + if (argv[0][strlen(argv[0])] == '"') { + argv[0][strlen(argv[0])] = '\0'; + } + if (!strlen(argv[0])) { + printf("ERR:NULL SSID not allowed.\n"); + return UAP_FAILURE; + } + cmd_len = + sizeof(apcmdbuf_sys_configure) + sizeof(tlvbuf_ssid) + + strlen(argv[0]); + } + + /* Initialize the command buffer */ + buffer = (t_u8 *)malloc(buf_len); + if (!buffer) { + printf("ERR:Cannot allocate buffer for command!\n"); + return UAP_FAILURE; + } + memset(buffer, 0, buf_len); + + /* Locate headers */ + cmd_buf = (apcmdbuf_sys_configure *)buffer; + tlv = (tlvbuf_ssid *)(buffer + sizeof(apcmdbuf_sys_configure)); + + /* Fill the command buffer */ + cmd_buf->cmd_code = APCMD_SYS_CONFIGURE; + cmd_buf->size = cmd_len; + cmd_buf->seq_num = 0; + cmd_buf->result = 0; + tlv->tag = MRVL_SSID_TLV_ID; + if (argc == 0) { + cmd_buf->action = ACTION_GET; + tlv->length = MAX_SSID_LENGTH; + } else { + cmd_buf->action = ACTION_SET; + tlv->length = strlen(argv[0]); + memcpy(tlv->ssid, argv[0], tlv->length); + } + + endian_convert_tlv_header_out(tlv); + + /* Send the command */ + ret = uap_ioctl((t_u8 *)cmd_buf, &cmd_len, buf_len); + + endian_convert_tlv_header_in(tlv); + + /* Process response */ + if (ret == UAP_SUCCESS) { + /* Verify response */ + if ((cmd_buf->cmd_code != + (APCMD_SYS_CONFIGURE | APCMD_RESP_CHECK)) || + (tlv->tag != MRVL_SSID_TLV_ID)) { + printf("ERR:Corrupted response! cmd_code=%x, Tlv->tag=%x\n", cmd_buf->cmd_code, tlv->tag); + free(buffer); + return UAP_FAILURE; + } + + /* Print response */ + if (cmd_buf->result == CMD_SUCCESS) { + if (argc == 0) { + memset(ssid, 0, sizeof(ssid)); + strncpy((char *)ssid, (char *)tlv->ssid, + sizeof(ssid) - 1); + + printf("SSID = %s\n", ssid); + } else { + printf("SSID setting successful\n"); + } + } else { + if (argc == 0) { + printf("ERR:Could not get SSID!\n"); + } else { + printf("ERR:Could not set SSID!\n"); + } + ret = UAP_FAILURE; + } + } else { + printf("ERR:Command sending failed!\n"); + } + + if (buffer) + free(buffer); + return ret; +} + +/** + * @brief Creates a sys_cfg request for beacon period + * and sends to the driver + * + * Usage: "sys_cfg_beacon_period [BEACON_PERIOD]" + * if BEACON_PERIOD is provided, a 'set' is performed + * else a 'get' is performed. + * + * BEACON_PERIOD is represented in ms + * + * @param argc Number of arguments + * @param argv Pointer to the arguments + * @return UAP_SUCCESS/UAP_FAILURE + */ +int +apcmd_sys_cfg_beacon_period(int argc, char *argv[]) +{ + apcmdbuf_sys_configure *cmd_buf = NULL; + tlvbuf_beacon_period *tlv = NULL; + t_u8 *buffer = NULL; + t_u16 cmd_len = 0; + t_u16 buf_len = MRVDRV_SIZE_OF_CMD_BUFFER; + int ret = UAP_SUCCESS; + int opt; + + while ((opt = getopt_long(argc, argv, "+", cmd_options, NULL)) != -1) { + switch (opt) { + default: + print_sys_cfg_beacon_period_usage(); + return UAP_SUCCESS; + } + } + argc -= optind; + argv += optind; + + /* Check arguments */ + if (argc && is_input_valid(BEACONPERIOD, argc, argv) != UAP_SUCCESS) { + print_sys_cfg_beacon_period_usage(); + return UAP_FAILURE; + } + /* Initialize the command length */ + cmd_len = sizeof(apcmdbuf_sys_configure) + sizeof(tlvbuf_beacon_period); + + /* Initialize the command buffer */ + buffer = (t_u8 *)malloc(buf_len); + if (!buffer) { + printf("ERR:Cannot allocate buffer for command!\n"); + return UAP_FAILURE; + } + memset(buffer, 0, buf_len); + + /* Locate headers */ + cmd_buf = (apcmdbuf_sys_configure *)buffer; + tlv = (tlvbuf_beacon_period *)(buffer + sizeof(apcmdbuf_sys_configure)); + + /* Fill the command buffer */ + cmd_buf->cmd_code = APCMD_SYS_CONFIGURE; + cmd_buf->size = cmd_len; + cmd_buf->seq_num = 0; + cmd_buf->result = 0; + tlv->tag = MRVL_BEACON_PERIOD_TLV_ID; + tlv->length = 2; + if (argc == 0) { + cmd_buf->action = ACTION_GET; + } else { + cmd_buf->action = ACTION_SET; + tlv->beacon_period_ms = (t_u16)atoi(argv[0]); + } + endian_convert_tlv_header_out(tlv); + tlv->beacon_period_ms = uap_cpu_to_le16(tlv->beacon_period_ms); + + /* Send the command */ + ret = uap_ioctl((t_u8 *)cmd_buf, &cmd_len, buf_len); + endian_convert_tlv_header_in(tlv); + tlv->beacon_period_ms = uap_le16_to_cpu(tlv->beacon_period_ms); + /* Process response */ + if (ret == UAP_SUCCESS) { + /* Verify response */ + if ((cmd_buf->cmd_code != + (APCMD_SYS_CONFIGURE | APCMD_RESP_CHECK)) || + (tlv->tag != MRVL_BEACON_PERIOD_TLV_ID)) { + printf("ERR:Corrupted response! cmd_code=%x, Tlv->tag=%x\n", cmd_buf->cmd_code, tlv->tag); + free(buffer); + return UAP_FAILURE; + } + /* Print response */ + if (cmd_buf->result == CMD_SUCCESS) { + if (argc == 0) { + printf("Beacon period = %d\n", + tlv->beacon_period_ms); + } else { + printf("Beacon period setting successful\n"); + } + } else { + if (argc == 0) { + printf("ERR:Could not get beacon period!\n"); + } else { + printf("ERR:Could not set beacon period!\n"); + } + ret = UAP_FAILURE; + } + } else { + printf("ERR:Command sending failed!\n"); + } + if (buffer) + free(buffer); + return ret; +} + +/** + * @brief Creates a sys_cfg request for DTIM period + * and sends to the driver + * + * Usage: "sys_cfg_dtim_period [DTIM_PERIOD]" + * if DTIM_PERIOD is provided, a 'set' is performed + * else a 'get' is performed + * + * @param argc Number of arguments + * @param argv Pointer to the arguments + * @return UAP_SUCCESS/UAP_FAILURE + */ +int +apcmd_sys_cfg_dtim_period(int argc, char *argv[]) +{ + apcmdbuf_sys_configure *cmd_buf = NULL; + tlvbuf_dtim_period *tlv = NULL; + t_u8 *buffer = NULL; + t_u16 cmd_len = 0; + t_u16 buf_len = MRVDRV_SIZE_OF_CMD_BUFFER; + int ret = UAP_SUCCESS; + int opt; + while ((opt = getopt_long(argc, argv, "+", cmd_options, NULL)) != -1) { + switch (opt) { + default: + print_sys_cfg_dtim_period_usage(); + return UAP_SUCCESS; + } + } + argc -= optind; + argv += optind; + /* Check arguments */ + if (argc && (is_input_valid(DTIMPERIOD, argc, argv) != UAP_SUCCESS)) { + print_sys_cfg_dtim_period_usage(); + return UAP_FAILURE; + } + + /* Initialize the command length */ + cmd_len = sizeof(apcmdbuf_sys_configure) + sizeof(tlvbuf_dtim_period); + + /* Initialize the command buffer */ + buffer = (t_u8 *)malloc(buf_len); + if (!buffer) { + printf("ERR:Cannot allocate buffer for command!\n"); + return UAP_FAILURE; + } + memset(buffer, 0, buf_len); + + /* Locate headers */ + cmd_buf = (apcmdbuf_sys_configure *)buffer; + tlv = (tlvbuf_dtim_period *)(buffer + sizeof(apcmdbuf_sys_configure)); + + /* Fill the command buffer */ + cmd_buf->cmd_code = APCMD_SYS_CONFIGURE; + cmd_buf->size = cmd_len; + cmd_buf->seq_num = 0; + cmd_buf->result = 0; + tlv->tag = MRVL_DTIM_PERIOD_TLV_ID; + tlv->length = 1; + if (argc == 0) { + cmd_buf->action = ACTION_GET; + } else { + cmd_buf->action = ACTION_SET; + tlv->dtim_period = (t_u8)atoi(argv[0]); + } + endian_convert_tlv_header_out(tlv); + /* Send the command */ + ret = uap_ioctl((t_u8 *)cmd_buf, &cmd_len, buf_len); + endian_convert_tlv_header_in(tlv); + + /* Process response */ + if (ret == UAP_SUCCESS) { + /* Verify response */ + if ((cmd_buf->cmd_code != + (APCMD_SYS_CONFIGURE | APCMD_RESP_CHECK)) || + (tlv->tag != MRVL_DTIM_PERIOD_TLV_ID)) { + printf("ERR:Corrupted response! cmd_code=%x, Tlv->tag=%x\n", cmd_buf->cmd_code, tlv->tag); + free(buffer); + return UAP_FAILURE; + } + /* Print response */ + if (cmd_buf->result == CMD_SUCCESS) { + if (argc == 0) { + printf("DTIM period = %d\n", tlv->dtim_period); + } else { + printf("DTIM period setting successful\n"); + } + } else { + if (argc == 0) { + printf("ERR:Could not get DTIM period!\n"); + } else { + printf("ERR:Could not set DTIM period!\n"); + } + ret = UAP_FAILURE; + } + } else { + printf("ERR:Command sending failed!\n"); + } + if (buffer) + free(buffer); + return ret; +} + +/** + * @brief Creates a sys_cfg request for bss_status + * and sends to the driver + * + * Usage: "sys_cfg_bss_status" + * + * @param argc Number of arguments + * @param argv Pointer to the arguments + * @return UAP_SUCCESS/UAP_FAILURE + */ +int +apcmd_sys_cfg_bss_status(int argc, char *argv[]) +{ + apcmdbuf_sys_configure *cmd_buf = NULL; + tlvbuf_bss_status *tlv = NULL; + t_u8 *buffer = NULL; + t_u16 cmd_len = 0; + t_u16 buf_len = MRVDRV_SIZE_OF_CMD_BUFFER; + int ret = UAP_SUCCESS; + int opt; + while ((opt = getopt_long(argc, argv, "+", cmd_options, NULL)) != -1) { + switch (opt) { + default: + print_sys_cfg_bss_status_usage(); + return UAP_SUCCESS; + } + } + argc -= optind; + argv += optind; + + /* Check arguments */ + if (argc != 0) { + printf("ERR:Too many arguments.\n"); + print_sys_cfg_bss_status_usage(); + return UAP_FAILURE; + } + + /* Initialize the command length */ + cmd_len = sizeof(apcmdbuf_sys_configure) + sizeof(tlvbuf_bss_status); + + /* Initialize the command buffer */ + buffer = (t_u8 *)malloc(buf_len); + if (!buffer) { + printf("ERR:Cannot allocate buffer for command!\n"); + return UAP_FAILURE; + } + memset(buffer, 0, buf_len); + + /* Locate headers */ + cmd_buf = (apcmdbuf_sys_configure *)buffer; + tlv = (tlvbuf_bss_status *)(buffer + sizeof(apcmdbuf_sys_configure)); + + /* Fill the command buffer */ + cmd_buf->cmd_code = APCMD_SYS_CONFIGURE; + cmd_buf->size = cmd_len; + cmd_buf->seq_num = 0; + cmd_buf->result = 0; + tlv->tag = MRVL_BSS_STATUS_TLV_ID; + tlv->length = 2; + cmd_buf->action = ACTION_GET; + + endian_convert_tlv_header_out(tlv); + /* Send the command */ + ret = uap_ioctl((t_u8 *)cmd_buf, &cmd_len, buf_len); + endian_convert_tlv_header_in(tlv); + tlv->bss_status = uap_le16_to_cpu(tlv->bss_status); + + /* Process response */ + if (ret == UAP_SUCCESS) { + /* Verify response */ + if ((cmd_buf->cmd_code != + (APCMD_SYS_CONFIGURE | APCMD_RESP_CHECK)) || + (tlv->tag != MRVL_BSS_STATUS_TLV_ID)) { + printf("ERR:Corrupted response! cmd_code=%x, Tlv->tag=%x\n", cmd_buf->cmd_code, tlv->tag); + free(buffer); + return UAP_FAILURE; + } + /* Print response */ + if (cmd_buf->result == CMD_SUCCESS) { + printf("BSS status = %s\n", + (tlv->bss_status == 0) ? "stopped" : "started"); + } else { + printf("ERR:Could not get BSS status!\n"); + ret = UAP_FAILURE; + } + } else { + printf("ERR:Command sending failed!\n"); + } + if (buffer) + free(buffer); + return ret; +} + +/** DFS Radar starting channel FCC */ +#define DFS_FCC_RADAR_CHANNEL_START 52 +/** DFS Radar ending channel FCC */ +#define DFS_FCC_RADAR_CHANNEL_END 144 + +/** DFS Radar starting channel ETSI */ +#define DFS_ETSI_RADAR_CHANNEL_START 52 +/** DFS Radar ending channel ETSI */ +#define DFS_ETSI_RADAR_CHANNEL_END 140 + +/** DFS Radar starting channel JAPAN */ +#define DFS_JAPAN_RADAR_CHANNEL_START 52 +/** DFS Radar ending channel JAPAN */ +#define DFS_JAPAN_RADAR_CHANNEL_END 140 + +/** list of RegDomain values */ +typedef enum { + RegDomain_Null = 0x00, + RegDomain_FCC = 0x01, + RegDomain_ETSI = 0x02, + RegDomain_MIC = 0x03, + RegDomain_Other = 0xFF, +} regdomain_e; + +/** mapping of region and domain code */ +typedef struct { + /** region */ + t_u8 region[COUNTRY_CODE_LEN]; + /** domain code */ + regdomain_e code; +} region_code_mapping_t; + +static region_code_mapping_t region_code_mapping[] = { + {"US ", RegDomain_FCC}, /* US FCC 0x10 */ + {"SG ", RegDomain_FCC}, /* Singapore 0x10 */ + {"EU ", RegDomain_ETSI}, /* ETSI 0x30 */ + {"AU ", RegDomain_ETSI}, /* Australia 0x30 */ + {"KR ", RegDomain_ETSI}, /* Republic Of Korea 0x30 */ + {"JP ", RegDomain_MIC}, /* Japan 0x40 */ + {"J1 ", RegDomain_MIC}, /* Japan1 0x41 */ +}; + +/** + * @brief This function converts region string to region code + * + * @param region_string Region string + * + * @return Region code + */ +regdomain_e +region_string_2_region_code(char *region_string) +{ + t_u8 i; + t_u8 size = sizeof(region_code_mapping) / sizeof(region_code_mapping_t); + + for (i = 0; i < COUNTRY_CODE_LEN && region_string[i]; i++) { + region_string[i] = toupper(region_string[i]); + } + + for (i = 0; i < size; i++) { + if (!memcmp(region_string, + region_code_mapping[i].region, COUNTRY_CODE_LEN)) { + return (region_code_mapping[i].code); + } + } + + /* default is US */ + return (region_code_mapping[0].code); +} + +/** + * @brief Checks if channel is dfs channel and allow only if 11h is enabled. + * + * @param channel Channel + * @param country Country + * @return UAP_FAILURE/UAP_SUCCESS + */ +int +is_dfs_channel(int channel, char *country) +{ + regdomain_e region; + t_u8 DFS_RadarDetectChannelStart = DFS_FCC_RADAR_CHANNEL_START; + t_u8 DFS_RadarDetectChannelEnd = DFS_FCC_RADAR_CHANNEL_END; + + region = region_string_2_region_code(country); + /* set radar start channel and end channel */ + switch (region) { + default: /* use FCC as default setting */ + case RegDomain_FCC: + DFS_RadarDetectChannelStart = DFS_FCC_RADAR_CHANNEL_START; + DFS_RadarDetectChannelEnd = DFS_FCC_RADAR_CHANNEL_END; + break; + case RegDomain_ETSI: + DFS_RadarDetectChannelStart = DFS_ETSI_RADAR_CHANNEL_START; + DFS_RadarDetectChannelEnd = DFS_ETSI_RADAR_CHANNEL_END; + break; + case RegDomain_MIC: + DFS_RadarDetectChannelStart = DFS_JAPAN_RADAR_CHANNEL_START; + DFS_RadarDetectChannelEnd = DFS_JAPAN_RADAR_CHANNEL_END; + break; + } + if (channel < DFS_RadarDetectChannelStart + || channel > DFS_RadarDetectChannelEnd) { + return UAP_FAILURE; + } + + return UAP_SUCCESS; +} + +/** + * @brief Checks if channel is valid for given 11d domain. + * + * @param channel Channel + * @param band Band + * @param set_domain Flag to indicate update domain info with this channel + * @return UAP_FAILURE/UAP_SUCCESS + */ +int +check_channel_validity_11d(int channel, int band, int set_domain) +{ + apcmdbuf_cfg_80211d *cmd_buf = NULL; + ieeetypes_subband_set_t sub_bands[MAX_SUB_BANDS]; + t_u8 *buf = NULL; + t_u16 cmd_len; + t_u16 buf_len = 0; + int ret = UAP_FAILURE; + int i, j, found = 0; + t_u8 no_of_sub_band = 0; + char country[4] = { ' ', ' ', 0, 0 }; + + buf_len = sizeof(apcmdbuf_cfg_80211d); + buf_len += MAX_SUB_BANDS * sizeof(ieeetypes_subband_set_t); + buf = (t_u8 *)malloc(buf_len); + if (!buf) { + printf("ERR:Cannot allocate buffer from command!\n"); + return UAP_FAILURE; + } + memset(buf, 0, buf_len); + /* Locate headers */ + cmd_buf = (apcmdbuf_cfg_80211d *)buf; + cmd_len = (sizeof(apcmdbuf_cfg_80211d) - sizeof(domain_param_t)); + + cmd_buf->size = cmd_len - BUF_HEADER_SIZE; + cmd_buf->result = 0; + cmd_buf->seq_num = 0; + cmd_buf->action = ACTION_GET; + cmd_buf->action = uap_cpu_to_le16(cmd_buf->action); + cmd_buf->cmd_code = HostCmd_CMD_802_11D_DOMAIN_INFO; + + ret = uap_ioctl((t_u8 *)cmd_buf, &cmd_len, buf_len); + + if (ret == UAP_SUCCESS) { + if (cmd_buf->result == CMD_SUCCESS) { + /* Check channel against US if country code is not set */ + if (! + (cmd_buf->domain.country_code[0] || + cmd_buf->domain.country_code[1] || + cmd_buf->domain.country_code[2])) { + country[0] = 'U'; + country[1] = 'S'; + country[2] = '\0'; + /* Do not send this country code to FW though */ + set_domain = 0; + } else { + country[0] = cmd_buf->domain.country_code[0]; + country[1] = cmd_buf->domain.country_code[1]; + } + if (cmd_buf->domain.country_code[2] == 'I') { + if ((channel != 36) && (channel != 40) && + (channel != 44) && (channel != 48)) { + printf("ERR: Channel not valid for indoor operation!\n"); + ret = UAP_FAILURE; + goto done; + } + } + if (is_dfs_channel(channel, country) == UAP_SUCCESS) { + printf("DFS channel selected.\n"); + } + no_of_sub_band = + parse_domain_file(country, band, sub_bands, + NULL); + /* copy third character of country code here as domain file cannot handle it */ + country[2] = cmd_buf->domain.country_code[2]; + if (no_of_sub_band == UAP_FAILURE) { + printf("Parsing of domain configuration file failed\n"); + ret = UAP_FAILURE; + goto done; + } + + for (i = 0; i < no_of_sub_band; i++) { + for (j = 0; j < sub_bands[i].no_of_chan; j++) { + if (channel == + (sub_bands[i].first_chan + j)) { + found = 1; + break; + } + } + if (found) + break; + } + + if (!found) { + printf("ERR:Invalid channel %d for given domain!\n", channel); + ret = UAP_FAILURE; + goto done; + } + } else { + printf("ERR:Command Response incorrect!\n"); + ret = UAP_FAILURE; + goto done; + } + } else { + printf("ERR:Command sending failed!\n"); + goto done; + } + if (found && set_domain) { + /* If channel is valid then set domain_info with new band */ + memset(buf, 0, buf_len); + buf_len = + sizeof(apcmdbuf_cfg_80211d) + + no_of_sub_band * sizeof(ieeetypes_subband_set_t); + cmd_buf = (apcmdbuf_cfg_80211d *)buf; + cmd_len = buf_len; + cmd_buf->size = cmd_len - BUF_HEADER_SIZE; + cmd_buf->result = 0; + cmd_buf->seq_num = 0; + cmd_buf->action = ACTION_SET; + cmd_buf->action = uap_cpu_to_le16(cmd_buf->action); + cmd_buf->cmd_code = HostCmd_CMD_802_11D_DOMAIN_INFO; + + cmd_buf->domain.tag = uap_cpu_to_le16(TLV_TYPE_DOMAIN); + cmd_buf->domain.length = uap_cpu_to_le16(sizeof(domain_param_t) + - BUF_HEADER_SIZE + + (no_of_sub_band * + sizeof + (ieeetypes_subband_set_t))); + + memset(cmd_buf->domain.country_code, ' ', + sizeof(cmd_buf->domain.country_code)); + memcpy(cmd_buf->domain.country_code, country, strlen(country)); + memcpy(cmd_buf->domain.subband, sub_bands, + no_of_sub_band * sizeof(ieeetypes_subband_set_t)); + + ret = uap_ioctl((t_u8 *)cmd_buf, &cmd_len, buf_len); + + if (ret == UAP_SUCCESS) { + if (cmd_buf->result == CMD_SUCCESS) { + ret = UAP_SUCCESS; + } else { + printf("ERR:Command Response incorrect!\n"); + ret = UAP_FAILURE; + goto done; + } + } else { + printf("ERR:Command sending failed!\n"); + ret = UAP_FAILURE; + goto done; + } + } +done: + if (buf) + free(buf); + return ret; +} + +/** + * @brief Creates a sys_cfg request for channel + * and sends to the driver + * + * Usage: "sys_cfg_channel [CHANNEL] [MODE]" + * if CHANNEL is provided, a 'set' is performed + * else a 'get' is performed + * if MODE is provided, a 'set' is performed with + * + * @param argc Number of arguments + * @param argv Pointer to the arguments + * @return UAP_SUCCESS/UAP_FAILURE + */ +int +apcmd_sys_cfg_channel(int argc, char *argv[]) +{ + apcmdbuf_sys_configure *cmd_buf = NULL; + tlvbuf_channel_config *tlv = NULL; + t_u8 *buffer = NULL; + t_u16 cmd_len = 0; + t_u16 buf_len = MRVDRV_SIZE_OF_CMD_BUFFER; + int ret = UAP_SUCCESS; + int opt; + int mode = 0; + + while ((opt = getopt_long(argc, argv, "+", cmd_options, NULL)) != -1) { + switch (opt) { + default: + print_sys_cfg_channel_usage(); + return UAP_SUCCESS; + } + } + argc -= optind; + argv += optind; + + /* Check arguments */ + if (argc && is_input_valid(CHANNEL, argc, argv) != UAP_SUCCESS) { + print_sys_cfg_channel_usage(); + return UAP_FAILURE; + } + + /* Initialize the command length */ + cmd_len = + sizeof(apcmdbuf_sys_configure) + sizeof(tlvbuf_channel_config); + + /* Initialize the command buffer */ + buffer = (t_u8 *)malloc(buf_len); + if (!buffer) { + printf("ERR:Cannot allocate buffer for command!\n"); + return UAP_FAILURE; + } + memset(buffer, 0, buf_len); + + /* Locate headers */ + cmd_buf = (apcmdbuf_sys_configure *)buffer; + tlv = (tlvbuf_channel_config *)(buffer + + sizeof(apcmdbuf_sys_configure)); + + /* Fill the command buffer */ + cmd_buf->cmd_code = APCMD_SYS_CONFIGURE; + cmd_buf->size = cmd_len; + cmd_buf->seq_num = 0; + cmd_buf->result = 0; + tlv->tag = MRVL_CHANNELCONFIG_TLV_ID; + tlv->length = sizeof(tlvbuf_channel_config) - TLVHEADER_LEN; + if (argc == 0) { + cmd_buf->action = ACTION_GET; + } else { + cmd_buf->action = ACTION_SET; + if (argc == 1) { + tlv->chan_number = (t_u8)atoi(argv[0]); + memset(&(tlv->bandcfg), 0, sizeof(tlv->bandcfg)); + } else { + mode = atoi(argv[1]); + memset(&(tlv->bandcfg), 0, sizeof(tlv->bandcfg)); + if (mode & BITMAP_ACS_MODE) { + int mode; + if (uap_ioctl_dfs_repeater_mode(&mode) == + UAP_SUCCESS) { + if (mode) { + printf("ERR: ACS in DFS Repeater mode" " is not allowed\n"); + ret = UAP_FAILURE; + goto done; + } + } + tlv->bandcfg.scanMode = SCAN_MODE_ACS; + } + if (mode & BITMAP_CHANNEL_ABOVE) + tlv->bandcfg.chan2Offset = SEC_CHAN_ABOVE; + if (mode & BITMAP_CHANNEL_BELOW) + tlv->bandcfg.chan2Offset = SEC_CHAN_BELOW; + tlv->chan_number = (t_u8)atoi(argv[0]); + } + if (atoi(argv[0]) > MAX_CHANNELS_BG) { + tlv->bandcfg.chanBand = BAND_5GHZ; + } + } + endian_convert_tlv_header_out(tlv); + /* Send the command */ + ret = uap_ioctl((t_u8 *)cmd_buf, &cmd_len, buf_len); + endian_convert_tlv_header_in(tlv); + /* Process response */ + if (ret == UAP_SUCCESS) { + /* Verify response */ + if ((cmd_buf->cmd_code != + (APCMD_SYS_CONFIGURE | APCMD_RESP_CHECK)) || + (tlv->tag != MRVL_CHANNELCONFIG_TLV_ID)) { + printf("ERR:Corrupted response! cmd_code=%x, Tlv->tag=%x\n", cmd_buf->cmd_code, tlv->tag); + free(buffer); + return UAP_FAILURE; + } + /* Print response */ + if (cmd_buf->result == CMD_SUCCESS) { + if (argc == 0) { + printf("Mode = %s\n", + (tlv->bandcfg.scanMode == + SCAN_MODE_ACS) ? "ACS" : "Manual"); + printf("Channel = %d\n", tlv->chan_number); + if (tlv->bandcfg.chan2Offset == SEC_CHAN_NONE) + printf("no secondary channel\n"); + else if (tlv->bandcfg.chan2Offset == + SEC_CHAN_ABOVE) + printf("secondary channel is above primary channel\n"); + else if (tlv->bandcfg.chan2Offset == + SEC_CHAN_BELOW) + printf("secondary channel is below primary channel\n"); + } else { + printf("Channel setting successful\n"); + } + } else { + if (argc == 0) { + printf("ERR:Could not get channel!\n"); + } else { + printf("ERR:Could not set channel!\n"); + } + ret = UAP_FAILURE; + } + } else { + printf("ERR:Command sending failed!\n"); + } +done: + if (buffer) + free(buffer); + return ret; +} + +/** + * @brief Creates a sys_cfg request for channel + * and sends to the driver + * + * Usage: "sys_cfg_channel_ext [CHANNEL] [BAND] [MODE]" + * if CHANNEL is provided, a 'set' is performed + * else a 'get' is performed + * if BAND is provided, a 'set' is performed with band info(2.4GHz/5GHz) + * if MODE is provided, a 'set' is performed with mode (ACS/secondary channel) + * + * @param argc Number of arguments + * @param argv Pointer to the arguments + * @return UAP_SUCCESS/UAP_FAILURE + */ +int +apcmd_sys_cfg_channel_ext(int argc, char *argv[]) +{ + apcmdbuf_sys_configure *cmd_buf = NULL; + tlvbuf_channel_config *tlv = NULL; + t_u8 *buffer = NULL; + t_u16 cmd_len = 0; + t_u16 buf_len = MRVDRV_SIZE_OF_CMD_BUFFER; + int ret = UAP_SUCCESS; + int opt; + int mode = 0; + + while ((opt = getopt_long(argc, argv, "+", cmd_options, NULL)) != -1) { + switch (opt) { + default: + print_sys_cfg_channel_ext_usage(); + return UAP_SUCCESS; + } + } + argc -= optind; + argv += optind; + + /* Check arguments */ + if (argc && is_input_valid(CHANNEL_EXT, argc, argv) != UAP_SUCCESS) { + print_sys_cfg_channel_ext_usage(); + return UAP_FAILURE; + } + + /* Initialize the command length */ + cmd_len = + sizeof(apcmdbuf_sys_configure) + sizeof(tlvbuf_channel_config); + + /* Initialize the command buffer */ + buffer = (t_u8 *)malloc(buf_len); + if (!buffer) { + printf("ERR:Cannot allocate buffer for command!\n"); + return UAP_FAILURE; + } + memset(buffer, 0, buf_len); + + /* Locate headers */ + cmd_buf = (apcmdbuf_sys_configure *)buffer; + tlv = (tlvbuf_channel_config *)(buffer + + sizeof(apcmdbuf_sys_configure)); + + /* Fill the command buffer */ + cmd_buf->cmd_code = APCMD_SYS_CONFIGURE; + cmd_buf->size = cmd_len; + cmd_buf->seq_num = 0; + cmd_buf->result = 0; + tlv->tag = MRVL_CHANNELCONFIG_TLV_ID; + tlv->length = sizeof(tlvbuf_channel_config) - TLVHEADER_LEN; + if (argc == 0) { + cmd_buf->action = ACTION_GET; + } else { + cmd_buf->action = ACTION_SET; + tlv->chan_number = (t_u8)atoi(argv[0]); + if (argc == 1) { + if (atoi(argv[0]) > MAX_CHANNELS_BG) + tlv->bandcfg.chanBand = BAND_5GHZ; + } else { + if (atoi(argv[1]) == 0) { + tlv->bandcfg.chanBand = BAND_2GHZ; + } else { + tlv->bandcfg.chanBand = BAND_5GHZ; + } + if (argc == 3) { + mode = atoi(argv[2]); + if (mode & BITMAP_ACS_MODE) { + int mode; + if (uap_ioctl_dfs_repeater_mode(&mode) + == UAP_SUCCESS) { + if (mode) { + printf("ERR: ACS in DFS Repeater mode" " is not allowed\n"); + ret = UAP_FAILURE; + goto done; + } + } + tlv->bandcfg.scanMode = SCAN_MODE_ACS; + } + if (mode & BITMAP_CHANNEL_ABOVE) + tlv->bandcfg.chan2Offset = + SEC_CHAN_ABOVE; + if (mode & BITMAP_CHANNEL_BELOW) + tlv->bandcfg.chan2Offset = + SEC_CHAN_BELOW; + } + } + } + endian_convert_tlv_header_out(tlv); + /* Send the command */ + ret = uap_ioctl((t_u8 *)cmd_buf, &cmd_len, buf_len); + endian_convert_tlv_header_in(tlv); + /* Process response */ + if (ret == UAP_SUCCESS) { + /* Verify response */ + if ((cmd_buf->cmd_code != + (APCMD_SYS_CONFIGURE | APCMD_RESP_CHECK)) || + (tlv->tag != MRVL_CHANNELCONFIG_TLV_ID)) { + printf("ERR:Corrupted response! cmd_code=%x, Tlv->tag=%x\n", cmd_buf->cmd_code, tlv->tag); + free(buffer); + return UAP_FAILURE; + } + /* Print response */ + if (cmd_buf->result == CMD_SUCCESS) { + if (argc == 0) { + printf("Mode = %s\n", + (tlv->bandcfg.scanMode == + SCAN_MODE_ACS) ? "ACS" : "Manual"); + printf("Channel = %d\n", tlv->chan_number); + printf("Band = %s\n", + (tlv->bandcfg.chanBand == + BAND_5GHZ) ? "5GHz" : "2.4GHz"); + if (tlv->bandcfg.chan2Offset == SEC_CHAN_NONE) + printf("no secondary channel\n"); + else if (tlv->bandcfg.chan2Offset == + SEC_CHAN_ABOVE) + printf("secondary channel is above primary channel\n"); + else if (tlv->bandcfg.chan2Offset == + SEC_CHAN_BELOW) + printf("secondary channel is below primary channel\n"); + } else { + printf("Channel setting successful\n"); + } + } else { + if (argc == 0) { + printf("ERR:Could not get channel!\n"); + } else { + printf("ERR:Could not set channel!\n"); + } + ret = UAP_FAILURE; + } + } else { + printf("ERR:Command sending failed!\n"); + } +done: + if (buffer) + free(buffer); + return ret; +} + +/** + * @brief Creates a sys_cfg request for channel list + * and sends to the driver + * + * Usage: "sys_cfg_scan_channels [CHANNEL[.BAND]]" + * if CHANNEL and BAND are provided, a 'set' is performed + * else a 'get' is performed + * + * @param argc Number of arguments + * @param argv Pointer to the arguments + * @return UAP_SUCCESS/UAP_FAILURE + */ +int +apcmd_sys_cfg_scan_channels(int argc, char *argv[]) +{ + apcmdbuf_sys_configure *cmd_buf = NULL; + tlvbuf_channel_list *tlv = NULL; + channel_list *pchan_list = NULL; + t_u8 *buffer = NULL; + t_u16 cmd_len = 0; + t_u16 buf_len = MRVDRV_SIZE_OF_CMD_BUFFER; + int ret = UAP_FAILURE; + int opt; + int i; + int scan_channels_band; + int chan_number = 0; + int band_flag = -1; + while ((opt = getopt_long(argc, argv, "+", cmd_options, NULL)) != -1) { + switch (opt) { + default: + print_sys_cfg_scan_channels_usage(); + return UAP_SUCCESS; + } + } + argc -= optind; + argv += optind; + + /* Check arguments */ + if (argc && is_input_valid(SCANCHANNELS, argc, argv) != UAP_SUCCESS) { + print_sys_cfg_scan_channels_usage(); + return UAP_FAILURE; + } + + /* Initialize the command length */ + if (argc == 0) + cmd_len = + sizeof(apcmdbuf_sys_configure) + + sizeof(tlvbuf_channel_list) + + sizeof(channel_list) * MAX_CHANNELS; + else + cmd_len = + sizeof(apcmdbuf_sys_configure) + + sizeof(tlvbuf_channel_list) + + sizeof(channel_list) * argc; + + /* Initialize the command buffer */ + buffer = (t_u8 *)malloc(buf_len); + if (!buffer) { + printf("ERR:Cannot allocate buffer for command!\n"); + return UAP_FAILURE; + } + memset(buffer, 0, buf_len); + + /* LOCATE HEADERS */ + cmd_buf = (apcmdbuf_sys_configure *)buffer; + tlv = (tlvbuf_channel_list *)(buffer + sizeof(apcmdbuf_sys_configure)); + + /* Fill the command buffer */ + cmd_buf->cmd_code = APCMD_SYS_CONFIGURE; + cmd_buf->size = cmd_len; + cmd_buf->seq_num = 0; + cmd_buf->result = 0; + tlv->tag = MRVL_CHANNELLIST_TLV_ID; + if (argc == 0) { + cmd_buf->action = ACTION_GET; + tlv->length = sizeof(channel_list) * MAX_CHANNELS; + } else { + cmd_buf->action = ACTION_SET; + tlv->length = sizeof(channel_list) * argc; + pchan_list = tlv->chan_list; + for (i = 0; i < argc; i++) { + band_flag = -1; + sscanf(argv[i], "%d.%d", &chan_number, &band_flag); + pchan_list->chan_number = chan_number; + pchan_list->bandcfg.chanBand = BAND_2GHZ; + if (((band_flag != -1) && (band_flag)) || + (chan_number > MAX_CHANNELS_BG)) { + pchan_list->bandcfg.chanBand = BAND_5GHZ; + } + scan_channels_band = BAND_B | BAND_G; + if ((scan_channels_band != BAND_A) && + (pchan_list->bandcfg.chanBand == BAND_5GHZ)) { + scan_channels_band = BAND_A; + } + if (check_channel_validity_11d + (pchan_list->chan_number, scan_channels_band, + 0) == UAP_FAILURE) { + free(buffer); + return UAP_FAILURE; + } + pchan_list++; + } + } + endian_convert_tlv_header_out(tlv); + /* Send the command */ + ret = uap_ioctl((t_u8 *)cmd_buf, &cmd_len, buf_len); + endian_convert_tlv_header_in(tlv); + /* Process response */ + if (ret == UAP_SUCCESS) { + /* Verify response */ + if ((cmd_buf->cmd_code != + (APCMD_SYS_CONFIGURE | APCMD_RESP_CHECK)) || + (tlv->tag != MRVL_CHANNELLIST_TLV_ID)) { + printf("ERR:Corrupted response! cmd_code=%x, Tlv->tag=%x\n", cmd_buf->cmd_code, tlv->tag); + free(buffer); + return UAP_FAILURE; + } + /* Print response */ + if (cmd_buf->result == CMD_SUCCESS) { + if (argc == 0) { + printf("Channels List = "); + if (tlv->length % sizeof(channel_list)) { + printf("Error: Length mismatch\n"); + free(buffer); + return UAP_FAILURE; + } + pchan_list = tlv->chan_list; + for (i = 0; + (unsigned int)i < + (tlv->length / sizeof(channel_list)); + i++) { + printf("\n%d\t%sGHz", + pchan_list->chan_number, + (pchan_list->bandcfg.chanBand == + BAND_5GHZ) ? "5" : "2.4"); + pchan_list++; + } + printf("\n"); + } else { + printf("Scan Channel List setting successful\n"); + } + } else { + printf("ERR:Could not %s scan channel list!\n", + argc ? "SET" : "GET"); + ret = UAP_FAILURE; + } + } else { + printf("ERR:Command sending failed!\n"); + } + if (buffer) + free(buffer); + return ret; +} + +/** + * @brief Parser for sys_cfg_rates_ext input + * + * @param argc Number of arguments + * @param argv Pointer to the arguments + * @param output Stores indexes for "rates, mbrate and urate" + * arguments + * + * e.g., + * + * "rates 0x82 4 16 22 0x30 mbrate 2 urate 16" + * + * will have output array as + * + * start_index end_index + * rates 0 5 + * mbrate 6 7 + * urate 8 9 + * + * @return NA + * + */ +void +parse_input(int argc, char **argv, int output[3][2]) +{ + int i, j, k = 0; + char *keywords[3] = { "rates", "mbrate", "urate" }; + + for (i = 0; i < 3; i++) + output[i][0] = -1; + + for (i = 0; i < argc; i++) { + for (j = 0; j < 3; j++) { + if (strcmp(argv[i], keywords[j]) == 0) { + output[j][1] = output[j][0] = i; + k = j; + break; + } + } + output[k][1] += 1; + } +} + +/** + * @brief Creates a sys_cfg request for setting data_rates, MCBC and + * TX data rates. + * + * Usage: "sys_cfg_rates_ext [RATES]" + * + * @param argc Number of arguments + * @param argv Pointer to the arguments + * @return UAP_SUCCESS/UAP_FAILURE + */ +int +apcmd_sys_cfg_rates_ext(int argc, char *argv[]) +{ + int i, j = 0, found = 0; + int opt; + int rflag = 0, mflag = 0; + char *argv_rate[14]; + int argc_rate = 0; + char *argv_mrate[1]; + int mrate_found = UAP_FAILURE; + t_u8 *tlv_buf = NULL; + tlvbuf_mcbc_data_rate *tlv_mrate = NULL; + tlvbuf_rates *tlv_rate = NULL; + t_u8 *buffer = NULL; + apcmdbuf_sys_configure *cmd_buf = NULL; + int ret = UAP_SUCCESS; + t_u16 cmd_len = 0; + t_u16 buf_len = MRVDRV_SIZE_OF_CMD_BUFFER; + int output[3][2]; + char *keywords[3] = { "rates", "mbrate" }; + while ((opt = getopt_long(argc, argv, "+", cmd_options, NULL)) != -1) { + switch (opt) { + default: + print_sys_cfg_rates_ext_usage(); + return UAP_SUCCESS; + } + } + argc -= optind; + argv += optind; + + if (argc) { + /* + * SET + */ + parse_input(argc, argv, output); + + for (i = 0; i < 3; i++) { + if (output[i][0] == -1) { + for (j = 0; j < 3; j++) { + if (output[j][0] == 0) + found = 1; + } + if (!found) { + printf("%s keyword not specified!\n", + keywords[i]); + ret = UAP_FAILURE; + goto done; + } + } + } + /* + * Rate + */ + if ((output[0][0] != -1) && (output[0][1] > output[0][0])) { + rflag = 1; + i = 0; + for (j = (output[0][0] + 1); j < output[0][1]; j++) { + argv_rate[i] = + (char *)malloc(sizeof(char) * + (strlen(argv[j]) + 1)); + memset(argv_rate[i], 0, + sizeof(char) * (strlen(argv[j]) + 1)); + strncpy(argv_rate[i], argv[j], strlen(argv[j])); + argc_rate = ++i; + } + } + + /* + * mrate + */ + + if ((output[1][0] != -1) && (output[1][1] > output[1][0])) { + if ((output[1][1] - output[1][0]) != 2) { + printf("\nERR: Invalid mrate input"); + print_sys_cfg_rates_ext_usage(); + ret = UAP_FAILURE; + goto done; + } + mflag = 1; + argv_mrate[0] = + (char *)malloc(sizeof(char) * + (strlen(argv[j]) + 1)); + memset(argv_mrate[0], 0, + sizeof(char) * (strlen(argv[j]) + 1)); + strncpy(argv_mrate[0], argv[output[1][0] + 1], + strlen(argv[j])); + } + if (!rflag && !mflag) { + printf("ERR: Invalid input\n"); + print_sys_cfg_rates_ext_usage(); + ret = UAP_FAILURE; + goto done; + } + + if (rflag && + is_input_valid(RATE, argc_rate, argv_rate) != UAP_SUCCESS) { + printf("ERR: Invalid RATE\n"); + print_sys_cfg_rates_ext_usage(); + ret = UAP_FAILURE; + goto done; + } + + if (mflag && + is_input_valid(MCBCDATARATE, 1, + argv_mrate) != UAP_SUCCESS) { + printf("ERR: Invalid MCBC RATE\n"); + print_sys_cfg_rates_ext_usage(); + ret = UAP_FAILURE; + goto done; + } + + if (!rflag && mflag) { + /* + * Check mrate wrt old Rates + */ + if (mflag && A2HEXDECIMAL(argv_mrate[0]) && + is_mcbc_rate_valid(A2HEXDECIMAL(argv_mrate[0])) != + UAP_SUCCESS) { + printf("ERR: invalid MCBC data rate."); + print_sys_cfg_rates_ext_usage(); + ret = UAP_FAILURE; + goto done; + } + } else if (rflag && mflag) { + /* + * Check mrate wrt new Rates + */ + for (i = 0; i < argc_rate; i++) { + /* + * MCBC rate must be from Basic rates + */ + if (mflag && !mrate_found && + A2HEXDECIMAL(argv_rate[i]) & + BASIC_RATE_SET_BIT) { + if (A2HEXDECIMAL(argv_mrate[0]) == + (A2HEXDECIMAL(argv_rate[i]) & + ~BASIC_RATE_SET_BIT)) { + mrate_found = UAP_SUCCESS; + } + } + } + + if (mflag && A2HEXDECIMAL(argv_mrate[0]) && + !(mrate_found == UAP_SUCCESS)) { + printf("ERR: mrate not valid\n"); + ret = UAP_FAILURE; + goto done; + } + } + /* Post-parsing */ + cmd_len = sizeof(apcmdbuf_sys_configure); + if (rflag) + cmd_len += sizeof(tlvbuf_rates) + argc_rate; + if (mflag) + cmd_len += sizeof(tlvbuf_mcbc_data_rate); + } else { + /* GET */ + cmd_len = sizeof(apcmdbuf_sys_configure) + + sizeof(tlvbuf_rates) + MAX_RATES + + sizeof(tlvbuf_mcbc_data_rate); + } + + buffer = (t_u8 *)malloc(buf_len); + if (!buffer) { + printf("ERR:Cannot allocate buffer for command!\n"); + return UAP_FAILURE; + } + memset(buffer, 0, buf_len); + + /* Fill the command buffer */ + cmd_buf = (apcmdbuf_sys_configure *)buffer; + cmd_buf->cmd_code = APCMD_SYS_CONFIGURE; + cmd_buf->size = cmd_len; + cmd_buf->seq_num = 0; + cmd_buf->result = 0; + cmd_buf->action = argc ? ACTION_SET : ACTION_GET; + tlv_buf = buffer + sizeof(apcmdbuf_sys_configure); + /* Locate headers */ + if (rflag || (!argc)) { + tlv_rate = + (tlvbuf_rates *)(buffer + + sizeof(apcmdbuf_sys_configure)); + tlv_rate->tag = MRVL_RATES_TLV_ID; + tlv_rate->length = argc ? argc_rate : MAX_RATES; + for (i = 0; i < argc_rate; i++) { + tlv_rate->operational_rates[i] = + (t_u8)A2HEXDECIMAL(argv_rate[i]); + } + tlv_buf += tlv_rate->length + sizeof(tlvbuf_rates); + endian_convert_tlv_header_out(tlv_rate); + } + if (mflag || (!argc)) { + tlv_mrate = (tlvbuf_mcbc_data_rate *)tlv_buf; + tlv_mrate->tag = MRVL_MCBC_DATA_RATE_TLV_ID; + tlv_mrate->length = 2; + tlv_mrate->mcbc_datarate = 0; + if (mflag) { + tlv_mrate->mcbc_datarate = + (t_u16)A2HEXDECIMAL(argv_mrate[0]) + & ~BASIC_RATE_SET_BIT; + tlv_mrate->mcbc_datarate = + uap_cpu_to_le16(tlv_mrate->mcbc_datarate); + } + tlv_buf += sizeof(tlvbuf_mcbc_data_rate); + endian_convert_tlv_header_out(tlv_mrate); + } + + /* Send the command */ + ret = uap_ioctl((t_u8 *)cmd_buf, &cmd_len, buf_len); + + tlv_buf = buffer + sizeof(apcmdbuf_sys_configure); + + if (ret == UAP_SUCCESS) { + /* Verify response */ + if (cmd_buf->cmd_code != + (APCMD_SYS_CONFIGURE | APCMD_RESP_CHECK)) { + printf("ERR:Corrupted response! cmd_code=%x\n", + cmd_buf->cmd_code); + ret = UAP_FAILURE; + goto done; + } + /* Print response */ + if (cmd_buf->result == CMD_SUCCESS) { + if (argc) { + printf("Rates setting successful\n"); + } else { + print_tlv((t_u8 *)tlv_buf, + cmd_buf->size - + sizeof(apcmdbuf_sys_configure) + + BUF_HEADER_SIZE); + } + } else { + printf("ERR:Could not %s operational rates!\n", + argc ? "set" : "get"); + if (argc) + printf("operational rates only allow to set before bss start.\n"); + ret = UAP_FAILURE; + } + } else { + printf("ERR:Command sending failed!\n"); + } +done: + if (rflag) { + for (i = 0; i < argc_rate; i++) { + free(argv_rate[i]); + } + } + if (mflag) + free(argv_mrate[0]); + if (buffer) + free(buffer); + return ret; +} + +/** + * @brief Creates a sys_cfg request for data rates + * and sends to the driver + * + * Usage: "sys_cfg_rates [RATES]" + * + * RATES is provided as a set of data rates, in + * unit of 500 kilobits/s. + * Maximum 12 rates can be provided. + * + * if no RATE is provided, then it gets configured rates + * + * Each rate must be separated by a space + * + * @param argc Number of arguments + * @param argv Pointer to the arguments + * @return UAP_SUCCESS/UAP_FAILURE + */ +int +apcmd_sys_cfg_rates(int argc, char *argv[]) +{ + apcmdbuf_sys_configure *cmd_buf = NULL; + tlvbuf_rates *tlv = NULL; + t_u8 *buffer = NULL; + t_u16 cmd_len = 0; + t_u16 buf_len = MRVDRV_SIZE_OF_CMD_BUFFER; + int ret = UAP_SUCCESS; + int i = 0; + int opt; + while ((opt = getopt_long(argc, argv, "+", cmd_options, NULL)) != -1) { + switch (opt) { + default: + print_sys_cfg_rates_usage(); + return UAP_SUCCESS; + } + } + argc -= optind; + argv += optind; + + /* Check arguments */ + if (argc && is_input_valid(RATE, argc, argv) != UAP_SUCCESS) { + print_sys_cfg_rates_usage(); + return UAP_FAILURE; + } + if (argc == 0) { + /* Initialize the command length */ + cmd_len = + sizeof(apcmdbuf_sys_configure) + sizeof(tlvbuf_rates) + + MAX_RATES; + } else { + /* Initialize the command length */ + cmd_len = + sizeof(apcmdbuf_sys_configure) + sizeof(tlvbuf_rates) + + argc; + } + /* Initialize the command buffer */ + buffer = (t_u8 *)malloc(buf_len); + if (!buffer) { + printf("ERR:Cannot allocate buffer for command!\n"); + return UAP_FAILURE; + } + memset(buffer, 0, buf_len); + + /* Locate headers */ + cmd_buf = (apcmdbuf_sys_configure *)buffer; + tlv = (tlvbuf_rates *)(buffer + sizeof(apcmdbuf_sys_configure)); + + /* Fill the command buffer */ + cmd_buf->cmd_code = APCMD_SYS_CONFIGURE; + cmd_buf->size = cmd_len; + cmd_buf->seq_num = 0; + cmd_buf->result = 0; + tlv->tag = MRVL_RATES_TLV_ID; + if (argc == 0) { + cmd_buf->action = ACTION_GET; + tlv->length = MAX_RATES; + } else { + cmd_buf->action = ACTION_SET; + tlv->length = argc; + for (i = 0; i < tlv->length; i++) { + tlv->operational_rates[i] = (t_u8)A2HEXDECIMAL(argv[i]); + } + } + + endian_convert_tlv_header_out(tlv); + /* Send the command */ + ret = uap_ioctl((t_u8 *)cmd_buf, &cmd_len, buf_len); + /* Process response */ + if (ret == UAP_SUCCESS) { + /* Verify response */ + if ((cmd_buf->cmd_code != + (APCMD_SYS_CONFIGURE | APCMD_RESP_CHECK)) || + (uap_le16_to_cpu(tlv->tag) != MRVL_RATES_TLV_ID)) { + printf("ERR:Corrupted response! cmd_code=%x, Tlv->tag=%x\n", cmd_buf->cmd_code, uap_le16_to_cpu(tlv->tag)); + free(buffer); + return UAP_FAILURE; + } + + /* Print response */ + if (cmd_buf->result == CMD_SUCCESS) { + if (argc == 0) { + print_rate(tlv); + } else { + printf("Rates setting successful\n"); + } + } else { + if (argc == 0) { + printf("ERR:Could not get operational rates!\n"); + } else { + printf("ERR:Could not set operational rates!\n"); + } + ret = UAP_FAILURE; + } + } else { + printf("ERR:Command sending failed!\n"); + } + if (buffer) + free(buffer); + return ret; +} + +/** + * @brief Checks if tx power is valid for given 11d domain. + * + * @param tx_pwr tx power + * @return UAP_FAILURE/UAP_SUCCESS + */ +int +check_tx_pwr_validity_11d(t_u8 tx_pwr) +{ + apcmdbuf_sys_configure *cmd_buf1 = NULL; + apcmdbuf_cfg_80211d *cmd_buf2 = NULL; + tlvbuf_channel_config *tlv = NULL; + ieeetypes_subband_set_t sub_bands[MAX_SUB_BANDS]; + t_u8 *buf = NULL; + t_u16 cmd_len; + t_u16 buf_len = 0; + int ret = UAP_FAILURE; + int i, found = 0, band = BAND_B | BAND_G; + t_u8 no_of_sub_band = 0, channel = 0; + char country[4] = { ' ', ' ', 0, 0 }; + + /* Initialize the command length */ + cmd_len = + sizeof(apcmdbuf_sys_configure) + sizeof(tlvbuf_channel_config); + + /* Initialize the command buffer */ + buf = (t_u8 *)malloc(cmd_len); + + if (!buf) { + printf("ERR:Cannot allocate buffer for command!\n"); + return UAP_FAILURE; + } + memset(buf, 0, cmd_len); + + /* Locate headers */ + cmd_buf1 = (apcmdbuf_sys_configure *)buf; + tlv = (tlvbuf_channel_config *)(buf + sizeof(apcmdbuf_sys_configure)); + + /* Fill the command buffer */ + cmd_buf1->cmd_code = APCMD_SYS_CONFIGURE; + cmd_buf1->size = cmd_len; + cmd_buf1->seq_num = 0; + cmd_buf1->result = 0; + tlv->tag = MRVL_CHANNELCONFIG_TLV_ID; + tlv->length = sizeof(tlvbuf_channel_config) - TLVHEADER_LEN; + cmd_buf1->action = ACTION_GET; + endian_convert_tlv_header_out(tlv); + /* Send the command */ + ret = uap_ioctl((t_u8 *)cmd_buf1, &cmd_len, cmd_len); + endian_convert_tlv_header_in(tlv); + /* Process response */ + if (ret == UAP_SUCCESS) { + /* Verify response */ + if ((cmd_buf1->cmd_code != + (APCMD_SYS_CONFIGURE | APCMD_RESP_CHECK)) || + (tlv->tag != MRVL_CHANNELCONFIG_TLV_ID)) { + printf("ERR:Corrupted response! cmd_code=%x, Tlv->tag=%x\n", cmd_buf1->cmd_code, tlv->tag); + free(buf); + return UAP_FAILURE; + } + /* Print response */ + if (cmd_buf1->result == CMD_SUCCESS) { + channel = tlv->chan_number; + printf("channel=%d\n", channel); + } else { + printf("ERR:Could not get channel!\n"); + free(buf); + return UAP_FAILURE; + } + } else { + printf("ERR:Command sending failed!\n"); + free(buf); + return UAP_FAILURE; + } + /* free current buffer */ + free(buf); + if (channel > MAX_CHANNELS_BG) + band = BAND_A; + /* initialize second command length and buffer */ + buf_len = sizeof(apcmdbuf_cfg_80211d); + buf_len += MAX_SUB_BANDS * sizeof(ieeetypes_subband_set_t); + buf = (t_u8 *)malloc(buf_len); + if (!buf) { + printf("ERR:Cannot allocate buffer from command!\n"); + return UAP_FAILURE; + } + memset(buf, 0, buf_len); + /* Locate headers */ + cmd_buf2 = (apcmdbuf_cfg_80211d *)buf; + cmd_len = (sizeof(apcmdbuf_cfg_80211d) - sizeof(domain_param_t)); + + cmd_buf2->size = cmd_len - BUF_HEADER_SIZE; + cmd_buf2->result = 0; + cmd_buf2->seq_num = 0; + cmd_buf2->action = ACTION_GET; + cmd_buf2->action = uap_cpu_to_le16(cmd_buf2->action); + cmd_buf2->cmd_code = HostCmd_CMD_802_11D_DOMAIN_INFO; + + ret = uap_ioctl((t_u8 *)cmd_buf2, &cmd_len, buf_len); + + if (ret == UAP_SUCCESS) { + if (cmd_buf2->result == CMD_SUCCESS) { + if (cmd_buf2->domain.country_code[0] || + cmd_buf2->domain.country_code[1] || + cmd_buf2->domain.country_code[2]) { + country[0] = cmd_buf2->domain.country_code[0]; + country[1] = cmd_buf2->domain.country_code[1]; + if (cmd_buf2->domain.country_code[2] == 'I') { + if (tx_pwr > MAX_TX_PWR_INDOOR) { + printf("Transmit power invalid for indoor operation!\n"); + ret = UAP_FAILURE; + goto done; + } + } + no_of_sub_band = + parse_domain_file(country, band, + sub_bands, NULL); + if (no_of_sub_band == UAP_FAILURE) { + printf("Parsing of domain configuration file failed\n"); + ret = UAP_FAILURE; + goto done; + } + + for (i = 0; i < no_of_sub_band; i++) { + if (tx_pwr <= (sub_bands[i].max_tx_pwr)) { + found = 1; + break; + } + } + + if (!found) { + printf("ERR:Invalid transmit power for given domain!\n"); + ret = UAP_FAILURE; + goto done; + } + } + } else { + printf("ERR:Command Response incorrect!\n"); + ret = UAP_FAILURE; + goto done; + } + } else { + printf("ERR:Command sending failed!\n"); + } +done: + if (buf) + free(buf); + return ret; +} + +/** + * @brief Creates a sys_cfg request for Tx power + * and sends to the driver + * + * Usage: "sys_cfg_tx_power [TX_POWER]" + * if TX_POWER is provided, a 'set' is performed + * else a 'get' is performed. + * + * TX_POWER is represented in dBm + * + * @param argc Number of arguments + * @param argv Pointer to the arguments + * @return UAP_SUCCESS/UAP_FAILURE + */ +int +apcmd_sys_cfg_tx_power(int argc, char *argv[]) +{ + apcmdbuf_sys_configure *cmd_buf = NULL; + tlvbuf_tx_power *tlv = NULL; + t_u8 *buffer = NULL; + t_u16 cmd_len = 0; + t_u16 buf_len = MRVDRV_SIZE_OF_CMD_BUFFER; + int ret = UAP_SUCCESS; + int opt; + t_u8 state = 0; + while ((opt = getopt_long(argc, argv, "+", cmd_options, NULL)) != -1) { + switch (opt) { + default: + print_sys_cfg_tx_power_usage(); + return UAP_SUCCESS; + } + } + argc -= optind; + argv += optind; + /* Check arguments */ + if (argc && is_input_valid(TXPOWER, argc, argv) != UAP_SUCCESS) { + print_sys_cfg_tx_power_usage(); + return UAP_FAILURE; + } + /* Check if tx power is valid for given domain. */ + if (argc) { + ret = sg_snmp_mib(ACTION_GET, OID_80211D_ENABLE, sizeof(state), + &state); + if (state) { + ret = check_tx_pwr_validity_11d(atoi(argv[0])); + if (ret == UAP_FAILURE) { + print_sys_cfg_tx_power_usage(); + return UAP_FAILURE; + } + } + } + /* Initialize the command length */ + cmd_len = sizeof(apcmdbuf_sys_configure) + sizeof(tlvbuf_tx_power); + + /* Initialize the command buffer */ + buffer = (t_u8 *)malloc(buf_len); + if (!buffer) { + printf("ERR:Cannot allocate buffer for command!\n"); + return UAP_FAILURE; + } + memset(buffer, 0, buf_len); + + /* Locate headers */ + cmd_buf = (apcmdbuf_sys_configure *)buffer; + tlv = (tlvbuf_tx_power *)(buffer + sizeof(apcmdbuf_sys_configure)); + + /* Fill the command buffer */ + cmd_buf->cmd_code = APCMD_SYS_CONFIGURE; + cmd_buf->size = cmd_len; + cmd_buf->seq_num = 0; + cmd_buf->result = 0; + tlv->tag = MRVL_TX_POWER_TLV_ID; + tlv->length = 1; + if (argc == 0) { + cmd_buf->action = ACTION_GET; + } else { + printf("Please check power calibration for board to see if this power\n" "setting is within calibrated range. Firmware may over-ride\n " "this setting if it is not within calibrated range, which can\n" "vary from board to board.\n"); + cmd_buf->action = ACTION_SET; + tlv->tx_power_dbm = (t_u8)atoi(argv[0]); + } + endian_convert_tlv_header_out(tlv); + /* Send the command */ + ret = uap_ioctl((t_u8 *)cmd_buf, &cmd_len, buf_len); + endian_convert_tlv_header_in(tlv); + /* Process response */ + if (ret == UAP_SUCCESS) { + /* Verify response */ + if ((cmd_buf->cmd_code != + (APCMD_SYS_CONFIGURE | APCMD_RESP_CHECK)) || + (tlv->tag != MRVL_TX_POWER_TLV_ID)) { + printf("ERR:Corrupted response! cmd_code=%x, Tlv->tag=%x\n", cmd_buf->cmd_code, tlv->tag); + free(buffer); + return UAP_FAILURE; + } + /* Print response */ + if (cmd_buf->result == CMD_SUCCESS) { + if (argc == 0) { + printf("Tx power = %d dBm\n", + tlv->tx_power_dbm); + } else { + printf("Tx power setting successful\n"); + } + } else { + if (argc == 0) { + printf("ERR:Could not get tx power!\n"); + } else { + printf("ERR:Could not set tx power!\n"); + } + ret = UAP_FAILURE; + } + } else { + printf("ERR:Command sending failed!\n"); + } + if (buffer) + free(buffer); + return ret; +} + +/** + * @brief Creates a sys_cfg request for SSID broadcast + * and sends to the driver + * + * Usage: "sys_cfg_bcast_ssid_ctl [0|1]" + * + * Options: 0 - Disable SSID broadcast + * 1 - Enable SSID broadcast + * empty - Get current SSID broadcast setting + * + * @param argc Number of arguments + * @param argv Pointer to the arguments + * @return UAP_SUCCESS/UAP_FAILURE + */ +int +apcmd_sys_cfg_bcast_ssid_ctl(int argc, char *argv[]) +{ + apcmdbuf_sys_configure *cmd_buf = NULL; + tlvbuf_bcast_ssid_ctl *tlv = NULL; + t_u8 *buffer = NULL; + t_u16 cmd_len = 0; + t_u16 buf_len = MRVDRV_SIZE_OF_CMD_BUFFER; + int ret = UAP_SUCCESS; + int opt; + + while ((opt = getopt_long(argc, argv, "+", cmd_options, NULL)) != -1) { + switch (opt) { + default: + print_sys_cfg_bcast_ssid_ctl_usage(); + return UAP_SUCCESS; + } + } + argc -= optind; + argv += optind; + /* Check arguments */ + if (argc && is_input_valid(BROADCASTSSID, argc, argv) != UAP_SUCCESS) { + print_sys_cfg_bcast_ssid_ctl_usage(); + return UAP_FAILURE; + } + /* Initialize the command length */ + cmd_len = + sizeof(apcmdbuf_sys_configure) + sizeof(tlvbuf_bcast_ssid_ctl); + + /* Initialize the command buffer */ + buffer = (t_u8 *)malloc(buf_len); + if (!buffer) { + printf("ERR:Cannot allocate buffer for command!\n"); + return UAP_FAILURE; + } + memset(buffer, 0, buf_len); + + /* Locate headers */ + cmd_buf = (apcmdbuf_sys_configure *)buffer; + tlv = (tlvbuf_bcast_ssid_ctl *)(buffer + + sizeof(apcmdbuf_sys_configure)); + + /* Fill the command buffer */ + cmd_buf->cmd_code = APCMD_SYS_CONFIGURE; + cmd_buf->size = cmd_len; + cmd_buf->seq_num = 0; + cmd_buf->result = 0; + tlv->tag = MRVL_BCAST_SSID_CTL_TLV_ID; + tlv->length = 1; + if (argc == 0) { + cmd_buf->action = ACTION_GET; + } else { + cmd_buf->action = ACTION_SET; + tlv->bcast_ssid_ctl = (t_u8)atoi(argv[0]); + } + endian_convert_tlv_header_out(tlv); + /* Send the command */ + ret = uap_ioctl((t_u8 *)cmd_buf, &cmd_len, buf_len); + endian_convert_tlv_header_in(tlv); + /* Process response */ + if (ret == UAP_SUCCESS) { + /* Verify response */ + if ((cmd_buf->cmd_code != + (APCMD_SYS_CONFIGURE | APCMD_RESP_CHECK)) || + (tlv->tag != MRVL_BCAST_SSID_CTL_TLV_ID)) { + printf("ERR:Corrupted response! cmd_code=%x, Tlv->tag=%x\n", cmd_buf->cmd_code, tlv->tag); + free(buffer); + return UAP_FAILURE; + } + /* Print response */ + if (cmd_buf->result == CMD_SUCCESS) { + if (argc == 0) { + printf("SSID broadcast is %s\n", + (tlv->bcast_ssid_ctl == + 1) ? "enabled" : "disabled"); + } else { + printf("SSID broadcast setting successful\n"); + } + } else { + if (argc == 0) { + printf("ERR:Could not get SSID broadcast!\n"); + } else { + printf("ERR:Could not set SSID broadcast!\n"); + } + ret = UAP_FAILURE; + } + } else { + printf("ERR:Command sending failed!\n"); + } + if (buffer) + free(buffer); + return ret; +} + +/** + * @brief Creates a sys_cfg request for preamble settings + * and sends to the driver + * + * Usage: "sys_cfg_preamble_ctl" + * + * @param argc Number of arguments + * @param argv Pointer to the arguments + * @return UAP_SUCCESS/UAP_FAILURE + */ +int +apcmd_sys_cfg_preamble_ctl(int argc, char *argv[]) +{ + apcmdbuf_sys_configure *cmd_buf = NULL; + tlvbuf_preamble_ctl *tlv = NULL; + t_u8 *buffer = NULL; + t_u16 cmd_len = 0; + t_u16 buf_len = MRVDRV_SIZE_OF_CMD_BUFFER; + int ret = UAP_SUCCESS; + int opt; + while ((opt = getopt_long(argc, argv, "+", cmd_options, NULL)) != -1) { + switch (opt) { + default: + print_sys_cfg_preamble_ctl_usage(); + return UAP_SUCCESS; + } + } + argc -= optind; + argv += optind; + + /* Check arguments */ + if (argc && (is_input_valid(PREAMBLETYPE, argc, argv) != UAP_SUCCESS)) { + print_sys_cfg_preamble_ctl_usage(); + return UAP_FAILURE; + } + /* Initialize the command length */ + cmd_len = sizeof(apcmdbuf_sys_configure) + sizeof(tlvbuf_preamble_ctl); + + /* Initialize the command buffer */ + buffer = (t_u8 *)malloc(buf_len); + if (!buffer) { + printf("ERR:Cannot allocate buffer for command!\n"); + return UAP_FAILURE; + } + memset(buffer, 0, buf_len); + + /* Locate headers */ + cmd_buf = (apcmdbuf_sys_configure *)buffer; + tlv = (tlvbuf_preamble_ctl *)(buffer + sizeof(apcmdbuf_sys_configure)); + + /* Fill the command buffer */ + cmd_buf->cmd_code = APCMD_SYS_CONFIGURE; + cmd_buf->size = cmd_len; + cmd_buf->seq_num = 0; + cmd_buf->result = 0; + tlv->tag = MRVL_PREAMBLE_CTL_TLV_ID; + tlv->length = 1; + if (argc == 0) { + cmd_buf->action = ACTION_GET; + } else { + cmd_buf->action = ACTION_SET; + tlv->preamble_type = (t_u16)atoi(argv[0]); + } + endian_convert_tlv_header_out(tlv); + /* Send the command */ + ret = uap_ioctl((t_u8 *)cmd_buf, &cmd_len, buf_len); + endian_convert_tlv_header_in(tlv); + /* Process response */ + if (ret == UAP_SUCCESS) { + /* Verify response */ + if ((cmd_buf->cmd_code != + (APCMD_SYS_CONFIGURE | APCMD_RESP_CHECK)) || + (tlv->tag != MRVL_PREAMBLE_CTL_TLV_ID)) { + printf("ERR:Corrupted response! cmd_code=%x, Tlv->tag=%x\n", cmd_buf->cmd_code, tlv->tag); + free(buffer); + return UAP_FAILURE; + } + /* Print response */ + if (cmd_buf->result == CMD_SUCCESS) { + if (argc == 0) { + printf("Preamble type is %s\n", + (tlv->preamble_type == + 0) ? "auto" : ((tlv->preamble_type == + 1) ? "short" : "long")); + } else { + printf("Preamble type setting successful\n"); + } + } else { + if (argc == 0) { + printf("ERR:Could not get preamble type!\n"); + } else { + printf("ERR:Could not set preamble type!\n"); + } + ret = UAP_FAILURE; + } + } else { + printf("ERR:Command sending failed!\n"); + } + if (buffer) + free(buffer); + return ret; +} + +/** + * @brief Creates a sys_cfg request for RTS threshold + * and sends to the driver + * + * Usage: "sys_cfg_rts_threshold [RTS_THRESHOLD]" + * if RTS_THRESHOLD is provided, a 'set' is performed + * else a 'get' is performed + * + * @param argc Number of arguments + * @param argv Pointer to the arguments + * @return UAP_SUCCESS/UAP_FAILURE + */ +int +apcmd_sys_cfg_rts_threshold(int argc, char *argv[]) +{ + apcmdbuf_sys_configure *cmd_buf = NULL; + tlvbuf_rts_threshold *tlv = NULL; + t_u8 *buffer = NULL; + t_u16 cmd_len = 0; + t_u16 buf_len = MRVDRV_SIZE_OF_CMD_BUFFER; + int ret = UAP_SUCCESS; + int opt; + while ((opt = getopt_long(argc, argv, "+", cmd_options, NULL)) != -1) { + switch (opt) { + default: + print_sys_cfg_rts_threshold_usage(); + return UAP_SUCCESS; + } + } + argc -= optind; + argv += optind; + /* Check arguments */ + if (argc && (is_input_valid(RTSTHRESH, argc, argv) != UAP_SUCCESS)) { + print_sys_cfg_rts_threshold_usage(); + return UAP_FAILURE; + } + /* Initialize the command length */ + cmd_len = sizeof(apcmdbuf_sys_configure) + sizeof(tlvbuf_rts_threshold); + + /* Initialize the command buffer */ + buffer = (t_u8 *)malloc(buf_len); + if (!buffer) { + printf("ERR:Cannot allocate buffer for command!\n"); + return UAP_FAILURE; + } + memset(buffer, 0, buf_len); + + /* Locate headers */ + cmd_buf = (apcmdbuf_sys_configure *)buffer; + tlv = (tlvbuf_rts_threshold *)(buffer + sizeof(apcmdbuf_sys_configure)); + + /* Fill the command buffer */ + cmd_buf->cmd_code = APCMD_SYS_CONFIGURE; + cmd_buf->size = cmd_len; + cmd_buf->seq_num = 0; + cmd_buf->result = 0; + tlv->tag = MRVL_RTS_THRESHOLD_TLV_ID; + tlv->length = 2; + if (argc == 0) { + cmd_buf->action = ACTION_GET; + } else { + cmd_buf->action = ACTION_SET; + tlv->rts_threshold = (t_u16)atoi(argv[0]); + } + endian_convert_tlv_header_out(tlv); + tlv->rts_threshold = uap_cpu_to_le16(tlv->rts_threshold); + /* Send the command */ + ret = uap_ioctl((t_u8 *)cmd_buf, &cmd_len, buf_len); + endian_convert_tlv_header_in(tlv); + tlv->rts_threshold = uap_le16_to_cpu(tlv->rts_threshold); + /* Process response */ + if (ret == UAP_SUCCESS) { + /* Verify response */ + if ((cmd_buf->cmd_code != + (APCMD_SYS_CONFIGURE | APCMD_RESP_CHECK)) || + (tlv->tag != MRVL_RTS_THRESHOLD_TLV_ID)) { + printf("ERR:Corrupted response! cmd_code=%x, Tlv->tag=%x\n", cmd_buf->cmd_code, tlv->tag); + free(buffer); + return UAP_FAILURE; + } + /* Print response */ + if (cmd_buf->result == CMD_SUCCESS) { + if (argc == 0) { + printf("RTS threshold = %d\n", + tlv->rts_threshold); + } else { + printf("RTS threshold setting successful\n"); + } + } else { + if (argc == 0) { + printf("ERR:Could not get RTS threshold!\n"); + } else { + printf("ERR:Could not set RTS threshold!\n"); + } + ret = UAP_FAILURE; + } + } else { + printf("ERR:Command sending failed!\n"); + } + if (buffer) + free(buffer); + return ret; +} + +/** + * @brief Creates a sys_cfg request for Fragmentation threshold + * and sends to the driver + * + * Usage: "sys_cfg_frag_threshold [FRAG_THRESHOLD]" + * if FRAG_THRESHOLD is provided, a 'set' is performed + * else a 'get' is performed + * + * @param argc Number of arguments + * @param argv Pointer to the arguments + * @return UAP_SUCCESS/UAP_FAILURE + */ +int +apcmd_sys_cfg_frag_threshold(int argc, char *argv[]) +{ + apcmdbuf_sys_configure *cmd_buf = NULL; + tlvbuf_frag_threshold *tlv = NULL; + t_u8 *buffer = NULL; + t_u16 cmd_len = 0; + t_u16 buf_len = MRVDRV_SIZE_OF_CMD_BUFFER; + int ret = UAP_SUCCESS; + int opt; + while ((opt = getopt_long(argc, argv, "+", cmd_options, NULL)) != -1) { + switch (opt) { + default: + print_sys_cfg_frag_threshold_usage(); + return UAP_SUCCESS; + } + } + argc -= optind; + argv += optind; + /* Check arguments */ + if (argc && (is_input_valid(FRAGTHRESH, argc, argv) != UAP_SUCCESS)) { + print_sys_cfg_frag_threshold_usage(); + return UAP_FAILURE; + } + /* Initialize the command length */ + cmd_len = + sizeof(apcmdbuf_sys_configure) + sizeof(tlvbuf_frag_threshold); + + /* Initialize the command buffer */ + buffer = (t_u8 *)malloc(buf_len); + if (!buffer) { + printf("ERR:Cannot allocate buffer for command!\n"); + return UAP_FAILURE; + } + memset(buffer, 0, buf_len); + + /* Locate headers */ + cmd_buf = (apcmdbuf_sys_configure *)buffer; + tlv = (tlvbuf_frag_threshold *)(buffer + + sizeof(apcmdbuf_sys_configure)); + + /* Fill the command buffer */ + cmd_buf->cmd_code = APCMD_SYS_CONFIGURE; + cmd_buf->size = cmd_len; + cmd_buf->seq_num = 0; + cmd_buf->result = 0; + tlv->tag = MRVL_FRAG_THRESHOLD_TLV_ID; + tlv->length = 2; + if (argc == 0) { + cmd_buf->action = ACTION_GET; + } else { + cmd_buf->action = ACTION_SET; + tlv->frag_threshold = (t_u16)atoi(argv[0]); + } + endian_convert_tlv_header_out(tlv); + tlv->frag_threshold = uap_cpu_to_le16(tlv->frag_threshold); + /* Send the command */ + ret = uap_ioctl((t_u8 *)cmd_buf, &cmd_len, buf_len); + endian_convert_tlv_header_in(tlv); + tlv->frag_threshold = uap_le16_to_cpu(tlv->frag_threshold); + + /* Process response */ + if (ret == UAP_SUCCESS) { + /* Verify response */ + if ((cmd_buf->cmd_code != + (APCMD_SYS_CONFIGURE | APCMD_RESP_CHECK)) || + (tlv->tag != MRVL_FRAG_THRESHOLD_TLV_ID)) { + printf("ERR:Corrupted response! cmd_code=%x, Tlv->tag=%x\n", cmd_buf->cmd_code, tlv->tag); + free(buffer); + return UAP_FAILURE; + } + /* Print response */ + if (cmd_buf->result == CMD_SUCCESS) { + if (argc == 0) { + printf("Fragmentation threshold = %d\n", + tlv->frag_threshold); + } else { + printf("Fragmentation threshold setting successful\n"); + } + } else { + if (argc == 1) { + printf("ERR:Could not set Fragmentation threshold!\n"); + } else { + printf("ERR:Could not get Fragmentation threshold!\n"); + } + ret = UAP_FAILURE; + } + } else { + printf("ERR:Command sending failed!\n"); + } + if (buffer) + free(buffer); + return ret; +} + +/** + * @brief Creates a sys_cfg request for RSN replay protection + * and sends to the driver + * + * Usage: "sys_cfg_rsn_replay_prot [0|1]" + * + * Options: 0 - Disable RSN replay protection + * 1 - Enable RSN replay protection + * empty - Get current RSN replay protection setting + * + * @param argc Number of arguments + * @param argv Pointer to the arguments + * @return UAP_SUCCESS/UAP_FAILURE + */ +int +apcmd_sys_cfg_rsn_replay_prot(int argc, char *argv[]) +{ + apcmdbuf_sys_configure *cmd_buf = NULL; + tlvbuf_rsn_replay_prot *tlv = NULL; + t_u8 *buffer = NULL; + t_u16 cmd_len = 0; + t_u16 buf_len = MRVDRV_SIZE_OF_CMD_BUFFER; + int ret = UAP_SUCCESS; + int opt; + + while ((opt = getopt_long(argc, argv, "+", cmd_options, NULL)) != -1) { + switch (opt) { + default: + print_sys_cfg_rsn_replay_prot_usage(); + return UAP_SUCCESS; + } + } + argc -= optind; + argv += optind; + /* Check arguments */ + if (argc && is_input_valid(RSNREPLAYPROT, argc, argv) != UAP_SUCCESS) { + print_sys_cfg_rsn_replay_prot_usage(); + return UAP_FAILURE; + } + /* Initialize the command length */ + cmd_len = + sizeof(apcmdbuf_sys_configure) + sizeof(tlvbuf_rsn_replay_prot); + + /* Initialize the command buffer */ + buffer = (t_u8 *)malloc(buf_len); + if (!buffer) { + printf("ERR:Cannot allocate buffer for command!\n"); + return UAP_FAILURE; + } + memset(buffer, 0, buf_len); + + /* Locate headers */ + cmd_buf = (apcmdbuf_sys_configure *)buffer; + tlv = (tlvbuf_rsn_replay_prot *)(buffer + + sizeof(apcmdbuf_sys_configure)); + + /* Fill the command buffer */ + cmd_buf->cmd_code = APCMD_SYS_CONFIGURE; + cmd_buf->size = cmd_len; + cmd_buf->seq_num = 0; + cmd_buf->result = 0; + tlv->tag = MRVL_RSN_REPLAY_PROT_TLV_ID; + tlv->length = 1; + if (argc == 0) { + cmd_buf->action = ACTION_GET; + } else { + cmd_buf->action = ACTION_SET; + tlv->rsn_replay_prot = (t_u8)atoi(argv[0]); + } + endian_convert_tlv_header_out(tlv); + /* Send the command */ + ret = uap_ioctl((t_u8 *)cmd_buf, &cmd_len, buf_len); + endian_convert_tlv_header_in(tlv); + /* Process response */ + if (ret == UAP_SUCCESS) { + /* Verify response */ + if ((cmd_buf->cmd_code != + (APCMD_SYS_CONFIGURE | APCMD_RESP_CHECK)) || + (tlv->tag != MRVL_RSN_REPLAY_PROT_TLV_ID)) { + printf("ERR:Corrupted response! cmd_code=%x, Tlv->Tag=%x\n", cmd_buf->cmd_code, tlv->tag); + free(buffer); + return UAP_FAILURE; + } + /* Print response */ + if (cmd_buf->result == CMD_SUCCESS) { + if (argc == 0) { + printf("RSN replay protection is %s\n", + (tlv->rsn_replay_prot == + 1) ? "enabled" : "disabled"); + } else { + printf("RSN replay protection setting successful\n"); + } + } else { + if (argc == 0) { + printf("ERR:Could not get RSN replay protection !\n"); + } else { + printf("ERR:Could not set RSN replay protection !\n"); + } + ret = UAP_FAILURE; + } + } else { + printf("ERR:Command sending failed!\n"); + } + if (buffer) + free(buffer); + return ret; +} + +/** + * @brief Creates a sys_cfg request for MCBC data rates + * and sends to the driver + * + * Usage: "sys_cfg_mcbc_data_rate [MCBC_DATA_RATE]" + * + * Options: 0 - Auto rate + * >0 - Set specified MCBC data rate + * empty - Get current MCBC data rate + * + * MCBC_DATA_RATE is represented in units of 500 kbps + * + * @param argc Number of arguments + * @param argv Pointer to the arguments + * @return UAP_SUCCESS/UAP_FAILURE + */ +int +apcmd_sys_cfg_mcbc_data_rate(int argc, char *argv[]) +{ + apcmdbuf_sys_configure *cmd_buf = NULL; + tlvbuf_mcbc_data_rate *tlv = NULL; + t_u8 *buffer = NULL; + t_u16 cmd_len = 0; + t_u16 buf_len = MRVDRV_SIZE_OF_CMD_BUFFER; + int ret = UAP_SUCCESS; + int opt; + while ((opt = getopt_long(argc, argv, "+", cmd_options, NULL)) != -1) { + switch (opt) { + default: + print_sys_cfg_mcbc_data_rates_usage(); + return UAP_SUCCESS; + } + } + argc -= optind; + argv += optind; + + /* Check arguments */ + if (argc) { + if (is_input_valid(MCBCDATARATE, argc, argv) != UAP_SUCCESS) { + printf("ERR: Invalid input\n"); + print_sys_cfg_mcbc_data_rates_usage(); + return UAP_FAILURE; + } + if ((A2HEXDECIMAL(argv[0]) != 0) && + (is_mcbc_rate_valid(A2HEXDECIMAL(argv[0])) != + UAP_SUCCESS)) { + printf("ERR: invalid MCBC data rate."); + print_sys_cfg_mcbc_data_rates_usage(); + return UAP_FAILURE; + } + } + + /* Initialize the command length */ + cmd_len = + sizeof(apcmdbuf_sys_configure) + sizeof(tlvbuf_mcbc_data_rate); + + /* Initialize the command buffer */ + buffer = (t_u8 *)malloc(buf_len); + if (!buffer) { + printf("ERR:Cannot allocate buffer for command!\n"); + return UAP_FAILURE; + } + memset(buffer, 0, buf_len); + + /* Locate headers */ + cmd_buf = (apcmdbuf_sys_configure *)buffer; + tlv = (tlvbuf_mcbc_data_rate *)(buffer + + sizeof(apcmdbuf_sys_configure)); + + /* Fill the command buffer */ + cmd_buf->cmd_code = APCMD_SYS_CONFIGURE; + cmd_buf->size = cmd_len; + cmd_buf->seq_num = 0; + cmd_buf->result = 0; + tlv->tag = MRVL_MCBC_DATA_RATE_TLV_ID; + tlv->length = 2; + if (argc == 0) { + cmd_buf->action = ACTION_GET; + } else { + cmd_buf->action = ACTION_SET; + tlv->mcbc_datarate = (t_u16)A2HEXDECIMAL(argv[0]); + } + endian_convert_tlv_header_out(tlv); + tlv->mcbc_datarate = uap_cpu_to_le16(tlv->mcbc_datarate); + + /* Send the command */ + ret = uap_ioctl((t_u8 *)cmd_buf, &cmd_len, buf_len); + endian_convert_tlv_header_in(tlv); + tlv->mcbc_datarate = uap_le16_to_cpu(tlv->mcbc_datarate); + + /* Process response */ + if (ret == UAP_SUCCESS) { + /* Verify response */ + if ((cmd_buf->cmd_code != + (APCMD_SYS_CONFIGURE | APCMD_RESP_CHECK)) || + (tlv->tag != MRVL_MCBC_DATA_RATE_TLV_ID)) { + printf("ERR:Corrupted response! cmd_code=%x, Tlv->tag=%x\n", cmd_buf->cmd_code, tlv->tag); + free(buffer); + return UAP_FAILURE; + } + /* Print response */ + if (cmd_buf->result == CMD_SUCCESS) { + if (argc == 0) { + if (tlv->mcbc_datarate == 0) { + printf("MCBC data rate is auto\n"); + } else { + printf("MCBC data rate = 0x%x\n", + tlv->mcbc_datarate); + } + } else { + printf("MCBC data rate setting successful\n"); + } + } else { + if (argc == 0) { + printf("ERR:Could not get MCBC data rate!\n"); + } else { + printf("ERR:Could not set MCBC data rate!\n"); + } + ret = UAP_FAILURE; + } + } else { + printf("ERR:Command sending failed!\n"); + } + if (buffer) + free(buffer); + return ret; +} + +/** + * @brief Creates a sys_cfg request for Tx beacon rates + * and sends to the driver + * + * Usage: "sys_cfg_tx_beacon_rate [TX_BEACON_RATE]" + * + * Options: 0 - Auto rate + * >0 - Set specified data rate + * empty - Get current data rate + * + * TX_BEACON_RATE is represented in units of 500 kbps + * + * @param argc Number of arguments + * @param argv Pointer to the arguments + * @return UAP_SUCCESS/UAP_FAILURE + */ +int +apcmd_sys_cfg_tx_beacon_rate(int argc, char *argv[]) +{ + apcmdbuf_sys_configure *cmd_buf = NULL; + tlvbuf_tx_data_rate *tlv = NULL; + t_u8 *buffer = NULL; + t_u16 cmd_len = 0; + t_u16 buf_len = MRVDRV_SIZE_OF_CMD_BUFFER; + int ret = UAP_SUCCESS; + int opt; + while ((opt = getopt_long(argc, argv, "+", cmd_options, NULL)) != -1) { + switch (opt) { + default: + print_sys_cfg_tx_beacon_rates_usage(); + return UAP_SUCCESS; + } + } + argc -= optind; + argv += optind; + + /* Check arguments */ + if (argc) { + if (is_input_valid(TXBEACONRATE, argc, argv) != UAP_SUCCESS) { + printf("ERR: Invalid input\n"); + return UAP_FAILURE; + } else if ((A2HEXDECIMAL(argv[0]) != 0) && + (is_tx_rate_valid(A2HEXDECIMAL(argv[0])) != + UAP_SUCCESS)) { + printf("ERR: invalid tx beacon rate."); + return UAP_FAILURE; + } + } + + /* Initialize the command length */ + cmd_len = sizeof(apcmdbuf_sys_configure) + sizeof(tlvbuf_tx_data_rate); + + /* Initialize the command buffer */ + buffer = (t_u8 *)malloc(buf_len); + if (!buffer) { + printf("ERR:Cannot allocate buffer for command!\n"); + return UAP_FAILURE; + } + memset(buffer, 0, buf_len); + + /* Locate headers */ + cmd_buf = (apcmdbuf_sys_configure *)buffer; + tlv = (tlvbuf_tx_data_rate *)(buffer + sizeof(apcmdbuf_sys_configure)); + + /* Fill the command buffer */ + cmd_buf->cmd_code = APCMD_SYS_CONFIGURE; + cmd_buf->size = cmd_len; + cmd_buf->seq_num = 0; + cmd_buf->result = 0; + tlv->tag = MRVL_TX_BEACON_RATE_TLV_ID; + tlv->length = 2; + if (argc == 0) { + cmd_buf->action = ACTION_GET; + } else { + cmd_buf->action = ACTION_SET; + tlv->tx_data_rate = (t_u16)A2HEXDECIMAL(argv[0]); + } + endian_convert_tlv_header_out(tlv); + tlv->tx_data_rate = uap_cpu_to_le16(tlv->tx_data_rate); + + /* Send the command */ + ret = uap_ioctl((t_u8 *)cmd_buf, &cmd_len, buf_len); + endian_convert_tlv_header_in(tlv); + tlv->tx_data_rate = uap_le16_to_cpu(tlv->tx_data_rate); + + /* Process response */ + if (ret == UAP_SUCCESS) { + /* Verify response */ + if ((cmd_buf->cmd_code != + (APCMD_SYS_CONFIGURE | APCMD_RESP_CHECK)) || + (tlv->tag != MRVL_TX_BEACON_RATE_TLV_ID)) { + printf("ERR:Corrupted response! cmd_code=%x, Tlv->tag=%x\n", cmd_buf->cmd_code, tlv->tag); + free(buffer); + return UAP_FAILURE; + } + /* Print response */ + if (cmd_buf->result == CMD_SUCCESS) { + if (argc == 0) { + if (tlv->tx_data_rate == 0) { + printf("Tx beacon rate is auto\n"); + } else { + printf("Tx beacon rate = 0x%x\n", + tlv->tx_data_rate); + } + } else { + printf("Tx beacon rate setting successful\n"); + } + } else { + if (argc == 0) { + printf("ERR:Could not get tx beacon rate!\n"); + } else { + printf("ERR:Could not set tx beacon rate!\n"); + } + ret = UAP_FAILURE; + } + } else { + printf("ERR:Command sending failed!\n"); + } + if (buffer) + free(buffer); + return ret; +} + +/** + * @brief Creates a sys_cfg request for packet forwarding + * and sends to the driver + * + * Usage: "sys_cfg_pkt_fwd_ctl [PKT_FWD_CTRL]" + * + * PKT_FWD_CTRL: bit 0 -- Packet forwarding handled by Host (0) or Firmware (1) + * bit 1 -- Intra-BSS broadcast packets are allowed (0) or denied (1) + * bit 2 -- Intra-BSS unicast packets are allowed (0) or denied (1) + * bit 3 -- Inter-BSS unicast packets are allowed (0) or denied (1) + * empty - Get current packet forwarding setting + * + * @param argc Number of arguments + * @param argv Pointer to the arguments + * @return UAP_SUCCESS/UAP_FAILURE + */ +int +apcmd_sys_cfg_pkt_fwd_ctl(int argc, char *argv[]) +{ + apcmdbuf_sys_configure *cmd_buf = NULL; + tlvbuf_pkt_fwd_ctl *tlv = NULL; + t_u8 *buffer = NULL; + t_u16 cmd_len = 0; + t_u16 buf_len = MRVDRV_SIZE_OF_CMD_BUFFER; + int ret = UAP_SUCCESS; + int opt; + while ((opt = getopt_long(argc, argv, "+", cmd_options, NULL)) != -1) { + switch (opt) { + default: + print_sys_cfg_pkt_fwd_ctl_usage(); + return UAP_SUCCESS; + } + } + argc -= optind; + argv += optind; + /* Check arguments */ + if (argc && (is_input_valid(PKTFWD, argc, argv) != UAP_SUCCESS)) { + print_sys_cfg_pkt_fwd_ctl_usage(); + return UAP_FAILURE; + } + /* Initialize the command length */ + cmd_len = sizeof(apcmdbuf_sys_configure) + sizeof(tlvbuf_pkt_fwd_ctl); + /* Initialize the command buffer */ + buffer = (t_u8 *)malloc(buf_len); + if (!buffer) { + printf("ERR:Cannot allocate buffer for command!\n"); + return UAP_FAILURE; + } + memset(buffer, 0, buf_len); + + /* Locate headers */ + cmd_buf = (apcmdbuf_sys_configure *)buffer; + tlv = (tlvbuf_pkt_fwd_ctl *)(buffer + sizeof(apcmdbuf_sys_configure)); + + /* Fill the command buffer */ + cmd_buf->cmd_code = APCMD_SYS_CONFIGURE; + cmd_buf->size = cmd_len; + cmd_buf->seq_num = 0; + cmd_buf->result = 0; + tlv->tag = MRVL_PKT_FWD_CTL_TLV_ID; + tlv->length = 1; + if (argc == 0) { + cmd_buf->action = ACTION_GET; + } else { + cmd_buf->action = ACTION_SET; + tlv->pkt_fwd_ctl = (t_u8)atoi(argv[0]); + } + endian_convert_tlv_header_out(tlv); + /* Send the command */ + ret = uap_ioctl((t_u8 *)cmd_buf, &cmd_len, buf_len); + endian_convert_tlv_header_in(tlv); + /* Process response */ + if (ret == UAP_SUCCESS) { + /* Verify response */ + if ((cmd_buf->cmd_code != + (APCMD_SYS_CONFIGURE | APCMD_RESP_CHECK)) || + (tlv->tag != MRVL_PKT_FWD_CTL_TLV_ID)) { + printf("ERR:Corrupted response! cmd_code=%x, Tlv->tag=%x\n", cmd_buf->cmd_code, tlv->tag); + free(buffer); + return UAP_FAILURE; + } + /* Print response */ + if (cmd_buf->result == CMD_SUCCESS) { + if (argc == 0) { + printf("%s handles packet forwarding -\n", + ((tlv->pkt_fwd_ctl & PKT_FWD_FW_BIT) == + 0) ? "Host" : "Firmware"); + printf("\tIntra-BSS broadcast packets are %s\n", + ((tlv-> + pkt_fwd_ctl & PKT_FWD_INTRA_BCAST) == + 0) ? "allowed" : "denied"); + printf("\tIntra-BSS unicast packets are %s\n", + ((tlv-> + pkt_fwd_ctl & PKT_FWD_INTRA_UCAST) == + 0) ? "allowed" : "denied"); + printf("\tInter-BSS unicast packets are %s\n", + ((tlv-> + pkt_fwd_ctl & PKT_FWD_INTER_UCAST) == + 0) ? "allowed" : "denied"); + } else { + printf("Packet control logic setting successful\n"); + } + } else { + if (argc == 0) { + printf("ERR:Could not get packet control logic!\n"); + } else { + printf("ERR:Could not set packet control logic!\n"); + } + ret = UAP_FAILURE; + } + } else { + printf("ERR:Command sending failed!\n"); + } + if (buffer) + free(buffer); + return ret; +} + +/** + * @brief Creates a sys_cfg request for STA ageout timer + * and sends to the driver + * + * Usage: "sys_cfg_sta_ageout_timer [STA_AGEOUT_TIMER]" + * if STA_AGEOUT_TIMER is provided, a 'set' is performed + * else a 'get' is performed. + * The value should between 100 and 864000 + * + * STA_AGEOUT_TIMER is represented in units of 100 ms + * + * @param argc Number of arguments + * @param argv Pointer to the arguments + * @return UAP_SUCCESS/UAP_FAILURE + */ +int +apcmd_sys_cfg_sta_ageout_timer(int argc, char *argv[]) +{ + apcmdbuf_sys_configure *cmd_buf = NULL; + tlvbuf_sta_ageout_timer *tlv = NULL; + t_u8 *buffer = NULL; + t_u16 cmd_len = 0; + t_u16 buf_len = MRVDRV_SIZE_OF_CMD_BUFFER; + int ret = UAP_SUCCESS; + int opt; + while ((opt = getopt_long(argc, argv, "+", cmd_options, NULL)) != -1) { + switch (opt) { + default: + print_sys_cfg_sta_ageout_timer_usage(); + return UAP_SUCCESS; + } + } + argc -= optind; + argv += optind; + /* Check arguments */ + if (argc && (is_input_valid(STAAGEOUTTIMER, argc, argv) != UAP_SUCCESS)) { + print_sys_cfg_sta_ageout_timer_usage(); + return UAP_FAILURE; + } + /* Initialize the command length */ + cmd_len = + sizeof(apcmdbuf_sys_configure) + + sizeof(tlvbuf_sta_ageout_timer); + + /* Initialize the command buffer */ + buffer = (t_u8 *)malloc(buf_len); + if (!buffer) { + printf("ERR:Cannot allocate buffer for command!\n"); + return UAP_FAILURE; + } + memset(buffer, 0, buf_len); + + /* Locate headers */ + cmd_buf = (apcmdbuf_sys_configure *)buffer; + tlv = (tlvbuf_sta_ageout_timer *)(buffer + + sizeof(apcmdbuf_sys_configure)); + + /* Fill the command buffer */ + cmd_buf->cmd_code = APCMD_SYS_CONFIGURE; + cmd_buf->size = cmd_len; + cmd_buf->seq_num = 0; + cmd_buf->result = 0; + tlv->tag = MRVL_STA_AGEOUT_TIMER_TLV_ID; + tlv->length = 4; + if (argc == 0) { + cmd_buf->action = ACTION_GET; + } else { + cmd_buf->action = ACTION_SET; + tlv->sta_ageout_timer_ms = (t_u32)atoi(argv[0]); + } + endian_convert_tlv_header_out(tlv); + tlv->sta_ageout_timer_ms = uap_cpu_to_le32(tlv->sta_ageout_timer_ms); + /* Send the command */ + ret = uap_ioctl((t_u8 *)cmd_buf, &cmd_len, buf_len); + endian_convert_tlv_header_in(tlv); + tlv->sta_ageout_timer_ms = uap_le32_to_cpu(tlv->sta_ageout_timer_ms); + /* Process response */ + if (ret == UAP_SUCCESS) { + /* Verify response */ + if ((cmd_buf->cmd_code != + (APCMD_SYS_CONFIGURE | APCMD_RESP_CHECK)) || + (tlv->tag != MRVL_STA_AGEOUT_TIMER_TLV_ID)) { + printf("ERR:Corrupted response! cmd_code=%x, Tlv->tag=%x\n", cmd_buf->cmd_code, tlv->tag); + free(buffer); + return UAP_FAILURE; + } + /* Print response */ + if (cmd_buf->result == CMD_SUCCESS) { + if (argc == 0) { + printf("STA ageout timer value = %d\n", + (int)tlv->sta_ageout_timer_ms); + } else { + printf("STA ageout timer setting successful\n"); + } + } else { + if (argc == 0) { + printf("ERR:Could not get STA ageout timer!\n"); + } else { + printf("ERR:Could not set STA ageout timer!\n"); + } + ret = UAP_FAILURE; + } + } else { + printf("ERR:Command sending failed!\n"); + } + if (buffer) + free(buffer); + return ret; +} + +/** + * @brief Creates a sys_cfg request for PS STA ageout timer + * and sends to the driver + * + * Usage: "sys_cfg_ps_sta_ageout_timer [PS_STA_AGEOUT_TIMER]" + * if PS_STA_AGEOUT_TIMER is provided, a 'set' is performed + * else a 'get' is performed. + * The value should between 100 and 864000 + * + * PS_STA_AGEOUT_TIMER is represented in units of 100 ms + * + * @param argc Number of arguments + * @param argv Pointer to the arguments + * @return UAP_SUCCESS/UAP_FAILURE + */ +int +apcmd_sys_cfg_ps_sta_ageout_timer(int argc, char *argv[]) +{ + apcmdbuf_sys_configure *cmd_buf = NULL; + tlvbuf_ps_sta_ageout_timer *tlv = NULL; + t_u8 *buffer = NULL; + t_u16 cmd_len = 0; + t_u16 buf_len = MRVDRV_SIZE_OF_CMD_BUFFER; + int ret = UAP_SUCCESS; + int opt; + while ((opt = getopt_long(argc, argv, "+", cmd_options, NULL)) != -1) { + switch (opt) { + default: + print_sys_cfg_ps_sta_ageout_timer_usage(); + return UAP_SUCCESS; + } + } + argc -= optind; + argv += optind; + /* Check arguments */ + if (argc && + (is_input_valid(PSSTAAGEOUTTIMER, argc, argv) != UAP_SUCCESS)) { + print_sys_cfg_ps_sta_ageout_timer_usage(); + return UAP_FAILURE; + } + /* Initialize the command length */ + cmd_len = + sizeof(apcmdbuf_sys_configure) + + sizeof(tlvbuf_ps_sta_ageout_timer); + + /* Initialize the command buffer */ + buffer = (t_u8 *)malloc(buf_len); + if (!buffer) { + printf("ERR:Cannot allocate buffer for command!\n"); + return UAP_FAILURE; + } + memset(buffer, 0, buf_len); + + /* Locate headers */ + cmd_buf = (apcmdbuf_sys_configure *)buffer; + tlv = (tlvbuf_ps_sta_ageout_timer *)(buffer + + sizeof(apcmdbuf_sys_configure)); + + /* Fill the command buffer */ + cmd_buf->cmd_code = APCMD_SYS_CONFIGURE; + cmd_buf->size = cmd_len; + cmd_buf->seq_num = 0; + cmd_buf->result = 0; + tlv->tag = MRVL_PS_STA_AGEOUT_TIMER_TLV_ID; + tlv->length = 4; + if (argc == 0) { + cmd_buf->action = ACTION_GET; + } else { + cmd_buf->action = ACTION_SET; + tlv->ps_sta_ageout_timer_ms = (t_u32)atoi(argv[0]); + } + endian_convert_tlv_header_out(tlv); + tlv->ps_sta_ageout_timer_ms = + uap_cpu_to_le32(tlv->ps_sta_ageout_timer_ms); + /* Send the command */ + ret = uap_ioctl((t_u8 *)cmd_buf, &cmd_len, buf_len); + endian_convert_tlv_header_in(tlv); + tlv->ps_sta_ageout_timer_ms = + uap_le32_to_cpu(tlv->ps_sta_ageout_timer_ms); + /* Process response */ + if (ret == UAP_SUCCESS) { + /* Verify response */ + if ((cmd_buf->cmd_code != + (APCMD_SYS_CONFIGURE | APCMD_RESP_CHECK)) || + (tlv->tag != MRVL_PS_STA_AGEOUT_TIMER_TLV_ID)) { + printf("ERR:Corrupted response! cmd_code=%x, Tlv->tag=%x\n", cmd_buf->cmd_code, tlv->tag); + free(buffer); + return UAP_FAILURE; + } + /* Print response */ + if (cmd_buf->result == CMD_SUCCESS) { + if (argc == 0) { + printf("PS STA ageout timer value = %d\n", + (int)tlv->ps_sta_ageout_timer_ms); + } else { + printf("PS STA ageout timer setting successful\n"); + } + } else { + if (argc == 0) { + printf("ERR:Could not get PS STA ageout timer!\n"); + } else { + printf("ERR:Could not set PS STA ageout timer!\n"); + } + ret = UAP_FAILURE; + } + } else { + printf("ERR:Command sending failed!\n"); + } + if (buffer) + free(buffer); + return ret; +} + +/** + * @brief Creates a sys_cfg request for authentication mode + * and sends to the driver + * + * Usage: "Usage : sys_cfg_auth [AUTHMODE]" + * + * Options: AUTHMODE : 0 - Open authentication + * 1 - Shared key authentication + * empty - Get current authentication mode + * + * @param argc Number of arguments + * @param argv Pointer to the arguments + * @return UAP_SUCCESS/UAP_FAILURE + */ +int +apcmd_sys_cfg_auth(int argc, char *argv[]) +{ + apcmdbuf_sys_configure *cmd_buf = NULL; + tlvbuf_auth_mode *tlv = NULL; + t_u8 *buffer = NULL; + t_u16 cmd_len = 0; + t_u16 buf_len = MRVDRV_SIZE_OF_CMD_BUFFER; + int ret = UAP_SUCCESS; + int opt; + while ((opt = getopt_long(argc, argv, "+", cmd_options, NULL)) != -1) { + switch (opt) { + default: + print_sys_cfg_auth_usage(); + return UAP_SUCCESS; + } + } + argc -= optind; + argv += optind; + /* Check arguments */ + if (argc && (is_input_valid(AUTHMODE, argc, argv) != UAP_SUCCESS)) { + print_sys_cfg_auth_usage(); + return UAP_FAILURE; + } + /* Initialize the command length */ + cmd_len = sizeof(apcmdbuf_sys_configure) + sizeof(tlvbuf_auth_mode); + + /* Initialize the command buffer */ + buffer = (t_u8 *)malloc(buf_len); + if (!buffer) { + printf("ERR:Cannot allocate buffer for command!\n"); + return UAP_FAILURE; + } + memset(buffer, 0, buf_len); + + /* Locate headers */ + cmd_buf = (apcmdbuf_sys_configure *)buffer; + tlv = (tlvbuf_auth_mode *)(buffer + sizeof(apcmdbuf_sys_configure)); + + /* Fill the command buffer */ + cmd_buf->cmd_code = APCMD_SYS_CONFIGURE; + cmd_buf->size = cmd_len; + cmd_buf->seq_num = 0; + cmd_buf->result = 0; + tlv->tag = MRVL_AUTH_TLV_ID; + tlv->length = 1; + if (argc == 0) { + cmd_buf->action = ACTION_GET; + } else { + cmd_buf->action = ACTION_SET; + tlv->auth_mode = (t_u8)atoi(argv[0]); + } + endian_convert_tlv_header_out(tlv); + /* Send the command */ + ret = uap_ioctl((t_u8 *)cmd_buf, &cmd_len, buf_len); + endian_convert_tlv_header_in(tlv); + + /* Process response */ + if (ret == UAP_SUCCESS) { + /* Verify response */ + if ((cmd_buf->cmd_code != + (APCMD_SYS_CONFIGURE | APCMD_RESP_CHECK)) || + (tlv->tag != MRVL_AUTH_TLV_ID)) { + printf("ERR:Corrupted response! cmd_code=%x, Tlv->tag=%x\n", cmd_buf->cmd_code, tlv->tag); + free(buffer); + return UAP_FAILURE; + } + /* Print response */ + if (cmd_buf->result == CMD_SUCCESS) { + if (argc == 0) { + print_auth(tlv); + } else { + printf("authentication mode setting successful\n"); + } + } else { + if (argc == 0) { + printf("ERR:Could not get authentication mode!\n"); + } else { + printf("ERR:Could not set authentication mode!\n"); + } + ret = UAP_FAILURE; + } + } else { + printf("ERR:Command sending failed!\n"); + } + if (buffer) + free(buffer); + return ret; +} + +/** + * @brief Creates a sys_cfg request for encryption protocol + * and sends to the driver + * + * Usage: "Usage : sys_cfg_protocol [PROTOCOL]" + * + * Options: PROTOCOL Bit 0 - No RSN + * Bit 1 - WEP Static + * Bit 3 - WPA + * Bit 3 - WPA2 + * empty - Get current protocol + * + * @param argc Number of arguments + * @param argv Pointer to the arguments + * @return UAP_SUCCESS/UAP_FAILURE + */ +int +apcmd_sys_cfg_protocol(int argc, char *argv[]) +{ + apcmdbuf_sys_configure *cmd_buf = NULL; + tlvbuf_protocol *tlv = NULL; + tlvbuf_akmp *akmp_tlv = NULL; + t_u8 *buffer = NULL; + t_u16 buf_len = MRVDRV_SIZE_OF_CMD_BUFFER; + t_u16 cmd_len = 0; + int ret = UAP_SUCCESS; + int opt; + int get_akm_val = 0; + int resend = 0; + t_u16 tlv_val_16 = 0; + while ((opt = getopt_long(argc, argv, "+", cmd_options, NULL)) != -1) { + switch (opt) { + default: + print_sys_cfg_protocol_usage(); + return UAP_SUCCESS; + } + } + argc -= optind; + argv += optind; + /* Check arguments */ + if (argc && (is_input_valid(PROTOCOL, argc, argv) != UAP_SUCCESS || + is_input_valid(AKM_SUITE, argc, argv) != UAP_SUCCESS)) { + print_sys_cfg_protocol_usage(); + return UAP_FAILURE; + } + + if ((argc == 1) && + ((atoi(argv[0]) == PROTOCOL_WPA) || + (atoi(argv[0]) == PROTOCOL_WPA2) || + (atoi(argv[0]) == PROTOCOL_WPA2_MIXED) + || (atoi(argv[0]) == PROTOCOL_WPA3_SAE) + )) { + get_akm_val = 1; + } + + /* Initialize the command buffer */ + buffer = (t_u8 *)malloc(buf_len); + if (!buffer) { + printf("ERR:Cannot allocate buffer for command!\n"); + return UAP_FAILURE; + } + + /* case such as ./uaputl.exe sys_cfg_protocol 8/32/40 */ + /* Don't assume PSK in such cases, query FW and then set */ + do { + memset(buffer, 0, buf_len); + + /* Initialize the command length */ + if ((argc == 1) && + ((atoi(argv[0]) == PROTOCOL_NO_SECURITY) || + (atoi(argv[0]) == PROTOCOL_STATIC_WEP))) { + cmd_len = + sizeof(apcmdbuf_sys_configure) + + sizeof(tlvbuf_protocol); + } else { + cmd_len = + sizeof(apcmdbuf_sys_configure) + + sizeof(tlvbuf_protocol) + sizeof(tlvbuf_akmp); + } + + /* Locate headers */ + cmd_buf = (apcmdbuf_sys_configure *)buffer; + tlv = (tlvbuf_protocol *)(buffer + + sizeof(apcmdbuf_sys_configure)); + akmp_tlv = + (tlvbuf_akmp *)(buffer + + sizeof(apcmdbuf_sys_configure) + + sizeof(tlvbuf_protocol)); + /* Fill the command buffer */ + cmd_buf->cmd_code = APCMD_SYS_CONFIGURE; + cmd_buf->size = cmd_len; + cmd_buf->seq_num = 0; + cmd_buf->result = 0; + tlv->tag = MRVL_PROTOCOL_TLV_ID; + tlv->length = 2; + if (argc == 0) { + cmd_buf->action = ACTION_GET; + akmp_tlv->tag = MRVL_AKMP_TLV_ID; + akmp_tlv->length = 4; /* sizeof(tlvbuf_akmp) - TLVHEADER_LEN */ + } else { + cmd_buf->action = ACTION_SET; + tlv->protocol = (t_u16)atoi(argv[0]); + printf("protocol: 0x%x\n", tlv->protocol); + if (tlv->protocol & (PROTOCOL_WPA | PROTOCOL_WPA2 + | PROTOCOL_WPA3_SAE)) { + akmp_tlv->tag = MRVL_AKMP_TLV_ID; + akmp_tlv->length = 4; /* sizeof(tlvbuf_akmp) - TLVHEADER_LEN */ + if (argc == 2) { + akmp_tlv->key_mgmt = + (t_u16)A2HEXDECIMAL(argv[1]); + } else { + akmp_tlv->key_mgmt = tlv_val_16; // AKM SUITE from FW in 2nd iteration + if (get_akm_val) { + /* Get AKM SUITE val from FW */ + cmd_buf->action = ACTION_GET; + resend = 1; + } else + resend = 0; + } + printf("KeyMgmt: 0x%x\n", akmp_tlv->key_mgmt); + akmp_tlv->key_mgmt = + uap_cpu_to_le16(akmp_tlv->key_mgmt); + } + } + endian_convert_tlv_header_out(tlv); + if (cmd_len == + (sizeof(apcmdbuf_sys_configure) + sizeof(tlvbuf_protocol) + + sizeof(tlvbuf_akmp))) { + endian_convert_tlv_header_out(akmp_tlv); + } + tlv->protocol = uap_cpu_to_le16(tlv->protocol); + + /* Send the command */ + ret = uap_ioctl((t_u8 *)cmd_buf, &cmd_len, buf_len); + + /* Process response */ + if (ret == UAP_SUCCESS) { + /* Verify response */ + if (cmd_buf->cmd_code != + (APCMD_SYS_CONFIGURE | APCMD_RESP_CHECK)) { + printf("ERR:Corrupted response! cmd_code=%x, Tlv->tag=%x\n", cmd_buf->cmd_code, uap_le16_to_cpu(tlv->tag)); + free(buffer); + return UAP_FAILURE; + } + /* Print response */ + if (cmd_buf->result == CMD_SUCCESS) { + if (argc == 0) { + print_tlv((t_u8 *)tlv, + cmd_buf->size - + sizeof(apcmdbuf_sys_configure) + + BUF_HEADER_SIZE); + } else { + if (get_akm_val) { + get_akm_val = 0; + /* AKM Suite value from FW */ + tlv_val_16 = + *(t_u8 *)&akmp_tlv-> + key_mgmt; + tlv_val_16 |= + (* + ((t_u8 *)&akmp_tlv-> + key_mgmt + 1) << 8); + } else + printf("protocol setting successful\n"); + } + } else { + if (argc == 0) { + printf("ERR:Could not get protocol!\n"); + } else { + printf("ERR:Could not set protocol!\n"); + } + ret = UAP_FAILURE; + } + } else { + printf("ERR:Command sending failed!\n"); + } + } while (resend && (ret == UAP_SUCCESS)); + + if (buffer) + free(buffer); + + return ret; +} + +/** + * @brief Creates a sys_cfg request for WEP keys settings + * and sends to the driver + * + * Usage: "sys_cfg_wep_key [INDEX_0 IS_DEFAULT KEY_0] [INDEX_1 IS_DEFAULT KEY_1] [INDEX_2 IS_DEFAULT KEY_2] [INDEX_3 IS_DEFAULT KEY_3]" + * + * Options: INDEX_* : 0 - KeyIndex is 0 + * 1 - KeyIndex is 1 + * 2 - KeyIndex is 2 + * 3 - KeyIndex is 3 + * IS_DEFAUL : 0 - KeyIndex is not the default + * 1 - KeyIndex is the default transmit key + * KEY_* : Key value + * empty - Get current WEP key settings + * + * @param argc Number of arguments + * @param argv Pointer to the arguments + * @return UAP_SUCCESS/UAP_FAILURE + */ +int +apcmd_sys_cfg_wep_key(int argc, char *argv[]) +{ + apcmdbuf_sys_configure *cmd_buf = NULL; + tlvbuf_wep_key *tlv = NULL; + t_u8 *buffer = NULL; + t_u8 *tmp_buffer = NULL; + t_u16 cmd_len = 0; + t_u16 buf_len = MRVDRV_SIZE_OF_CMD_BUFFER; + int ret = UAP_SUCCESS; + int key_len = -1; + int length = 0; + int number_of_keys = 0; + int i = 0; + int keyindex = -1; + int is_default = -1; + char *key = NULL; + int opt; + while ((opt = getopt_long(argc, argv, "+", cmd_options, NULL)) != -1) { + switch (opt) { + default: + print_sys_cfg_wep_key_usage(); + return UAP_SUCCESS; + } + } + argc -= optind; + argv += optind; + + /* Check arguments */ + if (argc > 12) { + printf("ERR:Too many arguments.\n"); + print_sys_cfg_wep_key_usage(); + return UAP_FAILURE; + } else if ((argc > 1) && ((argc % 3) != 0)) { + printf("ERR:Illegal number of parameters.\n"); + print_sys_cfg_wep_key_usage(); + return UAP_FAILURE; + } else if (argc > 1) { + + /* Find number of keys provided */ + number_of_keys = argc / 3; + for (i = 0; i < number_of_keys; i++) { + if ((ISDIGIT(argv[(3 * i)]) == 0) || + (atoi(argv[(3 * i)]) < 0) || + (atoi(argv[(3 * i)]) > 3)) { + printf("ERR:Illegal INDEX %s. Must be either '0', '1', '2', or '3'.\n", argv[(3 * i)]); + print_sys_cfg_wep_key_usage(); + return UAP_FAILURE; + } + if ((ISDIGIT(argv[(3 * i) + 1]) == 0) || + (atoi(argv[(3 * i) + 1]) < 0) || + (atoi(argv[(3 * i) + 1]) > 1)) { + printf("ERR:Illegal IS_DEFAULT %s. Must be either '0', or '1'.\n", argv[(3 * i) + 1]); + print_sys_cfg_wep_key_usage(); + return UAP_FAILURE; + } + if ((strlen(argv[(3 * i) + 2]) != 5) && + (strlen(argv[(3 * i) + 2]) != 10) + && (strlen(argv[(3 * i) + 2]) != 13) && + (strlen(argv[(3 * i) + 2]) != 26)) { + printf("ERR:Incorrect KEY_%d length %d\n", + atoi(argv[(3 * i)]), + (t_u32)strlen(argv[(3 * i) + 2])); + print_sys_cfg_wep_key_usage(); + return UAP_FAILURE; + } + if ((strlen(argv[(3 * i) + 2]) == 10) || + (strlen(argv[(3 * i) + 2]) == 26)) { + if (UAP_FAILURE == + ishexstring(argv[(3 * i) + 2])) { + printf("ERR:Only hex digits are allowed when key length is 10 or 26\n"); + print_sys_cfg_wep_key_usage(); + return UAP_FAILURE; + } + } + } + } else if (argc == 1) { + if ((ISDIGIT(argv[0]) == 0) || (atoi(argv[0]) < 0) || + (atoi(argv[0]) > 3)) { + printf("ERR:Illegal INDEX %s. Must be either '0', '1', '2', or '3'.\n", argv[0]); + print_sys_cfg_wep_key_usage(); + return UAP_FAILURE; + } + } + + /* Initialize the command length */ + if (argc == 0 || argc == 1) { + if (argc == 0) + cmd_len = + sizeof(apcmdbuf_sys_configure) + + sizeof(tlvbuf_header); + else + cmd_len = + sizeof(apcmdbuf_sys_configure) + + sizeof(tlvbuf_wep_key) - 1; + } else { + cmd_len = sizeof(apcmdbuf_sys_configure); + } + /* Initialize the command buffer */ + buffer = (t_u8 *)malloc(buf_len); + if (!buffer) { + printf("ERR:Cannot allocate buffer for command!\n"); + return UAP_FAILURE; + } + memset(buffer, 0, buf_len); + + /* Locate headers */ + cmd_buf = (apcmdbuf_sys_configure *)buffer; + + /* Fill the command buffer */ + cmd_buf->cmd_code = APCMD_SYS_CONFIGURE; + cmd_buf->seq_num = 0; + cmd_buf->result = 0; + if (argc == 0 || argc == 1) { + cmd_buf->action = ACTION_GET; + tlv = (tlvbuf_wep_key *)(buffer + + sizeof(apcmdbuf_sys_configure)); + tlv->tag = MRVL_WEP_KEY_TLV_ID; + if (argc == 0) + tlv->length = 0; + else { + tlv->length = 1; + tlv->key_index = atoi(argv[0]); + } + endian_convert_tlv_header_out(tlv); + } else { + cmd_buf->action = ACTION_SET; + } + /* Add key TLVs */ + for (i = 0; i < number_of_keys; i++) { + keyindex = atoi(argv[(3 * i)]); + is_default = atoi(argv[(3 * i) + 1]); + key = argv[(3 * i) + 2]; + length = strlen(key); + switch (length) { + case 5: + case 10: + key_len = 5; + break; + case 13: + case 26: + key_len = 13; + break; + default: + key_len = 0; + break; + } + /* Adjust command buffer */ + tmp_buffer = + realloc(buffer, + (cmd_len + sizeof(tlvbuf_wep_key) + key_len)); + if (!tmp_buffer) { + printf("ERR:Cannot append WEP key configurations TLV!\n"); + free(buffer); + return UAP_FAILURE; + } else { + buffer = tmp_buffer; + tmp_buffer = NULL; + } + /* Locate headers */ + cmd_buf = (apcmdbuf_sys_configure *)buffer; + tlv = (tlvbuf_wep_key *)(buffer + cmd_len); + /* Adjust command length */ + cmd_len += (sizeof(tlvbuf_wep_key) + key_len); + /* Set TLV fields */ + tlv->tag = MRVL_WEP_KEY_TLV_ID; + tlv->length = 2 + key_len; + tlv->key_index = (t_u8)keyindex; + tlv->is_default = (t_u8)is_default; + /* Check if string or raw */ + switch (length) { + case 5: + case 13: + memcpy(tlv->key, key, length); + break; + case 10: + case 26: + string2raw(key, tlv->key); + break; + default: + break; + } + endian_convert_tlv_header_out(tlv); + } + + /* Update command length */ + cmd_buf->size = cmd_len; + if ((argc != 0) && (argc != 1)) + buf_len = cmd_len; + + /* Send the command */ + ret = uap_ioctl((t_u8 *)cmd_buf, &cmd_len, buf_len); + /* Process response */ + if (ret == UAP_SUCCESS) { + /* Verify response */ + if (cmd_buf->cmd_code != + (APCMD_SYS_CONFIGURE | APCMD_RESP_CHECK)) { + printf("ERR:Corrupted response!\n"); + free(buffer); + return UAP_FAILURE; + } + /* Print response */ + if (cmd_buf->result == CMD_SUCCESS) { + if ((argc != 0) && (argc != 1)) { + printf("WEP key setting successful\n"); + } else { + printf("query WEP key setting successful\n"); + tlv = (tlvbuf_wep_key *)(buffer + + sizeof + (apcmdbuf_sys_configure)); + print_tlv((t_u8 *)tlv, + cmd_buf->size - + sizeof(apcmdbuf_sys_configure) + + BUF_HEADER_SIZE); + } + } else { + if ((argc != 0) && (argc != 1)) + printf("ERR:Could not set WEP keys!\n"); + else + printf("ERR:Could not get WEP keys!\n"); + ret = UAP_FAILURE; + } + } else { + printf("ERR:Command sending failed!\n"); + } + if (buffer) + free(buffer); + return ret; +} + +/** + * @brief Creates a sys_cfg request for cipher configurations + * and sends to the driver + * + * Usage: "sys_cfg_cipher [PAIRWISE_CIPHER GROUP_CIPHER]" + * + * Options: PAIRWISE_CIPHER : Bit 2 - TKIP + * Bit 3 - AES CCMP + * GROUP_CIPHER : Bit 2 - TKIP + * Bit 3 - AES CCMP + * empty - Get current cipher settings + * + * @param argc Number of arguments + * @param argv Pointer to the arguments + * @return UAP_SUCCESS/UAP_FAILURE + */ +int +apcmd_sys_cfg_cipher(int argc, char *argv[]) +{ + apcmdbuf_sys_configure *cmd_buf = NULL; + tlvbuf_cipher *tlv = NULL; + t_u8 *buffer = NULL; + t_u16 cmd_len = 0; + t_u16 buf_len = MRVDRV_SIZE_OF_CMD_BUFFER; + int ret = UAP_SUCCESS; + int opt; + while ((opt = getopt_long(argc, argv, "+", cmd_options, NULL)) != -1) { + switch (opt) { + default: + print_sys_cfg_cipher_usage(); + return UAP_FAILURE; + } + } + argc -= optind; + argv += optind; + + /* Check arguments */ + if ((argc != 0) && (argc != 2)) { + printf("ERR:wrong arguments.\n"); + print_sys_cfg_cipher_usage(); + return UAP_FAILURE; + } + if (argc == 2) { + if ((ISDIGIT(argv[0]) == 0) || (ISDIGIT(argv[1]) == 0)) { + print_sys_cfg_cipher_usage(); + return UAP_FAILURE; + } + if (atoi(argv[0]) & ~CIPHER_BITMAP) { + printf("ERR:Illegal PAIRWISE_CIPHER parameter %s.\n", + argv[0]); + print_sys_cfg_cipher_usage(); + return UAP_FAILURE; + } + if (atoi(argv[1]) & ~CIPHER_BITMAP) { + printf("ERR:Illegal GROUP_CIPHER parameter %s.\n", + argv[1]); + print_sys_cfg_cipher_usage(); + return UAP_FAILURE; + } + if (is_cipher_valid(atoi(argv[0]), atoi(argv[1])) != + UAP_SUCCESS) { + printf("ERR:Wrong group and pairwise cipher combination!\n"); + print_sys_cfg_cipher_usage(); + return UAP_FAILURE; + } + } + /* Initialize the command length */ + cmd_len = sizeof(apcmdbuf_sys_configure) + sizeof(tlvbuf_cipher); + + /* Initialize the command buffer */ + buffer = (t_u8 *)malloc(buf_len); + if (!buffer) { + printf("ERR:Cannot allocate buffer for command!\n"); + return UAP_FAILURE; + } + memset(buffer, 0, buf_len); + + /* Locate headers */ + cmd_buf = (apcmdbuf_sys_configure *)buffer; + tlv = (tlvbuf_cipher *)(buffer + sizeof(apcmdbuf_sys_configure)); + /* Fill the command buffer */ + cmd_buf->cmd_code = APCMD_SYS_CONFIGURE; + cmd_buf->size = cmd_len; + cmd_buf->seq_num = 0; + cmd_buf->result = 0; + tlv->tag = MRVL_CIPHER_TLV_ID; + tlv->length = 2; + if (argc == 0) { + cmd_buf->action = ACTION_GET; + } else { + cmd_buf->action = ACTION_SET; + tlv->pairwise_cipher = (t_u8)atoi(argv[0]); + tlv->group_cipher = (t_u8)atoi(argv[1]); + } + endian_convert_tlv_header_out(tlv); + /* Send the command */ + ret = uap_ioctl((t_u8 *)cmd_buf, &cmd_len, buf_len); + endian_convert_tlv_header_in(tlv); + /* Process response */ + if (ret == UAP_SUCCESS) { + /* Verify response */ + if ((cmd_buf->cmd_code != + (APCMD_SYS_CONFIGURE | APCMD_RESP_CHECK)) || + (tlv->tag != MRVL_CIPHER_TLV_ID)) { + printf("ERR:Corrupted response! cmd_code=%x, Tlv->tag=%x\n", cmd_buf->cmd_code, tlv->tag); + free(buffer); + return UAP_FAILURE; + } + /* Print response */ + if (cmd_buf->result == CMD_SUCCESS) { + if (argc == 0) { + print_cipher(tlv); + } else { + printf("cipher setting successful\n"); + } + } else { + if (argc == 0) { + printf("ERR:Could not get cipher parameters!\n"); + } else { + printf("ERR:Could not set cipher parameters!\n"); + } + ret = UAP_FAILURE; + } + } else { + printf("ERR:Command sending failed!\n"); + } + if (buffer) + free(buffer); + return ret; +} + +/** + * @brief Creates a sys_cfg request for pairwise cipher configurations + * and sends to the driver + * + * Usage: "sys_cfg_pwk_cipher [] [PAIRWISE_CIPHER]" + * + * Options: PROTOCOL : Bit 3 - WPA + * Bit 5 - WPA2 + * PAIRWISE_CIPHER : Bit 2 - TKIP + * Bit 3 - AES CCMP + * empty - Get current pairwise cipher settings + * + * @param argc Number of arguments + * @param argv Pointer to the arguments + * @return UAP_SUCCESS/UAP_FAILURE + */ +int +apcmd_sys_cfg_pwk_cipher(int argc, char *argv[]) +{ + apcmdbuf_sys_configure *cmd_buf = NULL; + tlvbuf_pwk_cipher *tlv = NULL; + HTCap_t htcap; + t_u16 proto = 0; + t_u8 *buffer = NULL; + t_u16 tlv_get_len = 0, protocol = 0, cmd_len = 0; + t_u16 buf_len = MRVDRV_SIZE_OF_CMD_BUFFER; + int ret = UAP_SUCCESS; + int opt; + while ((opt = getopt_long(argc, argv, "+", cmd_options, NULL)) != -1) { + switch (opt) { + default: + print_sys_cfg_pwk_cipher_usage(); + return UAP_SUCCESS; + } + } + argc -= optind; + argv += optind; + + /* Check arguments */ + if (argc) { + if (is_input_valid(PWK_CIPHER, argc, argv) != UAP_SUCCESS) { + print_sys_cfg_pwk_cipher_usage(); + return UAP_FAILURE; + } + if ((argc == 2) && (atoi(argv[1]) == CIPHER_TKIP)) { + if (UAP_SUCCESS == get_sys_cfg_protocol(&proto)) { + /* Ok to have TKIP in mixed mode */ + if (proto != PROTOCOL_WPA2_MIXED) { + memset(&htcap, 0, sizeof(htcap)); + if (UAP_SUCCESS == + get_sys_cfg_11n(&htcap)) { + if (htcap.supported_mcs_set[0]) { + printf("ERR: WPA/TKIP cannot be used when AP operates in 802.11n mode.\n"); + print_sys_cfg_pwk_cipher_usage + (); + return UAP_FAILURE; + } + } + } + } + } + } + + /* Initialize the command length */ + cmd_len = sizeof(apcmdbuf_sys_configure) + sizeof(tlvbuf_pwk_cipher); + + /* Initialize the command buffer */ + buffer = (t_u8 *)malloc(buf_len); + if (!buffer) { + printf("ERR:Cannot allocate buffer for command!\n"); + return UAP_FAILURE; + } + memset(buffer, 0, buf_len); + + /* Locate headers */ + cmd_buf = (apcmdbuf_sys_configure *)buffer; + tlv = (tlvbuf_pwk_cipher *)(buffer + sizeof(apcmdbuf_sys_configure)); + /* Fill the command buffer */ + cmd_buf->cmd_code = APCMD_SYS_CONFIGURE; + cmd_buf->size = cmd_len; + cmd_buf->seq_num = 0; + cmd_buf->result = 0; + tlv->tag = MRVL_CIPHER_PWK_TLV_ID; + if (argc < 2) { + cmd_buf->action = ACTION_GET; + tlv->length = 0; + /* Adjust cmd_len for 0 payload */ + cmd_len = cmd_len - (sizeof(tlvbuf_pwk_cipher) - TLVHEADER_LEN); + if (argc == 1) + protocol = atoi(argv[0]); + } else { + cmd_buf->action = ACTION_SET; + tlv->length = sizeof(tlvbuf_pwk_cipher) - TLVHEADER_LEN; + tlv->protocol = (t_u16)atoi(argv[0]); + tlv->pairwise_cipher = (t_u8)atoi(argv[1]); + } + endian_convert_tlv_header_out(tlv); + tlv->protocol = uap_cpu_to_le16(tlv->protocol); + /* Send the command */ + ret = uap_ioctl((t_u8 *)cmd_buf, &cmd_len, buf_len); + endian_convert_tlv_header_in(tlv); + + /* Process response */ + if (ret == UAP_SUCCESS) { + /* Verify response */ + if ((cmd_buf->cmd_code != + (APCMD_SYS_CONFIGURE | APCMD_RESP_CHECK)) || + (tlv->tag != MRVL_CIPHER_PWK_TLV_ID)) { + printf("ERR:Corrupted response! cmd_code=%x, Tlv->tag=%x\n", cmd_buf->cmd_code, tlv->tag); + free(buffer); + return UAP_FAILURE; + } + /* Print response */ + if (cmd_buf->result == CMD_SUCCESS) { + if (argc < 2) { + tlv_get_len = + cmd_buf->size - + sizeof(apcmdbuf_sys_configure) + + BUF_HEADER_SIZE; + if ((!tlv_get_len) || + (tlv_get_len % sizeof(tlvbuf_pwk_cipher)) || + (tlv_get_len > + (3 * sizeof(tlvbuf_pwk_cipher)))) { + printf("ERR:Corrupted response!\n"); + free(buffer); + return UAP_FAILURE; + } + if (!proto) + get_sys_cfg_protocol(&proto); + if (proto & PROTOCOL_WPA || + proto & PROTOCOL_WPA2) + printf("Active Protocol = %s\n", + (proto == PROTOCOL_WPA) + ? "WPA" : (proto == + PROTOCOL_WPA2) ? + "WPA2" : "WPA | WPA2"); + while (tlv_get_len > 0) { + endian_convert_tlv_header_in(tlv); + tlv->protocol = + uap_le16_to_cpu(tlv->protocol); + if ((argc == 1) && + (protocol != tlv->protocol)) { + tlv_get_len -= + sizeof + (tlvbuf_pwk_cipher); + tlv++; + continue; + } + print_pwk_cipher(tlv); + tlv_get_len -= + sizeof(tlvbuf_pwk_cipher); + tlv++; + } + } else { + printf("protocol and pairwise cipher setting successful\n"); + } + } else { + if (argc < 2) { + printf("ERR:Could not get pairwise cipher parameters!\n"); + } else { + printf("ERR:Could not set pairwise cipher parameters!\n"); + } + ret = UAP_FAILURE; + } + } else { + printf("ERR:Command sending failed!\n"); + } + if (buffer) + free(buffer); + return ret; +} + +/** + * @brief Creates a sys_cfg request for group cipher configurations + * and sends to the driver + * + * Usage: "sys_cfg_gwk_cipher [GROUP_CIPHER]" + * + * Options: GROUP_CIPHER : Bit 2 - TKIP + * Bit 3 - AES CCMP + * empty - Get current group cipher settings + * + * @param argc Number of arguments + * @param argv Pointer to the arguments + * @return UAP_SUCCESS/UAP_FAILURE + */ +int +apcmd_sys_cfg_gwk_cipher(int argc, char *argv[]) +{ + apcmdbuf_sys_configure *cmd_buf = NULL; + tlvbuf_gwk_cipher *tlv = NULL; + t_u8 *buffer = NULL; + t_u16 cmd_len = 0; + t_u16 buf_len = MRVDRV_SIZE_OF_CMD_BUFFER; + int ret = UAP_SUCCESS; + int opt; + while ((opt = getopt_long(argc, argv, "+", cmd_options, NULL)) != -1) { + switch (opt) { + default: + print_sys_cfg_gwk_cipher_usage(); + return UAP_SUCCESS; + } + } + argc -= optind; + argv += optind; + + /* Check arguments */ + if (argc) { + if (is_input_valid(GWK_CIPHER, argc, argv) != UAP_SUCCESS) { + print_sys_cfg_gwk_cipher_usage(); + return UAP_FAILURE; + } + } + + /* Initialize the command length */ + cmd_len = sizeof(apcmdbuf_sys_configure) + sizeof(tlvbuf_gwk_cipher); + + /* Initialize the command buffer */ + buffer = (t_u8 *)malloc(buf_len); + if (!buffer) { + printf("ERR:Cannot allocate buffer for command!\n"); + return UAP_FAILURE; + } + memset(buffer, 0, buf_len); + + /* Locate headers */ + cmd_buf = (apcmdbuf_sys_configure *)buffer; + tlv = (tlvbuf_gwk_cipher *)(buffer + sizeof(apcmdbuf_sys_configure)); + /* Fill the command buffer */ + cmd_buf->cmd_code = APCMD_SYS_CONFIGURE; + cmd_buf->size = cmd_len; + cmd_buf->seq_num = 0; + cmd_buf->result = 0; + tlv->tag = MRVL_CIPHER_GWK_TLV_ID; + tlv->length = 2; + if (argc == 0) { + cmd_buf->action = ACTION_GET; + } else { + cmd_buf->action = ACTION_SET; + tlv->group_cipher = (t_u8)atoi(argv[0]); + } + endian_convert_tlv_header_out(tlv); + /* Send the command */ + ret = uap_ioctl((t_u8 *)cmd_buf, &cmd_len, buf_len); + endian_convert_tlv_header_in(tlv); + /* Process response */ + if (ret == UAP_SUCCESS) { + /* Verify response */ + if ((cmd_buf->cmd_code != + (APCMD_SYS_CONFIGURE | APCMD_RESP_CHECK)) || + (tlv->tag != MRVL_CIPHER_GWK_TLV_ID)) { + printf("ERR:Corrupted response! cmd_code=%x, Tlv->tag=%x\n", cmd_buf->cmd_code, tlv->tag); + free(buffer); + return UAP_FAILURE; + } + /* Print response */ + if (cmd_buf->result == CMD_SUCCESS) { + if (argc == 0) { + print_gwk_cipher(tlv); + } else { + printf("group cipher setting successful\n"); + } + } else { + if (argc == 0) { + printf("ERR:Could not get group cipher parameters!\n"); + } else { + printf("ERR:Could not set group cipher parameters!\n"); + } + ret = UAP_FAILURE; + } + } else { + printf("ERR:Command sending failed!\n"); + } + if (buffer) + free(buffer); + return ret; +} + +/** + * @brief Creates a sys_cfg request for group re-key timer + * and sends to the driver + * + * Usage: "Usage : sys_cfg_group_rekey_timer [GROUP_REKEY_TIMER]" + * + * Options: GROUP_REKEY_TIME is represented in seconds + * Get current group re-key timer + * + * @param argc Number of arguments + * @param argv Pointer to the arguments + * @return UAP_SUCCESS/UAP_FAILURE + */ +int +apcmd_sys_cfg_group_rekey_timer(int argc, char *argv[]) +{ + apcmdbuf_sys_configure *cmd_buf = NULL; + tlvbuf_group_rekey_timer *tlv = NULL; + t_u8 *buffer = NULL; + t_u16 cmd_len = 0; + t_u16 buf_len = MRVDRV_SIZE_OF_CMD_BUFFER; + int ret = UAP_SUCCESS; + int opt; + while ((opt = getopt_long(argc, argv, "+", cmd_options, NULL)) != -1) { + switch (opt) { + default: + print_sys_cfg_group_rekey_timer_usage(); + return UAP_SUCCESS; + } + } + argc -= optind; + argv += optind; + /* Check arguments */ + if (argc && + (is_input_valid(GROUPREKEYTIMER, argc, argv) != UAP_SUCCESS)) { + print_sys_cfg_group_rekey_timer_usage(); + return UAP_FAILURE; + } + + /* Initialize the command length */ + cmd_len = + sizeof(apcmdbuf_sys_configure) + + sizeof(tlvbuf_group_rekey_timer); + /* Initialize the command buffer */ + buffer = (t_u8 *)malloc(buf_len); + if (!buffer) { + printf("ERR:Cannot allocate buffer for command!\n"); + return UAP_FAILURE; + } + memset(buffer, 0, buf_len); + + /* Locate headers */ + cmd_buf = (apcmdbuf_sys_configure *)buffer; + tlv = (tlvbuf_group_rekey_timer *)(buffer + + sizeof(apcmdbuf_sys_configure)); + + /* Fill the command buffer */ + cmd_buf->cmd_code = APCMD_SYS_CONFIGURE; + cmd_buf->size = cmd_len; + cmd_buf->seq_num = 0; + cmd_buf->result = 0; + tlv->tag = MRVL_GRP_REKEY_TIME_TLV_ID; + tlv->length = 4; + if (argc == 0) { + cmd_buf->action = ACTION_GET; + } else { + cmd_buf->action = ACTION_SET; + tlv->group_rekey_time_sec = (t_u32)atoi(argv[0]); + } + endian_convert_tlv_header_out(tlv); + tlv->group_rekey_time_sec = uap_cpu_to_le32(tlv->group_rekey_time_sec); + /* Send the command */ + ret = uap_ioctl((t_u8 *)cmd_buf, &cmd_len, buf_len); + endian_convert_tlv_header_in(tlv); + tlv->group_rekey_time_sec = uap_le32_to_cpu(tlv->group_rekey_time_sec); + /* Process response */ + if (ret == UAP_SUCCESS) { + /* Verify response */ + if ((cmd_buf->cmd_code != + (APCMD_SYS_CONFIGURE | APCMD_RESP_CHECK)) || + (tlv->tag != MRVL_GRP_REKEY_TIME_TLV_ID)) { + printf("ERR:Corrupted response! cmd_code=%x, Tlv->tag=%x\n", cmd_buf->cmd_code, tlv->tag); + free(buffer); + return UAP_FAILURE; + } + /* Print response */ + if (cmd_buf->result == CMD_SUCCESS) { + if (argc == 0) { + if (tlv->group_rekey_time_sec > 0) + printf("Group rekey time is %d s\n", + tlv->group_rekey_time_sec); + else + printf("Group rekey time is disabled\n"); + } else { + printf("group re-key time setting successful\n"); + } + } else { + if (argc == 0) { + printf("ERR:Could not get group re-key time!\n"); + } else { + printf("ERR:Could not set group re-key time!\n"); + } + ret = UAP_FAILURE; + } + } else { + printf("ERR:Command sending failed!\n"); + } + if (buffer) + free(buffer); + return ret; +} + +/** + * @brief Creates a sys_cfg request for WPA passphrase + * and sends to the driver + * + * Usage: "sys_cfg_wpa_passphrase [PASSPHRASE]" + * if PASSPHRASE is provided, a 'set' is performed + * else a 'get' is performed + * + * @param argc Number of arguments + * @param argv Pointer to the arguments + * @return UAP_SUCCESS/UAP_FAILURE + */ +int +apcmd_sys_cfg_wpa_passphrase(int argc, char *argv[]) +{ + apcmdbuf_sys_configure *cmd_buf = NULL; + tlvbuf_wpa_passphrase *tlv = NULL; + t_u8 *buffer = NULL; + t_u16 cmd_len = 0; + t_u16 buf_len = MRVDRV_SIZE_OF_CMD_BUFFER; + int ret = UAP_SUCCESS; + + argc--; + argv++; + + /* Check arguments */ + if (argc > 1) { + printf("ERR:Too many arguments.\n"); + print_sys_cfg_wpa_passphrase_usage(); + return UAP_FAILURE; + } + if ((argc == 1) && (strlen(argv[0]) > MAX_WPA_PASSPHRASE_LENGTH)) { + printf("ERR:PASSPHRASE too long.\n"); + return UAP_FAILURE; + } + if ((argc == 1) && (strlen(argv[0]) < MIN_WPA_PASSPHRASE_LENGTH)) { + printf("ERR:PASSPHRASE too short.\n"); + return UAP_FAILURE; + } + if ((argc == 1) && (strlen(argv[0]) == MAX_WPA_PASSPHRASE_LENGTH)) { + if (UAP_FAILURE == ishexstring(argv[0])) { + printf("ERR:Only hex digits are allowed when passphrase's length is 64\n"); + return UAP_FAILURE; + } + } + /* Initialize the command length */ + if (argc == 0) + cmd_len = + sizeof(apcmdbuf_sys_configure) + + sizeof(tlvbuf_wpa_passphrase) + + MAX_WPA_PASSPHRASE_LENGTH; + else + cmd_len = + sizeof(apcmdbuf_sys_configure) + + sizeof(tlvbuf_wpa_passphrase) + strlen(argv[0]); + /* Initialize the command buffer */ + buffer = (t_u8 *)malloc(buf_len); + if (!buffer) { + printf("ERR:Cannot allocate buffer for command!\n"); + return UAP_FAILURE; + } + memset(buffer, 0, buf_len); + + /* Locate headers */ + cmd_buf = (apcmdbuf_sys_configure *)buffer; + tlv = (tlvbuf_wpa_passphrase *)(buffer + + sizeof(apcmdbuf_sys_configure)); + /* Fill the command buffer */ + cmd_buf->cmd_code = APCMD_SYS_CONFIGURE; + cmd_buf->size = cmd_len; + cmd_buf->seq_num = 0; + cmd_buf->result = 0; + tlv->tag = MRVL_WPA_PASSPHRASE_TLV_ID; + if (argc == 0) { + cmd_buf->action = ACTION_GET; + tlv->length = MAX_WPA_PASSPHRASE_LENGTH; + } else { + cmd_buf->action = ACTION_SET; + tlv->length = strlen(argv[0]); + memcpy(tlv->passphrase, argv[0], tlv->length); + } + endian_convert_tlv_header_out(tlv); + /* Send the command */ + ret = uap_ioctl((t_u8 *)cmd_buf, &cmd_len, buf_len); + endian_convert_tlv_header_in(tlv); + /* Process response */ + if (ret == UAP_SUCCESS) { + /* Verify response */ + if ((cmd_buf->cmd_code != + (APCMD_SYS_CONFIGURE | APCMD_RESP_CHECK)) || + (tlv->tag != MRVL_WPA_PASSPHRASE_TLV_ID)) { + printf("ERR:Corrupted response! cmd_code=%x, Tlv->tag=%x\n", cmd_buf->cmd_code, tlv->tag); + free(buffer); + return UAP_FAILURE; + } + /* Print response */ + if (cmd_buf->result == CMD_SUCCESS) { + if (argc == 0) { + if (tlv->length > 0) + printf("WPA passphrase = %s\n", + tlv->passphrase); + else + printf("WPA passphrase: None\n"); + } else { + printf("WPA passphrase setting successful\n"); + } + } else { + if (argc == 0) { + printf("ERR:Could not get WPA passphrase!\n"); + } else { + printf("ERR:Could not set WPA passphrase!\n"); + } + ret = UAP_FAILURE; + } + } else { + printf("ERR:Command sending failed!\n"); + } + if (buffer) + free(buffer); + return ret; +} + +/** + * @brief Creates a sys_cfg request for WPA3 SAE password + * and sends to the driver + * + * Usage: "sys_cfg_wpa3_sae_password [PASSWORD]" + * if PASSWORD is provided, a 'set' is performed + * else a 'get' is performed + * + * @param argc Number of arguments + * @param argv Pointer to the arguments + * @return UAP_SUCCESS/UAP_FAILURE + */ +int +apcmd_sys_cfg_wpa3_sae_password(int argc, char *argv[]) +{ + apcmdbuf_sys_configure *cmd_buf = NULL; + tlvbuf_wpa3_sae_password *tlv = NULL; + t_u8 *buffer = NULL; + t_u16 cmd_len = 0; + t_u16 buf_len = MRVDRV_SIZE_OF_CMD_BUFFER; + int ret = UAP_SUCCESS; + + argc--; + argv++; + + /* Check arguments */ + if (argc > 1) { + printf("ERR:Too many arguments.\n"); + print_sys_cfg_wpa3_sae_password_usage(); + return UAP_FAILURE; + } + if ((argc == 1) && (strlen(argv[0]) > MAX_WPA3_SAE_PASSWORD_LENGTH)) { + printf("ERR:PASSWORD too long.\n"); + return UAP_FAILURE; + } + if ((argc == 1) && (strlen(argv[0]) < MIN_WPA3_SAE_PASSWORD_LENGTH)) { + printf("ERR:PASSWORD too short.\n"); + return UAP_FAILURE; + } + /* Initialize the command length */ + if (argc == 0) + cmd_len = + sizeof(apcmdbuf_sys_configure) + + sizeof(tlvbuf_wpa3_sae_password) + + MAX_WPA3_SAE_PASSWORD_LENGTH; + else + cmd_len = + sizeof(apcmdbuf_sys_configure) + + sizeof(tlvbuf_wpa3_sae_password) + strlen(argv[0]); + /* Initialize the command buffer */ + buffer = (t_u8 *)malloc(buf_len); + if (!buffer) { + printf("ERR:Cannot allocate buffer for command!\n"); + return UAP_FAILURE; + } + memset(buffer, 0, buf_len); + + /* Locate headers */ + cmd_buf = (apcmdbuf_sys_configure *)buffer; + tlv = (tlvbuf_wpa3_sae_password *) (buffer + + sizeof(apcmdbuf_sys_configure)); + /* Fill the command buffer */ + cmd_buf->cmd_code = APCMD_SYS_CONFIGURE; + cmd_buf->size = cmd_len; + cmd_buf->seq_num = 0; + cmd_buf->result = 0; + tlv->tag = MRVL_WPA3_SAE_PASSWORD_TLV_ID; + if (argc == 0) { + cmd_buf->action = ACTION_GET; + tlv->length = MAX_WPA3_SAE_PASSWORD_LENGTH; + } else { + cmd_buf->action = ACTION_SET; + tlv->length = strlen(argv[0]); + memcpy(tlv->password, argv[0], tlv->length); + } + endian_convert_tlv_header_out(tlv); + /* Send the command */ + ret = uap_ioctl((t_u8 *)cmd_buf, &cmd_len, buf_len); + endian_convert_tlv_header_in(tlv); + /* Process response */ + if (ret == UAP_SUCCESS) { + /* Verify response */ + if ((cmd_buf->cmd_code != + (APCMD_SYS_CONFIGURE | APCMD_RESP_CHECK)) || + (tlv->tag != MRVL_WPA3_SAE_PASSWORD_TLV_ID)) { + printf("ERR:Corrupted response! cmd_code=%x, Tlv->tag=%x\n", cmd_buf->cmd_code, tlv->tag); + free(buffer); + return UAP_FAILURE; + } + /* Print response */ + if (cmd_buf->result == CMD_SUCCESS) { + if (argc == 0) { + if (tlv->length > 0) + printf("WPA3 SAE password = %s\n", + tlv->password); + else + printf("WPA3 SAE password: None\n"); + } else { + printf("WPA3 SAE password setting successful\n"); + } + } else { + if (argc == 0) { + printf("ERR:Could not get WPA3 SAE password!\n"); + } else { + printf("ERR:Could not set WPA3 SAE password!\n"); + } + ret = UAP_FAILURE; + } + } else { + printf("ERR:Command sending failed!\n"); + } + if (buffer) + free(buffer); + return ret; +} + +/** + * @brief Creates a STA filter request and sends to the driver + * + * Usage: "sta_filter_table " + * + * Options: FILTERMODE : 0 - Disable filter table + * 1 - Allow mac address specified in the allwed list + * 2 - Block MAC addresses specified in the banned list + * MACADDRESS_LIST is the list of MAC addresses to be acted upon. Each + * MAC address must be separated with a space. Maximum of + * 16 MAC addresses are supported. + * + * @param argc Number of arguments + * @param argv Pointer to the arguments + * @return UAP_SUCCESS/UAP_FAILURE + */ +int +apcmd_sta_filter_table(int argc, char *argv[]) +{ + apcmdbuf_sys_configure *cmd_buf = NULL; + tlvbuf_sta_mac_addr_filter *tlv = NULL; + t_u8 *buffer = NULL; + t_u16 cmd_len = 0; + t_u16 buf_len = MRVDRV_SIZE_OF_CMD_BUFFER; + int ret = UAP_SUCCESS; + int i = 0; + int opt; + while ((opt = getopt_long(argc, argv, "+", cmd_options, NULL)) != -1) { + switch (opt) { + default: + print_sta_filter_table_usage(); + return UAP_SUCCESS; + } + } + argc -= optind; + argv += optind; + /* Check arguments */ + if (argc > (MAX_MAC_ONESHOT_FILTER + 1)) { + printf("ERR:Too many arguments.\n"); + print_sta_filter_table_usage(); + return UAP_FAILURE; + } + if (argc > 0) { + if ((ISDIGIT(argv[0]) == 0) || + ((atoi(argv[0]) < 0) || (atoi(argv[0]) > 2))) { + printf("ERR:Illegal FILTERMODE parameter %s. Must be either '0', '1', or '2'.\n", argv[1]); + print_sta_filter_table_usage(); + return UAP_FAILURE; + } + } + /* Initialize the command length */ + if (argc == 0) { + cmd_len = + sizeof(apcmdbuf_sys_configure) + + sizeof(tlvbuf_sta_mac_addr_filter) + + (MAX_MAC_ONESHOT_FILTER * ETH_ALEN); + } else { + if (argc == 1) { + cmd_len = sizeof(apcmdbuf_sys_configure) + + sizeof(tlvbuf_sta_mac_addr_filter) + + (MAX_MAC_ONESHOT_FILTER * ETH_ALEN); + } else { + cmd_len = + sizeof(apcmdbuf_sys_configure) + + sizeof(tlvbuf_sta_mac_addr_filter) + (argc - + 1) * + ETH_ALEN; + } + } + + /* Initialize the command buffer */ + buffer = (t_u8 *)malloc(buf_len); + if (!buffer) { + printf("ERR:Cannot allocate buffer for command!\n"); + return UAP_FAILURE; + } + memset(buffer, 0, buf_len); + + /* Locate headers */ + cmd_buf = (apcmdbuf_sys_configure *)buffer; + tlv = (tlvbuf_sta_mac_addr_filter *)(buffer + + sizeof(apcmdbuf_sys_configure)); + + /* Fill the command buffer */ + cmd_buf->cmd_code = APCMD_SYS_CONFIGURE; + cmd_buf->size = cmd_len; + cmd_buf->seq_num = 0; + cmd_buf->result = 0; + tlv->tag = MRVL_STA_MAC_ADDR_FILTER_TLV_ID; + if (argc == 0) { + cmd_buf->action = ACTION_GET; + tlv->count = MAX_MAC_ONESHOT_FILTER; + } else { + cmd_buf->action = ACTION_SET; + tlv->filter_mode = atoi(argv[0]); + tlv->count = argc - 1; + if (tlv->count) { + for (i = 0; i < tlv->count; i++) { + if ((ret = + mac2raw(argv[i + 1], + &tlv->mac_address[i * + ETH_ALEN])) != + UAP_SUCCESS) { + printf("ERR: %s Address\n", + ret == + UAP_FAILURE ? "Invalid MAC" : ret + == + UAP_RET_MAC_BROADCAST ? + "Broadcast" : "Multicast"); + print_sta_filter_table_usage(); + free(buffer); + return UAP_FAILURE; + } + } + } else { + memset(tlv->mac_address, 0, + MAX_MAC_ONESHOT_FILTER * ETH_ALEN); + } + } + if (tlv->count) { + tlv->length = tlv->count * ETH_ALEN + 2; + } else { + tlv->length = MAX_MAC_ONESHOT_FILTER * ETH_ALEN + 2; + } + endian_convert_tlv_header_out(tlv); + /* Send the command */ + ret = uap_ioctl((t_u8 *)cmd_buf, &cmd_len, buf_len); + endian_convert_tlv_header_in(tlv); + /* Process response */ + if (ret == UAP_SUCCESS) { + /* Verify response */ + if ((cmd_buf->cmd_code != + (APCMD_SYS_CONFIGURE | APCMD_RESP_CHECK)) || + (tlv->tag != MRVL_STA_MAC_ADDR_FILTER_TLV_ID)) { + printf("ERR:Corrupted response! cmd_code=%x, Tlv->tag=%x\n", cmd_buf->cmd_code, tlv->tag); + free(buffer); + return UAP_FAILURE; + } + /* Print response */ + if (cmd_buf->result == CMD_SUCCESS) { + if (argc == 0) { + print_mac_filter(tlv); + } else { + printf("MAC address filter table setting successful!\n"); + } + } else { + if (argc == 0) { + printf("ERR:Could not get MAC address filter table settings!\n"); + } else { + printf("ERR:Could not set MAC address filter table settings!\n"); + } + ret = UAP_FAILURE; + } + } else { + printf("ERR:Command sending failed!\n"); + } + if (buffer) + free(buffer); + return ret; +} + +/** + * @brief Creates a sys_cfg request for max station number + * and sends to the driver + * + * Usage: "sys_cfg_max_sta_num [STA_NUM]" + * if STA_NUM is provided, a 'set' is performed + * else a 'get' is performed. + * + * STA_NUM should not bigger than 8 + * + * @param argc Number of arguments + * @param argv Pointer to the arguments + * @return UAP_SUCCESS/UAP_FAILURE + */ +int +apcmd_sys_cfg_max_sta_num(int argc, char *argv[]) +{ + apcmdbuf_sys_configure *cmd_buf = NULL; + tlvbuf_max_sta_num *tlv = NULL; + t_u8 *buffer = NULL; + t_u16 cmd_len = 0; + t_u16 buf_len = MRVDRV_SIZE_OF_CMD_BUFFER; + int ret = UAP_SUCCESS; + int opt; + t_u16 max_sta_num_supported = 0; + + while ((opt = getopt_long(argc, argv, "+", cmd_options, NULL)) != -1) { + switch (opt) { + default: + print_sys_cfg_max_sta_num_usage(); + return UAP_SUCCESS; + } + } + argc -= optind; + argv += optind; + + /* Check arguments */ + if (argc && (is_input_valid(MAXSTANUM, argc, argv) != UAP_SUCCESS)) { + print_sys_cfg_max_sta_num_usage(); + return UAP_FAILURE; + } + if (argc) { + if (get_max_sta_num_supported(&max_sta_num_supported) == + UAP_FAILURE) { + return UAP_FAILURE; + } + if (atoi(argv[0]) > max_sta_num_supported) { + printf("ERR: MAX_STA_NUM must be less than %d\n", + max_sta_num_supported); + print_sys_cfg_max_sta_num_usage(); + return UAP_FAILURE; + } + } + /* Initialize the command length */ + cmd_len = sizeof(apcmdbuf_sys_configure) + sizeof(tlvbuf_max_sta_num); + if (argc) { + cmd_len -= sizeof(tlv->max_sta_num_supported); + } + + /* Initialize the command buffer */ + buffer = (t_u8 *)malloc(buf_len); + if (!buffer) { + printf("ERR:Cannot allocate buffer for command!\n"); + return UAP_FAILURE; + } + memset(buffer, 0, buf_len); + + /* Locate headers */ + cmd_buf = (apcmdbuf_sys_configure *)buffer; + tlv = (tlvbuf_max_sta_num *)(buffer + sizeof(apcmdbuf_sys_configure)); + + /* Fill the command buffer */ + cmd_buf->cmd_code = APCMD_SYS_CONFIGURE; + cmd_buf->size = cmd_len; + cmd_buf->seq_num = 0; + cmd_buf->result = 0; + tlv->tag = MRVL_MAX_STA_CNT_TLV_ID; + if (argc == 0) { + tlv->length = 4; + cmd_buf->action = ACTION_GET; + } else { + tlv->length = 2; + cmd_buf->action = ACTION_SET; + tlv->max_sta_num_configured = (t_u16)atoi(argv[0]); + } + endian_convert_tlv_header_out(tlv); + tlv->max_sta_num_configured = + uap_cpu_to_le16(tlv->max_sta_num_configured); + tlv->max_sta_num_supported = + uap_cpu_to_le16(tlv->max_sta_num_supported); + + /* Send the command */ + ret = uap_ioctl((t_u8 *)cmd_buf, &cmd_len, buf_len); + endian_convert_tlv_header_in(tlv); + tlv->max_sta_num_configured = + uap_le16_to_cpu(tlv->max_sta_num_configured); + tlv->max_sta_num_supported = + uap_le16_to_cpu(tlv->max_sta_num_supported); + /* Process response */ + if (ret == UAP_SUCCESS) { + /* Verify response */ + if ((cmd_buf->cmd_code != + (APCMD_SYS_CONFIGURE | APCMD_RESP_CHECK)) || + (tlv->tag != MRVL_MAX_STA_CNT_TLV_ID)) { + printf("ERR:Corrupted response! cmd_code=%x, Tlv->tag=%x\n", cmd_buf->cmd_code, tlv->tag); + free(buffer); + return UAP_FAILURE; + } + /* Print response */ + if (cmd_buf->result == CMD_SUCCESS) { + if (argc == 0) { + printf("configured max station count = %d\n", + tlv->max_sta_num_configured); + if (tlv->length == 4) { + printf("max number of stations supported = %d\n", tlv->max_sta_num_supported); + } + } else { + printf("max station number setting successful\n"); + } + } else { + if (argc == 0) { + printf("ERR:Could not get configured max station count and supported max station count!\n"); + } else { + printf("ERR:Could not set max station number!\n"); + } + ret = UAP_FAILURE; + } + } else { + printf("ERR:Command sending failed!\n"); + } + if (buffer) + free(buffer); + return ret; +} + +/** + * @brief Creates a sys_cfg request for retry limit + * and sends to the driver + * + * Usage: "sys_cfg_retry_limit [RETRY_LIMIT]" + * if RETRY_LIMIT is provided, a 'set' is performed + * else a 'get' is performed. + * + * RETRY_LIMIT should not bigger than 14 + * + * @param argc Number of arguments + * @param argv Pointer to the arguments + * @return UAP_SUCCESS/UAP_FAILURE + */ +int +apcmd_sys_cfg_retry_limit(int argc, char *argv[]) +{ + apcmdbuf_sys_configure *cmd_buf = NULL; + tlvbuf_retry_limit *tlv = NULL; + t_u8 *buffer = NULL; + t_u16 cmd_len = 0; + t_u16 buf_len = MRVDRV_SIZE_OF_CMD_BUFFER; + int ret = UAP_SUCCESS; + int opt; + + while ((opt = getopt_long(argc, argv, "+", cmd_options, NULL)) != -1) { + switch (opt) { + default: + print_sys_cfg_retry_limit_usage(); + return UAP_SUCCESS; + } + } + argc -= optind; + argv += optind; + + /* Check arguments */ + if (argc && (is_input_valid(RETRYLIMIT, argc, argv) != UAP_SUCCESS)) { + print_sys_cfg_retry_limit_usage(); + return UAP_FAILURE; + } + + /* Initialize the command length */ + cmd_len = sizeof(apcmdbuf_sys_configure) + sizeof(tlvbuf_retry_limit); + + /* Initialize the command buffer */ + buffer = (t_u8 *)malloc(buf_len); + if (!buffer) { + printf("ERR:Cannot allocate buffer for command!\n"); + return UAP_FAILURE; + } + memset(buffer, 0, buf_len); + + /* Locate headers */ + cmd_buf = (apcmdbuf_sys_configure *)buffer; + tlv = (tlvbuf_retry_limit *)(buffer + sizeof(apcmdbuf_sys_configure)); + + /* Fill the command buffer */ + cmd_buf->cmd_code = APCMD_SYS_CONFIGURE; + cmd_buf->size = cmd_len; + cmd_buf->seq_num = 0; + cmd_buf->result = 0; + tlv->tag = MRVL_RETRY_LIMIT_TLV_ID; + tlv->length = 1; + if (argc == 0) { + cmd_buf->action = ACTION_GET; + } else { + cmd_buf->action = ACTION_SET; + tlv->retry_limit = (t_u8)atoi(argv[0]); + } + endian_convert_tlv_header_out(tlv); + + /* Send the command */ + ret = uap_ioctl((t_u8 *)cmd_buf, &cmd_len, buf_len); + endian_convert_tlv_header_in(tlv); + + /* Process response */ + if (ret == UAP_SUCCESS) { + /* Verify response */ + if ((cmd_buf->cmd_code != + (APCMD_SYS_CONFIGURE | APCMD_RESP_CHECK)) || + (tlv->tag != MRVL_RETRY_LIMIT_TLV_ID)) { + printf("ERR:Corrupted response! cmd_code=%x, Tlv->tag=%x\n", cmd_buf->cmd_code, tlv->tag); + free(buffer); + return UAP_FAILURE; + } + /* Print response */ + if (cmd_buf->result == CMD_SUCCESS) { + if (argc == 0) { + printf("retry limit = %d\n", tlv->retry_limit); + } else { + printf("retry limit setting successful\n"); + } + } else { + if (argc == 0) { + printf("ERR:Could not get retry limit!\n"); + } else { + printf("ERR:Could not set retry limit!\n"); + } + ret = UAP_FAILURE; + } + } else { + printf("ERR:Command sending failed!\n"); + } + if (buffer) + free(buffer); + return ret; +} + +/** + * @brief Creates a sys_cfg request for sticky TIM configuration + * and sends to the driver + * + * Usage: "sys_cfg_sticky_tim_config [ENABLE] [ ]" + * + * @param argc Number of arguments + * @param argv Pointer to the arguments + * @return UAP_SUCCESS/UAP_FAILURE + */ +int +apcmd_sys_cfg_sticky_tim_config(int argc, char *argv[]) +{ + apcmdbuf_sys_configure *cmd_buf = NULL; + tlvbuf_sticky_tim_config *tlv = NULL; + t_u8 *buffer = NULL; + t_u16 cmd_len = 0; + t_u16 buf_len = MRVDRV_SIZE_OF_CMD_BUFFER; + int ret = UAP_SUCCESS; + int opt; + + while ((opt = getopt_long(argc, argv, "+", cmd_options, NULL)) != -1) { + switch (opt) { + default: + print_sys_cfg_sticky_tim_config_usage(); + return UAP_SUCCESS; + } + } + argc -= optind; + argv += optind; + + /* Check arguments */ + if (argc && + (is_input_valid(STICKYTIMCONFIG, argc, argv) != UAP_SUCCESS)) { + print_sys_cfg_sticky_tim_config_usage(); + return UAP_FAILURE; + } + /* Initialize the command length */ + cmd_len = + sizeof(apcmdbuf_sys_configure) + + sizeof(tlvbuf_sticky_tim_config); + /* Initialize the command buffer */ + buffer = (t_u8 *)malloc(buf_len); + + if (!buffer) { + printf("ERR:Cannot allocate buffer for command!\n"); + return UAP_FAILURE; + } + memset(buffer, 0, buf_len); + + /* Locate headers */ + cmd_buf = (apcmdbuf_sys_configure *)buffer; + tlv = (tlvbuf_sticky_tim_config *)(buffer + + sizeof(apcmdbuf_sys_configure)); + + /* Fill the command buffer */ + cmd_buf->cmd_code = APCMD_SYS_CONFIGURE; + cmd_buf->size = cmd_len; + cmd_buf->seq_num = 0; + cmd_buf->result = 0; + tlv->tag = MRVL_STICKY_TIM_CONFIG_TLV_ID; + tlv->length = sizeof(tlvbuf_sticky_tim_config) - TLVHEADER_LEN; + if (argc == 0) { + cmd_buf->action = ACTION_GET; + } else { + cmd_buf->action = ACTION_SET; + tlv->enable = (t_u16)atoi(argv[0]); + if (argc > 1) { + tlv->duration = (t_u16)atoi(argv[1]); + tlv->sticky_bitmask = (t_u16)atoi(argv[2]); + } + } + endian_convert_tlv_header_out(tlv); + tlv->enable = uap_cpu_to_le16(tlv->enable); + if (argc > 1) { + tlv->duration = uap_cpu_to_le16(tlv->duration); + tlv->sticky_bitmask = uap_cpu_to_le16(tlv->sticky_bitmask); + } + /* Send the command */ + ret = uap_ioctl((t_u8 *)cmd_buf, &cmd_len, buf_len); + endian_convert_tlv_header_in(tlv); + tlv->enable = uap_le16_to_cpu(tlv->enable); + if (argc > 1) { + tlv->duration = uap_le16_to_cpu(tlv->duration); + tlv->sticky_bitmask = uap_le16_to_cpu(tlv->sticky_bitmask); + } + + /* Process response */ + if (ret == UAP_SUCCESS) { + /* Verify response */ + if ((cmd_buf->cmd_code != + (APCMD_SYS_CONFIGURE | APCMD_RESP_CHECK)) || + (tlv->tag != MRVL_STICKY_TIM_CONFIG_TLV_ID)) { + printf("ERR:Corrupted response! cmd_code=%x, Tlv->tag=%x\n", cmd_buf->cmd_code, tlv->tag); + free(buffer); + return UAP_FAILURE; + } + /* Print response */ + if (cmd_buf->result == CMD_SUCCESS) { + if (argc == 0) { + printf("Sticky TIM is %s\n", + (tlv->enable == + 0) ? "disabled" : "enabled"); + printf("Duration = %d beacons\n", + tlv->duration); + printf("Sticky Bitmask = %x\n", + tlv->sticky_bitmask); + } else { + printf("sticky TIM configuration successful\n"); + } + } else { + if (argc == 0) { + printf("ERR:Could not get sticky TIM configuration!\n"); + } else { + printf("ERR:Could not set sticky TIM configuration!\n"); + } + ret = UAP_FAILURE; + } + } else { + printf("ERR:Command sending failed!\n"); + } + if (buffer) + free(buffer); + return ret; +} + +/** + * @brief Creates a sys_cfg request for sticky TIM station MAC address + * and sends to the driver + * + * Usage: "sys_cfg_sticky_tim_sta_mac_addr [CONTROL] [STA_MAC_ADDRESS]" + * + * @param argc Number of arguments + * @param argv Pointer to the arguments + * @return UAP_SUCCESS/UAP_FAILURE + */ +int +apcmd_sys_cfg_sticky_tim_sta_mac_addr(int argc, char *argv[]) +{ + apcmdbuf_sys_configure *cmd_buf = NULL; + tlvbuf_sticky_tim_sta_mac_addr *tlv = NULL; + t_u8 *buffer = NULL; + t_u16 cmd_len = 0; + t_u16 buf_len = MRVDRV_SIZE_OF_CMD_BUFFER; + int tlv_get_len = 0; + int ret = UAP_SUCCESS; + int opt; + + while ((opt = getopt_long(argc, argv, "+", cmd_options, NULL)) != -1) { + switch (opt) { + default: + print_sys_cfg_sticky_tim_sta_mac_addr_usage(); + return UAP_SUCCESS; + } + } + argc -= optind; + argv += optind; + + /* Check arguments */ + if (argc && + (is_input_valid(STICKYTIMSTAMACADDR, argc, argv) != UAP_SUCCESS)) { + print_sys_cfg_sticky_tim_sta_mac_addr_usage(); + return UAP_FAILURE; + } + /* Initialize the command length */ + cmd_len = + sizeof(apcmdbuf_sys_configure) + + sizeof(tlvbuf_sticky_tim_sta_mac_addr); + + /* Initialize the command buffer */ + buffer = (t_u8 *)malloc(buf_len); + if (!buffer) { + printf("ERR:Cannot allocate buffer for command!\n"); + return UAP_FAILURE; + } + memset(buffer, 0, buf_len); + + /* Locate headers */ + cmd_buf = (apcmdbuf_sys_configure *)buffer; + tlv = (tlvbuf_sticky_tim_sta_mac_addr *)(buffer + + sizeof + (apcmdbuf_sys_configure)); + + /* Fill the command buffer */ + cmd_buf->cmd_code = APCMD_SYS_CONFIGURE; + cmd_buf->size = cmd_len; + cmd_buf->seq_num = 0; + cmd_buf->result = 0; + tlv->tag = MRVL_STICKY_TIM_STA_MAC_ADDR_TLV_ID; + tlv->length = sizeof(tlvbuf_sticky_tim_sta_mac_addr) - TLVHEADER_LEN; + if (argc < 2) { + cmd_buf->action = ACTION_GET; + if (argc == 0) { + tlv->length = 0; + cmd_len -= + sizeof(tlvbuf_sticky_tim_sta_mac_addr) - + TLVHEADER_LEN; + } + if ((argc == 1) && + mac2raw(argv[0], tlv->sta_mac_address) != UAP_SUCCESS) { + printf("ERR: Invalid MAC address %s \n", argv[0]); + free(buffer); + return UAP_FAILURE; + } + } else { + cmd_buf->action = ACTION_SET; + tlv->control = (t_u16)atoi(argv[0]); + if (mac2raw(argv[1], tlv->sta_mac_address) != UAP_SUCCESS) { + printf("ERR: Invalid MAC address %s \n", argv[1]); + free(buffer); + return UAP_FAILURE; + } + } + endian_convert_tlv_header_out(tlv); + tlv->control = uap_cpu_to_le16(tlv->control); + /* Send the command */ + ret = uap_ioctl((t_u8 *)cmd_buf, &cmd_len, buf_len); + endian_convert_tlv_header_in(tlv); + tlv->control = uap_le16_to_cpu(tlv->control); + + /* Process response */ + if (ret == UAP_SUCCESS) { + /* Verify response */ + if ((cmd_buf->cmd_code != + (APCMD_SYS_CONFIGURE | APCMD_RESP_CHECK)) || + (tlv->tag != MRVL_STICKY_TIM_STA_MAC_ADDR_TLV_ID)) { + printf("ERR:Corrupted response! cmd_code=%x, Tlv->tag=%x\n", cmd_buf->cmd_code, tlv->tag); + free(buffer); + return UAP_FAILURE; + } + /* Print response */ + if (cmd_buf->result == CMD_SUCCESS) { + if (argc < 2) { + tlv_get_len = + cmd_buf->size - + sizeof(apcmdbuf_sys_configure) + + BUF_HEADER_SIZE; + while (tlv_get_len > 0) { + printf("station MAC address = "); + print_mac(tlv->sta_mac_address); + printf("\ncontrol = %x\n", + tlv->control); + tlv++; + tlv_get_len -= + sizeof + (tlvbuf_sticky_tim_sta_mac_addr); + } + } else { + printf("sticky TIM configuration for given station is successful\n"); + } + } else { + if (argc < 2) { + printf("ERR:Could not get sticky TIM configuration for station(s)!\n"); + } else { + printf("ERR:Could not set sticky TIM configuration for given station!\n"); + } + ret = UAP_FAILURE; + } + } else { + printf("ERR:Command sending failed!\n"); + } + if (buffer) + free(buffer); + return ret; +} + +/** + * @brief Creates a sys_cfg request for 20/40 coex configuration + * and sends to the driver + * + * Usage: "sys_cfg_2040_coex [ENABLE]" + * + * @param argc Number of arguments + * @param argv Pointer to the arguments + * @return UAP_SUCCESS/UAP_FAILURE + */ +int +apcmd_sys_cfg_2040_coex(int argc, char *argv[]) +{ + apcmdbuf_sys_configure *cmd_buf = NULL; + tlvbuf_2040_coex *tlv = NULL; + t_u8 *buffer = NULL; + t_u16 cmd_len = 0; + t_u16 buf_len = MRVDRV_SIZE_OF_CMD_BUFFER; + int ret = UAP_SUCCESS; + int opt; + + while ((opt = getopt_long(argc, argv, "+", cmd_options, NULL)) != -1) { + switch (opt) { + default: + print_sys_cfg_2040_coex_usage(); + return UAP_SUCCESS; + } + } + argc -= optind; + argv += optind; + + /* Check arguments */ + if (argc && (is_input_valid(COEX2040CONFIG, argc, argv) != UAP_SUCCESS)) { + print_sys_cfg_2040_coex_usage(); + return UAP_FAILURE; + } + /* Initialize the command length */ + cmd_len = sizeof(apcmdbuf_sys_configure) + sizeof(tlvbuf_2040_coex); + /* Initialize the command buffer */ + buffer = (t_u8 *)malloc(buf_len); + + if (!buffer) { + printf("ERR:Cannot allocate buffer for command!\n"); + return UAP_FAILURE; + } + memset(buffer, 0, buf_len); + + /* Locate headers */ + cmd_buf = (apcmdbuf_sys_configure *)buffer; + tlv = (tlvbuf_2040_coex *)(buffer + sizeof(apcmdbuf_sys_configure)); + + /* Fill the command buffer */ + cmd_buf->cmd_code = APCMD_SYS_CONFIGURE; + cmd_buf->size = cmd_len; + cmd_buf->seq_num = 0; + cmd_buf->result = 0; + tlv->tag = MRVL_2040_BSS_COEX_CONTROL_TLV_ID; + tlv->length = sizeof(tlvbuf_2040_coex) - TLVHEADER_LEN; + if (argc == 0) { + cmd_buf->action = ACTION_GET; + } else { + cmd_buf->action = ACTION_SET; + tlv->enable = (t_u8)atoi(argv[0]); + } + endian_convert_tlv_header_out(tlv); + + /* Send the command */ + ret = uap_ioctl((t_u8 *)cmd_buf, &cmd_len, buf_len); + endian_convert_tlv_header_in(tlv); + + /* Process response */ + if (ret == UAP_SUCCESS) { + /* Verify response */ + if ((cmd_buf->cmd_code != + (APCMD_SYS_CONFIGURE | APCMD_RESP_CHECK)) || + (tlv->tag != MRVL_2040_BSS_COEX_CONTROL_TLV_ID)) { + printf("ERR:Corrupted response! cmd_code=%x, Tlv->tag=%x\n", cmd_buf->cmd_code, tlv->tag); + free(buffer); + return UAP_FAILURE; + } + /* Print response */ + if (cmd_buf->result == CMD_SUCCESS) { + if (argc == 0) { + printf("20/40 BSS Co-existence is %s\n", + (tlv->enable == + 0) ? "disabled" : "enabled"); + } else { + printf("20/40 coex configuration successful\n"); + } + } else { + printf("ERR:Could not %s 2040 coex configuration!\n", + argc ? "set" : "get"); + if (argc) + printf("20/40 coex configuration is allowed to set only before bss start.\n"); + ret = UAP_FAILURE; + } + } else { + printf("ERR:Command sending failed!\n"); + } + if (buffer) + free(buffer); + return ret; +} + +/** + * @brief Creates a sys_cfg request for setting pairwise key handshake timeout + * and number of retries and sends to the driver + * + * Usage: "sys_cfg_eapol_pwk_hsk [ ]" + * If both TIMEOUT value and number of RETRIES are provided, + * a 'set' is performed else a 'get' is performed. + * + * @param argc Number of arguments + * @param argv Pointer to the arguments + * @return UAP_SUCCESS/UAP_FAILURE + */ +int +apcmd_sys_cfg_eapol_pwk_hsk(int argc, char *argv[]) +{ + int opt; + t_u16 cmd_len = 0; + t_u16 buf_len = MRVDRV_SIZE_OF_CMD_BUFFER; + int ret = UAP_SUCCESS; + t_u8 *tlv_buf = NULL; + t_u8 *buffer = NULL; + apcmdbuf_sys_configure *cmd_buf = NULL; + tlvbuf_eapol_pwk_hsk_timeout *timeout_tlv = NULL; + tlvbuf_eapol_pwk_hsk_retries *retries_tlv = NULL; + + while ((opt = getopt_long(argc, argv, "+", cmd_options, NULL)) != -1) { + switch (opt) { + default: + print_sys_cfg_eapol_pwk_hsk_usage(); + return UAP_SUCCESS; + } + } + argc -= optind; + argv += optind; + + /* Check Arguments */ + if (argc && (is_input_valid(EAPOL_PWK_HSK, argc, argv) != UAP_SUCCESS)) { + print_sys_cfg_eapol_pwk_hsk_usage(); + return UAP_FAILURE; + } + + /* Initialize the command length */ + cmd_len = + sizeof(apcmdbuf_sys_configure) + + sizeof(tlvbuf_eapol_pwk_hsk_timeout) + + sizeof(tlvbuf_eapol_pwk_hsk_retries); + + /* Initialize the command buffer */ + buffer = (t_u8 *)malloc(buf_len); + if (!buffer) { + printf("ERR:Cannot allocate buffer for command!\n"); + return UAP_FAILURE; + } + memset(buffer, 0, buf_len); + + /* Fill the command buffer */ + cmd_buf = (apcmdbuf_sys_configure *)buffer; + cmd_buf->cmd_code = APCMD_SYS_CONFIGURE; + cmd_buf->size = cmd_len; + cmd_buf->seq_num = 0; + cmd_buf->result = 0; + cmd_buf->action = argc ? ACTION_SET : ACTION_GET; + tlv_buf = buffer + sizeof(apcmdbuf_sys_configure); + + /* Fill Timeout tlv */ + timeout_tlv = + (tlvbuf_eapol_pwk_hsk_timeout *)(buffer + + sizeof + (apcmdbuf_sys_configure)); + timeout_tlv->tag = MRVL_EAPOL_PWK_HSK_TIMEOUT_TLV_ID; + timeout_tlv->length = 4; + if (argv[0]) + timeout_tlv->pairwise_update_timeout = (t_u32)atoi(argv[0]); + tlv_buf += sizeof(tlvbuf_eapol_pwk_hsk_timeout); + endian_convert_tlv_header_out(timeout_tlv); + timeout_tlv->pairwise_update_timeout = + uap_cpu_to_le32(timeout_tlv->pairwise_update_timeout); + + /* Fill retries tlv */ + retries_tlv = (tlvbuf_eapol_pwk_hsk_retries *)(tlv_buf); + retries_tlv->tag = MRVL_EAPOL_PWK_HSK_RETRIES_TLV_ID; + retries_tlv->length = 4; + if (argv[1]) + retries_tlv->pwk_retries = (t_u32)atoi(argv[1]); + endian_convert_tlv_header_out(retries_tlv); + retries_tlv->pwk_retries = uap_cpu_to_le32(retries_tlv->pwk_retries); + + /* Send the command */ + ret = uap_ioctl((t_u8 *)cmd_buf, &cmd_len, buf_len); + tlv_buf = buffer + sizeof(apcmdbuf_sys_configure); + + /* Process response */ + if (ret == UAP_SUCCESS) { + /* Verify response */ + if (cmd_buf->cmd_code != + (APCMD_SYS_CONFIGURE | APCMD_RESP_CHECK)) { + printf("ERR:Corrupted response! cmd_code=%x\n", + cmd_buf->cmd_code); + free(buffer); + return UAP_FAILURE; + } + /* Print response */ + if (cmd_buf->result == CMD_SUCCESS) { + if (argc) { + printf("PWK update timeout and retries setting successful\n"); + } else { + print_tlv((t_u8 *)tlv_buf, + cmd_buf->size - + sizeof(apcmdbuf_sys_configure) + + BUF_HEADER_SIZE); + } + } else { + printf("ERR:Could not %s pwk timeout and retries value!\n", argc ? "set" : "get"); + if (argc) + printf("PWK timeout and retries are allowed to set only before bss start.\n"); + ret = UAP_FAILURE; + } + } else { + printf("ERR:Command sending failed!\n"); + } + + if (buffer) + free(buffer); + return ret; +} + +/** + * @brief Creates a sys_cfg request for setting groupwise key handshake timeout + * and number of retries and sends to the driver + * + * Usage: "sys_cfg_eapol_gwk_hsk [ ]" + * If both TIMEOUT value and number of RETRIES are provided, + * a 'set' is performed else a 'get' is performed. + * + * @param argc Number of arguments + * @param argv Pointer to the arguments + * @return UAP_SUCCESS/UAP_FAILURE + */ +int +apcmd_sys_cfg_eapol_gwk_hsk(int argc, char *argv[]) +{ + int opt; + t_u16 cmd_len = 0; + t_u16 buf_len = MRVDRV_SIZE_OF_CMD_BUFFER; + int ret = UAP_SUCCESS; + t_u8 *tlv_buf = NULL; + t_u8 *buffer = NULL; + apcmdbuf_sys_configure *cmd_buf = NULL; + tlvbuf_eapol_gwk_hsk_timeout *timeout_tlv = NULL; + tlvbuf_eapol_gwk_hsk_retries *retries_tlv = NULL; + + while ((opt = getopt_long(argc, argv, "+", cmd_options, NULL)) != -1) { + switch (opt) { + default: + print_sys_cfg_eapol_gwk_hsk_usage(); + return UAP_SUCCESS; + } + } + argc -= optind; + argv += optind; + + /* Check Arguments */ + if (argc && (is_input_valid(EAPOL_GWK_HSK, argc, argv) != UAP_SUCCESS)) { + print_sys_cfg_eapol_gwk_hsk_usage(); + return UAP_FAILURE; + } + /* Initialize the command length */ + cmd_len = + sizeof(apcmdbuf_sys_configure) + + sizeof(tlvbuf_eapol_gwk_hsk_timeout) + + sizeof(tlvbuf_eapol_gwk_hsk_retries); + + /* Initialize the command buffer */ + buffer = (t_u8 *)malloc(buf_len); + if (!buffer) { + printf("ERR:Cannot allocate buffer for command!\n"); + return UAP_FAILURE; + } + memset(buffer, 0, buf_len); + + /* Fill the command buffer */ + cmd_buf = (apcmdbuf_sys_configure *)buffer; + cmd_buf->cmd_code = APCMD_SYS_CONFIGURE; + cmd_buf->size = cmd_len; + cmd_buf->seq_num = 0; + cmd_buf->result = 0; + cmd_buf->action = argc ? ACTION_SET : ACTION_GET; + tlv_buf = buffer + sizeof(apcmdbuf_sys_configure); + + /* Fill Timeout tlv */ + timeout_tlv = + (tlvbuf_eapol_gwk_hsk_timeout *)(buffer + + sizeof + (apcmdbuf_sys_configure)); + timeout_tlv->tag = MRVL_EAPOL_GWK_HSK_TIMEOUT_TLV_ID; + timeout_tlv->length = 4; + if (argv[0]) + timeout_tlv->groupwise_update_timeout = (t_u32)atoi(argv[0]); + tlv_buf += sizeof(tlvbuf_eapol_gwk_hsk_timeout); + endian_convert_tlv_header_out(timeout_tlv); + timeout_tlv->groupwise_update_timeout = + uap_cpu_to_le32(timeout_tlv->groupwise_update_timeout); + + /* Fill retries tlv */ + retries_tlv = (tlvbuf_eapol_gwk_hsk_retries *)(tlv_buf); + retries_tlv->tag = MRVL_EAPOL_GWK_HSK_RETRIES_TLV_ID; + retries_tlv->length = 4; + if (argv[1]) + retries_tlv->gwk_retries = (t_u32)atoi(argv[1]); + endian_convert_tlv_header_out(retries_tlv); + retries_tlv->gwk_retries = uap_cpu_to_le32(retries_tlv->gwk_retries); + + /* Send the command */ + ret = uap_ioctl((t_u8 *)cmd_buf, &cmd_len, buf_len); + tlv_buf = buffer + sizeof(apcmdbuf_sys_configure); + + /* Process response */ + if (ret == UAP_SUCCESS) { + /* Verify response */ + if (cmd_buf->cmd_code != + (APCMD_SYS_CONFIGURE | APCMD_RESP_CHECK)) { + printf("ERR:Corrupted response! cmd_code=%x\n", + cmd_buf->cmd_code); + free(buffer); + return UAP_FAILURE; + } + /* Print response */ + if (cmd_buf->result == CMD_SUCCESS) { + if (argc) { + printf("GWK update timeout and retries setting successful\n"); + } else { + print_tlv((t_u8 *)tlv_buf, + cmd_buf->size - + sizeof(apcmdbuf_sys_configure) + + BUF_HEADER_SIZE); + } + } else { + printf("ERR:Could not %s gwk timeout and retries value!\n", argc ? "set" : "get"); + if (argc) + printf("GWK timeout and retries are allowed to set only before bss start.\n"); + ret = UAP_FAILURE; + } + } else { + printf("ERR:Command sending failed!\n"); + } + + if (buffer) + free(buffer); + return ret; +} + +/** + * @brief Convert string to integer + * + * @param ptr A pointer to data buffer + * @param chr A pointer to return integer + * @return A pointer to next data field + */ +char * +convert2hex(char *ptr, t_u8 *chr) +{ + t_u8 val; + + for (val = 0; *ptr && isxdigit(*ptr); ptr++) { + val = (val * 16) + hexc2bin(*ptr); + } + + *chr = val; + + return ptr; +} + +/** + * @brief Parse hex data + * @param fp A pointer to FILE stream + * @param dst A pointer to receive hex data + * @return length of hex data + */ +int +fparse_for_hex(FILE * fp, t_u8 *dst) +{ + char *ptr; + t_u8 *dptr; + char buf[256]; + + dptr = dst; + while (fgets(buf, sizeof(buf), fp)) { + ptr = buf; + + while (*ptr) { + /* Skip leading spaces */ + while (*ptr && (isspace(*ptr) || *ptr == '\t')) + ptr++; + + /* Skip blank lines and lines beginning with '#' */ + if (*ptr == '\0' || *ptr == '#') + break; + + if (isxdigit(*ptr)) { + ptr = convert2hex(ptr, dptr++); + } else { + /* Invalid character on data line */ + ptr++; + } + } + } + + return (dptr - dst); +} + +/** + * @brief Creates a cfg_data request + * and sends to the driver + * + * Usage: "cfg_data " + * + * @param argc Number of arguments + * @param argv Pointer to the arguments + * @return UAP_SUCCESS/UAP_FAILURE + */ +int +apcmd_cfg_data(int argc, char *argv[]) +{ + apcmdbuf_cfg_data *cmd_buf = NULL; + t_u8 *buf = NULL; + t_u16 cmd_len = 0; + t_u16 buf_len = MRVDRV_SIZE_OF_CMD_BUFFER; + int ret = UAP_SUCCESS; + int opt; + FILE *fp = NULL; + while ((opt = getopt_long(argc, argv, "+", cmd_options, NULL)) != -1) { + switch (opt) { + default: + print_cfg_data_usage(); + return UAP_FAILURE; + } + } + argc -= optind; + argv += optind; + + /* Check arguments */ + if ((argc == 0) || (argc > 2)) { + printf("ERR:wrong arguments.\n"); + print_cfg_data_usage(); + return UAP_FAILURE; + } else { + if ((ISDIGIT(argv[0]) == 0) || (atoi(argv[0]) != 2)) { + printf("ERR:Illegal type parameter %s. Must be '2'.\n", + argv[0]); + print_cfg_data_usage(); + return UAP_FAILURE; + } + } + buf = (t_u8 *)malloc(buf_len); + if (buf == NULL) { + printf("Error: allocate memory for hostcmd failed\n"); + return UAP_FAILURE; + } + memset(buf, 0, buf_len); + cmd_buf = (apcmdbuf_cfg_data *)buf; + if (argc == 2) { + /* Check if file exists */ + fp = fopen(argv[1], "r"); + if (fp == NULL) { + printf("\nERR:Config file can not open %s.\n", argv[1]); + free(buf); + return UAP_FAILURE; + } + cmd_buf->action = ACTION_SET; + cmd_buf->data_len = fparse_for_hex(fp, cmd_buf->data); + fclose(fp); + if (cmd_buf->data_len > MAX_CFG_DATA_SIZE) { + printf("ERR: Config file is too big %d\n", + cmd_buf->data_len); + free(buf); + return UAP_FAILURE; + } + } else { + cmd_buf->action = ACTION_GET; + cmd_buf->data_len = 0; + } + + cmd_buf->action = uap_cpu_to_le16(cmd_buf->action); + cmd_buf->type = atoi(argv[0]); + cmd_buf->type = uap_cpu_to_le16(cmd_buf->type); + cmd_buf->data_len = uap_cpu_to_le16(cmd_buf->data_len); + + /* Fill the command buffer */ + cmd_len = + uap_le16_to_cpu(cmd_buf->data_len) + sizeof(apcmdbuf_cfg_data); + cmd_buf->cmd_code = HostCmd_CMD_CFG_DATA; + cmd_buf->size = cmd_len; + cmd_buf->seq_num = 0; + cmd_buf->result = 0; + + /* Send the command */ + ret = uap_ioctl((t_u8 *)cmd_buf, &cmd_len, buf_len); + /* Process response */ + if (ret == UAP_SUCCESS) { + cmd_buf->action = uap_le16_to_cpu(cmd_buf->action); + cmd_buf->data_len = uap_le16_to_cpu(cmd_buf->data_len); + if (cmd_buf->action == ACTION_GET) { + hexdump_data("cfg_data", cmd_buf->data, + cmd_buf->data_len, ' '); + } else + printf("download cfg data successful\n"); + } + if (buf) + free(buf); + return ret; +} + +/** + * @brief Show usage information for the sys_cfg_11n + * command + * + * $return N/A + */ +void +print_sys_cfg_11n_usage(void) +{ + printf("\nUsage : sys_cfg_11n [ENABLE] [HTCAP] [AMPDU] [TXBFCAP] [HT_MCS_MAP]\n"); + printf("\nOptions: ENABLE 0 - disable"); + printf("\n 1 - enable"); + printf("\n HTCAP: HT Capabilities info"); + printf("\n AMPDU: A-MPDU Parameter"); + printf("\n TXBFCAP: TX Beamforming capabilities info"); + printf("\n HT_MCS_MAP: Bitmap for supported MCS rates\n"); + printf("\n empty - Get current 802.11n parameters\n"); + return; +} + +/** + * @brief Get Ht capability Info from firmware + * + * @param pHtCap A pointer to HTCap_t structure + * @return UAP_SUCCESS/UAP_FAILURE + */ +int +get_sys_cfg_11n(HTCap_t *pHtCap) +{ + apcmdbuf_sys_configure *cmd_buf = NULL; + tlvbuf_htcap_t *tlv = NULL; + t_u8 *buffer = NULL; + t_u16 cmd_len; + int ret = UAP_FAILURE; + /* Initialize the command length */ + cmd_len = sizeof(apcmdbuf_sys_configure) + sizeof(tlvbuf_htcap_t); + /* Initialize the command buffer */ + buffer = (t_u8 *)malloc(cmd_len); + if (!buffer) { + printf("ERR:Cannot allocate buffer for command!\n"); + return -1; + } + memset(buffer, 0, cmd_len); + + /* Locate headers */ + cmd_buf = (apcmdbuf_sys_configure *)buffer; + tlv = (tlvbuf_htcap_t *)(buffer + sizeof(apcmdbuf_sys_configure)); + + /* Fill the command buffer */ + cmd_buf->cmd_code = APCMD_SYS_CONFIGURE; + cmd_buf->size = cmd_len - BUF_HEADER_SIZE; + cmd_buf->seq_num = 0; + cmd_buf->result = 0; + tlv->tag = HT_CAPABILITY_TLV_ID; + cmd_buf->action = ACTION_GET; + tlv->length = sizeof(HTCap_t); + + endian_convert_tlv_header_out(tlv); + /* Send the command */ + ret = uap_ioctl((t_u8 *)cmd_buf, &cmd_len, cmd_len); + endian_convert_tlv_header_in(tlv); + /* Process response */ + if (ret == UAP_SUCCESS) { + /* Verify response */ + if ((cmd_buf->cmd_code != + (APCMD_SYS_CONFIGURE | APCMD_RESP_CHECK)) || + (tlv->tag != HT_CAPABILITY_TLV_ID)) { + printf("ERR:Corrupted response! cmd_code=%x, Tlv->tag=%x\n", cmd_buf->cmd_code, tlv->tag); + free(buffer); + return UAP_FAILURE; + } + + /* Copy response */ + if (cmd_buf->result == CMD_SUCCESS) { + memcpy(pHtCap, &tlv->ht_cap, sizeof(HTCap_t)); + pHtCap->ht_cap_info = + uap_le16_to_cpu(pHtCap->ht_cap_info); + pHtCap->tx_bf_cap = uap_le32_to_cpu(pHtCap->tx_bf_cap); + ret = UAP_SUCCESS; + } else { + ret = UAP_FAILURE; + printf("ERR:Could not get HT capability!\n"); + } + } else { + printf("ERR:Command sending failed!\n"); + ret = UAP_FAILURE; + } + if (buffer) + free(buffer); + return ret; +} + +#ifdef RX_PACKET_COALESCE +void +print_rx_packet_coalesc_help() +{ + printf("\nUSAGE: rxpktcoal_cfg [PKT-THRESHOLD] [TIMEOUT]\n\n"); + printf("OPTIONS:"); + printf("PKT-THRESHOLD: count after which packets would be sent to host. Valid values 1-7\n"); + printf("\tTIMEOUT: Time after which packets would be sent to host Valid values 1-4\n"); + printf("\tCoalescing is disabled if both or either of PKT-THRESHOLD or TIMEOUT is zero\n\n"); + printf("\tEmpty - Get current packet coalescing settings\n"); +} + +int +apcmd_rx_pkt_coalesce(int argc, char *argv[]) +{ + apcmdbuf_sys_configure *cmd_buf = NULL; + tlvbuf_rx_pkt_coal_t *tlv = NULL; + t_u8 *buffer = NULL; + t_u16 cmd_len = 0; + t_u16 buf_len = MRVDRV_SIZE_OF_CMD_BUFFER; + int ret = UAP_SUCCESS; + int opt; + + while ((opt = getopt_long(argc, argv, "+", cmd_options, NULL)) != -1) { + switch (opt) { + default: + print_rx_packet_coalesc_help(); + return UAP_SUCCESS; + } + } + argc -= optind; + argv += optind; + + /* Check arguments */ + if (argc) { + if (argc != 2) { + printf("ERR: Invalid no. of arguments.\n"); + print_rx_packet_coalesc_help(); + return UAP_FAILURE; + } + if ((ISDIGIT(argv[0]) == 0) || (ISDIGIT(argv[1]) == 0)) { + printf("ERR: Invalid arguments %s/%s. Both params must be digits.\n", argv[0], argv[1]); + print_rx_packet_coalesc_help(); + return UAP_FAILURE; + } + } + + /* Initialize the command buffer */ + buffer = (t_u8 *)malloc(buf_len); + + if (!buffer) { + printf("ERR:Cannot allocate buffer for command!\n"); + return UAP_FAILURE; + } + memset(buffer, 0, buf_len); + + /* Locate headers */ + cmd_buf = (apcmdbuf_sys_configure *)buffer; + tlv = (tlvbuf_rx_pkt_coal_t *)(buffer + sizeof(apcmdbuf_sys_configure)); + + /* Initialize the command length */ + if (argc) { + cmd_len = + sizeof(apcmdbuf_sys_configure) + + sizeof(tlvbuf_rx_pkt_coal_t); + cmd_buf->action = ACTION_SET; + } else { + cmd_len = sizeof(apcmdbuf_sys_configure) + TLVHEADER_LEN; + cmd_buf->action = ACTION_GET; + } + + /* Fill the command buffer */ + cmd_buf->cmd_code = APCMD_SYS_CONFIGURE; + cmd_buf->size = cmd_len - BUF_HEADER_SIZE; + cmd_buf->seq_num = 0; + cmd_buf->result = 0; + + if (!argc) { + tlv->tag = MRVL_RX_PKT_COAL_TLV_ID; + tlv->length = 0; + //endian_convert_tlv_header_out(tlv); + } else { + tlv->length = sizeof(tlvbuf_rx_pkt_coal_t) - TLVHEADER_LEN; + tlv->tag = MRVL_RX_PKT_COAL_TLV_ID; + tlv->rx_pkt_count = uap_cpu_to_le32(atoi(argv[0])); + tlv->delay = uap_cpu_to_le16(atoi(argv[1])); + } + + endian_convert_tlv_header_out(tlv); + /* Send the command */ + ret = uap_ioctl((t_u8 *)cmd_buf, &cmd_len, buf_len); + /* Process response */ + if (ret == UAP_SUCCESS) { + /* Verify response */ + if (cmd_buf->cmd_code != + (APCMD_SYS_CONFIGURE | APCMD_RESP_CHECK)) { + printf("ERR:Corrupted response! cmd_code=%x\n", + cmd_buf->cmd_code); + free(buffer); + return UAP_FAILURE; + } + /* Print response */ + if (cmd_buf->result == CMD_SUCCESS) { + if (argc) { + printf("Configure RX packet coalesce parameters successful\n"); + } else { + + print_tlv((t_u8 *)tlv, cmd_buf->size - + sizeof(apcmdbuf_sys_configure) + + BUF_HEADER_SIZE); + } + + } else { + if (argc) + printf("ERR:Could not set RX packet coalesce parameters!\n"); + else + printf("ERR: Could not get RX packet coalesce parameters!\n"); + ret = UAP_FAILURE; + } + } else { + printf("ERR:Command sending failed!\n"); + } + if (buffer) + free(buffer); + return ret; + +} +#endif + +/** + * @brief Creates a sys_cfg request for 11n parameters + * and sends to the driver + * + * @param argc Number of arguments + * @param argv Pointer to the arguments + * @return UAP_SUCCESS/UAP_FAILURE + */ +int +apcmd_sys_cfg_11n(int argc, char *argv[]) +{ + apcmdbuf_sys_configure *cmd_buf = NULL; + tlvbuf_htcap_t *tlv = NULL; + tlvbuf_htinfo_t *ht_info_tlv = NULL; + HTCap_t htcap; + t_u8 *buffer = NULL; + t_u16 cmd_len = 0; + t_u16 buf_len = MRVDRV_SIZE_OF_CMD_BUFFER; + int ret = UAP_SUCCESS; + int opt; + t_u32 supported_mcs_set = 0; + fw_info fw; + while ((opt = getopt_long(argc, argv, "+", cmd_options, NULL)) != -1) { + switch (opt) { + default: + print_sys_cfg_11n_usage(); + return UAP_SUCCESS; + } + } + argc -= optind; + argv += optind; + + /* Check arguments */ + if (argc) { + if ((ISDIGIT(argv[0]) == 0) || (atoi(argv[0]) < 0) || + (atoi(argv[0]) > 1)) { + printf("ERR: Illegal ENABLE parameter %s. Must be either '0' or '1'.\n", argv[0]); + print_sys_cfg_11n_usage(); + return UAP_FAILURE; + } + if (argc > 5) { + printf("ERR:wrong arguments.\n"); + print_sys_cfg_11n_usage(); + return UAP_FAILURE; + } + if (argc > 1) { + if (IS_HEX_OR_DIGIT(argv[1]) == UAP_FAILURE) { + printf("ERR: Only Number values are allowed\n"); + print_sys_cfg_11n_usage(); + return UAP_FAILURE; + } + if ((((t_u16)A2HEXDECIMAL(argv[1])) & + (~HT_CAP_CONFIG_MASK)) != HT_CAP_CHECK_MASK) { + printf("ERR: Invalid HTCAP value!\n"); + print_sys_cfg_11n_usage(); + return UAP_FAILURE; + } + } + if (argc > 2) { + if (IS_HEX_OR_DIGIT(argv[2]) == UAP_FAILURE) { + printf("ERR: Only Number values are allowed\n"); + print_sys_cfg_11n_usage(); + return UAP_FAILURE; + } + if ((A2HEXDECIMAL(argv[2])) > AMPDU_CONFIG_MASK) { + printf("ERR: Invalid AMPDU value!\n"); + print_sys_cfg_11n_usage(); + return UAP_FAILURE; + } + } + if (argc > 3) { + if (IS_HEX_OR_DIGIT(argv[3]) == UAP_FAILURE) { + printf("ERR: Only Number values are allowed\n"); + print_sys_cfg_11n_usage(); + return UAP_FAILURE; + } + } + if (argc > 4) { + if (IS_HEX_OR_DIGIT(argv[4]) == UAP_FAILURE) { + printf("ERR: Only Number values are allowed\n"); + print_sys_cfg_11n_usage(); + return UAP_FAILURE; + } + if (0 == get_fw_info(&fw)) { + /* Check upper nibble of MCS support value + * and block MCS_SET_1 when 2X2 is not supported + * by the underlying hardware */ + if (((fw.hw_dev_mcs_support & 0xf0) < + STREAM_2X2_MASK) && + (A2HEXDECIMAL(argv[4]) & MCS_SET_1_MASK)) { + printf("ERR: Invalid HT_MCS_MAP\n"); + return UAP_FAILURE; + } + } + } + memset(&htcap, 0, sizeof(htcap)); + if (UAP_FAILURE == get_sys_cfg_11n(&htcap)) { + printf("Fail to get 11n parameters from firmware\n"); + return UAP_FAILURE; + } + } + + /* Initialize the command buffer */ + buffer = (t_u8 *)malloc(buf_len); + + if (!buffer) { + printf("ERR:Cannot allocate buffer for command!\n"); + return UAP_FAILURE; + } + memset(buffer, 0, buf_len); + + /* Locate headers */ + cmd_buf = (apcmdbuf_sys_configure *)buffer; + tlv = (tlvbuf_htcap_t *)(buffer + sizeof(apcmdbuf_sys_configure)); + tlv->tag = HT_CAPABILITY_TLV_ID; + + /* Initialize the command length */ + if (argc) { + cmd_len = + sizeof(apcmdbuf_sys_configure) + sizeof(tlvbuf_htcap_t); + cmd_buf->action = ACTION_SET; + } else { + cmd_len = sizeof(apcmdbuf_sys_configure) + 2 * TLVHEADER_LEN; + cmd_buf->action = ACTION_GET; + } + + /* Fill the command buffer */ + cmd_buf->cmd_code = APCMD_SYS_CONFIGURE; + cmd_buf->size = cmd_len - BUF_HEADER_SIZE; + cmd_buf->seq_num = 0; + cmd_buf->result = 0; + + if (!argc) { + tlv->length = 0; + /* Append HT_INFO TLV only for GET */ + ht_info_tlv = + (tlvbuf_htinfo_t *)(buffer + + sizeof(apcmdbuf_sys_configure) + + TLVHEADER_LEN); + ht_info_tlv->tag = HT_INFO_TLV_ID; + ht_info_tlv->length = 0; + endian_convert_tlv_header_out(ht_info_tlv); + } else { + tlv->length = sizeof(HTCap_t); + /* disable 802.11n */ + if (atoi(argv[0]) == 0) { + if (argc > 1) { + printf("ERR:wrong arguments.\n"); + print_sys_cfg_11n_usage(); + free(buffer); + return UAP_FAILURE; + } + memcpy(&tlv->ht_cap, &htcap, sizeof(HTCap_t)); + /* disable mcs rate */ + tlv->ht_cap.supported_mcs_set[0] = 0; + tlv->ht_cap.supported_mcs_set[4] = 0; + tlv->ht_cap.supported_mcs_set[1] = 0; + } else { + t_u8 is_40MHz_supported = 0; + /* enable 802.11n */ + memcpy(&tlv->ht_cap, &htcap, sizeof(HTCap_t)); + if (0 == get_fw_info(&fw)) { + if ((fw.hw_dev_mcs_support & 0x0f) >= 2) + tlv->ht_cap.supported_mcs_set[1] = + DEFAULT_MCS_SET_1; + } + if (argc >= 2) { + tlv->ht_cap.ht_cap_info = + DEFAULT_HT_CAP_VALUE & + ~HT_CAP_CONFIG_MASK; + tlv->ht_cap.ht_cap_info |= + (t_u16)A2HEXDECIMAL(argv[1]) & + HT_CAP_CONFIG_MASK; + tlv->ht_cap.ht_cap_info = + uap_cpu_to_le16(tlv->ht_cap. + ht_cap_info); + is_40MHz_supported = + tlv->ht_cap.ht_cap_info & MBIT(1); + } + /* enable mcs rate */ + tlv->ht_cap.supported_mcs_set[0] = DEFAULT_MCS_SET_0; + /* enable MCS32 only in case of both 20/40 MHz support */ + if (is_40MHz_supported) + tlv->ht_cap.supported_mcs_set[4] = + DEFAULT_MCS_SET_4; + else + tlv->ht_cap.supported_mcs_set[4] = 0; + + if (argc >= 3) + tlv->ht_cap.ampdu_param = + (t_u8)A2HEXDECIMAL(argv[2]) & + AMPDU_CONFIG_MASK; + if (argc >= 4) { + tlv->ht_cap.tx_bf_cap = + (t_u32)A2HEXDECIMAL(argv[3]); + tlv->ht_cap.tx_bf_cap = + uap_cpu_to_le32(tlv->ht_cap.tx_bf_cap); + } + if (argc == 5) { + supported_mcs_set = + (t_u32)A2HEXDECIMAL(argv[4]); + supported_mcs_set = + uap_cpu_to_le32(supported_mcs_set); + memcpy(tlv->ht_cap.supported_mcs_set, + &supported_mcs_set, sizeof(t_u32)); + } + } + } + + endian_convert_tlv_header_out(tlv); + /* Send the command */ + ret = uap_ioctl((t_u8 *)cmd_buf, &cmd_len, buf_len); + /* Process response */ + if (ret == UAP_SUCCESS) { + /* Verify response */ + if (cmd_buf->cmd_code != + (APCMD_SYS_CONFIGURE | APCMD_RESP_CHECK)) { + printf("ERR:Corrupted response! cmd_code=%x\n", + cmd_buf->cmd_code); + free(buffer); + return UAP_FAILURE; + } + /* Print response */ + if (cmd_buf->result == CMD_SUCCESS) { + if (argc) { + printf("Configure 802.11n parameters successful\n"); + } else { + print_tlv((t_u8 *)tlv, cmd_buf->size - + sizeof(apcmdbuf_sys_configure) + + BUF_HEADER_SIZE); + } + + } else { + if (argc) + printf("ERR:Could not set 802.11n parameters!\n"); + else + printf("ERR: Could not get 802.11n parameters!\n"); + ret = UAP_FAILURE; + } + } else { + printf("ERR:Command sending failed!\n"); + } + if (buffer) + free(buffer); + return ret; +} + +/** + * @brief Show usage information for the sys_cfg_wmm + * command + * + * $return N/A + */ +void +print_sys_cfg_wmm_usage(void) +{ + printf("\nUsage : sys_cfg_wmm [qosinfo=] [AC_BE AIFSN ECW_MAX ECW_MIN TX_OP]\n"); + printf("\n [AC_BK AIFSN ECW_MAX ECW_MIN TX_OP]\n"); + printf("\n [AC_VI AIFSN ECW_MAX ECW_MIN TX_OP]\n"); + printf("\n [AC_VO AIFSN ECW_MAX ECW_MIN TX_OP]\n"); + printf("\nOptions: qosinfo - 0x80 or 0x00"); + printf("\n AC_BE - 0, AC_BK - 1"); + printf("\n AC_VI - 2, AC_VO - 3"); + printf("\n AIFSN - AIFSN value"); + printf("\n ECW_MAX: ECW max"); + printf("\n ECW_MIN: ECW min"); + printf("\n TX_OP: TXOP Limit"); + printf("\n empty - Get current wmm parameters\n"); + return; +} + + /** +@brief Show usage information for the sys_cfg_ap_wmm +* command +* +* $return N/A +*/ +void +print_sys_cfg_ap_wmm_usage(void) +{ + printf("\nUsage : sys_cfg_wmm [AC_BE AIFSN ECW_MAX ECW_MIN TX_OP]\n"); + printf("\n [AC_BK AIFSN ECW_MAX ECW_MIN TX_OP]\n"); + printf("\n [AC_VI AIFSN ECW_MAX ECW_MIN TX_OP]\n"); + printf("\n [AC_VO AIFSN ECW_MAX ECW_MIN TX_OP]\n"); + printf("\nOptions: AC_BE - 0, AC_BK - 1"); + printf("\n AC_VI - 2, AC_VO - 3"); + printf("\n AIFSN - AIFSN value"); + printf("\n ECW_MAX: ECW max"); + printf("\n ECW_MIN: ECW min"); + printf("\n TX_OP: TXOP Limit"); + printf("\n empty - Get current wmm parameters\n"); + return; +} + +/** + * @brief Get WMM parameters from firmware + * + * @param pWmm A pointer to WmmParameter_t structure + * @param tlv_tag TLV ID + * @return UAP_SUCCESS/UAP_FAILURE + */ +int +get_wmm_parameters(WmmParameter_t *pWmm, t_u16 tlv_tag) +{ + apcmdbuf_sys_configure *cmd_buf = NULL; + tlvbuf_wmm_para_t *tlv = NULL; + t_u8 *buffer = NULL; + t_u16 cmd_len; + t_u8 oui_type[4] = { 0x00, 0x50, 0xF2, 0x02 }; + + int ret = UAP_FAILURE; + /* Initialize the command length */ + cmd_len = sizeof(apcmdbuf_sys_configure) + sizeof(tlvbuf_wmm_para_t); + /* Initialize the command buffer */ + buffer = (t_u8 *)malloc(cmd_len); + if (!buffer) { + printf("ERR:Cannot allocate buffer for command!\n"); + return -1; + } + memset(buffer, 0, cmd_len); + + /* Locate headers */ + cmd_buf = (apcmdbuf_sys_configure *)buffer; + tlv = (tlvbuf_wmm_para_t *)(buffer + sizeof(apcmdbuf_sys_configure)); + + /* Fill the command buffer */ + cmd_buf->cmd_code = APCMD_SYS_CONFIGURE; + cmd_buf->size = cmd_len - BUF_HEADER_SIZE; + cmd_buf->seq_num = 0; + cmd_buf->result = 0; + tlv->tag = tlv_tag; + cmd_buf->action = ACTION_GET; + tlv->length = sizeof(WmmParameter_t); + memcpy(tlv->wmm_para.ouitype, oui_type, sizeof(oui_type)); + tlv->wmm_para.ouisubtype = 1; + tlv->wmm_para.version = 1; + endian_convert_tlv_header_out(tlv); + /* Send the command */ + ret = uap_ioctl((t_u8 *)cmd_buf, &cmd_len, cmd_len); + endian_convert_tlv_header_in(tlv); + /* Process response */ + if (ret == UAP_SUCCESS) { + /* Verify response */ + if ((cmd_buf->cmd_code != + (APCMD_SYS_CONFIGURE | APCMD_RESP_CHECK)) || + (tlv->tag != tlv_tag) || + (tlv->length != sizeof(WmmParameter_t))) { + printf("ERR:Corrupted response! cmd_code=%x, Tlv->tag=%x\n", cmd_buf->cmd_code, tlv->tag); + free(buffer); + return UAP_FAILURE; + } + + /* Copy response */ + if (cmd_buf->result == CMD_SUCCESS) { + memcpy(pWmm, &tlv->wmm_para, sizeof(WmmParameter_t)); + ret = UAP_SUCCESS; + } else { + ret = UAP_FAILURE; + printf("ERR:Could not get wmm parameters!\n"); + } + } else { + printf("ERR:Command sending failed!\n"); + ret = UAP_FAILURE; + } + if (buffer) + free(buffer); + return ret; +} + +/** + * @brief Creates a sys_cfg request for wmm parameters + * and sends to the driver + * + * @param argc Number of arguments + * @param argv Pointer to the arguments + * @return UAP_SUCCESS/UAP_FAILURE + */ +int +apcmd_sys_cfg_wmm(int argc, char *argv[]) +{ + apcmdbuf_sys_configure *cmd_buf = NULL; + tlvbuf_wmm_para_t *tlv = NULL; + WmmParameter_t wmm_para; + t_u8 *buffer = NULL; + t_u16 cmd_len = 0; + t_u16 buf_len = MRVDRV_SIZE_OF_CMD_BUFFER; + int i; + int ret = UAP_SUCCESS; + int opt; + t_u8 ac = 0; + t_u8 wmm_disable = 1; + t_u8 qos_info = 0; + t_u8 flag = 0; + char str[13]; + while ((opt = getopt_long(argc, argv, "+", cmd_options, NULL)) != -1) { + switch (opt) { + default: + print_sys_cfg_wmm_usage(); + return UAP_SUCCESS; + } + } + argc -= optind; + argv += optind; + memset(&wmm_para, 0, sizeof(wmm_para)); + memset(str, 0, sizeof(str)); + if (UAP_FAILURE == + get_wmm_parameters(&wmm_para, VENDOR_SPECIFIC_IE_TLV_ID)) { + printf("Fail to get wmm parameters from firmware\n"); + return UAP_FAILURE; + } + + if (!argc) { + printf("wmm parameters:\n"); + printf("\tqos_info = 0x%x\n", wmm_para.qos_info); + printf("\tBE: AIFSN=%d, CW_MAX=%d CW_MIN=%d, TXOP=%d\n", + wmm_para.ac_params[AC_BE].aci_aifsn.aifsn, + wmm_para.ac_params[AC_BE].ecw.ecw_max, + wmm_para.ac_params[AC_BE].ecw.ecw_min, + uap_le16_to_cpu(wmm_para.ac_params[AC_BE].tx_op_limit)); + printf("\tBK: AIFSN=%d, CW_MAX=%d CW_MIN=%d, TXOP=%d\n", + wmm_para.ac_params[AC_BK].aci_aifsn.aifsn, + wmm_para.ac_params[AC_BK].ecw.ecw_max, + wmm_para.ac_params[AC_BK].ecw.ecw_min, + uap_le16_to_cpu(wmm_para.ac_params[AC_BK].tx_op_limit)); + printf("\tVI: AIFSN=%d, CW_MAX=%d CW_MIN=%d, TXOP=%d\n", + wmm_para.ac_params[AC_VI].aci_aifsn.aifsn, + wmm_para.ac_params[AC_VI].ecw.ecw_max, + wmm_para.ac_params[AC_VI].ecw.ecw_min, + uap_le16_to_cpu(wmm_para.ac_params[AC_VI].tx_op_limit)); + printf("\tVO: AIFSN=%d, CW_MAX=%d CW_MIN=%d, TXOP=%d\n", + wmm_para.ac_params[AC_VO].aci_aifsn.aifsn, + wmm_para.ac_params[AC_VO].ecw.ecw_max, + wmm_para.ac_params[AC_VO].ecw.ecw_min, + uap_le16_to_cpu(wmm_para.ac_params[AC_VO].tx_op_limit)); + return UAP_SUCCESS; + } + + if (strlen(argv[0]) > 8) { + if (strncmp(argv[0], "qosinfo=", 8) == 0) { + strncpy(str, argv[0], sizeof(str) - 1); + strncpy(str, strchr(str, '=') + 1, 4); + qos_info = A2HEXDECIMAL(str); + if ((qos_info != ENABLE_WMM_PS) && + (qos_info != DISABLE_WMM_PS)) { + printf("ERR:qos_info must be either 0x80 or 0x00\n"); + print_sys_cfg_wmm_usage(); + return UAP_FAILURE; + } + argc -= 1; + argv += 1; + flag = 1; + } else { + printf("ERR:Invalid argument!\n"); + print_sys_cfg_wmm_usage(); + return UAP_FAILURE; + } + } + /* Check arguments */ + if ((argc != 1) && ((argc > 20) || ((argc > 0) && ((argc % 5) != 0)))) { + printf("ERR:Illegal number of parameters.\n"); + print_sys_cfg_wmm_usage(); + return UAP_FAILURE; + } + for (i = 0; i < argc; i++) { + if (IS_HEX_OR_DIGIT(argv[i]) == UAP_FAILURE) { + printf("ERR: Only Number values are allowed\n"); + print_sys_cfg_wmm_usage(); + return UAP_FAILURE; + } + if (A2HEXDECIMAL(argv[i])) + wmm_disable = 0; + } + if ((argc == 1) && A2HEXDECIMAL(argv[0])) { + printf("ERR: Only 0 is allowed to disable WMM using single parameter.\n"); + print_sys_cfg_wmm_usage(); + return UAP_FAILURE; + } + if (argc != 20 && argc != 1) + wmm_disable = 0; + + /* Initialize the command length */ + cmd_len = sizeof(apcmdbuf_sys_configure) + sizeof(tlvbuf_wmm_para_t); + + /* Initialize the command buffer */ + buffer = (t_u8 *)malloc(buf_len); + + if (!buffer) { + printf("ERR:Cannot allocate buffer for command!\n"); + return UAP_FAILURE; + } + memset(buffer, 0, buf_len); + + /* Locate headers */ + cmd_buf = (apcmdbuf_sys_configure *)buffer; + tlv = (tlvbuf_wmm_para_t *)(buffer + sizeof(apcmdbuf_sys_configure)); + tlv->tag = VENDOR_SPECIFIC_IE_TLV_ID; + tlv->length = sizeof(WmmParameter_t); + + /* Fill the command buffer */ + cmd_buf->cmd_code = APCMD_SYS_CONFIGURE; + cmd_buf->size = cmd_len - BUF_HEADER_SIZE; + cmd_buf->seq_num = 0; + cmd_buf->result = 0; + cmd_buf->action = ACTION_SET; + endian_convert_tlv_header_out(tlv); + + memcpy(&tlv->wmm_para, &wmm_para, sizeof(WmmParameter_t)); + if (wmm_disable) { + /* clear AC parameters to disalbe wmm */ + memset((t_u8 *)tlv->wmm_para.ac_params, 0, + sizeof(IEEEtypes_WmmAcParameters_t) * MAX_AC_QUEUES); + } else { + if (flag) { + if (qos_info) + tlv->wmm_para.qos_info = + wmm_para.qos_info | qos_info; + else + tlv->wmm_para.qos_info = + wmm_para.qos_info & WMM_PS_MASK; + } + for (i = 0; i < (argc / 5); i++) { + ac = (t_u8)A2HEXDECIMAL(argv[i * 5]); + if (ac > AC_VO) { + printf("ERR: Invalid AC queue index, Only support AC_BE, AC_BK, AC_VI, AC_VO\n"); + print_sys_cfg_wmm_usage(); + free(buffer); + return UAP_FAILURE; + } + tlv->wmm_para.ac_params[ac].aci_aifsn.aifsn = + (t_u8)A2HEXDECIMAL(argv[i * 5 + 1]); + tlv->wmm_para.ac_params[ac].aci_aifsn.aci = (t_u8)ac; + tlv->wmm_para.ac_params[ac].ecw.ecw_max = + (t_u8)A2HEXDECIMAL(argv[i * 5 + 2]); + tlv->wmm_para.ac_params[ac].ecw.ecw_min = + (t_u8)A2HEXDECIMAL(argv[i * 5 + 3]); + tlv->wmm_para.ac_params[ac].tx_op_limit = + uap_cpu_to_le16((t_u16) + A2HEXDECIMAL(argv[i * 5 + 4])); + } + } + + /* Send the command */ + ret = uap_ioctl((t_u8 *)cmd_buf, &cmd_len, buf_len); + endian_convert_tlv_header_in(tlv); + /* Process response */ + if (ret == UAP_SUCCESS) { + /* Verify response */ + if ((cmd_buf->cmd_code != + (APCMD_SYS_CONFIGURE | APCMD_RESP_CHECK)) || + (tlv->tag != VENDOR_SPECIFIC_IE_TLV_ID)) { + printf("ERR:Corrupted response! cmd_code=%x, Tlv->tag=%x\n", cmd_buf->cmd_code, tlv->tag); + free(buffer); + return UAP_FAILURE; + } + /* Print response */ + if (cmd_buf->result == CMD_SUCCESS) { + printf("Configure wmm parameters successful\n"); + + } else { + printf("ERR:Could not set wmm parameters!\n"); + ret = UAP_FAILURE; + } + } else { + printf("ERR:Command sending failed!\n"); + } + if (buffer) + free(buffer); + return ret; +} + +/** +* @param argc Number of arguments +* @param argv Pointer to the arguments +* @return UAP_SUCCESS/UAP_FAILURE +*/ +int +apcmd_sys_cfg_ap_wmm(int argc, char *argv[]) +{ + apcmdbuf_sys_configure *cmd_buf = NULL; + tlvbuf_wmm_para_t *tlv = NULL; + WmmParameter_t wmm_para; + t_u8 *buffer = NULL; + t_u16 cmd_len = 0; + t_u16 buf_len = MRVDRV_SIZE_OF_CMD_BUFFER; + int i; + int opt; + t_u8 ac = 0; + t_u8 wmm_reset = 1; + int ret = UAP_SUCCESS; + + while ((opt = getopt_long(argc, argv, "+", cmd_options, NULL)) != -1) { + switch (opt) { + default: + print_sys_cfg_ap_wmm_usage(); + return UAP_SUCCESS; + } + } + argc -= optind; + argv += optind; + memset(&wmm_para, 0, sizeof(wmm_para)); + if (UAP_FAILURE == + get_wmm_parameters(&wmm_para, MRVL_AP_WMM_PARAM_TLV_ID)) { + printf("Fail to get ap wmm parameters from firmware\n"); + return UAP_FAILURE; + } + + if (!argc) { + printf("ap wmm parameters:\n"); + printf("\tBE: AIFSN=%d, CW_MAX=%d CW_MIN=%d, TXOP=%d\n", + wmm_para.ac_params[AC_BE].aci_aifsn.aifsn, + wmm_para.ac_params[AC_BE].ecw.ecw_max, + wmm_para.ac_params[AC_BE].ecw.ecw_min, + uap_le16_to_cpu(wmm_para.ac_params[AC_BE].tx_op_limit)); + printf("\tBK: AIFSN=%d, CW_MAX=%d CW_MIN=%d, TXOP=%d\n", + wmm_para.ac_params[AC_BK].aci_aifsn.aifsn, + wmm_para.ac_params[AC_BK].ecw.ecw_max, + wmm_para.ac_params[AC_BK].ecw.ecw_min, + uap_le16_to_cpu(wmm_para.ac_params[AC_BK].tx_op_limit)); + printf("\tVI: AIFSN=%d, CW_MAX=%d CW_MIN=%d, TXOP=%d\n", + wmm_para.ac_params[AC_VI].aci_aifsn.aifsn, + wmm_para.ac_params[AC_VI].ecw.ecw_max, + wmm_para.ac_params[AC_VI].ecw.ecw_min, + uap_le16_to_cpu(wmm_para.ac_params[AC_VI].tx_op_limit)); + printf("\tVO: AIFSN=%d, CW_MAX=%d CW_MIN=%d, TXOP=%d\n", + wmm_para.ac_params[AC_VO].aci_aifsn.aifsn, + wmm_para.ac_params[AC_VO].ecw.ecw_max, + wmm_para.ac_params[AC_VO].ecw.ecw_min, + uap_le16_to_cpu(wmm_para.ac_params[AC_VO].tx_op_limit)); + return UAP_SUCCESS; + } + + /* Check arguments */ + if ((argc != 1) && ((argc > 20) || ((argc > 0) && ((argc % 5) != 0)))) { + printf("ERR:Illegal number of parameters.\n"); + print_sys_cfg_ap_wmm_usage(); + return UAP_FAILURE; + } + for (i = 0; i < argc; i++) { + if (IS_HEX_OR_DIGIT(argv[i]) == UAP_FAILURE) { + printf("ERR: Only Number values are allowed\n"); + print_sys_cfg_ap_wmm_usage(); + return UAP_FAILURE; + } + if (A2HEXDECIMAL(argv[i])) + wmm_reset = 0; + } + if ((argc == 1) && A2HEXDECIMAL(argv[0])) { + printf("ERR: Only 0 is allowed to reset AP WMM using single parameter.\n"); + print_sys_cfg_ap_wmm_usage(); + return UAP_FAILURE; + } + if (argc != 20 && argc != 1) + wmm_reset = 0; + + /* Initialize the command length */ + cmd_len = sizeof(apcmdbuf_sys_configure) + sizeof(tlvbuf_wmm_para_t); + + /* Initialize the command buffer */ + buffer = (t_u8 *)malloc(buf_len); + if (!buffer) { + printf("ERR:Cannot allocate buffer for command!\n"); + return UAP_FAILURE; + } + memset(buffer, 0, buf_len); + + /* Locate headers */ + cmd_buf = (apcmdbuf_sys_configure *)buffer; + tlv = (tlvbuf_wmm_para_t *)(buffer + sizeof(apcmdbuf_sys_configure)); + tlv->tag = MRVL_AP_WMM_PARAM_TLV_ID; + /* Fill the command buffer */ + cmd_buf->cmd_code = APCMD_SYS_CONFIGURE; + cmd_buf->size = cmd_len - BUF_HEADER_SIZE; + cmd_buf->seq_num = 0; + cmd_buf->result = 0; + cmd_buf->action = ACTION_SET; + endian_convert_tlv_header_out(tlv); + + memcpy(&tlv->wmm_para, &wmm_para, sizeof(WmmParameter_t)); + if (wmm_reset) { + /* clear AC parameters to reset ap wmm */ + memset((t_u8 *)tlv->wmm_para.ac_params, 0, + sizeof(IEEEtypes_WmmAcParameters_t) * MAX_AC_QUEUES); + } else { + for (i = 0; i < (argc / 5); i++) { + ac = (t_u8)A2HEXDECIMAL(argv[i * 5]); + if (ac > AC_VO) { + printf("ERR: Invalid AC queue index, Only support AC_BE, AC_BK, AC_VI, AC_VO\n"); + print_sys_cfg_ap_wmm_usage(); + free(buffer); + return UAP_FAILURE; + } + tlv->wmm_para.ac_params[ac].aci_aifsn.aifsn = + (t_u8)A2HEXDECIMAL(argv[i * 5 + 1]); + tlv->wmm_para.ac_params[ac].aci_aifsn.aci = (t_u8)ac; + tlv->wmm_para.ac_params[ac].ecw.ecw_max = + (t_u8)A2HEXDECIMAL(argv[i * 5 + 2]); + tlv->wmm_para.ac_params[ac].ecw.ecw_min = + (t_u8)A2HEXDECIMAL(argv[i * 5 + 3]); + tlv->wmm_para.ac_params[ac].tx_op_limit = + uap_cpu_to_le16((t_u16) + A2HEXDECIMAL(argv[i * 5 + 4])); + } + } + + /* Send the command */ + ret = uap_ioctl((t_u8 *)cmd_buf, &cmd_len, buf_len); + endian_convert_tlv_header_in(tlv); + /* Process response */ + if (ret == UAP_SUCCESS) { + /* Verify response */ + if ((cmd_buf->cmd_code != + (APCMD_SYS_CONFIGURE | APCMD_RESP_CHECK)) || + (tlv->tag != MRVL_AP_WMM_PARAM_TLV_ID)) { + printf("ERR:Corrupted response! cmd_code=%x, Tlv->tag=%x\n", cmd_buf->cmd_code, tlv->tag); + free(buffer); + return UAP_FAILURE; + } + /* Print response */ + if (cmd_buf->result == CMD_SUCCESS) { + printf("Configure ap wmm parameters successful\n"); + } else { + printf("ERR:Could not set ap wmm parameters!\n"); + ret = UAP_FAILURE; + } + } else { + printf("ERR:Command sending failed!\n"); + } + + if (buffer) + free(buffer); + return ret; +} + +/** + * @brief Show usage information for the sys_cfg_restrict_client_mode + * command + * + * $return N/A + */ +void +print_sys_cfg_restrict_client_mode_usage(void) +{ + printf("\nUsage : sys_cfg_restrict_client_mode [ [MODE_CONFIG]]\n"); + printf("\nOptions:"); + printf("\n Bit 0: 1 enable restricted client mode"); + printf("\n 0 disable restricted client mode"); + printf("\n Bits [1-7] : set to 0"); + printf("\n Bits [8:12]:"); + printf("\n Bit 8: B only Mode"); + printf("\n Bit 9: A only Mode"); + printf("\n Bit 10: G only Mode"); + printf("\n Bit 11: N only Mode"); + printf("\n Bit 12: AC only Mode"); + printf("\n Bits [13:15]: set to 0"); + printf("\n"); + printf("\n Empty - Get current restricted client mode setting.\n"); + return; +} + +/** + * @brief Creates a sys_cfg request to Set/Get restricted client mode + * and sends to the driver + * + * Usage: "sys_cfg_restrict_client_mode [ [MODE_CONFIG]]" + * If arguments are provided, a 'set' is performed + * else a 'get' is performed. + * + * @param argc Number of arguments + * @param argv Pointer to the arguments + * @return UAP_SUCCESS/UAP_FAILURE + */ +int +apcmd_sys_cfg_restrict_client_mode(int argc, char *argv[]) +{ + apcmdbuf_sys_configure *cmd_buf = NULL; + tlvbuf_restrict_client_mode *tlv = NULL; + t_u8 *buffer = NULL; + t_u16 cmd_len = 0; + t_u16 buf_len = MRVDRV_SIZE_OF_CMD_BUFFER; + int ret = UAP_SUCCESS; + int opt; + + while ((opt = getopt_long(argc, argv, "+", cmd_options, NULL)) != -1) { + switch (opt) { + default: + print_sys_cfg_restrict_client_mode_usage(); + return UAP_SUCCESS; + } + } + argc -= optind; + argv += optind; + + /* Check arguments */ + if (argc && + is_input_valid(RESTRICT_CLIENT_MODE, argc, argv) != UAP_SUCCESS) { + print_sys_cfg_restrict_client_mode_usage(); + return UAP_FAILURE; + } + + /* Initialize the command buffer */ + buffer = (t_u8 *)malloc(buf_len); + if (!buffer) { + printf("ERR:Cannot allocate buffer for command!\n"); + return UAP_FAILURE; + } + memset(buffer, 0, buf_len); + + /* Locate headers */ + cmd_buf = (apcmdbuf_sys_configure *)buffer; + tlv = (tlvbuf_restrict_client_mode *)(buffer + + sizeof(apcmdbuf_sys_configure)); + + /* Fill the command buffer */ + cmd_buf->cmd_code = APCMD_SYS_CONFIGURE; + cmd_buf->seq_num = 0; + cmd_buf->result = 0; + tlv->tag = MRVL_RESTRICT_CLIENT_MODE_TLV_ID; + if (argc == 0) { + cmd_buf->action = ACTION_GET; + tlv->length = 0; + } else { + cmd_buf->action = ACTION_SET; + tlv->length = sizeof(t_u16); + tlv->mode_config = + (t_u16)((tlv-> + mode_config | RESTRICT_CLIENT_MODE_ENABLE_MASK) + & atoi(argv[0])); + if (argc == 2) { + tlv->mode_config |= (t_u16)(A2HEXDECIMAL(argv[1]) << 8); + } + tlv->mode_config = uap_cpu_to_le16(tlv->mode_config); + } + cmd_buf->size = + sizeof(apcmdbuf_sys_configure) + + sizeof(tlvbuf_restrict_client_mode); + cmd_len = + sizeof(apcmdbuf_sys_configure) + + sizeof(tlvbuf_restrict_client_mode); + endian_convert_tlv_header_out(tlv); + /* Send the command */ + ret = uap_ioctl((t_u8 *)cmd_buf, &cmd_len, buf_len); + endian_convert_tlv_header_in(tlv); + /* Process response */ + if (ret == UAP_SUCCESS) { + /* Verify response */ + if ((cmd_buf->cmd_code != + (APCMD_SYS_CONFIGURE | APCMD_RESP_CHECK)) || + (tlv->tag != MRVL_RESTRICT_CLIENT_MODE_TLV_ID)) { + printf("ERR:Corrupted response! cmd_code=%x, Tlv->tag=%x\n", cmd_buf->cmd_code, tlv->tag); + free(buffer); + return UAP_FAILURE; + } + /* Print response */ + if (cmd_buf->result == CMD_SUCCESS) { + if (argc == 0) { + tlv->mode_config = + uap_le16_to_cpu(tlv->mode_config); + printf("Restricted Client Mode: %s\n", + (tlv-> + mode_config & + RESTRICT_CLIENT_MODE_ENABLE_MASK) ? + "Enabled" : "Disabled"); + if (tlv-> + mode_config & + RESTRICT_CLIENT_MODE_ENABLE_MASK) { + printf("Current client mode : "); + if (tlv->mode_config & B_ONLY_MASK) + printf("B Only\n"); + else if (tlv->mode_config & A_ONLY_MASK) + printf("A Only\n"); + else if (tlv->mode_config & G_ONLY_MASK) + printf("G Only\n"); + else if (tlv->mode_config & N_ONLY_MASK) + printf("N Only\n"); + else if (tlv-> + mode_config & AC_ONLY_MASK) + printf("AC Only\n"); + } + } else { + printf("Restricted client mode setting successful\n"); + } + } else { + if (argc == 0) { + printf("ERR:Could not get restrict client mode setting!\n"); + } else { + printf("ERR:Could not set restrict client mode setting!\n"); + } + ret = UAP_FAILURE; + } + } else { + printf("ERR:Command sending failed!\n"); + } + if (buffer) + free(buffer); + return ret; +} diff --git a/mxm_wifiex/wlan_src/mapp/uaputl/uapcmd.h b/mxm_wifiex/wlan_src/mapp/uaputl/uapcmd.h new file mode 100644 index 0000000..7942d2a --- /dev/null +++ b/mxm_wifiex/wlan_src/mapp/uaputl/uapcmd.h @@ -0,0 +1,86 @@ +/** @file uapcmd.h + * + * @brief This file contains declaration referring to + * functions defined in uapcmd.c + * + * + * Copyright 2014-2020 NXP + * + * NXP CONFIDENTIAL + * The source code contained or described herein and all documents related to + * the source code (Materials) are owned by NXP, its + * suppliers and/or its licensors. Title to the Materials remains with NXP, + * its suppliers and/or its licensors. The Materials contain + * trade secrets and proprietary and confidential information of NXP, its + * suppliers and/or its licensors. The Materials are protected by worldwide copyright + * and trade secret laws and treaty provisions. No part of the Materials may be + * used, copied, reproduced, modified, published, uploaded, posted, + * transmitted, distributed, or disclosed in any way without NXP's prior + * express written permission. + * + * No license under any patent, copyright, trade secret or other intellectual + * property right is granted to or conferred upon you by disclosure or delivery + * of the Materials, either expressly, by implication, inducement, estoppel or + * otherwise. Any license under such intellectual property rights must be + * express and approved by NXP in writing. + * + */ +/************************************************************************ +Change log: + 03/01/08: Initial creation +************************************************************************/ + +#ifndef _UAPCMD_H +#define _UAPCMD_H + +/** Function Prototype Declaration */ +int apcmd_sys_cfg_ap_mac_address(int argc, char *argv[]); +int apcmd_sys_cfg_ssid(int argc, char *argv[]); +int apcmd_sys_cfg_beacon_period(int argc, char *argv[]); +int apcmd_sys_cfg_dtim_period(int argc, char *argv[]); +int apcmd_sys_cfg_bss_status(int argc, char *argv[]); +int apcmd_sys_cfg_channel(int argc, char *argv[]); +int apcmd_sys_cfg_channel_ext(int argc, char *argv[]); +int apcmd_sys_cfg_scan_channels(int argc, char *argv[]); +int apcmd_sys_cfg_rates(int argc, char *argv[]); +int apcmd_sys_cfg_rates_ext(int argc, char *argv[]); +int apcmd_sys_cfg_tx_power(int argc, char *argv[]); +int apcmd_sys_cfg_bcast_ssid_ctl(int argc, char *argv[]); +int apcmd_sys_cfg_preamble_ctl(int argc, char *argv[]); +int apcmd_sys_cfg_rts_threshold(int argc, char *argv[]); +int apcmd_sys_cfg_frag_threshold(int argc, char *argv[]); +int apcmd_sys_cfg_radio_ctl(int argc, char *argv[]); +int apcmd_sys_cfg_rsn_replay_prot(int argc, char *argv[]); +int apcmd_sys_cfg_tx_beacon_rate(int argc, char *argv[]); +int apcmd_sys_cfg_mcbc_data_rate(int argc, char *argv[]); +int apcmd_sys_cfg_pkt_fwd_ctl(int argc, char *argv[]); +int apcmd_sys_cfg_sta_ageout_timer(int argc, char *argv[]); +int apcmd_sys_cfg_ps_sta_ageout_timer(int argc, char *argv[]); +int apcmd_sys_cfg_auth(int argc, char *argv[]); +int apcmd_sys_cfg_protocol(int argc, char *argv[]); +int apcmd_sys_cfg_wep_key(int argc, char *argv[]); +int apcmd_sys_cfg_cipher(int argc, char *argv[]); +int apcmd_sys_cfg_pwk_cipher(int argc, char *argv[]); +int apcmd_sys_cfg_gwk_cipher(int argc, char *argv[]); +int apcmd_sys_cfg_wpa_passphrase(int argc, char *argv[]); +int apcmd_sys_cfg_wpa3_sae_password(int argc, char *argv[]); +int apcmd_sys_cfg_group_rekey_timer(int argc, char *argv[]); +int apcmd_sta_filter_table(int argc, char *argv[]); +int apcmd_sys_cfg_max_sta_num(int argc, char *argv[]); +int apcmd_sys_cfg_retry_limit(int argc, char *argv[]); +int apcmd_sys_cfg_sticky_tim_config(int argc, char *argv[]); +int apcmd_sys_cfg_sticky_tim_sta_mac_addr(int argc, char *argv[]); +int apcmd_sys_cfg_eapol_pwk_hsk(int argc, char *argv[]); +int apcmd_sys_cfg_eapol_gwk_hsk(int argc, char *argv[]); +int apcmd_cfg_data(int argc, char *argv[]); +int apcmd_sys_cfg_custom_ie(int argc, char *argv[]); +int apcmd_sys_cfg_wmm(int argc, char *argv[]); +int apcmd_sys_cfg_ap_wmm(int argc, char *argv[]); +int apcmd_sys_cfg_11n(int argc, char *argv[]); +#ifdef RX_PACKET_COALESCE +int apcmd_rx_pkt_coalesce(int argc, char *argv[]); +void print_rx_packet_coalesc_help(void); +#endif +int apcmd_sys_cfg_2040_coex(int argc, char *argv[]); +int apcmd_sys_cfg_restrict_client_mode(int argc, char *argv[]); +#endif /* _UAP_H */ diff --git a/mxm_wifiex/wlan_src/mapp/uaputl/uaphostcmd.c b/mxm_wifiex/wlan_src/mapp/uaputl/uaphostcmd.c new file mode 100644 index 0000000..a7ad024 --- /dev/null +++ b/mxm_wifiex/wlan_src/mapp/uaputl/uaphostcmd.c @@ -0,0 +1,343 @@ +/** @file uaphostcmd.c + * + * @brief This file contains uAP hostcmd functions + * + * + * Copyright 2014-2020 NXP + * + * NXP CONFIDENTIAL + * The source code contained or described herein and all documents related to + * the source code (Materials) are owned by NXP, its + * suppliers and/or its licensors. Title to the Materials remains with NXP, + * its suppliers and/or its licensors. The Materials contain + * trade secrets and proprietary and confidential information of NXP, its + * suppliers and/or its licensors. The Materials are protected by worldwide copyright + * and trade secret laws and treaty provisions. No part of the Materials may be + * used, copied, reproduced, modified, published, uploaded, posted, + * transmitted, distributed, or disclosed in any way without NXP's prior + * express written permission. + * + * No license under any patent, copyright, trade secret or other intellectual + * property right is granted to or conferred upon you by disclosure or delivery + * of the Materials, either expressly, by implication, inducement, estoppel or + * otherwise. Any license under such intellectual property rights must be + * express and approved by NXP in writing. + * + */ +/************************************************************************ +Change log: + 11/26/2008: initial version +************************************************************************/ + +#include +#include +#include +#include +#include "uaputl.h" + +#ifndef MIN +/** Find minimum value */ +#define MIN(a, b) ((a) < (b) ? (a) : (b)) +#endif /* MIN */ + +/******************************************************** + Local Variables +********************************************************/ + +/******************************************************** + Global Variables +********************************************************/ + +/******************************************************** + Local Functions +********************************************************/ +/* + * @brief convert String to integer + * + * @param value A pointer to string + * @return integer + */ +static t_u32 +a2hex_or_atoi(char *value) +{ + if (value[0] == '0' && (value[1] == 'X' || value[1] == 'x')) { + return a2hex(value + 2); + } else if (isdigit(*value)) { + return atoi(value); + } else { + return *value; + } +} + +/** + * @brief Get one line from the File + * + * @param fp File handler + * @param str Storage location for data. + * @param size Maximum number of characters to read. + * @param lineno A pointer to return current line number + * @return returns string or NULL + */ +char * +mlan_config_get_line(FILE * fp, char *str, t_s32 size, int *lineno) +{ + char *start, *end; + int out, next_line; + + if (!fp || !str) + return NULL; + + do { +read_line: + if (!fgets(str, size, fp)) + break; + start = str; + start[size - 1] = '\0'; + end = start + strlen(str); + (*lineno)++; + + out = 1; + while (out && (start < end)) { + next_line = 0; + /* Remove empty lines and lines starting with # */ + switch (start[0]) { + case ' ': /* White space */ + case '\t': /* Tab */ + start++; + break; + case '#': + case '\n': + case '\0': + next_line = 1; + break; + case '\r': + if (start[1] == '\n') + next_line = 1; + else + start++; + break; + default: + out = 0; + break; + } + if (next_line) + goto read_line; + } + + /* Remove # comments unless they are within a double quoted + * string. Remove trailing white space. */ + if ((end = strstr(start, "\""))) { + if (!(end = strstr(end + 1, "\""))) + end = start; + } else + end = start; + + if ((end = strstr(end + 1, "#"))) + *end-- = '\0'; + else + end = start + strlen(start) - 1; + + out = 1; + while (out && (start < end)) { + switch (*end) { + case ' ': /* White space */ + case '\t': /* Tab */ + case '\n': + case '\r': + *end = '\0'; + end--; + break; + default: + out = 0; + break; + } + } + + if (*start == '\0') + continue; + + return start; + } while (1); + + return NULL; +} + +/** + * @brief get hostcmd data + * + * @param ln A pointer to line number + * @param buf A pointer to hostcmd data + * @param size A pointer to the return size of hostcmd buffer + * @return UAP_SUCCESS + */ +static int +mlan_get_hostcmd_data(FILE * fp, int *ln, t_u8 *buf, t_u16 *size) +{ + t_s32 errors = 0, i; + char line[512], *pos, *pos1, *pos2, *pos3; + t_u16 len; + + while ((pos = mlan_config_get_line(fp, line, sizeof(line), ln))) { + (*ln)++; + if (strcmp(pos, "}") == 0) { + break; + } + + pos1 = strchr(pos, ':'); + if (pos1 == NULL) { + printf("Line %d: Invalid hostcmd line '%s'\n", *ln, + pos); + errors++; + continue; + } + *pos1++ = '\0'; + + pos2 = strchr(pos1, '='); + if (pos2 == NULL) { + printf("Line %d: Invalid hostcmd line '%s'\n", *ln, + pos); + errors++; + continue; + } + *pos2++ = '\0'; + + len = a2hex_or_atoi(pos1); + if (len < 1 || len > MRVDRV_SIZE_OF_CMD_BUFFER) { + printf("Line %d: Invalid hostcmd line '%s'\n", *ln, + pos); + errors++; + continue; + } + + *size += len; + + if (*pos2 == '"') { + pos2++; + if ((pos3 = strchr(pos2, '"')) == NULL) { + printf("Line %d: invalid quotation '%s'\n", *ln, + pos); + errors++; + continue; + } + *pos3 = '\0'; + memset(buf, 0, len); + memmove(buf, pos2, MIN(strlen(pos2), len)); + buf += len; + } else if (*pos2 == '\'') { + pos2++; + if ((pos3 = strchr(pos2, '\'')) == NULL) { + printf("Line %d: invalid quotation '%s'\n", *ln, + pos); + errors++; + continue; + } + *pos3 = ','; + for (i = 0; i < len; i++) { + if ((pos3 = strchr(pos2, ',')) != NULL) { + *pos3 = '\0'; + *buf++ = (t_u8)a2hex_or_atoi(pos2); + pos2 = pos3 + 1; + } else + *buf++ = 0; + } + } else if (*pos2 == '{') { + t_u16 tlvlen = 0, tmp_tlvlen; + mlan_get_hostcmd_data(fp, ln, buf + len, &tlvlen); + tmp_tlvlen = tlvlen; + while (len--) { + *buf++ = (t_u8)(tmp_tlvlen & 0xff); + tmp_tlvlen >>= 8; + } + *size += tlvlen; + buf += tlvlen; + } else { + t_u32 value = a2hex_or_atoi(pos2); + while (len--) { + *buf++ = (t_u8)(value & 0xff); + value >>= 8; + } + } + } + return UAP_SUCCESS; +} + +/******************************************************** + Global Functions +********************************************************/ + +/** + * @brief Prepare host-command buffer + * @param fname path to the config file + * @param cmd_name Command name + * @param buf A pointer to comand buffer + * @return UAP_SUCCESS--success, otherwise--fail + */ +int +prepare_host_cmd_buffer(char *fname, char *cmd_name, t_u8 *buf) +{ + char line[256], cmdname[256], *pos, cmdcode[10]; + apcmdbuf *hostcmd; + int ln = 0; + int cmdname_found = 0, cmdcode_found = 0; + FILE *config_fp; + int ret = UAP_SUCCESS; + + config_fp = fopen(fname, "r"); + + if (!config_fp) { + printf("Unable to find %s. Exiting...\n", fname); + return UAP_FAILURE; + } + + memset(buf, 0, MRVDRV_SIZE_OF_CMD_BUFFER); + hostcmd = (apcmdbuf *)buf; + hostcmd->cmd_code = 0xffff; + + snprintf(cmdname, sizeof(cmdname), "%s={", cmd_name); + cmdname_found = 0; + while ((pos = mlan_config_get_line(config_fp, line, sizeof(line), &ln))) { + if (strcmp(pos, cmdname) == 0) { + cmdname_found = 1; + snprintf(cmdcode, sizeof(cmdcode), "CmdCode="); + cmdcode_found = 0; + while ((pos = + mlan_config_get_line(config_fp, line, + sizeof(line), &ln))) { + if (strncmp(pos, cmdcode, strlen(cmdcode)) == 0) { + t_u16 len = 0; + cmdcode_found = 1; + hostcmd->cmd_code = + a2hex_or_atoi(pos + + strlen(cmdcode)); + hostcmd->size = + sizeof(apcmdbuf) - + BUF_HEADER_SIZE; + mlan_get_hostcmd_data(config_fp, &ln, + buf + + sizeof(apcmdbuf), + &len); + hostcmd->size += len; + break; + } + } + if (!cmdcode_found) { + fprintf(stderr, + "uaputl: CmdCode not found in conf file\n"); + ret = UAP_FAILURE; + goto done; + } + break; + } + } + + if (!cmdname_found) { + fprintf(stderr, + "uaputl: cmdname '%s' is not found in conf file\n", + cmd_name); + ret = UAP_FAILURE; + goto done; + } +done: + fclose(config_fp); + return ret; +} diff --git a/mxm_wifiex/wlan_src/mapp/uaputl/uaputl.c b/mxm_wifiex/wlan_src/mapp/uaputl/uaputl.c new file mode 100644 index 0000000..da8dc65 --- /dev/null +++ b/mxm_wifiex/wlan_src/mapp/uaputl/uaputl.c @@ -0,0 +1,14536 @@ +/** @file uaputl.c + * + * @brief Program to send AP commands to the driver/firmware of the uAP + * driver. + * + * Usage: uaputl.exe [-option params] + * or uaputl.exe [command] [params] + * + * + * Copyright 2014-2020 NXP + * + * NXP CONFIDENTIAL + * The source code contained or described herein and all documents related to + * the source code (Materials) are owned by NXP, its + * suppliers and/or its licensors. Title to the Materials remains with NXP, + * its suppliers and/or its licensors. The Materials contain + * trade secrets and proprietary and confidential information of NXP, its + * suppliers and/or its licensors. The Materials are protected by worldwide copyright + * and trade secret laws and treaty provisions. No part of the Materials may be + * used, copied, reproduced, modified, published, uploaded, posted, + * transmitted, distributed, or disclosed in any way without NXP's prior + * express written permission. + * + * No license under any patent, copyright, trade secret or other intellectual + * property right is granted to or conferred upon you by disclosure or delivery + * of the Materials, either expressly, by implication, inducement, estoppel or + * otherwise. Any license under such intellectual property rights must be + * express and approved by NXP in writing. + * + */ +/**************************************************************************** +Change log: + 03/01/08: Initial creation +****************************************************************************/ + +/**************************************************************************** + Header files +****************************************************************************/ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "uaputl.h" +#include "uapcmd.h" + +/**************************************************************************** + Definitions +****************************************************************************/ +/** Default debug level */ +int debug_level = MSG_NONE; + +/** Enable or disable debug outputs */ +#define DEBUG 1 + +/** Convert character to integer */ +#define CHAR2INT(x) (((x) >= 'A') ? ((x) - 'A' + 10) : ((x) - '0')) + +/** Supported stream modes */ +#define HT_STREAM_MODE_1X1 0x11 +#define HT_STREAM_MODE_2X2 0x22 + +static int get_bss_config(t_u8 *buf); + +/**************************************************************************** + Global variables +****************************************************************************/ +/** Device name */ +static char dev_name[IFNAMSIZ + 1]; +/** Option for cmd */ +struct option cmd_options[] = { + {"help", 0, 0, 'h'}, + {0, 0, 0, 0} +}; + +/** Flag to check if custom IE is present in sys_config response from FW */ +int custom_ie_present = 0; + +/** Flag to check if max mgmt IE is printed in sys_config response from FW */ +int max_mgmt_ie_print = 0; + +/** Flag to bypass re-route path */ +int uap_ioctl_no_reroute = 0; + +/**************************************************************************** + Local functions +****************************************************************************/ +/** + * @brief Convert char to hex integer + * + * @param chr Char + * @return Hex integer + */ +unsigned char +hexc2bin(char chr) +{ + if (chr >= '0' && chr <= '9') + chr -= '0'; + else if (chr >= 'A' && chr <= 'F') + chr -= ('A' - 10); + else if (chr >= 'a' && chr <= 'f') + chr -= ('a' - 10); + + return chr; +} + +/** + * @brief Check protocol is valid or not + * + * @param protocol Protocol + * + * @return UAP_SUCCESS or UAP_FAILURE + */ +int +is_protocol_valid(int protocol) +{ + int ret = UAP_FAILURE; + switch (protocol) { + case PROTOCOL_NO_SECURITY: + case PROTOCOL_STATIC_WEP: + case PROTOCOL_WPA: + case PROTOCOL_WPA2: + case PROTOCOL_WPA2_MIXED: + case PROTOCOL_WPA3_SAE: + ret = UAP_SUCCESS; + break; + default: + printf("ERR: Invalid Protocol: %d\n", protocol); + break; + } + return ret; +} + +/** + * @brief Function to check valid rate + * + * + * @param rate Rate to verify + * + * return UAP_SUCCESS or UAP_FAILURE + **/ +int +is_rate_valid(int rate) +{ + int ret = UAP_SUCCESS; + switch (rate) { + case 2: + case 4: + case 11: + case 13: + case 22: + case 12: + case 18: + case 24: + case 48: + case 72: + case 96: + case 108: + case 36: + break; + default: + ret = UAP_FAILURE; + break; + } + return ret; +} + +/** + * @brief Check for mandatory rates + * + * + * 2, 4, 11, 22 must be present + * + * 6 12 and 24 must be present for ofdm + * + * @param argc Number of arguments + * @param argv Pointer to the arguments + * @return UAP_FAILURE or UAP_SUCCESS + * + */ +static int +check_mandatory_rates(int argc, char **argv) +{ + int i; + int tmp; + t_u32 rate_bitmap = 0; + int cck_enable = 0; + int ofdm_enable = 0; +#define BITMAP_RATE_1M 0x01 +#define BITMAP_RATE_2M 0x02 +#define BITMAP_RATE_5_5M 0x04 +#define BITMAP_RATE_11M 0x8 +#define B_RATE_MANDATORY 0x0f +#define BITMAP_RATE_6M 0x10 +#define BITMAP_RATE_12M 0x20 +#define BITMAP_RATE_24M 0x40 +#define G_RATE_MANDATORY 0x70 + for (i = 0; i < argc; i++) { + tmp = (A2HEXDECIMAL(argv[i]) & ~BASIC_RATE_SET_BIT); + switch (tmp) { + case 2: + cck_enable = 1; + rate_bitmap |= BITMAP_RATE_1M; + break; + case 4: + cck_enable = 1; + rate_bitmap |= BITMAP_RATE_2M; + break; + case 11: + cck_enable = 1; + rate_bitmap |= BITMAP_RATE_5_5M; + break; + case 22: + cck_enable = 1; + rate_bitmap |= BITMAP_RATE_11M; + break; + case 12: + ofdm_enable = 1; + rate_bitmap |= BITMAP_RATE_6M; + break; + case 24: + ofdm_enable = 1; + rate_bitmap |= BITMAP_RATE_12M; + break; + case 48: + ofdm_enable = 1; + rate_bitmap |= BITMAP_RATE_24M; + break; + case 18: + case 36: + case 72: + case 96: + case 108: + ofdm_enable = 1; + break; + } + } +#ifdef WIFI_DIRECT_SUPPORT + if (strncmp(dev_name, "wfd", 3)) +#endif + if ((rate_bitmap & B_RATE_MANDATORY) != B_RATE_MANDATORY) { + if (cck_enable) { + printf("Basic Rates 2, 4, 11 and 22 (500K units) \n" "must be present in basic or non-basic rates\n"); + return UAP_FAILURE; + } + } + if (ofdm_enable && + ((rate_bitmap & G_RATE_MANDATORY) != G_RATE_MANDATORY)) { + printf("OFDM Rates 12, 24 and 48 ( 500Kb units)\n" + "must be present in basic or non-basic rates\n"); + return UAP_FAILURE; + } + return UAP_SUCCESS; +} + +/** + * @brief Convert string to hex integer + * + * @param s A pointer string buffer + * @return Hex integer + */ +unsigned int +a2hex(char *s) +{ + unsigned int val = 0; + if (!strncasecmp("0x", s, 2)) { + s += 2; + } + while (*s && isxdigit(*s)) { + val = (val << 4) + hexc2bin(*s++); + } + return val; +} + +/** + * @brief Dump hex data + * + * @param prompt A pointer prompt buffer + * @param p A pointer to data buffer + * @param len The len of data buffer + * @param delim Delim char + * @return None + */ +void +hexdump_data(char *prompt, void *p, int len, char delim) +{ + int i; + unsigned char *s = p; + + if (prompt) { + printf("%s: len=%d\n", prompt, (int)len); + } + for (i = 0; i < len; i++) { + if (i != len - 1) + printf("%02x%c", *s++, delim); + else + printf("%02x\n", *s); + if ((i + 1) % 16 == 0) + printf("\n"); + } + printf("\n"); +} + +#if DEBUG +/** + * @brief Conditional printf + * + * @param level Severity level of the message + * @param fmt Printf format string, followed by optional arguments + */ +void +uap_printf(int level, char *fmt, ...) +{ + va_list ap; + va_start(ap, fmt); + if (level <= debug_level) { + vprintf(fmt, ap); + } + va_end(ap); +} + +/** + * @brief Dump hex data + * + * @param prompt A pointer prompt buffer + * @param p A pointer to data buffer + * @param len The len of data buffer + * @param delim Delim char + * @return None + */ +void +hexdump(char *prompt, void *p, int len, char delim) +{ + if (debug_level < MSG_ALL) + return; + hexdump_data(prompt, p, len, delim); +} +#endif + +/** + * @brief Hex to number + * + * @param c Hex value + * @return Integer value or -1 + */ +int +hex2num(char c) +{ + if (c >= '0' && c <= '9') + return c - '0'; + if (c >= 'a' && c <= 'f') + return c - 'a' + 10; + if (c >= 'A' && c <= 'F') + return c - 'A' + 10; + + return -1; +} + +/** + * @brief Show usage information for the sys_info command + * + * $return N/A + */ +void +print_sys_info_usage(void) +{ + printf("\nUsage : sys_info\n"); + return; +} + +/** + * @brief Get Max sta num from firmware + * + * @return max number of stations + */ +int +get_max_sta_num_supported(t_u16 *max_sta_num_supported) +{ + apcmdbuf_sys_configure *cmd_buf = NULL; + tlvbuf_max_sta_num *tlv = NULL; + t_u8 *buffer = NULL; + t_u16 cmd_len = 0; + t_u16 buf_len = MRVDRV_SIZE_OF_CMD_BUFFER; + int ret = UAP_SUCCESS; + + /* Initialize the command length */ + cmd_len = sizeof(apcmdbuf_sys_configure) + sizeof(tlvbuf_max_sta_num); + + /* Initialize the command buffer */ + buffer = (t_u8 *)malloc(buf_len); + if (!buffer) { + printf("ERR:Cannot allocate buffer for command!\n"); + return UAP_FAILURE; + } + memset(buffer, 0, buf_len); + + /* Locate headers */ + cmd_buf = (apcmdbuf_sys_configure *)buffer; + tlv = (tlvbuf_max_sta_num *)(buffer + sizeof(apcmdbuf_sys_configure)); + + /* Fill the command buffer */ + cmd_buf->cmd_code = APCMD_SYS_CONFIGURE; + cmd_buf->size = cmd_len; + cmd_buf->seq_num = 0; + cmd_buf->result = 0; + tlv->tag = MRVL_MAX_STA_CNT_TLV_ID; + tlv->length = 4; + cmd_buf->action = ACTION_GET; + + endian_convert_tlv_header_out(tlv); + tlv->max_sta_num_configured = + uap_cpu_to_le16(tlv->max_sta_num_configured); + tlv->max_sta_num_supported = + uap_cpu_to_le16(tlv->max_sta_num_supported); + + /* Send the command */ + ret = uap_ioctl((t_u8 *)cmd_buf, &cmd_len, buf_len); + endian_convert_tlv_header_in(tlv); + tlv->max_sta_num_configured = + uap_le16_to_cpu(tlv->max_sta_num_configured); + tlv->max_sta_num_supported = + uap_le16_to_cpu(tlv->max_sta_num_supported); + /* Process response */ + if (ret == UAP_SUCCESS) { + /* Verify response */ + if ((cmd_buf->cmd_code != + (APCMD_SYS_CONFIGURE | APCMD_RESP_CHECK)) || + (tlv->tag != MRVL_MAX_STA_CNT_TLV_ID)) { + printf("ERR:Corrupted response! cmd_code=%x, Tlv->tag=%x\n", cmd_buf->cmd_code, tlv->tag); + free(buffer); + return UAP_FAILURE; + } + /* Print response */ + if (cmd_buf->result != CMD_SUCCESS) { + printf("ERR:Could not get max station number!\n"); + ret = UAP_FAILURE; + } else { + if (tlv->length == 4) { + *max_sta_num_supported = + tlv->max_sta_num_supported; + } else { + *max_sta_num_supported = MAX_STA_COUNT; + } + } + } else { + printf("ERR:Command sending failed!\n"); + } + if (buffer) + free(buffer); + return ret; +} + +/** + * @brief Parse domain name for domain_code + * + * @param dom_name Domain name + * @return domain_code / UAP_FAILURE + */ +static t_u8 +parse_domain_name(char *domain_name) +{ + t_u8 domain_code = UAP_FAILURE; + + if (strstr(domain_name, "DOMAIN_CODE_")) { + domain_name += sizeof("DOMAIN_CODE_") - 1; + + if (!(strncmp(domain_name, "FCC", sizeof("FCC") - 1))) + domain_code = DOMAIN_CODE_FCC; + else if (!(strcmp(domain_name, "ETSI"))) + domain_code = DOMAIN_CODE_ETSI; + else if (!(strcmp(domain_name, "MKK"))) + domain_code = DOMAIN_CODE_MKK; + else if (!(strcmp(domain_name, "IN"))) + domain_code = DOMAIN_CODE_IN; + else if (!(strcmp(domain_name, "MY"))) + domain_code = DOMAIN_CODE_MY; + } + return domain_code; +} + +/** + * @brief Parse domain file for country information + * + * @param country Country name + * @param band Band Info. 0x01 : B band, 0x02 : G band, 0x04 : A band. + * @param sub_bands Band information + * @param pdomain_code Pointer to receive domain_code + * @return number of band/ UAP_FAILURE + */ +t_u8 +parse_domain_file(char *country, int band, ieeetypes_subband_set_t *sub_bands, + t_u8 *pdomain_code) +{ + FILE *fp; + char str[64]; + char domain_name[64]; + int cflag = 0; + int dflag = 0; + int found = 0; + int skip = 0; + int j = -1, reset_j = 0; + t_u8 no_of_sub_band = 0; + char *strp = NULL; + int ret = 0; + + fp = fopen("config/80211d_domain.conf", "r"); + if (fp == NULL) { + printf("File opening Error\n"); + return UAP_FAILURE; + } + + /** + * Search specific domain name + */ + memset(domain_name, 0, sizeof(domain_name)); + memset(str, 0, 64); + while (!feof(fp)) { + ret = fscanf(fp, "%63s", str); + if (ret <= 0) + break; + if (cflag) { + strncpy(domain_name, str, sizeof(domain_name) - 1); + cflag = 0; + } + if (!strcmp(str, "COUNTRY:")) { + /** Store next string to domain_name */ + cflag = 1; + } + + if (!strcmp(str, country)) { + /** Country is matched ;)*/ + found = 1; + break; + } + } + + if (!found) { + printf("No match found for Country = %s in the 80211d_domain.conf \n", country); + fclose(fp); + found = 0; + return UAP_FAILURE; + } + + /** + * Search domain specific information + */ + while (!feof(fp)) { + ret = fscanf(fp, "%63s", str); + if (ret <= 0) + break; + + if (feof(fp) + ) { + break; + } + + if (dflag && !strcmp(str, "DOMAIN:")) { + + if ((band & BAND_A) == 0) + break; + + /* parse next domain */ + cflag = 0; + dflag = 0; + j = -1; + reset_j = 0; + } + if (dflag) { + j++; + if (strchr(str, ',')) + reset_j = 1; + + strp = strtok(str, ", "); + + if (strp == NULL) { + if (reset_j) { + j = -1; + reset_j = 0; + } + continue; + } else { + strncpy(str, strp, (sizeof(str) - 1)); + } + + if (IS_HEX_OR_DIGIT(str) == UAP_FAILURE) { + printf("ERR: Only Number values are allowed\n"); + fclose(fp); + return UAP_FAILURE; + } + + switch (j) { + case 0: + sub_bands[no_of_sub_band].first_chan = + (t_u8)A2HEXDECIMAL(str); + break; + case 1: + sub_bands[no_of_sub_band].no_of_chan = + (t_u8)A2HEXDECIMAL(str); + break; + case 2: + sub_bands[no_of_sub_band++].max_tx_pwr = + (t_u8)A2HEXDECIMAL(str); + break; + default: + printf("ERR: Incorrect 80211d_domain.conf file\n"); + fclose(fp); + return UAP_FAILURE; + } + + if (reset_j) { + j = -1; + reset_j = 0; + } + } + + if (cflag && !strcmp(str, domain_name)) { + /* Followed will be the band details */ + cflag = 0; + if (band & (BAND_B | BAND_G) || skip) + dflag = 1; + else + skip = 1; + } + if (!dflag && !strcmp(str, "DOMAIN:")) { + cflag = 1; + } + } + fclose(fp); + + if (pdomain_code && no_of_sub_band && (band & BAND_A)) { + *pdomain_code = parse_domain_name(domain_name); + } + return (no_of_sub_band); +} + +/** + * + * @brief Set/Get SNMP MIB + * + * @param action 0-GET 1-SET + * @param oid Oid + * @param size Size of oid value + * @param oid_buf Oid value + * @return UAP_FAILURE or UAP_SUCCESS + * + */ +int +sg_snmp_mib(t_u16 action, t_u16 oid, t_u16 size, t_u8 *oid_buf) +{ + apcmdbuf_snmp_mib *cmd_buf = NULL; + tlvbuf_header *tlv = NULL; + int ret = UAP_FAILURE; + t_u8 *buf = NULL; + t_u16 buf_len = MRVDRV_SIZE_OF_CMD_BUFFER; + t_u16 cmd_len; + int i; + + cmd_len = sizeof(apcmdbuf_snmp_mib) + sizeof(tlvbuf_header) + size; + buf = (t_u8 *)malloc(buf_len); + if (!buf) { + printf("ERR:Cannot allocate buffer from command!\n"); + return ret; + } + memset(buf, 0, buf_len); + + /* Locate Headers */ + cmd_buf = (apcmdbuf_snmp_mib *)buf; + tlv = (tlvbuf_header *)(buf + sizeof(apcmdbuf_snmp_mib)); + cmd_buf->size = buf_len - BUF_HEADER_SIZE; + cmd_buf->result = 0; + cmd_buf->seq_num = 0; + cmd_buf->cmd_code = HostCmd_SNMP_MIB; + + tlv->type = uap_cpu_to_le16(oid); + tlv->len = uap_cpu_to_le16(size); + for (i = 0; action && (i < size); i++) { + tlv->data[i] = oid_buf[i]; + } + + cmd_buf->action = uap_cpu_to_le16(action); + ret = uap_ioctl((t_u8 *)cmd_buf, &cmd_len, buf_len); + if (ret == UAP_SUCCESS) { + if (cmd_buf->result == CMD_SUCCESS) { + if (!action) { + /** Relocate the headers */ + tlv = (tlvbuf_header *)((t_u8 *)cmd_buf + + sizeof + (apcmdbuf_snmp_mib)); + for (i = 0; + i < MIN(uap_le16_to_cpu(tlv->len), size); + i++) { + oid_buf[i] = tlv->data[i]; + } + } + ret = UAP_SUCCESS; + } else { + printf("ERR:Command Response incorrect!\n"); + ret = UAP_FAILURE; + } + } else { + printf("ERR:Command sending failed!\n"); + } + free(buf); + return ret; +} + +/** + * @brief Creates a sys_info request and sends to the driver + * + * Usage: "sys_info" + * + * @param argc Number of arguments + * @param argv Pointer to the arguments + * @return UAP_SUCCESS/UAP_FAILURE + */ +int +apcmd_sys_info(int argc, char *argv[]) +{ + apcmdbuf_sys_info_request *cmd_buf = NULL; + apcmdbuf_sys_info_response *response_buf = NULL; + t_u8 *buf = NULL; + t_u16 cmd_len; + t_u16 buf_len = MRVDRV_SIZE_OF_CMD_BUFFER; + int ret = UAP_SUCCESS; + int opt; + + while ((opt = getopt_long(argc, argv, "+", cmd_options, NULL)) != -1) { + switch (opt) { + default: + print_sys_info_usage(); + return UAP_FAILURE; + } + } + argc -= optind; + argv += optind; + + /* Check arguments */ + if (argc != 0) { + printf("ERR:Too many arguments.\n"); + print_sys_info_usage(); + return UAP_FAILURE; + } + + /* Alloc buf for command */ + buf = (t_u8 *)malloc(buf_len); + + if (!buf) { + printf("ERR:Cannot allocate buffer from command!\n"); + return UAP_FAILURE; + } + memset(buf, 0, buf_len); + + /* Locate headers */ + cmd_len = sizeof(apcmdbuf_sys_info_request); + cmd_buf = (apcmdbuf_sys_info_request *)buf; + response_buf = (apcmdbuf_sys_info_response *)buf; + + /* Fill the command buffer */ + cmd_buf->cmd_code = APCMD_SYS_INFO; + cmd_buf->size = cmd_len; + cmd_buf->seq_num = 0; + cmd_buf->result = 0; + + /* Send the command */ + ret = uap_ioctl((t_u8 *)cmd_buf, &cmd_len, buf_len); + + /* Process response */ + if (ret == UAP_SUCCESS) { + /* Verify response */ + if (response_buf->cmd_code != + (APCMD_SYS_INFO | APCMD_RESP_CHECK)) { + printf("ERR:Corrupted response!\n"); + free(buf); + return UAP_FAILURE; + } + /* Print response */ + if (response_buf->result == CMD_SUCCESS) { + printf("System information = %s\n", + response_buf->sys_info); + } else { + printf("ERR:Could not retrieve system information!\n"); + ret = UAP_FAILURE; + } + } else { + printf("ERR:Command sending failed!\n"); + } + + free(buf); + return ret; +} + +/** + * @brief Show usage information for deepsleep command + * + * $return N/A + */ +void +print_deepsleep_usage(void) +{ + printf("\nUsage : deepsleep [MODE][IDLE_TIME]"); + printf("\nOptions: MODE : 0 - Disable auto deep sleep mode"); + printf("\n 1 - Enable auto deep sleep mode"); + printf("\n IDLE_TIME: Idle time in milliseconds, default value is 100 ms"); + printf("\n empty - get auto deep sleep mode\n"); + return; +} + +/** + * @brief Creates deepsleep request and send to driver + * + * + * @param argc Number of arguments + * @param argv Pointer to the arguments + * @return UAP_SUCCESS/UAP_FAILURE + */ +int +apcmd_deepsleep(int argc, char *argv[]) +{ + int opt; + deep_sleep_para param; + struct ifreq ifr; + t_s32 sockfd; + while ((opt = getopt_long(argc, argv, "+", cmd_options, NULL)) != -1) { + switch (opt) { + default: + print_deepsleep_usage(); + return UAP_SUCCESS; + } + } + argc -= optind; + argv += optind; + + memset(¶m, 0, sizeof(param)); + /* Check arguments */ + if (argc > 2) { + printf("ERR:wrong arguments. Only support 2 arguments\n"); + print_deepsleep_usage(); + return UAP_FAILURE; + } + param.subcmd = UAP_DEEP_SLEEP; + if (argc) { + if (argc >= 1) { + if ((IS_HEX_OR_DIGIT(argv[0]) == UAP_FAILURE) || + ((atoi(argv[0]) < 0) || (atoi(argv[0]) > 1))) { + printf("ERR: Only Number values are allowed\n"); + print_deepsleep_usage(); + return UAP_FAILURE; + } + } + param.action = 1; + param.deep_sleep = (t_u16)A2HEXDECIMAL(argv[0]); + param.idle_time = 0; + if (argc == 2) { + if (IS_HEX_OR_DIGIT(argv[0]) == UAP_FAILURE) { + printf("ERR: Only Number values are allowed\n"); + print_deepsleep_usage(); + return UAP_FAILURE; + } + param.idle_time = (t_u16)A2HEXDECIMAL(argv[1]); + } + } else { + param.action = 0; + } + /* Open socket */ + if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) { + printf("ERR:Cannot open socket\n"); + return UAP_FAILURE; + } + /* Initialize the ifr structure */ + memset(&ifr, 0, sizeof(ifr)); + strncpy(ifr.ifr_ifrn.ifrn_name, dev_name, IFNAMSIZ - 1); + ifr.ifr_ifru.ifru_data = (void *)¶m; + /* Perform ioctl */ + errno = 0; + if (ioctl(sockfd, UAP_IOCTL_CMD, &ifr)) { + if (argc) + printf("ERR: deep sleep must be disabled before changing idle time\n"); + else { + perror(""); + printf("ERR:deep sleep failed\n"); + } + close(sockfd); + return UAP_FAILURE; + } + if (!argc) { + if (param.deep_sleep == 1) { + printf("deep sleep mode: enabled\n"); + printf("idle time = %dms\n", param.idle_time); + } else { + printf("deep sleep mode: disabled\n"); + } + } + /* Close socket */ + close(sockfd); + return UAP_SUCCESS; +} + +/** + * @brief Configure Band Steering + * + * Usage: band_steering_cfg state block_2g_prb_req max_btm_req_allowed + * + * State 0 or 1 + * + * @param argc Number of arguments + * @param argv Pointer to the arguments + * @return UAP_SUCCESS/UAP_FAILURE + */ + +int +apcmd_band_steering(int argc, char *argv[]) +{ + int opt; + band_steer_para param; + struct ifreq ifr; + t_s32 sockfd; + t_u8 state = 0; + t_u8 block2gPrbReq = 0; + t_u8 maxBtmReqAllowed = 0; + + t_u8 i; + while ((opt = getopt_long(argc, argv, "+", cmd_options, NULL)) != -1) { + switch (opt) { + default: + printf("\nUsage: band_steering_cfg \n"); + return UAP_SUCCESS; + } + } + argc -= optind; + argv += optind; + memset(¶m, 0, sizeof(param)); + /* Check arguments */ + if (!(argc == 0 || argc == 2 || argc == 4 || argc == 6)) { + printf("ERR:wrong arguments.\n"); + return UAP_FAILURE; + } + param.subcmd = UAP_BAND_STEER; + + if (argc) { + if (strcmp(argv[0], "state") && + strcmp(argv[0], "block_2g_prb_req") && + strcmp(argv[0], "max_btm_req_allowed")) { + printf("ERR: Incorrect input. Either state, block_2g_prb_req or max_btm_req_allowed is needed.\n"); + return UAP_FAILURE; + } + /** SET */ + for (i = 0; i < argc; i = i + 2) { + if (strcmp(argv[i], "state") == 0) { + param.action += ACT_SET_STATE; + if (strcmp(argv[i + 1], "0") == 0) { + state = 0; + } else if (strcmp(argv[i + 1], "1") == 0) { + state = 1; + } else { + printf("ERR: Invalid State value."); + return UAP_FAILURE; + } + } else if (strcmp(argv[i], "block_2g_prb_req") == 0) { + param.action += ACT_SET_BLOCK_2G_PRB_REQ; + block2gPrbReq = atoi(argv[i + 1]); + if (block2gPrbReq < 0 || block2gPrbReq > 15) { + printf("ERR: Invalid block_2g_prb_req value. Enter value between 0 and 15"); + return UAP_FAILURE; + } + } else if (strcmp(argv[i], "max_btm_req_allowed") == 0) { + param.action += ACT_SET_MAX_BTM_REQ_ALLOWED; + maxBtmReqAllowed = atoi(argv[i + 1]); + if (maxBtmReqAllowed <= 0 || + maxBtmReqAllowed > 255) { + printf("ERR: Invalid max_btm_req_allowed value."); + return UAP_FAILURE; + } + } else { + printf("ERR: Incorrect input. state, block_2g_prb_req and/or max_btm_req_allowed is needed in decimal format."); + return UAP_FAILURE; + } + } + } + param.state = state; + param.block_2g_prb_req = block2gPrbReq; + param.max_btm_req_allowed = maxBtmReqAllowed; + + /* Open socket */ + if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) { + printf("ERR:Cannot open socket\n"); + return UAP_FAILURE; + } + /* Initialize the ifr structure */ + memset(&ifr, 0, sizeof(ifr)); + strncpy(ifr.ifr_ifrn.ifrn_name, dev_name, IFNAMSIZ - 1); + ifr.ifr_ifru.ifru_data = (void *)¶m; + /* Perform ioctl */ + ioctl(sockfd, UAP_IOCTL_CMD, &ifr); + + if (argc) { + printf("Set Successfull\n"); + printf("state = %d \n", param.state); + printf("block_2g_prb_req = %d\n", param.block_2g_prb_req); + printf("max_btm_req_allowed = %d\n", param.max_btm_req_allowed); + } else { + printf("Get Successfull\n"); + if (param.state == 1) { + printf("band steering mode: enabled\n"); + printf("block_2g_prb_req = %d\n", + param.block_2g_prb_req); + printf("max_btm_req_allowed = %d\n", + param.max_btm_req_allowed); + } else { + printf("band steering: disabled\n"); + } + + close(sockfd); + return UAP_FAILURE; + } + /* Close socket */ + close(sockfd); + return UAP_SUCCESS; +} + +/** + * @brief Show usage information for tx_data_pause command + * + * $return N/A + */ +void +print_txdatapause_usage(void) +{ + printf("\nUsage : tx_data_pause [ENABLE][TX_BUF_CNT]"); + printf("\nOptions: ENABLE : 0 - Disable Tx data pause events"); + printf("\n 1 - Enable Tx data pause events"); + printf("\n TX_BUF_CNT: Max number of TX buffer for PS clients"); + printf("\n empty - get Tx data pause settings\n"); + return; +} + +/** + * @brief Set/get txpause setting + * + * @param txpause A pointer to the Tx data pause parameters structure + * @return UAP_SUCCESS/UAP_FAILURE + */ +int +send_txpause_ioctl(tx_data_pause_para *txpause) +{ + struct ifreq ifr; + t_s32 sockfd; + /* Open socket */ + if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) { + printf("ERR:Cannot open socket\n"); + return UAP_FAILURE; + } + /* Initialize the ifr structure */ + memset(&ifr, 0, sizeof(ifr)); + strncpy(ifr.ifr_ifrn.ifrn_name, dev_name, IFNAMSIZ - 1); + ifr.ifr_ifru.ifru_data = (void *)txpause; + /* Perform ioctl */ + errno = 0; + if (ioctl(sockfd, UAP_IOCTL_CMD, &ifr)) { + perror(""); + printf("ERR:txpause is not supported by %s\n", dev_name); + close(sockfd); + return UAP_FAILURE; + } + /* Close socket */ + close(sockfd); + return UAP_SUCCESS; +} + +/** + * @brief Creates tx_data_pause request and sends to driver + * + * + * @param argc Number of arguments + * @param argv Pointer to the arguments + * @return UAP_SUCCESS/UAP_FAILURE + */ +int +apcmd_txdatapause(int argc, char *argv[]) +{ + int opt; + tx_data_pause_para param; + while ((opt = getopt_long(argc, argv, "+", cmd_options, NULL)) != -1) { + switch (opt) { + default: + print_txdatapause_usage(); + return UAP_SUCCESS; + } + } + argc -= optind; + argv += optind; + + memset(¶m, 0, sizeof(param)); + /* Check arguments */ + if (argc > 2) { + printf("ERR: Wrong number of arguments\n"); + print_txdatapause_usage(); + return UAP_FAILURE; + } + param.subcmd = UAP_TX_DATA_PAUSE; + if (argc) { + if (argc >= 1) { + if ((IS_HEX_OR_DIGIT(argv[0]) == UAP_FAILURE) || + ((atoi(argv[0]) < TX_DATA_PAUSE_DISABLE) || + (atoi(argv[0]) > TX_DATA_PAUSE_ENABLE))) { + printf("ERR: First argument can either be 0 or 1\n"); + print_txdatapause_usage(); + return UAP_FAILURE; + } + } + if (argc == 1) { + param.action = ACTION_GET; + if (UAP_FAILURE == send_txpause_ioctl(¶m)) { + return UAP_FAILURE; + } + } + param.action = ACTION_SET; + param.txpause = (t_u16)A2HEXDECIMAL(argv[0]); + if (argc == 2) { + if (IS_HEX_OR_DIGIT(argv[1]) == UAP_FAILURE) { + printf("ERR: Max buffer length must be numeric\n"); + print_txdatapause_usage(); + return UAP_FAILURE; + } + param.txbufcnt = (t_u16)A2HEXDECIMAL(argv[1]); + } + } else { + param.action = ACTION_GET; + } + if (UAP_FAILURE == send_txpause_ioctl(¶m)) + return UAP_FAILURE; + if ((argc == 2) && ((t_u16)A2HEXDECIMAL(argv[1]) != param.txbufcnt)) { + printf("Max number of TX buffer allowed for all PS client: %d\n", param.txbufcnt); + return UAP_FAILURE; + } + if (!argc) { + printf("Tx data pause: %s\n", + (param.txpause == 1) ? "enabled" : "disabled"); + printf("Max number of TX buffer allowed for all PS client: %d\n", param.txbufcnt); + } + return UAP_SUCCESS; +} + +/** + * @brief Process host_cmd + * + * + * @param argc Number of arguments + * @param argv Pointer to the arguments + * @return N/A + */ +int +apcmd_hostcmd(int argc, char *argv[]) +{ + apcmdbuf *hdr; + t_u8 *buffer = NULL; + int ret = UAP_SUCCESS; + t_u16 cmd_len = 0; + t_u16 buf_len = MRVDRV_SIZE_OF_CMD_BUFFER; + char cmdname[256]; + + if (argc <= 2) { + printf("Error: invalid no of arguments\n"); + printf("Syntax: ./uaputl hostcmd \n"); + return UAP_FAILURE; + } + + buffer = (t_u8 *)malloc(buf_len); + if (!buffer) { + printf("ERR:Cannot allocate buffer for command!\n"); + return UAP_FAILURE; + } + + memset(buffer, 0, buf_len); + sprintf(cmdname, "%s", argv[2]); + ret = prepare_host_cmd_buffer(argv[1], cmdname, buffer); + if (ret == UAP_FAILURE) + goto _exit_; + + /* Locate headers */ + hdr = (apcmdbuf *)buffer; + cmd_len = hdr->size + BUF_HEADER_SIZE; + + /* Send the command */ + ret = uap_ioctl((t_u8 *)buffer, &cmd_len, buf_len); + + /* Process response */ + if (ret == UAP_SUCCESS) { + hdr->cmd_code &= HostCmd_CMD_ID_MASK; + if (!hdr->result) { + printf("UAPHOSTCMD: CmdCode=%#04x, Size=%#04x, SeqNum=%#04x, Result=%#04x\n", hdr->cmd_code, hdr->size, hdr->seq_num, hdr->result); + hexdump_data("payload", + (void *)(buffer + APCMDHEADERLEN), + hdr->size - (APCMDHEADERLEN - + BUF_HEADER_SIZE), ' '); + } else + printf("UAPHOSTCMD failed: CmdCode=%#04x, Size=%#04x, SeqNum=%#04x, Result=%#04x\n", hdr->cmd_code, hdr->size, hdr->seq_num, hdr->result); + } else + printf("ERR:Command sending failed!\n"); + +_exit_: + if (buffer) + free(buffer); + return ret; +} + +#ifdef SDIO +/** + * @brief Show usage information for cmd52rw command + * + * $return N/A + */ +void +print_cmd52rw_usage(void) +{ + printf("\nUsage : sdcmd52rw
[data]"); + printf("\nOptions: FN no : SDIO function number."); + printf("\n address: SDIO address"); + printf("\n data: data for SDIO write operation."); + printf("\n Read is performed if data is not provided."); + return; +} + +/** + * @brief Process cmd52 read/write handler + * + * + * @param argc Number of arguments + * @param argv Pointer to the arguments + * @return N/A + */ +int +apcmd_cmd52_readwrite(int argc, char *argv[]) +{ + int opt; + sdcmd52_para param; + struct ifreq ifr; + t_s32 sockfd; + while ((opt = getopt_long(argc, argv, "+", cmd_options, NULL)) != -1) { + switch (opt) { + default: + print_cmd52rw_usage(); + return UAP_SUCCESS; + } + } + argc -= optind; + argv += optind; + + memset(¶m, 0, sizeof(sdcmd52_para)); + /* Check arguments */ + if (argc < 2 || argc > 3) { + printf("ERR:wrong arguments.\n"); + print_cmd52rw_usage(); + return UAP_FAILURE; + } + if ((IS_HEX_OR_DIGIT(argv[0]) == UAP_FAILURE) || + (IS_HEX_OR_DIGIT(argv[1]) == UAP_FAILURE)) { + printf("ERR: Only Number values are allowed\n"); + print_cmd52rw_usage(); + return UAP_FAILURE; + } + param.cmd52_params[0] = (t_u8)A2HEXDECIMAL(argv[0]); + if (param.cmd52_params[0] > 7) { + printf("ERR: Invalid function number!\n"); + return UAP_FAILURE; + } + param.cmd52_params[1] = (t_u8)A2HEXDECIMAL(argv[1]); + param.action = 0; + if (argc == 3) { + if (IS_HEX_OR_DIGIT(argv[2]) == UAP_FAILURE) { + printf("ERR: Only Number values are allowed\n"); + print_cmd52rw_usage(); + return UAP_FAILURE; + } + param.cmd52_params[2] = (t_u8)A2HEXDECIMAL(argv[2]); + param.action = 1; + } + param.subcmd = UAP_SDCMD52_RW; + + /* Open socket */ + if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) { + printf("ERR:Cannot open socket\n"); + return UAP_FAILURE; + } + /* Initialize the ifr structure */ + memset(&ifr, 0, sizeof(ifr)); + strncpy(ifr.ifr_ifrn.ifrn_name, dev_name, IFNAMSIZ - 1); + ifr.ifr_ifru.ifru_data = (void *)¶m; + /* Perform ioctl */ + errno = 0; + if (ioctl(sockfd, UAP_IOCTL_CMD, &ifr)) { + perror(""); + printf("ERR:cmd52rw failed\n"); + close(sockfd); + return UAP_FAILURE; + } + if (argc == 2) + printf("Cmd52 read done. "); + else + printf("Cmd52 write done. "); + printf("func=%d, reg=%d, data=0x%02X\n", + param.cmd52_params[0], param.cmd52_params[1], + param.cmd52_params[2]); + /* Close socket */ + close(sockfd); + return UAP_SUCCESS; +} +#endif + +/** + * @brief Show usage information for addbapara command + * + * $return N/A + */ +void +print_addbapara_usage(void) +{ + printf("\nUsage : addbapara [timeout txwinsize rxwinsize]"); + printf("\nOptions: timeout : 0 - Disable"); + printf("\n 1 - 65535 : Block Ack Timeout in TU"); + printf("\n txwinsize: Buffer size for ADDBA request"); + printf("\n rxwinsize: Buffer size for ADDBA response"); + printf("\n txamsdu: amsdu for ADDBA request"); + printf("\n rxamsdu: amsdu for ADDBA response"); + printf("\n empty - get ADDBA parameters\n"); + return; +} + +/** + * @brief Creates addbaparam request and send to driver + * + * + * @param argc Number of arguments + * @param argv Pointer to the arguments + * @return UAP_SUCCESS/UAP_FAILURE + */ +int +apcmd_addbapara(int argc, char *argv[]) +{ + int opt; + addba_param param; + struct ifreq ifr; + t_s32 sockfd; + while ((opt = getopt_long(argc, argv, "+", cmd_options, NULL)) != -1) { + switch (opt) { + default: + print_addbapara_usage(); + return UAP_SUCCESS; + } + } + argc -= optind; + argv += optind; + + memset(¶m, 0, sizeof(param)); + /* Check arguments */ + if ((argc != 0) && (argc != 5)) { + printf("ERR:wrong arguments. Only support 0 or 5 arguments\n"); + print_addbapara_usage(); + return UAP_FAILURE; + } + param.subcmd = UAP_ADDBA_PARA; + if (argc) { + if ((IS_HEX_OR_DIGIT(argv[0]) == UAP_FAILURE) + || (IS_HEX_OR_DIGIT(argv[1]) == UAP_FAILURE) + || (IS_HEX_OR_DIGIT(argv[2]) == UAP_FAILURE) + || (IS_HEX_OR_DIGIT(argv[3]) == UAP_FAILURE) + || (IS_HEX_OR_DIGIT(argv[4]) == UAP_FAILURE) + ) { + printf("ERR: Only Number values are allowed\n"); + print_addbapara_usage(); + return UAP_FAILURE; + } + param.action = 1; + param.timeout = (t_u32)A2HEXDECIMAL(argv[0]); + if (param.timeout > DEFAULT_BLOCK_ACK_TIMEOUT) { + printf("ERR: Block Ack timeout should be in range [1-65535]\n"); + print_addbapara_usage(); + return UAP_FAILURE; + } + param.txwinsize = (t_u32)A2HEXDECIMAL(argv[1]); + param.rxwinsize = (t_u32)A2HEXDECIMAL(argv[2]); + if (param.txwinsize > MAX_TXRX_WINDOW_SIZE || + param.rxwinsize > MAX_TXRX_WINDOW_SIZE) { + printf("ERR: Tx/Rx window size should not be greater than 1023\n"); + print_addbapara_usage(); + return UAP_FAILURE; + } + param.txamsdu = (t_u8)A2HEXDECIMAL(argv[3]); + param.rxamsdu = (t_u8)A2HEXDECIMAL(argv[4]); + if (param.txamsdu > 1 || param.rxamsdu > 1) { + printf("ERR: Tx/Rx amsdu should not be 0 or 1\n"); + print_addbapara_usage(); + return UAP_FAILURE; + } + } else { + param.action = 0; + } + /* Open socket */ + if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) { + printf("ERR:Cannot open socket\n"); + return UAP_FAILURE; + } + /* Initialize the ifr structure */ + memset(&ifr, 0, sizeof(ifr)); + strncpy(ifr.ifr_ifrn.ifrn_name, dev_name, IFNAMSIZ - 1); + ifr.ifr_ifru.ifru_data = (void *)¶m; + /* Perform ioctl */ + errno = 0; + if (ioctl(sockfd, UAP_IOCTL_CMD, &ifr)) { + perror(""); + printf("ERR:ADDBA PARA failed\n"); + close(sockfd); + return UAP_FAILURE; + } + if (!argc) { + printf("ADDBA parameters:\n"); + printf("\ttimeout=%d\n", (int)param.timeout); + printf("\ttxwinsize=%d\n", (int)param.txwinsize); + printf("\trxwinsize=%d\n", (int)param.rxwinsize); + printf("\ttxamsdu=%d\n", (int)param.txamsdu); + printf("\trxamsdu=%d\n", (int)param.rxamsdu); + } + /* Close socket */ + close(sockfd); + return UAP_SUCCESS; +} + +/** + * @brief Show usage information for aggrpriotbl command + * + * $return N/A + */ +void +print_aggrpriotbl_usage(void) +{ + printf("\nUsage : aggrpriotbl ... "); + printf("\nOptions: : 0 - 7, 0xff to disable AMPDU aggregation."); + printf("\n : 0 - 7, 0xff to disable AMSDU aggregation."); + printf("\n empty - get the priority table\n"); + return; +} + +/** + * @brief Creates aggrpriotbl request and send to driver + * + * + * @param argc Number of arguments + * @param argv Pointer to the arguments + * @return UAP_SUCCESS/UAP_FAILURE + */ +int +apcmd_aggrpriotbl(int argc, char *argv[]) +{ + int opt; + aggr_prio_tbl prio_tbl; + struct ifreq ifr; + t_s32 sockfd; + t_u8 value; + int i; + while ((opt = getopt_long(argc, argv, "+", cmd_options, NULL)) != -1) { + switch (opt) { + default: + print_aggrpriotbl_usage(); + return UAP_SUCCESS; + } + } + argc -= optind; + argv += optind; + + memset(&prio_tbl, 0, sizeof(prio_tbl)); + /* Check arguments */ + if ((argc != 0) && (argc != 16)) { + printf("ERR:wrong arguments. Only support 0 or 16 arguments\n"); + print_aggrpriotbl_usage(); + return UAP_FAILURE; + } + prio_tbl.subcmd = UAP_AGGR_PRIOTBL; + if (argc) { + for (i = 0; i < argc; i++) { + if ((IS_HEX_OR_DIGIT(argv[i]) == UAP_FAILURE)) { + printf("ERR: Only Number values are allowed\n"); + print_aggrpriotbl_usage(); + return UAP_FAILURE; + } + value = (t_u8)A2HEXDECIMAL(argv[i]); + if ((value > 7) && (value != 0xff)) { + printf("ERR: Invalid priority, Valid value 0-7, 0xff to disable aggregation.\n"); + print_aggrpriotbl_usage(); + return UAP_FAILURE; + } + } + prio_tbl.action = 1; + for (i = 0; i < MAX_NUM_TID; i++) { + prio_tbl.ampdu[i] = (t_u8)A2HEXDECIMAL(argv[i * 2]); + prio_tbl.amsdu[i] = (t_u8)A2HEXDECIMAL(argv[i * 2 + 1]); + } + } else { + prio_tbl.action = 0; + } + /* Open socket */ + if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) { + printf("ERR:Cannot open socket\n"); + return UAP_FAILURE; + } + /* Initialize the ifr structure */ + memset(&ifr, 0, sizeof(ifr)); + strncpy(ifr.ifr_ifrn.ifrn_name, dev_name, IFNAMSIZ - 1); + ifr.ifr_ifru.ifru_data = (void *)&prio_tbl; + /* Perform ioctl */ + errno = 0; + if (ioctl(sockfd, UAP_IOCTL_CMD, &ifr)) { + perror(""); + printf("ERR: priority table failed\n"); + close(sockfd); + return UAP_FAILURE; + } + if (!argc) { + printf("AMPDU/AMSDU priority table:"); + for (i = 0; i < MAX_NUM_TID; i++) { + printf(" %d %d", prio_tbl.ampdu[i], prio_tbl.amsdu[i]); + } + printf("\n"); + } + /* Close socket */ + close(sockfd); + return UAP_SUCCESS; +} + +/** + * @brief Show usage information for addbareject command + * + * $return N/A + */ +void +print_addba_reject_usage(void) +{ + printf("\nUsage : addbareject ... "); + printf("\nOptions: : 1 enables rejection of ADDBA request for TidX."); + printf("\n 0 would accept any ADDBAs for TidX."); + printf("\n empty - get the addbareject table\n"); + return; +} + +/** + * @brief Creates addbareject request and send to driver + * + * + * @param argc Number of arguments + * @param argv Pointer to the arguments + * @return UAP_SUCCESS/UAP_FAILURE + */ +int +apcmd_addbareject(int argc, char *argv[]) +{ + int opt; + addba_reject_para param; + struct ifreq ifr; + t_s32 sockfd; + int i; + while ((opt = getopt_long(argc, argv, "+", cmd_options, NULL)) != -1) { + switch (opt) { + default: + print_addba_reject_usage(); + return UAP_SUCCESS; + } + } + argc -= optind; + argv += optind; + + memset(¶m, 0, sizeof(param)); + /* Check arguments */ + if ((argc != 0) && (argc != 8)) { + printf("ERR:wrong arguments. Only support 0 or 8 arguments\n"); + print_addba_reject_usage(); + return UAP_FAILURE; + } + param.subcmd = UAP_ADDBA_REJECT; + if (argc) { + for (i = 0; i < argc; i++) { + if ((ISDIGIT(argv[i]) == UAP_FAILURE) || + (atoi(argv[i]) < 0) || (atoi(argv[i]) > 1)) { + printf("ERR: Only allow 0 or 1\n"); + print_addba_reject_usage(); + return UAP_FAILURE; + } + } + param.action = 1; + for (i = 0; i < MAX_NUM_TID; i++) { + param.addba_reject[i] = (t_u8)atoi(argv[i]); + } + } else { + param.action = 0; + } + /* Open socket */ + if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) { + printf("ERR:Cannot open socket\n"); + return UAP_FAILURE; + } + /* Initialize the ifr structure */ + memset(&ifr, 0, sizeof(ifr)); + strncpy(ifr.ifr_ifrn.ifrn_name, dev_name, IFNAMSIZ - 1); + ifr.ifr_ifru.ifru_data = (void *)¶m; + /* Perform ioctl */ + errno = 0; + if (ioctl(sockfd, UAP_IOCTL_CMD, &ifr)) { + perror(""); + printf("ERR: addba reject table failed\n"); + close(sockfd); + return UAP_FAILURE; + } + if (!argc) { + printf("addba reject table: "); + for (i = 0; i < MAX_NUM_TID; i++) { + printf("%d ", param.addba_reject[i]); + } + printf("\n"); + } + /* Close socket */ + close(sockfd); + return UAP_SUCCESS; +} + +/** + * @brief Creates get_fw_info request and send to driver + * + * + * @param pfw_info Pointer to FW information structure + * @return 0--success, otherwise fail + */ +int +get_fw_info(fw_info *pfw_info) +{ + struct ifreq ifr; + t_s32 sockfd; + + memset(pfw_info, 0, sizeof(fw_info)); + pfw_info->subcmd = UAP_FW_INFO; + pfw_info->action = 0; + /* Open socket */ + if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) { + printf("ERR:Cannot open socket\n"); + return -1; + } + /* Initialize the ifr structure */ + memset(&ifr, 0, sizeof(ifr)); + strncpy(ifr.ifr_ifrn.ifrn_name, dev_name, IFNAMSIZ - 1); + ifr.ifr_ifru.ifru_data = (void *)pfw_info; + /* Perform ioctl */ + errno = 0; + if (ioctl(sockfd, UAP_IOCTL_CMD, &ifr)) { + perror(""); + printf("ERR: get fw info failed\n"); + close(sockfd); + return -1; + } + /* Close socket */ + close(sockfd); + return 0; +} + +/** + * @brief Show usage information for HT Tx command + * + * $return N/A + */ +void +print_ht_tx_usage(void) +{ + printf("\nUsage : httxcfg []"); + printf("\nOptions: txcfg : This is a bitmap and should be used as following"); + printf("\n Bit 15-7: Reserved set to 0"); + printf("\n Bit 6: Short GI in 40 Mhz enable/disable"); + printf("\n Bit 5: Short GI in 20 Mhz enable/disable"); + printf("\n Bit 4: Green field enable/disable"); + printf("\n Bit 3-2: Reserved set to 0"); + printf("\n Bit 1: 20/40 Mhz enable disable."); + printf("\n Bit 0: Reserved set to 0"); + return; +} + +/** + * @brief Process HT Tx configuration + * @param argc Number of arguments + * @param argv A pointer to arguments array + * @return MLAN_STATUS_SUCCESS--success, otherwise--fail + */ +int +apcmd_sys_cfg_ht_tx(int argc, char *argv[]) +{ + int opt; + ht_tx_cfg_para param; + struct ifreq ifr; + t_s32 sockfd; + + while ((opt = getopt_long(argc, argv, "+", cmd_options, NULL)) != -1) { + switch (opt) { + default: + print_ht_tx_usage(); + return UAP_SUCCESS; + } + } + argc -= optind; + argv += optind; + + memset(¶m, 0, sizeof(param)); + /* Check arguments */ + if (argc == 0) { + param.action = ACTION_GET; + } else if (argc == 1) { + param.action = ACTION_SET; + param.tx_cfg.httxcap = (t_u16)A2HEXDECIMAL(argv[0]); + } else { + print_ht_tx_usage(); + return UAP_FAILURE; + } + param.subcmd = UAP_HT_TX_CFG; + + /* Open socket */ + if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) { + printf("ERR:Cannot open socket\n"); + return UAP_FAILURE; + } + /* Initialize the ifr structure */ + memset(&ifr, 0, sizeof(ifr)); + strncpy(ifr.ifr_ifrn.ifrn_name, dev_name, IFNAMSIZ - 1); + ifr.ifr_ifru.ifru_data = (void *)¶m; + /* Perform ioctl */ + errno = 0; + if (ioctl(sockfd, UAP_IOCTL_CMD, &ifr)) { + perror(""); + printf("ERR: HT Tx configuration failed\n"); + close(sockfd); + return UAP_FAILURE; + } + + /* Handle response */ + if (param.action == ACTION_GET) { + printf("HT Tx cfg: 0x%08x\n", param.tx_cfg.httxcap); + } + + /* Close socket */ + close(sockfd); + return UAP_SUCCESS; +} + +/** + * @brief Show usage information for vhtcfg command + * + * $return N/A + */ +void +print_vht_usage(void) +{ + printf("\nUsage : vhtcfg " + ""); + printf("\nOption: band : This is the band info for vhtcfg settings."); + printf("\n 0: Settings for both 2.4G and 5G bands"); + printf("\n 1: Settings for 2.4G band"); + printf("\n 2: Settings for 5G band"); + printf("\n txrx : This parameter specifies the configuration of VHT" "operation for TX or/and VHT capabilities."); + printf("\n 1: configuration of VHT capabilities tx"); + printf("\n 2: configuration of VHT capabilities rx"); + printf("\n bwcfg : This parameter specifies the bandwidth (BW)" + "configuration applied to the vhtcfg."); + printf("\n If is 1/3 (Tx operations)"); + printf("\n 0: Tx BW follows the BW (20/40 MHz) from" "11N CFG"); + printf("\n 1: Tx BW follows the BW (80/160/80+80 MHz)" "from VHT Capabilities."); + printf("\n vhtcap : This parameter specifies the VHT capabilities info."); + printf("\n tx_mcs_map : This parameter specifies the TX MCS map."); + printf("\n rx_mcs_map : This parameter specifies the RX MCS map.\n"); + return; +} + +/** + * @brief Handle response of the vhtcfg command + * + * @param vhtcfg Pointer to structure eth_priv_vhtcfg + * + * $return N/A + */ +void +print_vht_response(struct eth_priv_vhtcfg *vhtcfg) +{ + /* GET operation */ + /* Band */ + if (vhtcfg->band == BAND_SELECT_BG) + printf("Band: 2.4G\n"); + else + printf("Band: 5G\n"); + /* BW confi9 */ + if (vhtcfg->txrx & 0x3) { + if (vhtcfg->bwcfg == 0) + printf(" BW config: the 11N config\n"); + else + printf(" BW config: the VHT Capabilities\n"); + } + /* Tx/Rx */ + if (vhtcfg->txrx & 0x1) + printf(" VHT operation for Tx: 0x%08x\n", + vhtcfg->vht_cap_info); + if (vhtcfg->txrx & 0x2) + /* VHT capabilities */ + printf(" VHT Capabilities Info: 0x%08x\n", + vhtcfg->vht_cap_info); + /* MCS */ + printf(" Tx MCS set: 0x%04x\n", vhtcfg->vht_tx_mcs); + printf(" Rx MCS set: 0x%04x\n", vhtcfg->vht_rx_mcs); +} + +/** + * @brief Set/Get 11AC configurations + * @param argc Number of arguments + * @param argv A pointer to arguments array + * @return MLAN_STATUS_SUCCESS--success, otherwise--fail + */ +int +apcmd_sys_cfg_vht(int argc, char *argv[]) +{ + int opt, i = 0; + vht_cfg_para param; + struct eth_priv_vhtcfg vhtcfg; + struct ifreq ifr; + t_s32 sockfd; + t_u8 *respbuf = NULL, num = 0; + fw_info fw; + if (0 == get_fw_info(&fw)) { + /*check whether support 802.11AC through BAND_AAC bit */ + if (!(fw.fw_bands & BAND_AAC)) { + printf("ERR: No support 802 11AC.\n"); + return UAP_FAILURE; + } + } else { + printf("ERR: get_fw_info fail\n"); + return UAP_FAILURE; + } + + memset(¶m, 0, sizeof(param)); + while ((opt = getopt_long(argc, argv, "+", cmd_options, NULL)) != -1) { + switch (opt) { + default: + print_vht_usage(); + return UAP_SUCCESS; + } + } + argc -= optind; + argv += optind; + + respbuf = (t_u8 *)malloc(MRVDRV_SIZE_OF_CMD_BUFFER); + if (!respbuf) { + printf("ERR:Cannot allocate buffer for command!\n"); + return UAP_FAILURE; + } + memset(respbuf, 0, MRVDRV_SIZE_OF_CMD_BUFFER); + + /* Check arguments */ + if ((argc > 6) || (argc < 2)) { + printf("ERR: Invalid number of arguments.\n"); + print_vht_usage(); + free(respbuf); + return UAP_FAILURE; + } + if ((atoi(argv[0]) < 0) || (atoi(argv[0]) > 2)) { + printf("ERR: Invalid band selection.\n"); + print_vht_usage(); + free(respbuf); + return UAP_FAILURE; + } else { + param.vht_cfg.band = (t_u32)A2HEXDECIMAL(argv[0]); + } + if ((atoi(argv[1]) <= 0) || (atoi(argv[1]) > 3)) { + printf("ERR: Invalid Tx/Rx selection.\n"); + print_vht_usage(); + free(respbuf); + return UAP_FAILURE; + } else { + param.vht_cfg.txrx = (t_u32)A2HEXDECIMAL(argv[1]); + } + if (argc == 2) { + param.action = ACTION_GET; + } else if (argc > 2) { + param.vht_cfg.band = (t_u32)A2HEXDECIMAL(argv[0]); + param.vht_cfg.txrx = (t_u32)A2HEXDECIMAL(argv[1]); + if (argc == 3) { + printf("ERR: Invalid number of arguments.\n"); + print_vht_usage(); + free(respbuf); + return UAP_FAILURE; + } + if (argc >= 4) { + if ((atoi(argv[2]) < 0) || (atoi(argv[2]) > 1) || + ((atoi(argv[2]) == 1) && + (atoi(argv[0]) & BAND_SELECT_BG))) { + printf("ERR: Invalid BW cfg selection.\n"); + print_vht_usage(); + free(respbuf); + return UAP_FAILURE; + } else { + param.vht_cfg.bwcfg = + (t_u32)A2HEXDECIMAL(argv[2]); + } + param.vht_cfg.vht_cap_info = + (t_u32)A2HEXDECIMAL(argv[3]); + if (argc == 4) { + param.vht_cfg.vht_tx_mcs = 0xffffffff; + param.vht_cfg.vht_rx_mcs = 0xffffffff; + } else { + if (argc == 5) { + printf("ERR: Invalid number of arguments.\n"); + print_vht_usage(); + free(respbuf); + return UAP_FAILURE; + } + param.vht_cfg.vht_tx_mcs = + (t_u32)A2HEXDECIMAL(argv[4]); + param.vht_cfg.vht_rx_mcs = + (t_u32)A2HEXDECIMAL(argv[5]); + } + } + param.action = ACTION_SET; + } else { + print_vht_usage(); + free(respbuf); + return UAP_FAILURE; + } + param.subcmd = UAP_VHT_CFG; + memcpy(respbuf, ¶m, sizeof(vht_cfg_para)); + + /* Open socket */ + if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) { + printf("ERR:Cannot open socket\n"); + free(respbuf); + return UAP_FAILURE; + } + /* Initialize the ifr structure */ + memset(&ifr, 0, sizeof(ifr)); + strncpy(ifr.ifr_ifrn.ifrn_name, dev_name, IFNAMSIZ - 1); + ifr.ifr_ifru.ifru_data = (void *)respbuf; + /* Perform ioctl */ + errno = 0; + if (ioctl(sockfd, UAP_IOCTL_CMD, &ifr)) { + perror(""); + printf("ERR: 11ac VHT configuration failed\n"); + close(sockfd); + free(respbuf); + return UAP_FAILURE; + } + + /* Handle response */ + if (param.action == ACTION_GET) { + /* Process result */ + /* the first attribute is the number of vhtcfg entries */ + num = *respbuf; + printf("11AC VHT Configuration: \n"); + for (i = 0; i < num; i++) { + memcpy(&vhtcfg, respbuf + 1 + i * sizeof(vhtcfg), + sizeof(vhtcfg)); + print_vht_response(&vhtcfg); + } + } else + printf("11AC VHT Configuration success!\n"); + + /* Close socket */ + close(sockfd); + if (respbuf) + free(respbuf); + return UAP_SUCCESS; +} + +/** + * @brief Show usage information for TX BF command + * + * $return N/A + */ +void +print_tx_bf_usage(void) +{ + printf("\nUsage : httxbfcfg [ACT_DATA]"); + printf("\nOptions: ACTION : 1 - Performs NDP Sounding for PEER"); + printf("\n 2 - TX BF interval in milliseconds"); + printf("\n 3 - Not to perform any sounding"); + printf("\n 4 - TX BF SNR Threshold for peer"); + printf("\n ACT_DATA : Specific data for the above actions"); + printf("\n For 1: PEER MAC and status"); + printf("\n For 2: TX BF interval"); + printf("\n For 3: PEER MAC"); + printf("\n For 4: PEER MAC and SNR"); + printf("\n empty - get action specific settings\n"); + return; +} + +/** + * @brief Handle response of the TX BF command + * + * @param param Pointer to structure tx_bf_cfg_para + * + * $return N/A + */ +void +print_tx_bf_response(tx_bf_cfg_para *param) +{ + int i; + trigger_sound_args *bf_sound = param->body.bf_sound; + tx_bf_peer_args *tx_bf_peer = param->body.tx_bf_peer; + snr_thr_args *bf_snr = param->body.bf_snr; + bf_periodicity_args *bf_periodicity = param->body.bf_periodicity; + bf_global_cfg_args *bf_global = ¶m->body.bf_global_cfg; + + switch (param->bf_action) { + case BF_GLOBAL_CONFIGURATION: + printf("Global BF Status :%s\n", + bf_global->bf_enbl ? "ENABLED" : "DISABLED"); + printf("Global Sounding Status :%s\n", + bf_global->sounding_enbl ? "ENABLED" : "DISABLED"); + printf("Default FB Type :%d\n", bf_global->fb_type); + printf("Default SNR Threshold :%d\n", bf_global->snr_threshold); + printf("Default Sounding Interval :%d\n", + bf_global->sounding_interval); + printf("Beamforming Mode :%d\n", bf_global->bf_mode); + break; + case TRIGGER_SOUNDING_FOR_PEER: + printf("PEER MAC = %02X:%02X:%02X:%02X:%02X:%02X, STATUS = %s\n", 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], bf_sound->status ? "Failure" : "Success"); + break; + case SET_GET_BF_PERIODICITY: + printf("PEER MAC = %02x:%02x:%02x:%02x:%02x:%02x, Interval (ms) = %d\n", 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], bf_periodicity->interval); + break; + case TX_BF_FOR_PEER_ENBL: + for (i = 0; i < param->no_of_peers; i++) { + printf("PEER MAC = %02x:%02x:%02x:%02x:%02x:%02x\n", + 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]); + printf("BF Status : %s\n", + tx_bf_peer->bf_enbl ? "ENABLED" : "DISABLED"); + printf("Sounding Status : %s\n", + tx_bf_peer-> + sounding_enbl ? "ENABLED" : "DISABLED"); + printf("FB Type : %d\n", tx_bf_peer->fb_type); + tx_bf_peer++; + } + break; + case SET_SNR_THR_PEER: + for (i = 0; i < param->no_of_peers; i++) { + printf("PEER MAC = %02x:%02x:%02x:%02x:%02x:%02x, SNR = %d\n", 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], bf_snr->snr); + bf_snr++; + } + break; + } +} + +/** 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 BF_CFG_ACT_GET 0 +#define BF_CFG_ACT_SET 1 + +/** + * @brief Creates TX BF request and send to driver + * + * @param argc Number of arguments + * @param argv Pointer to the arguments + * @return UAP_SUCCESS/UAP_FAILURE + */ +int +apcmd_sys_cfg_tx_bf(int argc, char *argv[]) +{ + int opt, ret = UAP_FAILURE; + tx_bf_cfg_para param; + struct ifreq ifr; + t_s32 sockfd; + t_u32 bf_action = 0; + + while ((opt = getopt_long(argc, argv, "+", cmd_options, NULL)) != -1) { + switch (opt) { + default: + print_tx_bf_usage(); + return UAP_SUCCESS; + } + } + argc -= optind; + argv += optind; + + memset(¶m, 0, sizeof(param)); + /* Check arguments */ + if (argc < 1) { + printf("ERR: wrong arguments.\n"); + print_tx_bf_usage(); + return UAP_FAILURE; + } + if ((IS_HEX_OR_DIGIT(argv[0]) == UAP_FAILURE) || + ((atoi(argv[0]) < BF_GLOBAL_CONFIGURATION) || + (atoi(argv[0]) > SET_SNR_THR_PEER))) { + printf("ERR: Only Number values are allowed\n"); + print_tx_bf_usage(); + return UAP_FAILURE; + } + bf_action = (t_u32)A2HEXDECIMAL(argv[0]); + param.subcmd = UAP_TX_BF_CFG; + param.bf_action = bf_action; + switch (bf_action) { + case BF_GLOBAL_CONFIGURATION: + if (argc != 1 && argc != 7) { + printf("Invalid argument for Global BF Configuration\n"); + return UAP_FAILURE; + } + if (argc == 1) { + param.bf_cmd_action = BF_CFG_ACT_GET; + param.action = ACTION_GET; + } else { + param.bf_cmd_action = BF_CFG_ACT_SET; + param.action = ACTION_SET; + param.body.bf_global_cfg.bf_enbl = + atoi(argv[BF_ENABLE_PARAM]); + param.body.bf_global_cfg.sounding_enbl = + atoi(argv[SOUND_ENABLE_PARAM]); + param.body.bf_global_cfg.fb_type = + atoi(argv[FB_TYPE_PARAM]); + param.body.bf_global_cfg.snr_threshold = + atoi(argv[SNR_THRESHOLD_PARAM]); + param.body.bf_global_cfg.sounding_interval = + atoi(argv[SOUND_INTVL_PARAM]); + param.body.bf_global_cfg.bf_mode = + atoi(argv[BF_MODE_PARAM]); + } + break; + case TRIGGER_SOUNDING_FOR_PEER: + if (argc != 2) { + printf("ERR: wrong arguments.\n"); + print_tx_bf_usage(); + return UAP_FAILURE; + } + if ((ret = + mac2raw(argv[1], + param.body.bf_sound[0].peer_mac)) != UAP_SUCCESS) { + printf("ERR: %s Address\n", + ret == UAP_FAILURE ? "Invalid MAC" : ret == + UAP_RET_MAC_BROADCAST ? "Broadcast" : + "Multicast"); + return UAP_FAILURE; + } + param.bf_cmd_action = BF_CFG_ACT_SET; + param.action = ACTION_SET; + break; + case SET_GET_BF_PERIODICITY: + if (argc != 2 && argc != 3) { + printf("ERR: wrong arguments.\n"); + print_tx_bf_usage(); + return UAP_FAILURE; + } + if ((ret = + mac2raw(argv[1], + param.body.bf_periodicity[0].peer_mac)) != + UAP_SUCCESS) { + printf("ERR: %s Address\n", + ret == UAP_FAILURE ? "Invalid MAC" : ret == + UAP_RET_MAC_BROADCAST ? "Broadcast" : + "Multicast"); + return UAP_FAILURE; + } + + if (argc == 3) { + if (IS_HEX_OR_DIGIT(argv[2]) == UAP_FAILURE) + return UAP_FAILURE; + param.body.bf_periodicity[0].interval = + (t_u32)A2HEXDECIMAL(argv[2]); + param.bf_cmd_action = BF_CFG_ACT_SET; + param.action = ACTION_SET; + } else { + param.bf_cmd_action = BF_CFG_ACT_GET; + param.action = ACTION_GET; + } + break; + case TX_BF_FOR_PEER_ENBL: + if (argc != 1 && argc != 5) { + printf("ERR: wrong arguments.\n"); + print_tx_bf_usage(); + return UAP_FAILURE; + } + if (argc == 1) { + param.bf_cmd_action = BF_CFG_ACT_GET; + param.action = ACTION_GET; + } else { + if ((ret = + mac2raw(argv[1], + param.body.tx_bf_peer[0].peer_mac)) != + UAP_SUCCESS) { + printf("ERR: %s Address\n", + ret == + UAP_FAILURE ? "Invalid MAC" : ret == + UAP_RET_MAC_BROADCAST ? "Broadcast" : + "Multicast"); + return UAP_FAILURE; + } + param.body.tx_bf_peer->bf_enbl = atoi(argv[2]); + param.body.tx_bf_peer->sounding_enbl = atoi(argv[3]); + param.body.tx_bf_peer->fb_type = atoi(argv[4]); + param.bf_cmd_action = BF_CFG_ACT_SET; + param.action = ACTION_SET; + } + break; + case SET_SNR_THR_PEER: + if (argc != 1 && argc != 3) { + printf("ERR: wrong arguments.\n"); + print_tx_bf_usage(); + return UAP_FAILURE; + } + if (argc == 1) { + param.bf_cmd_action = BF_CFG_ACT_GET; + param.action = ACTION_GET; + } else { + if ((ret = + mac2raw(argv[1], + param.body.bf_snr[0].peer_mac)) != + UAP_SUCCESS) { + printf("ERR: %s Address\n", + ret == + UAP_FAILURE ? "Invalid MAC" : ret == + UAP_RET_MAC_BROADCAST ? "Broadcast" : + "Multicast"); + return UAP_FAILURE; + } + if (IS_HEX_OR_DIGIT(argv[2]) == UAP_FAILURE) + return UAP_FAILURE; + param.body.bf_snr[0].snr = (t_u8)A2HEXDECIMAL(argv[2]); + param.bf_cmd_action = BF_CFG_ACT_SET; + param.action = ACTION_SET; + } + break; + default: + return UAP_FAILURE; + } + + /* Open socket */ + if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) { + printf("ERR:Cannot open socket\n"); + return UAP_FAILURE; + } + /* Initialize the ifr structure */ + memset(&ifr, 0, sizeof(ifr)); + strncpy(ifr.ifr_ifrn.ifrn_name, dev_name, IFNAMSIZ - 1); + ifr.ifr_ifru.ifru_data = (void *)¶m; + /* Perform ioctl */ + errno = 0; + if (ioctl(sockfd, UAP_IOCTL_CMD, &ifr)) { + perror(""); + printf("ERR: TX BF configuration failed\n"); + close(sockfd); + return UAP_FAILURE; + } + + printf("TX BF configuration successful\n"); + /* Handle response */ + if (param.action == ACTION_GET) + print_tx_bf_response(¶m); + + /* Close socket */ + close(sockfd); + return UAP_SUCCESS; +} + +/** + * @brief Show usage information for hscfg command + * + * $return N/A + */ +void +print_hscfg_usage(void) +{ + printf("\nUsage : hscfg [condition [[GPIO# [gap]]]]"); + printf("\nOptions: condition : bit 0 = 1 -- broadcast data"); + printf("\n bit 1 = 1 -- unicast data"); + printf("\n bit 2 = 1 -- mac event"); + printf("\n bit 3 = 1 -- multicast packet"); + printf("\n bit 6 = 1 -- mgmt frame received"); + printf("\n GPIO: the pin number (e.g. 0-7) of GPIO used to wakeup the host"); + printf("\n or 0xff interface (e.g. SDIO) used to wakeup the host"); + printf("\n gap: time between wakeup signal and wakeup event (in milliseconds)"); + printf("\n or 0xff for special setting when GPIO is used to wakeup host"); + printf("\n empty - get current host sleep parameters\n"); + return; +} + +/** + * @brief Creates host sleep parameter request and send to driver + * + * + * @param argc Number of arguments + * @param argv Pointer to the arguments + * @return UAP_SUCCESS/UAP_FAILURE + */ +int +apcmd_hscfg(int argc, char *argv[]) +{ + int opt; + int i = 0; + ds_hs_cfg hscfg; + struct ifreq ifr; + t_s32 sockfd; + + if ((argc == 2) && strstr(argv[1], "-1")) + strcpy(argv[1], "0xffff"); + + while ((opt = getopt_long(argc, argv, "+", cmd_options, NULL)) != -1) { + switch (opt) { + default: + print_hscfg_usage(); + return UAP_SUCCESS; + } + } + argc -= optind; + argv += optind; + + memset(&hscfg, 0, sizeof(hscfg)); + hscfg.subcmd = UAP_HS_CFG; + /* Check arguments */ + if (argc > 3) { + printf("ERR:wrong arguments.\n"); + print_hscfg_usage(); + return UAP_FAILURE; + } + if (argc) { + for (i = 0; i < argc; i++) { + if (IS_HEX_OR_DIGIT(argv[i]) == UAP_FAILURE) { + printf("ERR: Invalid argument %s\n", argv[i]); + print_hscfg_usage(); + return UAP_FAILURE; + } + } + } + + if (argc) { + hscfg.flags |= HS_CFG_FLAG_SET | HS_CFG_FLAG_CONDITION; + hscfg.conditions = (t_u32)A2HEXDECIMAL(argv[0]); + if (hscfg.conditions >= 0xffff) + hscfg.conditions = HS_CFG_CANCEL; + if ((hscfg.conditions != HS_CFG_CANCEL) && + (hscfg.conditions & ~HS_CFG_CONDITION_MASK)) { + printf("ERR:Illegal conditions 0x%x\n", + hscfg.conditions); + print_hscfg_usage(); + return UAP_FAILURE; + } + if (argc > 1) { + hscfg.flags |= HS_CFG_FLAG_GPIO; + hscfg.gpio = (t_u32)A2HEXDECIMAL(argv[1]); + if (hscfg.gpio > 255) { + printf("ERR:Illegal gpio 0x%x\n", hscfg.gpio); + print_hscfg_usage(); + return UAP_FAILURE; + } + } + if (argc > 2) { + hscfg.flags |= HS_CFG_FLAG_GAP; + hscfg.gap = (t_u32)A2HEXDECIMAL(argv[2]); + } + } else { + hscfg.flags = HS_CFG_FLAG_GET; + } + /* Open socket */ + if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) { + printf("ERR:Cannot open socket\n"); + return UAP_FAILURE; + } + /* Initialize the ifr structure */ + memset(&ifr, 0, sizeof(ifr)); + strncpy(ifr.ifr_ifrn.ifrn_name, dev_name, IFNAMSIZ - 1); + ifr.ifr_ifru.ifru_data = (void *)&hscfg; + /* Perform ioctl */ + errno = 0; + if (ioctl(sockfd, UAP_IOCTL_CMD, &ifr)) { + perror(""); + printf("ERR:UAP_HS_CFG failed\n"); + close(sockfd); + return UAP_FAILURE; + } + if (!argc) { + printf("Host sleep parameters:\n"); + printf("\tconditions=%d\n", (int)hscfg.conditions); + printf("\tGPIO=%d\n", (int)hscfg.gpio); + printf("\tgap=%d\n", (int)hscfg.gap); + } + /* Close socket */ + close(sockfd); + return UAP_SUCCESS; +} + +/** + * @brief Show usage information for hssetpara command + * + * $return N/A + */ +void +print_hssetpara_usage(void) +{ + printf("\nUsage : hssetpara condition [[GPIO# [gap]]]"); + printf("\nOptions: condition : bit 0 = 1 -- broadcast data"); + printf("\n bit 1 = 1 -- unicast data"); + printf("\n bit 2 = 1 -- mac event"); + printf("\n bit 3 = 1 -- multicast packet"); + printf("\n bit 6 = 1 -- mgmt frame received"); + printf("\n GPIO: the pin number (e.g. 0-7) of GPIO used to wakeup the host"); + printf("\n or 0xff interface (e.g. SDIO) used to wakeup the host"); + printf("\n gap: time between wakeup signal and wakeup event (in milliseconds)"); + printf("\n or 0xff for special setting when GPIO is used to wakeup host\n"); + return; +} + +/** + * @brief Creates host sleep parameter request and send to driver + * + * @param argc Number of arguments + * @param argv Pointer to the arguments + * @return UAP_SUCCESS/UAP_FAILURE + */ +int +apcmd_hssetpara(int argc, char *argv[]) +{ + int opt; + int i = 0; + ds_hs_cfg hscfg; + struct ifreq ifr; + t_s32 sockfd; + + if ((argc == 2) && strstr(argv[1], "-1")) + strcpy(argv[1], "0xffff"); + + while ((opt = getopt_long(argc, argv, "+", cmd_options, NULL)) != -1) { + switch (opt) { + default: + print_hssetpara_usage(); + return UAP_SUCCESS; + } + } + argc -= optind; + argv += optind; + + memset(&hscfg, 0, sizeof(hscfg)); + hscfg.subcmd = UAP_HS_SET_PARA; + /* Check arguments */ + if ((argc < 1) || (argc > 3)) { + printf("ERR:wrong arguments.\n"); + print_hssetpara_usage(); + return UAP_FAILURE; + } + for (i = 0; i < argc; i++) { + if (IS_HEX_OR_DIGIT(argv[i]) == UAP_FAILURE) { + printf("ERR: Invalid argument %s\n", argv[i]); + print_hssetpara_usage(); + return UAP_FAILURE; + } + } + + hscfg.flags |= HS_CFG_FLAG_SET | HS_CFG_FLAG_CONDITION; + hscfg.conditions = (t_u32)A2HEXDECIMAL(argv[0]); + if (hscfg.conditions >= 0xffff) + hscfg.conditions = HS_CFG_CANCEL; + if ((hscfg.conditions != HS_CFG_CANCEL) && + (hscfg.conditions & ~HS_CFG_CONDITION_MASK)) { + printf("ERR:Illegal conditions 0x%x\n", hscfg.conditions); + print_hssetpara_usage(); + return UAP_FAILURE; + } + if (argc > 1) { + hscfg.flags |= HS_CFG_FLAG_GPIO; + hscfg.gpio = (t_u32)A2HEXDECIMAL(argv[1]); + if (hscfg.gpio > 255) { + printf("ERR:Illegal gpio 0x%x\n", hscfg.gpio); + print_hssetpara_usage(); + return UAP_FAILURE; + } + } + if (argc > 2) { + hscfg.flags |= HS_CFG_FLAG_GAP; + hscfg.gap = (t_u32)A2HEXDECIMAL(argv[2]); + } + /* Open socket */ + if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) { + printf("ERR:Cannot open socket\n"); + return UAP_FAILURE; + } + /* Initialize the ifr structure */ + memset(&ifr, 0, sizeof(ifr)); + strncpy(ifr.ifr_ifrn.ifrn_name, dev_name, strlen(dev_name)); + ifr.ifr_ifru.ifru_data = (void *)&hscfg; + /* Perform ioctl */ + errno = 0; + if (ioctl(sockfd, UAP_IOCTL_CMD, &ifr)) { + perror(""); + printf("ERR:UAP_HS_SET_PARA failed\n"); + close(sockfd); + return UAP_FAILURE; + } + printf("Host sleep parameters setting successful!\n"); + printf("\tconditions=%d\n", (int)hscfg.conditions); + printf("\tGPIO=%d\n", (int)hscfg.gpio); + printf("\tgap=%d\n", (int)hscfg.gap); + /* Close socket */ + close(sockfd); + return UAP_SUCCESS; +} + +/** + * @brief get dfs repeater mode + * + * @param mode status of DFS repeater mode is returned here + * @return UAP_SUCCESS/UAP_FAILURE + */ +int +uap_ioctl_dfs_repeater_mode(int *mode) +{ + struct ifreq ifr; + dfs_repeater_mode param; + t_s32 sockfd; + /* Open socket */ + if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) { + printf("ERR:Cannot open socket\n"); + return UAP_FAILURE; + } + /* Initialize the ifr structure */ + memset(&ifr, 0, sizeof(ifr)); + strncpy(ifr.ifr_ifrn.ifrn_name, dev_name, IFNAMSIZ - 1); + ifr.ifr_ifru.ifru_data = (void *)¶m; + param.action = ACTION_GET; + param.subcmd = UAP_DFS_REPEATER_MODE; + /* Perform ioctl */ + errno = 0; + if (ioctl(sockfd, UAP_IOCTL_CMD, &ifr)) { + printf("ERR:UAP_DFS_REPEATER_MODE is not" + "supported by %s\n", dev_name); + close(sockfd); + return UAP_FAILURE; + } + *mode = (int)param.mode; + close(sockfd); + return UAP_SUCCESS; +} + +/** + * @brief Get CAC timer status + * + * @param mode status of CAC timer is returned here + * @return UAP_SUCCESS/UAP_FAILURE + */ +int +uap_ioctl_cac_timer_status(unsigned int *mode) +{ + struct ifreq ifr; + cac_timer_status param; + t_s32 sockfd; + /* Open socket */ + if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) { + printf("ERR:Cannot open socket\n"); + return UAP_FAILURE; + } + /* Initialize the ifr structure */ + memset(&ifr, 0, sizeof(ifr)); + strncpy(ifr.ifr_ifrn.ifrn_name, dev_name, IFNAMSIZ - 1); + ifr.ifr_ifru.ifru_data = (void *)¶m; + param.action = ACTION_GET; + param.subcmd = UAP_CAC_TIMER_STATUS; + /* Perform ioctl */ + errno = 0; + if (ioctl(sockfd, UAP_IOCTL_CMD, &ifr)) { + printf("ERR:UAP_CAC_TIMER_STATUS is not" + "supported by %s\n", dev_name); + close(sockfd); + return UAP_FAILURE; + } + *mode = (int)param.mode; + close(sockfd); + return UAP_SUCCESS; +} + +/** + * @brief Set/get power mode + * + * @param pm A pointer to ps_mgmt structure + * @param flag flag for query + * @return UAP_SUCCESS/UAP_FAILURE + */ +int +send_power_mode_ioctl(ps_mgmt * pm, int flag) +{ + struct ifreq ifr; + t_s32 sockfd; + t_u32 result = 0; + /* Open socket */ + if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) { + printf("ERR:Cannot open socket\n"); + return UAP_FAILURE; + } + /* Initialize the ifr structure */ + memset(&ifr, 0, sizeof(ifr)); + strncpy(ifr.ifr_ifrn.ifrn_name, dev_name, IFNAMSIZ - 1); + ifr.ifr_ifru.ifru_data = (void *)pm; + /* Perform ioctl */ + errno = 0; + if (ioctl(sockfd, UAP_POWER_MODE, &ifr)) { + memcpy((void *)&result, (void *)pm, sizeof(result)); + if (result == 1) { + printf("ERR:Power mode needs to be disabled before modifying it\n"); + } else { + perror(""); + printf("ERR:UAP_POWER_MODE is not supported by %s\n", + dev_name); + } + close(sockfd); + return UAP_FAILURE; + } + if (flag) { + /* Close socket */ + close(sockfd); + return UAP_SUCCESS; + } + switch (pm->ps_mode) { + case 0: + printf("power mode = Disabled\n"); + break; + case 1: + printf("power mode = Periodic DTIM PS\n"); + break; + case 2: + printf("power mode = Inactivity based PS \n"); + break; + } + if (pm->flags & PS_FLAG_SLEEP_PARAM) { + printf("Sleep param:\n"); + printf("\tctrl_bitmap=%d\n", (int)pm->sleep_param.ctrl_bitmap); + printf("\tmin_sleep=%d us\n", (int)pm->sleep_param.min_sleep); + printf("\tmax_sleep=%d us\n", (int)pm->sleep_param.max_sleep); + } + if (pm->flags & PS_FLAG_INACT_SLEEP_PARAM) { + printf("Inactivity sleep param:\n"); + printf("\tinactivity_to=%d us\n", + (int)pm->inact_param.inactivity_to); + printf("\tmin_awake=%d us\n", (int)pm->inact_param.min_awake); + printf("\tmax_awake=%d us\n", (int)pm->inact_param.max_awake); + } + /* Close socket */ + close(sockfd); + return UAP_SUCCESS; +} + +/** + * @brief Show usage information for the pscfg command + * + * $return N/A + */ +void +print_pscfg_usage(void) +{ + printf("\nUsage : pscfg [MODE] [CTRL INACTTO MIN_SLEEP MAX_SLEEP MIN_AWAKE MAX_AWAKE]"); + printf("\nOptions: MODE : 0 - disable power mode"); + printf("\n 1 - periodic DTIM power save mode"); + printf("\n 2 - inactivity based power save mode"); + printf("\n PS PARAMS:"); + printf("\n CTRL: 0 - disable protection frame Tx before PS"); + printf("\n 1 - enable protection frame Tx before PS"); + printf("\n INACTTO: Inactivity timeout in miroseconds"); + printf("\n MIN_SLEEP: Minimum sleep duration in microseconds"); + printf("\n MAX_SLEEP: Maximum sleep duration in miroseconds"); + printf("\n MIN_AWAKE: Minimum awake duration in microseconds"); + printf("\n MAX_AWAKE: Maximum awake duration in microseconds"); + printf("\n MIN_AWAKE,MAX_AWAKE only valid for inactivity based power save mode"); + printf("\n empty - get current power mode\n"); + return; +} + +/** + * @brief Creates power mode request and send to driver + * and sends to the driver + * + * + * @param argc Number of arguments + * @param argv Pointer to the arguments + * @return UAP_SUCCESS/UAP_FAILURE + */ +int +apcmd_pscfg(int argc, char *argv[]) +{ + int opt; + ps_mgmt pm; + int ret = UAP_SUCCESS; + while ((opt = getopt_long(argc, argv, "+", cmd_options, NULL)) != -1) { + switch (opt) { + default: + print_pscfg_usage(); + return UAP_SUCCESS; + } + } + argc -= optind; + argv += optind; + + memset(&pm, 0, sizeof(ps_mgmt)); + /* Check arguments */ + if ((argc > 7) || + ((argc != 0) && (argc != 1) && (argc != 5) && (argc != 7))) { + printf("ERR:wrong arguments.\n"); + print_pscfg_usage(); + return UAP_FAILURE; + } + + if (argc) { + if (send_power_mode_ioctl(&pm, 1) == UAP_FAILURE) + return UAP_FAILURE; + if ((ISDIGIT(argv[0]) == 0) || (atoi(argv[0]) < 0) || + (atoi(argv[0]) > 2)) { + printf("ERR:Illegal power mode %s. Must be either '0' '1' or '2'.\n", argv[0]); + print_pscfg_usage(); + return UAP_FAILURE; + } + pm.flags = PS_FLAG_PS_MODE; + pm.ps_mode = atoi(argv[0]); + if ((pm.ps_mode == PS_MODE_DISABLE) && (argc > 1)) { + printf("ERR: Illegal parameter for disable power mode\n"); + print_pscfg_usage(); + return UAP_FAILURE; + } + if ((pm.ps_mode != PS_MODE_INACTIVITY) && (argc > 5)) { + printf("ERR:Min awake period and Max awake period are valid only for inactivity based power save mode\n"); + print_pscfg_usage(); + return UAP_FAILURE; + } + if (argc >= 5) { + if ((ISDIGIT(argv[1]) == 0) || (atoi(argv[1]) < 0) || + (atoi(argv[1]) > 1)) { + printf("ERR:Illegal ctrl bitmap = %s. Must be either '0' or '1'.\n", argv[1]); + print_pscfg_usage(); + return UAP_FAILURE; + } + pm.flags |= + PS_FLAG_SLEEP_PARAM | PS_FLAG_INACT_SLEEP_PARAM; + pm.sleep_param.ctrl_bitmap = atoi(argv[1]); + if ((ISDIGIT(argv[2]) == 0) || (ISDIGIT(argv[3]) == 0) + || (ISDIGIT(argv[4]) == 0)) { + printf("ERR:Illegal parameter\n"); + print_pscfg_usage(); + return UAP_FAILURE; + } + pm.inact_param.inactivity_to = atoi(argv[2]); + pm.sleep_param.min_sleep = atoi(argv[3]); + pm.sleep_param.max_sleep = atoi(argv[4]); + if (pm.sleep_param.min_sleep > pm.sleep_param.max_sleep) { + printf("ERR: MIN_SLEEP value should be less than or equal to MAX_SLEEP\n"); + return UAP_FAILURE; + } + if (pm.sleep_param.min_sleep < PS_SLEEP_PARAM_MIN || + ((pm.sleep_param.max_sleep > PS_SLEEP_PARAM_MAX) && + pm.sleep_param.ctrl_bitmap)) { + printf("ERR: Incorrect value of sleep period. Please check README\n"); + return UAP_FAILURE; + } + if (argc == 7) { + if ((ISDIGIT(argv[5]) == 0) || + (ISDIGIT(argv[6]) == 0)) { + printf("ERR:Illegal parameter\n"); + print_pscfg_usage(); + return UAP_FAILURE; + } + pm.inact_param.min_awake = atoi(argv[5]); + pm.inact_param.max_awake = atoi(argv[6]); + if (pm.inact_param.min_awake > + pm.inact_param.max_awake) { + printf("ERR: MIN_AWAKE value should be less than or equal to MAX_AWAKE\n"); + return UAP_FAILURE; + } + if (pm.inact_param.min_awake < + PS_AWAKE_PERIOD_MIN) { + printf("ERR: Incorrect value of MIN_AWAKE period.\n"); + return UAP_FAILURE; + } + } + } + } + ret = send_power_mode_ioctl(&pm, 0); + return ret; +} + +/** + * @brief Get bss status started/stopped + * + * @param current bss status + * @return UAP_SUCCESS/UAP_FAILURE + */ +static int +get_bss_status(int *status) +{ + apcmdbuf_sys_configure *cmd_buf = NULL; + tlvbuf_bss_status *tlv = NULL; + t_u8 *buffer = NULL; + t_u16 cmd_len = 0; + t_u16 buf_len = MRVDRV_SIZE_OF_CMD_BUFFER; + int ret = UAP_FAILURE; + + /* Initialize the command length */ + cmd_len = sizeof(apcmdbuf_sys_configure) + sizeof(tlvbuf_bss_status); + + /* Initialize the command buffer */ + buffer = (t_u8 *)malloc(buf_len); + + if (!buffer) { + printf("ERR:Cannot allocate buffer for command!\n"); + return UAP_FAILURE; + } + memset(buffer, 0, buf_len); + /* Locate headers */ + cmd_buf = (apcmdbuf_sys_configure *)buffer; + tlv = (tlvbuf_bss_status *)(buffer + sizeof(apcmdbuf_sys_configure)); + + /* Fill the command buffer */ + cmd_buf->cmd_code = APCMD_SYS_CONFIGURE; + cmd_buf->size = cmd_len; + cmd_buf->seq_num = 0; + cmd_buf->result = 0; + tlv->tag = MRVL_BSS_STATUS_TLV_ID; + tlv->length = 2; + cmd_buf->action = ACTION_GET; + + endian_convert_tlv_header_out(tlv); + /* Send the command */ + ret = uap_ioctl((t_u8 *)cmd_buf, &cmd_len, buf_len); + endian_convert_tlv_header_in(tlv); + tlv->bss_status = uap_le16_to_cpu(tlv->bss_status); + + /* Process response */ + if (ret == UAP_SUCCESS) { + /* Verify response */ + if ((cmd_buf->cmd_code != + (APCMD_SYS_CONFIGURE | APCMD_RESP_CHECK)) || + (tlv->tag != MRVL_BSS_STATUS_TLV_ID)) { + printf("ERR:Corrupted response! cmd_code=%x, Tlv->tag=%x\n", cmd_buf->cmd_code, tlv->tag); + free(buffer); + return UAP_FAILURE; + } + /* Print response */ + if (cmd_buf->result == CMD_SUCCESS) { + if (tlv->bss_status == 0) + *status = UAP_BSS_STOP; + else + *status = UAP_BSS_START; + } else { + printf("ERR:Could not get BSS status!\n"); + } + } else { + printf("ERR:Command sending failed!\n"); + } + if (buffer) + free(buffer); + return ret; +} + +/** + * @brief start/stop/reset bss + * + * @param mode bss control mode + * @return UAP_SUCCESS/UAP_FAILURE + */ +int +send_bss_ctl_ioctl(int mode) +{ + struct ifreq ifr; + t_s32 sockfd; + t_u32 data = (t_u32)mode; + /* Open socket */ + if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) { + printf("ERR:Cannot open socket\n"); + return UAP_FAILURE; + } + /* Initialize the ifr structure */ + memset(&ifr, 0, sizeof(ifr)); + strncpy(ifr.ifr_ifrn.ifrn_name, dev_name, IFNAMSIZ - 1); + ifr.ifr_ifru.ifru_data = (void *)&data; + /* Perform ioctl */ + errno = 0; + if (ioctl(sockfd, UAP_BSS_CTRL, &ifr)) { + printf("ERR:UAP_BSS_CTRL fail, result=%d\n", (int)data); + switch (mode) { + case UAP_BSS_START: + if (data == BSS_FAILURE_START_INVAL) + printf("ERR:Could not start BSS! Invalid BSS parameters.\n"); + else + printf("ERR:Could not start BSS!\n"); + break; + case UAP_BSS_STOP: + printf("ERR:Could not stop BSS!\n"); + break; + case UAP_BSS_RESET: + printf("ERR:Could not reset system!\n"); + break; + } + close(sockfd); + return UAP_FAILURE; + } + + switch (mode) { + case UAP_BSS_START: + printf("BSS start successful!\n"); + break; + case UAP_BSS_STOP: + printf("BSS stop successful!\n"); + break; + case UAP_BSS_RESET: + printf("System reset successful!\n"); + break; + } + + /* Close socket */ + close(sockfd); + return UAP_SUCCESS; +} + +/** + * @brief Show usage information for the sys_reset command + * + * $return N/A + */ +void +print_sys_reset_usage(void) +{ + printf("\nUsage : sys_reset\n"); + return; +} + +/** + * @brief Creates a sys_reset request and sends to the driver + * + * Usage: "sys_reset" + * + * @param argc Number of arguments + * @param argv Pointer to the arguments + * @return UAP_SUCCESS/UAP_FAILURE + */ +int +apcmd_sys_reset(int argc, char *argv[]) +{ + int opt; + int ret = UAP_SUCCESS; + ps_mgmt pm; + while ((opt = getopt_long(argc, argv, "+", cmd_options, NULL)) != -1) { + switch (opt) { + default: + print_sys_reset_usage(); + return UAP_SUCCESS; + } + } + argc -= optind; + argv += optind; + + /* Check arguments */ + if (argc != 0) { + printf("ERR:Too many arguments.\n"); + print_sys_reset_usage(); + return UAP_FAILURE; + } + memset(&pm, 0, sizeof(ps_mgmt)); + pm.flags = PS_FLAG_PS_MODE; + pm.ps_mode = PS_MODE_DISABLE; + if (send_power_mode_ioctl(&pm, 0) == UAP_FAILURE) + return UAP_FAILURE; + ret = send_bss_ctl_ioctl(UAP_BSS_RESET); + return ret; +} + +/** + * @brief Show usage information for the bss_start command + * + * $return N/A + */ +void +print_bss_start_usage(void) +{ + printf("\nUsage : bss_start\n"); + return; +} + +/** + * @brief Creates a BSS start request and sends to the driver + * + * Usage: "bss_start" + * + * @param argc Number of arguments + * @param argv Pointer to the arguments + * @return UAP_SUCCESS/UAP_FAILURE + */ +int +apcmd_bss_start(int argc, char *argv[]) +{ + int opt; + t_u8 *buf = NULL; + t_u16 buf_len = 0; + int status = 0; + int ret = UAP_SUCCESS; + + while ((opt = getopt_long(argc, argv, "+", cmd_options, NULL)) != -1) { + switch (opt) { + default: + print_bss_start_usage(); + return UAP_SUCCESS; + } + } + argc -= optind; + argv += optind; + + /* Check arguments */ + if (argc != 0) { + printf("ERR:Too many arguments.\n"); + print_bss_start_usage(); + return UAP_FAILURE; + } + + if (get_bss_status(&status) != UAP_SUCCESS) { + printf("ERR:Cannot get current bss status!\n"); + return UAP_FAILURE; + } + + if (status == UAP_BSS_START) { + printf("ERR: Could not start BSS! BSS already started!\n"); + return UAP_FAILURE; + } + + /* Query BSS settings */ + + /* Alloc buf for command */ + buf_len = sizeof(apcmdbuf_bss_configure) + sizeof(bss_config_t); + buf = (t_u8 *)malloc(buf_len); + if (!buf) { + printf("ERR:Cannot allocate buffer from command!\n"); + return UAP_FAILURE; + } + memset((char *)buf, 0, buf_len); + + /* Get all parametes first */ + if (get_bss_config(buf) == UAP_FAILURE) { + printf("ERR:Reading current bss configuration\n"); + free(buf); + return UAP_FAILURE; + } + + ret = check_bss_config(buf + sizeof(apcmdbuf_bss_configure)); + + if (ret == UAP_FAILURE) { + printf("ERR: Wrong bss configuration!\n"); + goto done; + } + + ret = send_bss_ctl_ioctl(UAP_BSS_START); + +done: + if (buf) + free(buf); + return ret; +} + +/** + * @brief Show usage information for the bss_stop command + * + * $return N/A + */ +void +print_bss_stop_usage(void) +{ + printf("\nUsage : bss_stop\n"); + return; +} + +/** + * @brief Creates a BSS stop request and sends to the driver + * + * Usage: "bss_stop" + * + * @param argc Number of arguments + * @param argv Pointer to the arguments + * @return UAP_SUCCESS/UAP_FAILURE + */ +int +apcmd_bss_stop(int argc, char *argv[]) +{ + int opt; + int status = 0; + int ret = UAP_SUCCESS; + unsigned int cac_timer = 0; + + while ((opt = getopt_long(argc, argv, "+", cmd_options, NULL)) != -1) { + switch (opt) { + default: + print_bss_stop_usage(); + return UAP_SUCCESS; + } + } + argc -= optind; + argv += optind; /* Check arguments */ + + if (argc != 0) { + printf("ERR:Too many arguments.\n"); + print_bss_stop_usage(); + return UAP_FAILURE; + } + if (get_bss_status(&status) != UAP_SUCCESS) { + printf("ERR:Cannot get current bss status!\n"); + return UAP_FAILURE; + } + + if ((status != UAP_BSS_STOP) + || ((uap_ioctl_cac_timer_status(&cac_timer) == UAP_SUCCESS) + && (cac_timer)) + ) + ret = send_bss_ctl_ioctl(UAP_BSS_STOP); + else { + printf("ERR: Could not stop BSS! BSS already stopped!\n"); + ret = UAP_FAILURE; + } + return ret; +} + +void +print_skip_cac_usage(void) +{ + printf("\nUsage : skip_cac [MODE]"); + printf("\nOptions: MODE : 0 - Disable skip CAC mode"); + printf("\n 1 - Enable skip CAC mode"); + printf("\n empty - get skip CAC mode\n"); + return; +} + +/** + * @brief Skip CAC for next immediate BSS_START + * + * Usage: "skip_cac [1/0]" + * + * @param argc Number of arguments + * @param argv Pointer to the arguments + * @return UAP_SUCCESS/UAP_FAILURE + */ +int +apcmd_skip_cac(int argc, char *argv[]) +{ + int opt; + skip_cac_para param; + struct ifreq ifr; + t_s32 sockfd; + while ((opt = getopt_long(argc, argv, "+", cmd_options, NULL)) != -1) { + switch (opt) { + default: + print_skip_cac_usage(); + return UAP_SUCCESS; + } + } + argc -= optind; + argv += optind; + + memset(¶m, 0, sizeof(param)); + /* Check arguments */ + if (argc > 1) { + printf("ERR:wrong arguments. Only support 1 argument\n"); + print_skip_cac_usage(); + return UAP_FAILURE; + } + param.subcmd = UAP_SKIP_CAC; + if (argc) { + if (argc == 1) { + if ((IS_HEX_OR_DIGIT(argv[0]) == UAP_FAILURE) || + ((atoi(argv[0]) < 0) || (atoi(argv[0]) > 1))) { + printf("ERR: Only Number values are allowed\n"); + print_skip_cac_usage(); + return UAP_FAILURE; + } + } + param.action = 1; + param.skip_cac = (t_u16)A2HEXDECIMAL(argv[0]); + } else { + param.action = 0; + } + /* Open socket */ + if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) { + printf("ERR:Cannot open socket\n"); + return UAP_FAILURE; + } + /* Initialize the ifr structure */ + memset(&ifr, 0, sizeof(ifr)); + strncpy(ifr.ifr_ifrn.ifrn_name, dev_name, IFNAMSIZ - 1); + ifr.ifr_ifru.ifru_data = (void *)¶m; + /* Perform ioctl */ + errno = 0; + if (ioctl(sockfd, UAP_IOCTL_CMD, &ifr)) { + if (argc) + printf("ERR:skip_cac set failed\n"); + else { + perror(""); + printf("ERR:skip_cac get failed\n"); + } + close(sockfd); + return UAP_FAILURE; + } + if (!argc) { + if (param.skip_cac == 1) { + printf("skip CAC mode: enabled\n"); + } else { + printf("skip CAC mode: disabled\n"); + } + } + /* Close socket */ + close(sockfd); + return UAP_SUCCESS; +} + +/** + * @brief Show usage information for the sta_list command + * + * $return N/A + */ +void +print_sta_list_usage(void) +{ + printf("\nUsage : sta_list\n"); + return; +} + +/** + * @brief Creates a STA list request and sends to the driver + * + * Usage: "sta_list" + * + * @param argc Number of arguments + * @param argv Pointer to the arguments + * @return UAP_SUCCESS/UAP_FAILURE + */ +int +apcmd_sta_list(int argc, char *argv[]) +{ + struct ifreq ifr; + t_s32 sockfd; + sta_list list; + int i = 0; + int opt; + int rssi = 0; + + while ((opt = getopt_long(argc, argv, "+", cmd_options, NULL)) != -1) { + switch (opt) { + default: + print_sta_list_usage(); + return UAP_SUCCESS; + } + } + argc -= optind; + argv += optind; + + /* Check arguments */ + if (argc != 0) { + printf("ERR:Too many arguments.\n"); + print_sta_list_usage(); + return UAP_FAILURE; + } + memset(&list, 0, sizeof(sta_list)); + + /* Open socket */ + if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) { + printf("ERR:Cannot open socket\n"); + return UAP_FAILURE; + } + /* Initialize the ifr structure */ + memset(&ifr, 0, sizeof(ifr)); + strncpy(ifr.ifr_ifrn.ifrn_name, dev_name, IFNAMSIZ - 1); + ifr.ifr_ifru.ifru_data = (void *)&list; + /* Perform ioctl */ + errno = 0; + if (ioctl(sockfd, UAP_GET_STA_LIST, &ifr)) { + perror(""); + printf("ERR:UAP_GET_STA_LIST is not supported by %s\n", + dev_name); + close(sockfd); + return UAP_FAILURE; + } + printf("Number of STA = %d\n\n", list.sta_count); + + for (i = 0; i < list.sta_count; i++) { + printf("STA %d information:\n", i + 1); + printf("=====================\n"); + printf("MAC Address: "); + print_mac(list.info[i].mac_address); + printf("\nPower mgmt status: %s\n", + (list.info[i].power_mgmt_status == + 0) ? "active" : "power save"); + printf("Mode: %s\n", + (list.info[i].bandmode == + BAND_B) ? "11b," : (list.info[i].bandmode == + BAND_G) ? "11g," : (list.info[i]. + bandmode == + BAND_A) ? "11a," + : (list.info[i].bandmode == + BAND_GN) ? "2.4G_11n," : (list.info[i].bandmode == + BAND_AN) ? "5G_11n," + : (list.info[i].bandmode == + BAND_GAC) ? "2.4G_11ac," : (list.info[i].bandmode == + BAND_AAC) ? "5G_11ac," + : (list.info[i].bandmode == + BAND_GAX) ? "2.4G_11ax," : (list.info[i].bandmode == + BAND_AAX) ? "5G_11ax," : + "unknown"); + /** On some platform, s8 is same as unsigned char*/ + rssi = (int)list.info[i].rssi; + if (rssi > 0x7f) + rssi = -(256 - rssi); + printf("Rssi : %d dBm\n\n", rssi); + if (list.info[i].ie_len) + hexdump_data("IE", (void *)list.info[i].ie_buf, + list.info[i].ie_len, ' '); + } + /* Close socket */ + close(sockfd); + return UAP_SUCCESS; +} + +/** + * @brief Show usage information for the sta_deauth command + * + * $return N/A + */ +void +print_sta_deauth_usage(void) +{ + printf("\nUsage : sta_deauth \n"); + return; +} + +/** + * @brief Creates a STA deauth request and sends to the driver + * + * Usage: "sta_deauth " + * + * @param argc Number of arguments + * @param argv Pointer to the arguments + * @return UAP_SUCCESS/UAP_FAILURE + */ +int +apcmd_sta_deauth(int argc, char *argv[]) +{ + APCMDBUF_STA_DEAUTH *cmd_buf = NULL; + t_u8 *buffer = NULL; + t_u16 cmd_len = 0; + t_u16 buf_len = MRVDRV_SIZE_OF_CMD_BUFFER; + int ret = UAP_FAILURE; + int opt; + + while ((opt = getopt_long(argc, argv, "+", cmd_options, NULL)) != -1) { + switch (opt) { + default: + print_sta_deauth_usage(); + return UAP_SUCCESS; + } + } + argc -= optind; + argv += optind; + + /* Check arguments */ + if (argc != 1) { + printf("ERR:wrong arguments! Must provide STA_MAC_ADDRESS.\n"); + print_sta_deauth_usage(); + return UAP_FAILURE; + } + + /* Initialize the command length */ + cmd_len = sizeof(APCMDBUF_STA_DEAUTH); + + /* Initialize the command buffer */ + buffer = (t_u8 *)malloc(buf_len); + if (!buffer) { + printf("ERR:Cannot allocate buffer for command!\n"); + return UAP_FAILURE; + } + memset(buffer, 0, buf_len); + + /* Locate headers */ + cmd_buf = (APCMDBUF_STA_DEAUTH *)buffer; + + /* Fill the command buffer */ + cmd_buf->cmd_code = APCMD_STA_DEAUTH; + cmd_buf->size = cmd_len - BUF_HEADER_SIZE; + cmd_buf->seq_num = 0; + cmd_buf->result = 0; + if ((ret = mac2raw(argv[0], cmd_buf->sta_mac_address)) != UAP_SUCCESS) { + printf("ERR: %s Address\n", ret == UAP_FAILURE ? "Invalid MAC" : + ret == + UAP_RET_MAC_BROADCAST ? "Broadcast" : "Multicast"); + free(buffer); + return UAP_FAILURE; + } + + /* Send the command */ + ret = uap_ioctl((t_u8 *)cmd_buf, &cmd_len, buf_len); + + /* Process response */ + if (ret == UAP_SUCCESS) { + /* Verify response */ + if (cmd_buf->cmd_code != (APCMD_STA_DEAUTH | APCMD_RESP_CHECK)) { + printf("ERR:Corrupted response!\n"); + free(buffer); + return UAP_FAILURE; + } + + /* Print response */ + if (cmd_buf->result == CMD_SUCCESS) { + printf("Deauthentication successful!\n"); + } else { + printf("ERR:Deauthentication unsuccessful!\n"); + ret = UAP_FAILURE; + } + } else { + printf("ERR:Command sending failed!\n"); + } + if (buffer) + free(buffer); + return ret; +} + +/** + * @brief Show usage information for the sta_deauth_ext command + * + * $return N/A + */ +void +print_sta_deauth_ext_usage(void) +{ + printf("\nUsage : sta_deauth \n"); + return; +} + +/** + * @brief Creates a STA deauth request and sends to the driver + * + * Usage: "sta_deauth " + * + * @param argc Number of arguments + * @param argv Pointer to the arguments + * @return UAP_SUCCESS/UAP_FAILURE + */ +int +apcmd_sta_deauth_ext(int argc, char *argv[]) +{ + int ret = UAP_SUCCESS; + int opt; + deauth_param param; + struct ifreq ifr; + t_s32 sockfd; + t_u32 result = 0; + + while ((opt = getopt_long(argc, argv, "+", cmd_options, NULL)) != -1) { + switch (opt) { + default: + print_sta_deauth_usage(); + return UAP_SUCCESS; + } + } + argc -= optind; + argv += optind; + + /* Check arguments */ + if (argc != 2) { + printf("ERR:wrong arguments! Must provide STA_MAC_ADDRESS, REASON_CODE.\n"); + print_sta_deauth_ext_usage(); + return UAP_FAILURE; + } + memset(¶m, 0, sizeof(deauth_param)); + + if ((ret = mac2raw(argv[0], param.mac_addr)) != UAP_SUCCESS) { + printf("ERR: %s Address\n", ret == UAP_FAILURE ? "Invalid MAC" : + ret == + UAP_RET_MAC_BROADCAST ? "Broadcast" : "Multicast"); + return UAP_FAILURE; + } + + if ((IS_HEX_OR_DIGIT(argv[1]) == UAP_FAILURE) || + (atoi(argv[1]) > MAX_DEAUTH_REASON_CODE)) { + printf("ERR: Invalid input for reason code\n"); + return UAP_FAILURE; + } + param.reason_code = (t_u16)A2HEXDECIMAL(argv[1]); + /* Open socket */ + if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) { + printf("ERR:Cannot open socket\n"); + return UAP_FAILURE; + } + /* Initialize the ifr structure */ + memset(&ifr, 0, sizeof(ifr)); + strncpy(ifr.ifr_ifrn.ifrn_name, dev_name, IFNAMSIZ - 1); + ifr.ifr_ifru.ifru_data = (void *)¶m; + /* Perform ioctl */ + errno = 0; + if (ioctl(sockfd, UAP_STA_DEAUTH, &ifr)) { + memcpy((void *)&result, (void *)¶m, sizeof(result)); + if (result == 1) + printf("ERR:UAP_STA_DEAUTH fail\n"); + else + perror(""); + close(sockfd); + return UAP_FAILURE; + } + printf("Station deauth successful\n"); + /* Close socket */ + close(sockfd); + return ret; +} + +/** + * @brief Show usage information for the radioctrl command + * + * $return N/A + */ +void +print_radio_ctl_usage(void) +{ + printf("\nUsage : radioctrl [ 0 | 1 ]\n"); + return; +} + +/** + * @brief Creates a Radio control request and sends to the driver + * + * Usage: "radioctrl [0 | 1]" + * + * @param argc Number of arguments + * @param argv Pointer to the arguments + * @return UAP_SUCCESS/UAP_FAILURE + */ +int +apcmd_radio_ctl(int argc, char *argv[]) +{ + int opt; + int param[2] = { 0, 0 }; /* action (Set/Get), Control (ON/OFF) */ + struct ifreq ifr; + t_s32 sockfd; + + while ((opt = getopt_long(argc, argv, "+", cmd_options, NULL)) != -1) { + switch (opt) { + default: + print_radio_ctl_usage(); + return UAP_SUCCESS; + } + } + argc -= optind; + argv += optind; + + /* Check arguments */ + if (argc > 1) { + printf("ERR:wrong arguments! Only 1 or 0 arguments are supported.\n"); + print_radio_ctl_usage(); + return UAP_FAILURE; + } + if (argc && (is_input_valid(RADIOCONTROL, argc, argv) != UAP_SUCCESS)) { + print_radio_ctl_usage(); + return UAP_FAILURE; + } + if (argc) { + param[0] = ACTION_SET; + param[1] = atoi(argv[0]); + } + + /* Open socket */ + if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) { + printf("ERR:Cannot open socket\n"); + return UAP_FAILURE; + } + /* Initialize the ifr structure */ + memset(&ifr, 0, sizeof(ifr)); + strncpy(ifr.ifr_ifrn.ifrn_name, dev_name, IFNAMSIZ - 1); + ifr.ifr_ifru.ifru_data = (void *)param; + /* Perform ioctl */ + errno = 0; + if (ioctl(sockfd, UAP_RADIO_CTL, &ifr)) { + printf("ERR:UAP_RADIO_CTL fail\n"); + close(sockfd); + return UAP_FAILURE; + } + if (argc) + printf("Radio setting successful\n"); + else + printf("Radio is %s.\n", (param[1]) ? "on" : "off"); + /* Close socket */ + close(sockfd); + return UAP_SUCCESS; +} + +/** + * @brief Show usage information for the txratecfg command + * + * $return N/A + */ +void +print_txratecfg_usage(void) +{ + printf("\nUsage : txratecfg Index should be one of the following.\n"); + printf("\n [l] is "); + printf("\n - This parameter specifies the data rate format used in this command"); + printf("\n 0: LG"); + printf("\n 1: HT"); + printf("\n 2: VHT"); + printf("\n 3: HE"); + printf("\n 0xff: Auto"); + printf("\n"); + printf("\n [m] is "); + printf("\n - This parameter specifies the rate or MCS index"); + printf("\n If is 0 (LG),"); + printf("\n 0 1 Mbps"); + printf("\n 1 2 Mbps"); + printf("\n 2 5.5 Mbps"); + printf("\n 3 11 Mbps"); + printf("\n 4 6 Mbps"); + printf("\n 5 9 Mbps"); + printf("\n 6 12 Mbps"); + printf("\n 7 18 Mbps"); + printf("\n 8 24 Mbps"); + printf("\n 9 36 Mbps"); + printf("\n 10 48 Mbps"); + printf("\n 11 54 Mbps"); + printf("\n If is 1 (HT), "); + printf("\n 0 MCS0"); + printf("\n 1 MCS1"); + printf("\n 2 MCS2"); + printf("\n 3 MCS3"); + printf("\n 4 MCS4"); + printf("\n 5 MCS5"); + printf("\n 6 MCS6"); + printf("\n 7 MCS7"); + printf("\n 8 MCS8"); + printf("\n 9 MCS9"); + printf("\n 10 MCS10"); + printf("\n 11 MCS11"); + printf("\n 12 MCS12"); + printf("\n 13 MCS13"); + printf("\n 14 MCS14"); + printf("\n 15 MCS15"); + printf("\n 32 MCS32"); + printf("\n If is 2 (VHT), "); + printf("\n 0 MCS0"); + printf("\n 1 MCS1"); + printf("\n 2 MCS2"); + printf("\n 3 MCS3"); + printf("\n 4 MCS4"); + printf("\n 5 MCS5"); + printf("\n 6 MCS6"); + printf("\n 7 MCS7"); + printf("\n 8 MCS8"); + printf("\n 9 MCS9"); + printf("\n [n] is "); + printf("\n - This parameter specifies the NSS. It is valid only for VHT"); + printf("\n If is 2 (VHT), "); + printf("\n 1 NSS1"); + printf("\n 2 NSS2"); + printf("\n If is 3 (HE), "); + printf("\n 0 MCS0"); + printf("\n 1 MCS1"); + printf("\n 2 MCS2"); + printf("\n 3 MCS3"); + printf("\n 4 MCS4"); + printf("\n 5 MCS5"); + printf("\n 6 MCS6"); + printf("\n 7 MCS7"); + printf("\n 8 MCS8"); + printf("\n 9 MCS9"); + printf("\n 10 MCS10"); + printf("\n 11 MCS11"); + printf("\n [n] is "); + printf("\n - This parameter specifies the NSS. It is valid only for HE"); + printf("\n If is 3 (HE), "); + printf("\n 1 NSS1"); + printf("\n 2 NSS2"); + printf("\n"); + return; +} + +/** + * @brief Creates a Tx Rate Config get request and sends to the driver + * @param rate_config Tx rate config struct + * @return UAP_SUCCESS/UAP_FAILURE + */ +static int +get_tx_rate_cfg(tx_rate_cfg_t *rate_config) +{ + struct ifreq ifr; + t_s32 sockfd; + int ret = UAP_SUCCESS; + + /* Open socket */ + if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) { + printf("ERR:Cannot open socket\n"); + return UAP_FAILURE; + } + /* Initialize the ifr structure */ + memset(rate_config, 0, sizeof(tx_rate_cfg_t)); + rate_config->subcmd = UAP_TX_RATE_CFG; + memset(&ifr, 0, sizeof(ifr)); + strncpy(ifr.ifr_ifrn.ifrn_name, dev_name, strlen(dev_name)); + ifr.ifr_ifru.ifru_data = (void *)rate_config; + /* Perform ioctl */ + errno = 0; + if (ioctl(sockfd, UAP_IOCTL_CMD, &ifr)) { + printf("ERR:UAP_IOCTL_CMD fail\n"); + close(sockfd); + return UAP_FAILURE; + } + /* Close socket */ + close(sockfd); + return ret; +} + +static char *rate_format[4] = { "LG", "HT", "VHT", "HE" }; + +static char *lg_rate[] = { "1 Mbps", "2 Mbps", "5.5 Mbps", "11 Mbps", + "6 Mbps", "9 Mbps", "12 Mbps", "18 Mbps", + "24 Mbps", "36 Mbps", "48 Mbps", "54 Mbps" +}; + +/** + * @brief Creates a Tx Rate Config request and sends to the driver + * + * Usage: "txratecfg " + * + * @param argc Number of arguments + * @param argv Pointer to the arguments + * @return UAP_SUCCESS/UAP_FAILURE + */ +int +apcmd_tx_rate_cfg(int argc, char *argv[]) +{ + int opt; + int status = 0; + tx_rate_cfg_t tx_rate_config; + struct ifreq ifr; + t_s32 sockfd; + HTCap_t htcap; + + while ((opt = getopt_long(argc, argv, "+", cmd_options, NULL)) != -1) { + switch (opt) { + default: + print_txratecfg_usage(); + return UAP_SUCCESS; + } + } + argc -= optind; + argv += optind; + + /* Check arguments */ + if (argc > 3) { + printf("ERR:wrong arguments! Only 0~3 arguments are supported.\n"); + print_txratecfg_usage(); + return UAP_FAILURE; + } + if (argc && (is_input_valid(TXRATECFG, argc, argv) != UAP_SUCCESS)) { + print_txratecfg_usage(); + return UAP_FAILURE; + } + memset(&tx_rate_config, 0, sizeof(tx_rate_cfg_t)); + tx_rate_config.subcmd = UAP_TX_RATE_CFG; + if (argc) { + tx_rate_config.action = ACTION_SET; + tx_rate_config.rate_format = A2HEXDECIMAL(argv[0]); + if (argc >= 2) + tx_rate_config.rate = A2HEXDECIMAL(argv[1]); + if (argc >= 3) + tx_rate_config.nss = A2HEXDECIMAL(argv[2]); + if (argc == 4) + tx_rate_config.rate_setting = A2HEXDECIMAL(argv[3]); + tx_rate_config.user_data_cnt = argc; + /* If bss is already started and uAP is in (short GI in 20 MHz + GF) mode, block MCS0-MCS7 rates */ + if (get_bss_status(&status) != UAP_SUCCESS) { + printf("ERR:Cannot get current bss status!\n"); + return UAP_FAILURE; + } + if (UAP_SUCCESS == get_sys_cfg_11n(&htcap)) { + if (htcap.supported_mcs_set[0] && + (status == UAP_BSS_START)) { + if (((tx_rate_config.rate >= 0) && + (tx_rate_config.rate <= 7)) + && + (IS_11N_20MHZ_SHORTGI_ENABLED + (htcap.ht_cap_info) && + IS_11N_GF_ENABLED(htcap.ht_cap_info))) { + printf("ERR: Invalid rate for bss in (20MHz Short GI + Green Field) mode\n"); + return UAP_FAILURE; + } + if ((tx_rate_config.rate == 32) && + (!(IS_11N_40MHZ_ENABLED + (htcap.ht_cap_info)))) { + printf("ERR:uAP must be configured to operate in 40MHz if tx_rate is MCS32\n"); + return UAP_FAILURE; + } + } + } + } + + /* Open socket */ + if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) { + printf("ERR:Cannot open socket\n"); + return UAP_FAILURE; + } + /* Initialize the ifr structure */ + memset(&ifr, 0, sizeof(ifr)); + strncpy(ifr.ifr_ifrn.ifrn_name, dev_name, strlen(dev_name)); + ifr.ifr_ifru.ifru_data = (void *)&tx_rate_config; + /* Perform ioctl */ + errno = 0; + if (ioctl(sockfd, UAP_IOCTL_CMD, &ifr)) { + printf("ERR:UAP_IOCTL_CMD fail\n"); + close(sockfd); + return UAP_FAILURE; + } + if (argc) { + printf("Transmit Rate setting successful\n"); + } else { + /* GET operation */ + printf("Tx Rate Configuration: \n"); + /* format */ + if (tx_rate_config.rate_format == 0xFF) { + printf(" Type: 0xFF (Auto)\n"); + } else if (tx_rate_config.rate_format <= 3) { + printf(" Type: %d (%s)\n", + tx_rate_config.rate_format, + rate_format[tx_rate_config.rate_format]); + if (tx_rate_config.rate_format == 0) + printf(" Rate Index: %d (%s)\n", + tx_rate_config.rate, + lg_rate[tx_rate_config.rate]); + else if (tx_rate_config.rate_format >= 1) + printf(" MCS Index: %d\n", + (int)tx_rate_config.rate); + if (tx_rate_config.rate_format == 2 || + tx_rate_config.rate_format == 3) + printf(" NSS: %d\n", + (int)tx_rate_config.nss); + if (tx_rate_config.rate_setting == 0xffff) + printf("Rate setting :Preamble type/BW/GI/STBC/.. : auto \n"); + else { + printf("Preamble type: %x\n", + (tx_rate_config.rate_setting & 0x0003)); + printf("BW: %x\n", + (tx_rate_config. + rate_setting & 0x001C) >> 2); + printf("LTF + GI size %x\n", + (tx_rate_config. + rate_setting & 0x0060) >> 5); + printf("STBC %x\n", + (tx_rate_config. + rate_setting & 0x0080) >> 7); + printf("DCM %x\n", + (tx_rate_config. + rate_setting & 0x0100) >> 8); + printf("Coding %x\n", + (tx_rate_config. + rate_setting & 0x0200) >> 9); + printf("maxPE %x\n", + (tx_rate_config. + rate_setting & 0x3000) >> 12); + } + } else { + printf(" Unknown rate format.\n"); + } + } + /* Close socket */ + close(sockfd); + return UAP_SUCCESS; +} + +/** + * @brief Show usage information for the antcfg + * command + * + * $return N/A + */ +void +print_antcfg_usage(void) +{ + printf("\nUsage : antcfg [ ]\n"); + printf("\n MODE : 1 - Antenna A"); + printf("\n 2 - Antenna B"); + printf("\n 3 - Antenna A+B"); + printf("\n empty - Get current antenna settings\n"); + return; +} + +/** + * @brief Creates a RF Antenna Mode Config request and sends to the driver + * + * Usage: "antcfg [MODE]" + * + * @param argc Number of arguments + * @param argv Pointer to the arguments + * @return UAP_SUCCESS/UAP_FAILURE + */ +int +apcmd_antcfg(int argc, char *argv[]) +{ + int opt; + int tx_val = 0; + int rx_val = 0; + ant_cfg_t antenna_config; + struct ifreq ifr; + t_s32 sockfd; + + while ((opt = getopt_long(argc, argv, "+", cmd_options, NULL)) != -1) { + switch (opt) { + default: + print_antcfg_usage(); + return UAP_SUCCESS; + } + } + argc -= optind; + argv += optind; + + /* Check arguments */ + if (argc > 2) { + printf("ERR:wrong arguments!\n"); + print_antcfg_usage(); + return UAP_FAILURE; + } + if (argc) { + sscanf(argv[0], "%x", (unsigned int *)&tx_val); + if (tx_val < 1 || tx_val > 0x303) { + printf("ERR:Illegal ANTENNA parameter %s. Must be either '1', '2' or '3'.\n", argv[0]); + print_antcfg_usage(); + return UAP_FAILURE; + } + if (argc == 2) { + sscanf(argv[1], "%x", (unsigned int *)&rx_val); + if (rx_val < 1 || rx_val > 0x303) { + printf("ERR:Illegal RX ANTENNA parameter %s. Must be either '1', '2' or '3'.\n", argv[1]); + print_antcfg_usage(); + return UAP_FAILURE; + } + } + } + memset(&antenna_config, 0, sizeof(ant_cfg_t)); + antenna_config.subcmd = UAP_ANTENNA_CFG; + if (argc) { + antenna_config.action = ACTION_SET; + if (argc == 1) { + antenna_config.tx_mode = tx_val; + antenna_config.rx_mode = tx_val; + } else { + antenna_config.tx_mode = tx_val; + antenna_config.rx_mode = rx_val; + } + } + /* Open socket */ + if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) { + printf("ERR:Cannot open socket\n"); + return UAP_FAILURE; + } + /* Initialize the ifr structure */ + memset(&ifr, 0, sizeof(ifr)); + strncpy(ifr.ifr_ifrn.ifrn_name, dev_name, strlen(dev_name)); + ifr.ifr_ifru.ifru_data = (void *)&antenna_config; + /* Perform ioctl */ + errno = 0; + if (ioctl(sockfd, UAP_IOCTL_CMD, &ifr)) { + printf("ERR:UAP_IOCTL_CMD fail\n"); + close(sockfd); + return UAP_FAILURE; + } + if (argc) { + printf("Antenna mode setting successful\n"); + } else { + printf("TX Antenna mode is 0x%x.\n", antenna_config.tx_mode); + printf("RX Antenna mode is 0x%x.\n", antenna_config.rx_mode); + } + /* Close socket */ + close(sockfd); + return UAP_SUCCESS; +} + +/** + * @brief Show usage information for the htstreamcfg + * command + * + * $return N/A + */ +void +print_htstreamcfg_usage(void) +{ + printf("\nUsage : htstreamcfg []\n"); + printf("\n Where "); + printf("\n 0x11: HT stream 1x1 mode"); + printf("\n 0x22: HT stream 2x2 mode\n"); + return; +} + +/** + * @brief Set/get HT stream configurations + * @param argc Number of arguments + * @param argv Pointer to the arguments + * @return UAP_SUCCESS/UAP_FAILURE + */ +int +apcmd_htstreamcfg(int argc, char *argv[]) +{ + int opt; + htstream_cfg_t htstream_cfg; + struct ifreq ifr; + t_s32 sockfd; + + while ((opt = getopt_long(argc, argv, "+", cmd_options, NULL)) != -1) { + switch (opt) { + default: + print_htstreamcfg_usage(); + return UAP_SUCCESS; + } + } + argc -= optind; + argv += optind; + + /* Check arguments */ + + memset(&htstream_cfg, 0, sizeof(htstream_cfg)); + if (argc == 0) { + htstream_cfg.action = ACTION_GET; + } else if (argc == 1) { + if ((t_u32)A2HEXDECIMAL(argv[0]) != HT_STREAM_MODE_1X1 + && (t_u32)A2HEXDECIMAL(argv[0]) != HT_STREAM_MODE_2X2) { + printf("ERR:Invalid argument\n"); + return UAP_FAILURE; + } + htstream_cfg.action = ACTION_SET; + htstream_cfg.stream_cfg = (t_u32)A2HEXDECIMAL(argv[0]); + } else { + print_htstreamcfg_usage(); + return UAP_FAILURE; + } + htstream_cfg.subcmd = UAP_HT_STREAM_CFG; + + /* Open socket */ + if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) { + printf("ERR:Cannot open socket\n"); + return UAP_FAILURE; + } + /* Initialize the ifr structure */ + memset(&ifr, 0, sizeof(ifr)); + strncpy(ifr.ifr_ifrn.ifrn_name, dev_name, IFNAMSIZ - 1); + ifr.ifr_ifru.ifru_data = (void *)&htstream_cfg; + /* Perform ioctl */ + errno = 0; + if (ioctl(sockfd, UAP_IOCTL_CMD, &ifr)) { + perror(""); + printf("ERR: HT STREAM configuration failed\n"); + close(sockfd); + return UAP_FAILURE; + } + + /* Handle response */ + if (htstream_cfg.action == ACTION_GET) { + if (htstream_cfg.stream_cfg == HT_STREAM_MODE_1X1) + printf("HT stream is in 1x1 mode\n"); + else if (htstream_cfg.stream_cfg == HT_STREAM_MODE_2X2) + printf("HT stream is in 2x2 mode\n"); + else + printf("HT stream is unknown mode\n"); + } + + /* Close socket */ + close(sockfd); + return UAP_SUCCESS; +} + +static int +get_802_11ac_cfg(struct eth_priv_vhtcfg *vhtcfg) +{ + t_u8 *buf = NULL; + t_u8 *pos = NULL; + mrvl_priv_cmd *cmd = NULL; + struct ifreq ifr; + t_s32 sockfd; + + buf = (t_u8 *)malloc(MRVDRV_SIZE_OF_CMD_BUFFER); + if (!buf) { + printf("ERR: cannot allocate buffer for command payload \n"); + return UAP_FAILURE; + } + memset(buf, 0, MRVDRV_SIZE_OF_CMD_BUFFER); + + cmd = (mrvl_priv_cmd *)malloc(sizeof(mrvl_priv_cmd)); + if (!cmd) { + printf("ERR: cannot allocate buffer for cmd \n"); + free(buf); + return UAP_FAILURE; + } + + /*prepare command: mlanutl uap0 vhtcfg 2 3 , GET operation */ + pos = buf; + strncpy((char *)pos, CMD_NXP, strlen(CMD_NXP)); + pos += strlen(CMD_NXP); + strncpy((char *)pos, "vhtcfg2 3", strlen("vhtcfg2 3")); + + /* fill up buffer */ + cmd->buf = buf; + cmd->used_len = 0; + cmd->total_len = MRVDRV_SIZE_OF_CMD_BUFFER; + + /* Perform IOCTL */ + memset(&ifr, 0, sizeof(struct ifreq)); + strncpy(ifr.ifr_ifrn.ifrn_name, dev_name, strlen(dev_name)); + ifr.ifr_ifru.ifru_data = (void *)cmd; + + /* Open socket */ + if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) { + printf("ERR:Cannot open socket\n"); + if (cmd) + free(cmd); + if (buf) + free(buf); + return UAP_FAILURE; + } + + if (ioctl(sockfd, MRVLPRIVCMD, &ifr)) { + if (cmd) + free(cmd); + if (buf) + free(buf); + close(sockfd); + return UAP_FAILURE; + } + + /* Process result */ + memcpy(vhtcfg, buf + 1, sizeof(struct eth_priv_vhtcfg)); + + close(sockfd); + free(cmd); + free(buf); + + return UAP_SUCCESS; +} + +/** + * @brief Show usage information for the sys_config command + * + * $return N/A + */ +void +print_sys_config_usage(void) +{ + printf("\nUsage : sys_config [CONFIG_FILE]\n"); + printf("\nIf CONFIG_FILE is provided, a 'set' is performed, else a 'get' is performed.\n"); + printf("CONFIG_FILE is file contain all the Micro AP settings.\n"); + return; +} + +/** + * @brief Show usage information for the rdeeprom command + * + * $return N/A + */ +void +print_apcmd_read_eeprom_usage(void) +{ + printf("\nUsage: rdeeprom \n"); + printf(" offset : 0,4,8,..., multiple of 4\n"); + printf(" bytecount : 4-20, multiple of 4\n"); + return; +} + +/** + * @brief Show protocol tlv + * + * @param protocol Protocol number + * + * $return N/A + */ +void +print_protocol(t_u16 protocol) +{ + switch (protocol) { + case 0: + case PROTOCOL_NO_SECURITY: + printf("PROTOCOL = No security\n"); + break; + case PROTOCOL_STATIC_WEP: + printf("PROTOCOL = Static WEP\n"); + break; + case PROTOCOL_WPA: + printf("PROTOCOL = WPA \n"); + break; + case PROTOCOL_WPA2: + printf("PROTOCOL = WPA2 \n"); + break; + case PROTOCOL_WPA | PROTOCOL_WPA2: + printf("PROTOCOL = WPA/WPA2 \n"); + break; + case PROTOCOL_WPA3_SAE: + printf("PROTOCOL = WPA3 SAE \n"); + break; + default: + printf("Unknown PROTOCOL: 0x%x \n", protocol); + break; + } +} + +/** + * @brief Show wep tlv + * + * @param tlv Pointer to wep tlv + * + * $return N/A + */ +void +print_wep_key(tlvbuf_wep_key *tlv) +{ + int i; + t_u16 tlv_len; + + tlv_len = *(t_u8 *)&tlv->length; + tlv_len |= (*((t_u8 *)&tlv->length + 1) << 8); + + if (tlv_len <= 2) { + printf("wrong wep_key tlv: length=%d\n", tlv_len); + return; + } + printf("WEP KEY_%d = ", tlv->key_index); + for (i = 0; i < tlv_len - 2; i++) + printf("%02x ", tlv->key[i]); + if (tlv->is_default) + printf("\nDefault WEP Key = %d\n", tlv->key_index); + else + printf("\n"); +} + +/** + * @brief Parses a command line + * + * @param line The line to parse + * @param args Pointer to the argument buffer to be filled in + * @return Number of arguments in the line or EOF + */ +static int +parse_line(char *line, char *args[]) +{ + int arg_num = 0; + int is_start = 0; + int is_quote = 0; + int is_escape = 0; + int length = 0; + int i = 0; + int j = 0; + + arg_num = 0; + length = strlen(line); + /* Process line */ + + /* Find number of arguments */ + is_start = 0; + is_quote = 0; + for (i = 0; i < length; i++) { + /* Ignore leading spaces */ + if (is_start == 0) { + if (line[i] == ' ') { + continue; + } else if (line[i] == '\t') { + continue; + } else if (line[i] == '\n') { + break; + } else { + is_start = 1; + args[arg_num] = &line[i]; + arg_num++; + } + } + if (is_start == 1) { + if ((line[i] == '\\') && (i < (length - 1))) { + if (line[i + 1] == '"') { + is_escape = 1; + for (j = i; j < length - 1; j++) { + line[j] = line[j + 1]; + } + line[length - 1] = '\0'; + continue; + } + } + /* Ignore comments */ + if (line[i] == '#') { + if (is_quote == 0) { + line[i] = '\0'; + arg_num--; + } + break; + } + /* Separate by '=' */ + if (line[i] == '=') { + if (is_quote == 0) { + line[i] = '\0'; + is_start = 0; + continue; + } + } + /* Separate by ',' */ + if (line[i] == ',') { + if (is_quote == 0) { + line[i] = '\0'; + is_start = 0; + continue; + } + } + /* Change ',' to ' ', but not inside quotes */ + if ((line[i] == ',') && (is_quote == 0)) { + line[i] = ' '; + continue; + } + } + /* Remove newlines */ + if (line[i] == '\n') { + line[i] = '\0'; + } + /* Check for quotes */ + if (line[i] == '"') { + if (is_escape) { + is_escape = 0; + /* no change in is_quote */ + } else { + is_quote = (is_quote == 1) ? 0 : 1; + } + continue; + } + if (((line[i] == ' ') || (line[i] == '\t')) && (is_quote == 0)) { + line[i] = '\0'; + is_start = 0; + continue; + } + } + return arg_num; +} + +/** + * @brief Parse function for a configuration line + * + * @param s Storage buffer for data + * @param size Maximum size of data + * @param stream File stream pointer + * @param line Pointer to current line within the file + * @param _pos Output string or NULL + * @return String or NULL + */ +static char * +config_get_line(char *s, int size, FILE * stream, int *line, char **_pos) +{ + *_pos = mlan_config_get_line(stream, s, size, line); + return *_pos; +} + +/** + * @brief Read the profile and sends to the driver + * + * @param argc Number of arguments + * @param argv Pointer to the arguments + * @return UAP_SUCCESS or UAP_FAILURE + */ +int +apcmd_sys_config_profile(int argc, char *argv[]) +{ + FILE *config_file = NULL; + char *line = NULL; + int li = 0; + char *pos = NULL; + int arg_num = 0; + char *args[30]; + int i; + int is_ap_config = 0; + int is_ap_mac_filter = 0; + apcmdbuf_sys_configure *cmd_buf = NULL; + HTCap_t htcap; + int enable_11n = -1; + t_u16 tlv_offset_11n = 0; + t_u32 supported_mcs_set = 0; + t_u8 *buffer = NULL; + t_u8 *tmp_buffer = NULL; + t_u16 cmd_len = 0; + t_u16 tlv_len = 0; + int keyindex = -1; + int protocol = -1; + int pwkcipher_wpa = -1; + int pwkcipher_wpa2 = -1; + int gwkcipher = -1; + tlvbuf_sta_mac_addr_filter *filter_tlv = NULL; + tlvbuf_channel_config *channel_band_tlv = NULL; + int filter_mac_count = -1; + int tx_data_rate = -1; + int tx_beacon_rate = -1; + int mcbc_data_rate = -1; + t_u8 rate[MAX_RATES]; + int found = 0; + char country_80211d[4]; + t_u8 state_80211d = 0; + int chan_mode = 0; + int band = 0; + int band_flag = 0; + int chan_number = 0; + t_u16 max_sta_num_supported = 0; + fw_info fw; + struct eth_priv_vhtcfg vhtcfg = { 0 }; + int ret = UAP_SUCCESS; + memset(rate, 0, MAX_RATES); + /* Check if file exists */ + config_file = fopen(argv[0], "r"); + if (config_file == NULL) { + printf("\nERR:Config file can not open.\n"); + return UAP_FAILURE; + } + line = (char *)malloc(MAX_CONFIG_LINE); + if (!line) { + printf("ERR:Cannot allocate memory for line\n"); + ret = UAP_FAILURE; + goto done; + } + memset(line, 0, MAX_CONFIG_LINE); + + /* Parse file and process */ + while (config_get_line(line, MAX_CONFIG_LINE, config_file, &li, &pos)) { +#if DEBUG + uap_printf(MSG_DEBUG, "DBG:Received config line (%d) = %s\n", + li, line); +#endif + arg_num = parse_line(line, args); +#if DEBUG + uap_printf(MSG_DEBUG, "DBG:Number of arguments = %d\n", + arg_num); + for (i = 0; i < arg_num; i++) { + uap_printf(MSG_DEBUG, "\tDBG:Argument %d. %s\n", i + 1, + args[i]); + } +#endif + /* Check for end of AP configurations */ + if (is_ap_config == 1) { + if (strcmp(args[0], "}") == 0) { + is_ap_config = 0; + if (tx_data_rate != -1) { + if ((!rate[0]) && (tx_data_rate) && + (is_tx_rate_valid + ((t_u8)tx_data_rate) != + UAP_SUCCESS)) { + printf("ERR: Invalid Tx Data Rate \n"); + ret = UAP_FAILURE; + goto done; + } + if (rate[0] && tx_data_rate) { + for (i = 0; rate[i] != 0; i++) { + if ((rate[i] & + ~BASIC_RATE_SET_BIT) + == tx_data_rate) { + found = 1; + break; + } + } + if (!found) { + printf("ERR: Invalid Tx Data Rate \n"); + ret = UAP_FAILURE; + goto done; + } + } + } + if (tx_beacon_rate != -1) { + if ((!rate[0]) && (tx_beacon_rate) && + (is_tx_rate_valid + ((t_u8)tx_beacon_rate) != + UAP_SUCCESS)) { + printf("ERR: Invalid Tx Beacon Rate \n"); + ret = UAP_FAILURE; + goto done; + } + if (rate[0] && tx_beacon_rate) { + for (i = 0; rate[i] != 0; i++) { + if ((rate[i] & + ~BASIC_RATE_SET_BIT) + == tx_beacon_rate) { + found = 1; + break; + } + } + if (!found) { + printf("ERR: Invalid Tx Beacon Rate \n"); + ret = UAP_FAILURE; + goto done; + } + } + /* Append a new TLV */ + tlvbuf_tx_data_rate *tlv = NULL; + tlv_len = sizeof(tlvbuf_tx_data_rate); + tmp_buffer = + realloc(buffer, + cmd_len + tlv_len); + if (!tmp_buffer) { + printf("ERR:Cannot append tx beacon rate TLV!\n"); + ret = UAP_FAILURE; + goto done; + } else { + buffer = tmp_buffer; + tmp_buffer = NULL; + } + cmd_buf = + (apcmdbuf_sys_configure *) + buffer; + tlv = (tlvbuf_tx_data_rate *)(buffer + + cmd_len); + cmd_len += tlv_len; + /* Set TLV fields */ + tlv->tag = MRVL_TX_BEACON_RATE_TLV_ID; + tlv->length = 2; + tlv->tx_data_rate = tx_beacon_rate; + endian_convert_tlv_header_out(tlv); + tlv->tx_data_rate = + uap_cpu_to_le16(tlv-> + tx_data_rate); + } + if (mcbc_data_rate != -1) { + if ((!rate[0]) && (mcbc_data_rate) && + (is_mcbc_rate_valid + ((t_u8)mcbc_data_rate) != + UAP_SUCCESS)) { + printf("ERR: Invalid Tx Data Rate \n"); + ret = UAP_FAILURE; + goto done; + } + if (rate[0] && mcbc_data_rate) { + for (i = 0; rate[i] != 0; i++) { + if (rate[i] & + BASIC_RATE_SET_BIT) + { + if ((rate[i] & + ~BASIC_RATE_SET_BIT) + == + mcbc_data_rate) + { + found = 1; + break; + } + } + } + if (!found) { + printf("ERR: Invalid MCBC Data Rate \n"); + ret = UAP_FAILURE; + goto done; + } + } + + /* Append a new TLV */ + tlvbuf_mcbc_data_rate *tlv = NULL; + tlv_len = sizeof(tlvbuf_mcbc_data_rate); + tmp_buffer = + realloc(buffer, + cmd_len + tlv_len); + if (!tmp_buffer) { + printf("ERR:Cannot append tx data rate TLV!\n"); + ret = UAP_FAILURE; + goto done; + } else { + buffer = tmp_buffer; + tmp_buffer = NULL; + } + cmd_buf = + (apcmdbuf_sys_configure *) + buffer; + tlv = (tlvbuf_mcbc_data_rate *)(buffer + + cmd_len); + cmd_len += tlv_len; + /* Set TLV fields */ + tlv->tag = MRVL_MCBC_DATA_RATE_TLV_ID; + tlv->length = 2; + tlv->mcbc_datarate = mcbc_data_rate; + endian_convert_tlv_header_out(tlv); + tlv->mcbc_datarate = + uap_cpu_to_le16(tlv-> + mcbc_datarate); + } + if ((protocol == PROTOCOL_STATIC_WEP) && + (enable_11n == 1)) { + printf("ERR:WEP cannot be used when AP operates in 802.11n mode.\n"); + ret = UAP_FAILURE; + goto done; + } + if ((protocol == PROTOCOL_WPA2_MIXED) && + ((pwkcipher_wpa < 0) || + (pwkcipher_wpa2 < 0))) { + printf("ERR:Both PwkCipherWPA and PwkCipherWPA2 should be defined for Mixed mode.\n"); + ret = UAP_FAILURE; + goto done; + } + + if (((pwkcipher_wpa >= 0) || + (pwkcipher_wpa2 >= 0)) && + (gwkcipher >= 0)) { + if ((protocol == PROTOCOL_WPA) || + (protocol == PROTOCOL_WPA2_MIXED)) { + if (enable_11n != -1) { + if (is_cipher_valid_with_11n(pwkcipher_wpa, gwkcipher, protocol, enable_11n) != UAP_SUCCESS) { + printf("ERR:Wrong group cipher and WPA pairwise cipher combination!\n"); + ret = UAP_FAILURE; + goto done; + } + } else if + (is_cipher_valid_with_proto + (pwkcipher_wpa, + gwkcipher, + protocol) != + UAP_SUCCESS) { + printf("ERR:Wrong group cipher and WPA pairwise cipher combination!\n"); + ret = UAP_FAILURE; + goto done; + } + } + if ((protocol == PROTOCOL_WPA2) || + (protocol == PROTOCOL_WPA2_MIXED) + || (protocol == PROTOCOL_WPA3_SAE) + ) { + if (enable_11n != -1) { + if (is_cipher_valid_with_11n(pwkcipher_wpa2, gwkcipher, protocol, enable_11n) != UAP_SUCCESS) { + printf("ERR:Wrong group cipher and WPA2 pairwise cipher combination!\n"); + ret = UAP_FAILURE; + goto done; + } + } else if + (is_cipher_valid_with_proto + (pwkcipher_wpa2, + gwkcipher, + protocol) != + UAP_SUCCESS) { + printf("ERR:Wrong group cipher and WPA2 pairwise cipher combination!\n"); + ret = UAP_FAILURE; + goto done; + } + } + } + + if (0 == get_fw_info(&fw)) { + /*check whether support 802.11AC through BAND_AAC bit */ + if (fw.fw_bands & BAND_AAC) { + ret = get_802_11ac_cfg(&vhtcfg); + if (ret != UAP_SUCCESS) + goto done; + if (enable_11n != -1) { + /* Note: When 11AC is disabled, FW sets vht_rx_mcs to 0xffff */ + if ((vhtcfg. + vht_rx_mcs != + 0xffff) && + (!enable_11n)) { + printf("ERR: 11n must be enabled when AP operates in 11ac mode. \n"); + ret = UAP_FAILURE; + goto done; + } + } + } else + printf("No support 802 11AC.\n"); + } else { + printf("ERR: get_fw_info fail\n"); + ret = UAP_FAILURE; + goto done; + } + + if (protocol != -1) { + tlvbuf_protocol *tlv = NULL; + /* Append a new TLV */ + tlv_len = sizeof(tlvbuf_protocol); + tmp_buffer = + realloc(buffer, + cmd_len + tlv_len); + if (!tmp_buffer) { + printf("ERR:Cannot append protocol TLV!\n"); + ret = UAP_FAILURE; + goto done; + } else { + buffer = tmp_buffer; + tmp_buffer = NULL; + } + cmd_buf = + (apcmdbuf_sys_configure *) + buffer; + tlv = (tlvbuf_protocol *)(buffer + + cmd_len); + cmd_len += tlv_len; + /* Set TLV fields */ + tlv->tag = MRVL_PROTOCOL_TLV_ID; + tlv->length = 2; + tlv->protocol = protocol; + endian_convert_tlv_header_out(tlv); + tlv->protocol = + uap_cpu_to_le16(tlv->protocol); + if (protocol & + (PROTOCOL_WPA | PROTOCOL_WPA2 | + PROTOCOL_WPA3_SAE)) { + tlvbuf_akmp *tlv = NULL; + /* Append a new TLV */ + tlv_len = sizeof(tlvbuf_akmp); + tmp_buffer = + realloc(buffer, + cmd_len + + tlv_len); + if (!tmp_buffer) { + printf("ERR:Cannot append AKMP TLV!\n"); + ret = UAP_FAILURE; + goto done; + } else { + buffer = tmp_buffer; + tmp_buffer = NULL; + } + cmd_buf = + (apcmdbuf_sys_configure + *)buffer; + tlv = (tlvbuf_akmp *)(buffer + + cmd_len); + cmd_len += tlv_len; + /* Set TLV fields */ + tlv->tag = MRVL_AKMP_TLV_ID; + tlv->length = 4; /* sizeof(tlvbuf_akmp) - TLVHEADER */ + if (protocol & + PROTOCOL_WPA3_SAE) { + tlv->key_mgmt = + KEY_MGMT_SAE; + } else { + tlv->key_mgmt = + KEY_MGMT_PSK; + } + endian_convert_tlv_header_out + (tlv); + tlv->key_mgmt = + uap_cpu_to_le16(tlv-> + key_mgmt); + tlv->key_mgmt_operation = 0; + } + } + if (pwkcipher_wpa >= 0) { + tlvbuf_pwk_cipher *tlv = NULL; + /* Append a new TLV */ + tlv_len = sizeof(tlvbuf_pwk_cipher); + tmp_buffer = + realloc(buffer, + cmd_len + tlv_len); + if (!tmp_buffer) { + printf("ERR:Cannot append cipher TLV!\n"); + ret = UAP_FAILURE; + goto done; + } else { + buffer = tmp_buffer; + tmp_buffer = NULL; + } + cmd_buf = + (apcmdbuf_sys_configure *) + buffer; + tlv = (tlvbuf_pwk_cipher *)(buffer + + cmd_len); + memset(tlv, 0, tlv_len); + cmd_len += tlv_len; + /* Set TLV fields */ + tlv->tag = MRVL_CIPHER_PWK_TLV_ID; + tlv->length = + sizeof(tlvbuf_pwk_cipher) - + TLVHEADER_LEN; + tlv->pairwise_cipher = pwkcipher_wpa; + tlv->protocol = PROTOCOL_WPA; + endian_convert_tlv_header_out(tlv); + tlv->protocol = + uap_cpu_to_le16(tlv->protocol); + } + + if (pwkcipher_wpa2 >= 0) { + tlvbuf_pwk_cipher *tlv = NULL; + /* Append a new TLV */ + tlv_len = sizeof(tlvbuf_pwk_cipher); + tmp_buffer = + realloc(buffer, + cmd_len + tlv_len); + if (!tmp_buffer) { + printf("ERR:Cannot append cipher TLV!\n"); + ret = UAP_FAILURE; + goto done; + } else { + buffer = tmp_buffer; + tmp_buffer = NULL; + } + cmd_buf = + (apcmdbuf_sys_configure *) + buffer; + tlv = (tlvbuf_pwk_cipher *)(buffer + + cmd_len); + memset(tlv, 0, tlv_len); + cmd_len += tlv_len; + /* Set TLV fields */ + tlv->tag = MRVL_CIPHER_PWK_TLV_ID; + tlv->length = + sizeof(tlvbuf_pwk_cipher) - + TLVHEADER_LEN; + tlv->pairwise_cipher = pwkcipher_wpa2; + tlv->protocol = PROTOCOL_WPA2; + endian_convert_tlv_header_out(tlv); + tlv->protocol = + uap_cpu_to_le16(tlv->protocol); + } + + if (gwkcipher >= 0) { + tlvbuf_gwk_cipher *tlv = NULL; + /* Append a new TLV */ + tlv_len = sizeof(tlvbuf_gwk_cipher); + tmp_buffer = + realloc(buffer, + cmd_len + tlv_len); + if (!tmp_buffer) { + printf("ERR:Cannot append cipher TLV!\n"); + ret = UAP_FAILURE; + goto done; + } else { + buffer = tmp_buffer; + tmp_buffer = NULL; + } + cmd_buf = + (apcmdbuf_sys_configure *) + buffer; + tlv = (tlvbuf_gwk_cipher *)(buffer + + cmd_len); + memset(tlv, 0, tlv_len); + cmd_len += tlv_len; + /* Set TLV fields */ + tlv->tag = MRVL_CIPHER_GWK_TLV_ID; + tlv->length = + sizeof(tlvbuf_gwk_cipher) - + TLVHEADER_LEN; + tlv->group_cipher = gwkcipher; + endian_convert_tlv_header_out(tlv); + } + + cmd_buf->size = cmd_len; + /* Send collective command */ + if (uap_ioctl + ((t_u8 *)cmd_buf, &cmd_len, + cmd_len) == UAP_SUCCESS) { + if (cmd_buf->result != CMD_SUCCESS) { + printf("ERR: Failed to set the configuration!\n"); + ret = UAP_FAILURE; + goto done; + } + } else { + printf("ERR: Command sending failed!\n"); + ret = UAP_FAILURE; + goto done; + } + cmd_len = 0; + if (buffer) { + free(buffer); + buffer = NULL; + } + continue; + } + } + + /* Check for beginning of AP configurations */ + if (strcmp(args[0], "ap_config") == 0) { + is_ap_config = 1; + cmd_len = sizeof(apcmdbuf_sys_configure); + if (buffer) { + free(buffer); + buffer = NULL; + } + buffer = (t_u8 *)malloc(cmd_len); + if (!buffer) { + printf("ERR:Cannot allocate memory!\n"); + ret = UAP_FAILURE; + goto done; + } + cmd_buf = (apcmdbuf_sys_configure *)buffer; + cmd_buf->cmd_code = APCMD_SYS_CONFIGURE; + cmd_buf->size = cmd_len; + cmd_buf->seq_num = 0; + cmd_buf->result = 0; + cmd_buf->action = ACTION_SET; + continue; + } + + /* Check for end of AP MAC address filter configurations */ + if (is_ap_mac_filter == 1) { + if (strcmp(args[0], "}") == 0) { + is_ap_mac_filter = 0; + if (filter_tlv->count != filter_mac_count) { + printf("ERR:Number of MAC address provided does not match 'Count'\n"); + ret = UAP_FAILURE; + goto done; + } + if (filter_tlv->count) { + filter_tlv->length = + (filter_tlv->count * ETH_ALEN) + + 2; + cmd_len -= + (MAX_MAC_ONESHOT_FILTER - + filter_mac_count) * ETH_ALEN; + } else { + filter_tlv->length = + (MAX_MAC_ONESHOT_FILTER * + ETH_ALEN) + 2; + memset(filter_tlv->mac_address, 0, + MAX_MAC_ONESHOT_FILTER * + ETH_ALEN); + } + cmd_buf->size = cmd_len; + endian_convert_tlv_header_out(filter_tlv); + if (uap_ioctl + ((t_u8 *)cmd_buf, &cmd_len, + cmd_len) == UAP_SUCCESS) { + if (cmd_buf->result != CMD_SUCCESS) { + printf("ERR: Failed to set the configuration!\n"); + ret = UAP_FAILURE; + goto done; + } + } else { + printf("ERR: Command sending failed!\n"); + ret = UAP_FAILURE; + goto done; + } + + cmd_len = 0; + if (buffer) { + free(buffer); + buffer = NULL; + } + continue; + } + } + + if (strcmp(args[0], "11d_enable") == 0) { + if (IS_HEX_OR_DIGIT(args[1]) == UAP_FAILURE) { + printf("ERR: valid input for state are 0 or 1\n"); + ret = UAP_FAILURE; + goto done; + } + state_80211d = (t_u8)A2HEXDECIMAL(args[1]); + + if ((state_80211d != 0) && (state_80211d != 1)) { + printf("ERR: valid input for state are 0 or 1 \n"); + ret = UAP_FAILURE; + goto done; + } + if (sg_snmp_mib + (ACTION_SET, OID_80211D_ENABLE, + sizeof(state_80211d), &state_80211d) + == UAP_FAILURE) { + ret = UAP_FAILURE; + goto done; + } + } + + if (strcmp(args[0], "country") == 0) { + apcmdbuf_cfg_80211d *cmd_buf = NULL; + ieeetypes_subband_set_t sub_bands[MAX_SUB_BANDS]; + t_u8 no_of_sub_band = 0; + t_u16 buf_len; + t_u16 cmdlen; + t_u8 *buf = NULL; + + if ((strlen(args[1]) > 3) || (strlen(args[1]) == 0)) { + printf("In-correct country input\n"); + ret = UAP_FAILURE; + goto done; + } + strncpy(country_80211d, args[1], + sizeof(country_80211d) - 1); + for (i = 0; (unsigned int)i < strlen(country_80211d); + i++) { + if ((country_80211d[i] < 'A') || + (country_80211d[i] > 'z')) { + printf("Invalid Country Code\n"); + ret = UAP_FAILURE; + goto done; + } + if (country_80211d[i] > 'Z') + country_80211d[i] = + country_80211d[i] - 'a' + 'A'; + } + no_of_sub_band = + parse_domain_file(country_80211d, band, + sub_bands, NULL); + if (no_of_sub_band == UAP_FAILURE) { + printf("Parsing Failed\n"); + ret = UAP_FAILURE; + goto done; + } + buf_len = sizeof(apcmdbuf_cfg_80211d); + buf_len += + no_of_sub_band * + sizeof(ieeetypes_subband_set_t); + buf = (t_u8 *)malloc(buf_len); + if (!buf) { + printf("ERR:Cannot allocate buffer from command!\n"); + ret = UAP_FAILURE; + goto done; + } + memset(buf, 0, buf_len); + cmd_buf = (apcmdbuf_cfg_80211d *)buf; + cmdlen = buf_len; + cmd_buf->size = cmdlen - BUF_HEADER_SIZE; + cmd_buf->result = 0; + cmd_buf->seq_num = 0; + cmd_buf->action = uap_cpu_to_le16(ACTION_SET); + cmd_buf->cmd_code = HostCmd_CMD_802_11D_DOMAIN_INFO; + cmd_buf->domain.tag = uap_cpu_to_le16(TLV_TYPE_DOMAIN); + cmd_buf->domain.length = + uap_cpu_to_le16(sizeof(domain_param_t) + - BUF_HEADER_SIZE + + (no_of_sub_band * + sizeof + (ieeetypes_subband_set_t))); + + memset(cmd_buf->domain.country_code, ' ', + sizeof(cmd_buf->domain.country_code)); + memcpy(cmd_buf->domain.country_code, country_80211d, + strlen(country_80211d)); + memcpy(cmd_buf->domain.subband, sub_bands, + no_of_sub_band * + sizeof(ieeetypes_subband_set_t)); + + /* Send the command */ + if (uap_ioctl((t_u8 *)cmd_buf, &cmdlen, cmdlen) == + UAP_SUCCESS) { + if (cmd_buf->result != CMD_SUCCESS) { + printf("ERR: Failed to set the configuration!\n"); + ret = UAP_FAILURE; + goto done; + } + } else { + printf("ERR: Command sending failed!\n"); + ret = UAP_FAILURE; + goto done; + } + + if (buf) + free(buf); + } + + /* Check for beginning of AP MAC address filter configurations */ + if (strcmp(args[0], "ap_mac_filter") == 0) { + is_ap_mac_filter = 1; + cmd_len = + sizeof(apcmdbuf_sys_configure) + + sizeof(tlvbuf_sta_mac_addr_filter) + + (MAX_MAC_ONESHOT_FILTER * ETH_ALEN); + if (buffer) { + free(buffer); + buffer = NULL; + } + buffer = (t_u8 *)malloc(cmd_len); + if (!buffer) { + printf("ERR:Cannot allocate memory!\n"); + ret = UAP_FAILURE; + goto done; + } + cmd_buf = (apcmdbuf_sys_configure *)buffer; + cmd_buf->cmd_code = APCMD_SYS_CONFIGURE; + cmd_buf->size = cmd_len; + cmd_buf->seq_num = 0; + cmd_buf->result = 0; + cmd_buf->action = ACTION_SET; + filter_tlv = + (tlvbuf_sta_mac_addr_filter *)(buffer + + sizeof + (apcmdbuf_sys_configure)); + filter_tlv->tag = MRVL_STA_MAC_ADDR_FILTER_TLV_ID; + filter_tlv->length = 2; + filter_tlv->count = 0; + filter_mac_count = 0; + continue; + } + if ((strcmp(args[0], "FilterMode") == 0) && is_ap_mac_filter) { + if ((ISDIGIT(args[1]) == 0) || (atoi(args[1]) < 0) || + (atoi(args[1]) > 2)) { + printf("ERR:Illegal FilterMode paramter %d. Must be either '0', '1', or '2'.\n", atoi(args[1])); + ret = UAP_FAILURE; + goto done; + } + filter_tlv->filter_mode = atoi(args[1]); + continue; + } + if ((strcmp(args[0], "Count") == 0) && is_ap_mac_filter) { + filter_tlv->count = atoi(args[1]); + if ((ISDIGIT(args[1]) == 0) || + (filter_tlv->count > MAX_MAC_ONESHOT_FILTER)) { + printf("ERR: Illegal Count parameter.\n"); + ret = UAP_FAILURE; + goto done; + } + } + if ((strncmp(args[0], "mac_", 4) == 0) && is_ap_mac_filter) { + if (filter_mac_count < MAX_MAC_ONESHOT_FILTER) { + if (mac2raw + (args[1], + &filter_tlv->mac_address[filter_mac_count * + ETH_ALEN]) != + UAP_SUCCESS) { + printf("ERR: Invalid MAC address %s \n", + args[1]); + ret = UAP_FAILURE; + goto done; + } + filter_mac_count++; + } else { + printf("ERR: Filter table can not have more than %d MAC addresses\n", MAX_MAC_ONESHOT_FILTER); + ret = UAP_FAILURE; + goto done; + } + } + + if (strcmp(args[0], "SSID") == 0) { + if (arg_num == 1) { + printf("ERR:SSID field is blank!\n"); + ret = UAP_FAILURE; + goto done; + } else { + tlvbuf_ssid *tlv = NULL; + if (args[1][0] == '"') { + args[1]++; + } + if (args[1][strlen(args[1]) - 1] == '"') { + args[1][strlen(args[1]) - 1] = '\0'; + } + if ((strlen(args[1]) > MAX_SSID_LENGTH) || + (strlen(args[1]) == 0)) { + printf("ERR:SSID length out of range (%d to %d).\n", MIN_SSID_LENGTH, MAX_SSID_LENGTH); + ret = UAP_FAILURE; + goto done; + } + /* Append a new TLV */ + tlv_len = sizeof(tlvbuf_ssid) + strlen(args[1]); + tmp_buffer = realloc(buffer, cmd_len + tlv_len); + if (!tmp_buffer) { + printf("ERR:Cannot realloc SSID TLV!\n"); + ret = UAP_FAILURE; + goto done; + } else { + buffer = tmp_buffer; + tmp_buffer = NULL; + } + cmd_buf = (apcmdbuf_sys_configure *)buffer; + tlv = (tlvbuf_ssid *)(buffer + cmd_len); + cmd_len += tlv_len; + /* Set TLV fields */ + tlv->tag = MRVL_SSID_TLV_ID; + tlv->length = strlen(args[1]); + memcpy(tlv->ssid, args[1], tlv->length); + endian_convert_tlv_header_out(tlv); + } + } + if (strcmp(args[0], "BeaconPeriod") == 0) { + if (is_input_valid(BEACONPERIOD, arg_num - 1, args + 1) + != UAP_SUCCESS) { + ret = UAP_FAILURE; + goto done; + } + tlvbuf_beacon_period *tlv = NULL; + /* Append a new TLV */ + tlv_len = sizeof(tlvbuf_beacon_period); + tmp_buffer = realloc(buffer, cmd_len + tlv_len); + if (!tmp_buffer) { + printf("ERR:Cannot realloc beacon period TLV!\n"); + ret = UAP_FAILURE; + goto done; + } else { + buffer = tmp_buffer; + tmp_buffer = NULL; + } + cmd_buf = (apcmdbuf_sys_configure *)buffer; + tlv = (tlvbuf_beacon_period *)(buffer + cmd_len); + cmd_len += tlv_len; + /* Set TLV fields */ + tlv->tag = MRVL_BEACON_PERIOD_TLV_ID; + tlv->length = 2; + tlv->beacon_period_ms = (t_u16)atoi(args[1]); + endian_convert_tlv_header_out(tlv); + tlv->beacon_period_ms = + uap_cpu_to_le16(tlv->beacon_period_ms); + } + if (strcmp(args[0], "ChanList") == 0) { + if (is_input_valid(SCANCHANNELS, arg_num - 1, args + 1) + != UAP_SUCCESS) { + ret = UAP_FAILURE; + goto done; + } + + tlvbuf_channel_list *tlv = NULL; + channel_list *pchan_list = NULL; + /* Append a new TLV */ + tlv_len = + sizeof(tlvbuf_channel_list) + + ((arg_num - 1) * sizeof(channel_list)); + tmp_buffer = realloc(buffer, cmd_len + tlv_len); + if (!tmp_buffer) { + printf("ERR:Cannot append channel list TLV!\n"); + ret = UAP_FAILURE; + goto done; + } else { + buffer = tmp_buffer; + tmp_buffer = NULL; + } + cmd_buf = (apcmdbuf_sys_configure *)buffer; + tlv = (tlvbuf_channel_list *)(buffer + cmd_len); + cmd_len += tlv_len; + /* Set TLV fields */ + tlv->tag = MRVL_CHANNELLIST_TLV_ID; + tlv->length = sizeof(channel_list) * (arg_num - 1); + pchan_list = (channel_list *) tlv->chan_list; + for (i = 0; i < (arg_num - 1); i++) { + band_flag = -1; + sscanf(args[i + 1], "%d.%d", &chan_number, + &band_flag); + pchan_list->chan_number = chan_number; + pchan_list->bandcfg.chanBand = BAND_2GHZ; + if (((band_flag != -1) && (band_flag)) || + (chan_number > MAX_CHANNELS_BG)) { + pchan_list->bandcfg.chanBand = + BAND_5GHZ; + } + pchan_list++; + } + endian_convert_tlv_header_out(tlv); + } + if (strcmp(args[0], "Channel") == 0) { + if (is_input_valid(CHANNEL, arg_num - 1, args + 1) != + UAP_SUCCESS) { + ret = UAP_FAILURE; + goto done; + } + tlvbuf_channel_config *tlv = NULL; + /* Append a new TLV */ + tlv_len = sizeof(tlvbuf_channel_config); + tmp_buffer = realloc(buffer, cmd_len + tlv_len); + if (!tmp_buffer) { + printf("ERR:Cannot append channel TLV!\n"); + ret = UAP_FAILURE; + goto done; + } else { + buffer = tmp_buffer; + tmp_buffer = NULL; + } + cmd_buf = (apcmdbuf_sys_configure *)buffer; + tlv = (tlvbuf_channel_config *)(buffer + cmd_len); + channel_band_tlv = tlv; + cmd_len += tlv_len; + /* Set TLV fields */ + tlv->tag = MRVL_CHANNELCONFIG_TLV_ID; + tlv->length = + sizeof(tlvbuf_channel_config) - TLVHEADER_LEN; + tlv->chan_number = (t_u8)atoi(args[1]); + if (tlv->chan_number > MAX_CHANNELS_BG) + band = BAND_A; + else + band = BAND_B | BAND_G; + if ((arg_num - 1) == 2) { + chan_mode = atoi(args[2]); + memset(&(tlv->bandcfg), 0, + sizeof(tlv->bandcfg)); + if (chan_mode & BITMAP_ACS_MODE) { + int mode; + if (uap_ioctl_dfs_repeater_mode(&mode) + == UAP_SUCCESS) { + if (mode) { + printf("ERR: ACS in DFS Repeater mode" " is not allowed\n"); + ret = UAP_FAILURE; + goto done; + } + } + tlv->bandcfg.scanMode = SCAN_MODE_ACS; + } + if (chan_mode & BITMAP_CHANNEL_ABOVE) + tlv->bandcfg.chan2Offset = + SEC_CHAN_ABOVE; + if (chan_mode & BITMAP_CHANNEL_BELOW) + tlv->bandcfg.chan2Offset = + SEC_CHAN_BELOW; + } else + memset(&(tlv->bandcfg), 0, + sizeof(tlv->bandcfg)); + if (tlv->chan_number > MAX_CHANNELS_BG) { + tlv->bandcfg.chanBand = BAND_5GHZ; + } + endian_convert_tlv_header_out(tlv); + } + if (strcmp(args[0], "Band") == 0) { + if (is_input_valid(BAND, arg_num - 1, args + 1) != + UAP_SUCCESS) { + ret = UAP_FAILURE; + goto done; + } + if (channel_band_tlv == NULL) { + printf("ERR: Channel parameter should be specified before Band\n"); + ret = UAP_FAILURE; + goto done; + } + /* If band is provided, clear previous value of band */ + channel_band_tlv->bandcfg.chanBand = BAND_2GHZ; + if (atoi(args[1]) == 0) { + band = BAND_B | BAND_G; + } else { + channel_band_tlv->bandcfg.chanBand = BAND_5GHZ; + band = BAND_A; + } + } + if (strcmp(args[0], "AP_MAC") == 0) { + tlvbuf_ap_mac_address *tlv = NULL; + /* Append a new TLV */ + tlv_len = sizeof(tlvbuf_ap_mac_address); + tmp_buffer = realloc(buffer, cmd_len + tlv_len); + if (!tmp_buffer) { + printf("ERR:Cannot append ap_mac TLV!\n"); + ret = UAP_FAILURE; + goto done; + } else { + buffer = tmp_buffer; + tmp_buffer = NULL; + } + cmd_buf = (apcmdbuf_sys_configure *)buffer; + tlv = (tlvbuf_ap_mac_address *)(buffer + cmd_len); + cmd_len += tlv_len; + cmd_buf->action = ACTION_SET; + tlv->tag = MRVL_AP_MAC_ADDRESS_TLV_ID; + tlv->length = ETH_ALEN; + if ((ret = + mac2raw(args[1], + tlv->ap_mac_addr)) != UAP_SUCCESS) { + printf("ERR: %s Address \n", + ret == + UAP_FAILURE ? "Invalid MAC" : ret == + UAP_RET_MAC_BROADCAST ? "Broadcast" : + "Multicast"); + ret = UAP_FAILURE; + goto done; + } + endian_convert_tlv_header_out(tlv); + } + + if (strcmp(args[0], "Rate") == 0) { + if (is_input_valid(RATE, arg_num - 1, args + 1) != + UAP_SUCCESS) { + printf("ERR: Invalid Rate input\n"); + ret = UAP_FAILURE; + goto done; + } + tlvbuf_rates *tlv = NULL; + /* Append a new TLV */ + tlv_len = sizeof(tlvbuf_rates) + arg_num - 1; + tmp_buffer = realloc(buffer, cmd_len + tlv_len); + if (!tmp_buffer) { + printf("ERR:Cannot append rates TLV!\n"); + ret = UAP_FAILURE; + goto done; + } else { + buffer = tmp_buffer; + tmp_buffer = NULL; + } + cmd_buf = (apcmdbuf_sys_configure *)buffer; + tlv = (tlvbuf_rates *)(buffer + cmd_len); + cmd_len += tlv_len; + /* Set TLV fields */ + tlv->tag = MRVL_RATES_TLV_ID; + tlv->length = arg_num - 1; + for (i = 0; i < tlv->length; i++) { + rate[i] = tlv->operational_rates[i] = + (t_u8)A2HEXDECIMAL(args[i + 1]); + } + endian_convert_tlv_header_out(tlv); + } + if (strcmp(args[0], "TxPowerLevel") == 0) { + if (is_input_valid(TXPOWER, arg_num - 1, args + 1) != + UAP_SUCCESS) { + printf("ERR:Invalid TxPowerLevel \n"); + ret = UAP_FAILURE; + goto done; + } else { + tlvbuf_tx_power *tlv = NULL; + /* Append a new TLV */ + tlv_len = sizeof(tlvbuf_tx_power); + tmp_buffer = realloc(buffer, cmd_len + tlv_len); + if (!tmp_buffer) { + printf("ERR:Cannot append tx power level TLV!\n"); + ret = UAP_FAILURE; + goto done; + } else { + buffer = tmp_buffer; + tmp_buffer = NULL; + } + cmd_buf = (apcmdbuf_sys_configure *)buffer; + tlv = (tlvbuf_tx_power *)(buffer + cmd_len); + cmd_len += tlv_len; + /* Set TLV fields */ + tlv->tag = MRVL_TX_POWER_TLV_ID; + tlv->length = 1; + tlv->tx_power_dbm = (t_u8)atoi(args[1]); + endian_convert_tlv_header_out(tlv); + } + } + if (strcmp(args[0], "BroadcastSSID") == 0) { + if (is_input_valid(BROADCASTSSID, arg_num - 1, args + 1) + != UAP_SUCCESS) { + ret = UAP_FAILURE; + goto done; + } + tlvbuf_bcast_ssid_ctl *tlv = NULL; + /* Append a new TLV */ + tlv_len = sizeof(tlvbuf_bcast_ssid_ctl); + tmp_buffer = realloc(buffer, cmd_len + tlv_len); + if (!tmp_buffer) { + printf("ERR:Cannot append SSID broadcast control TLV!\n"); + ret = UAP_FAILURE; + goto done; + } else { + buffer = tmp_buffer; + tmp_buffer = NULL; + } + cmd_buf = (apcmdbuf_sys_configure *)buffer; + tlv = (tlvbuf_bcast_ssid_ctl *)(buffer + cmd_len); + cmd_len += tlv_len; + /* Set TLV fields */ + tlv->tag = MRVL_BCAST_SSID_CTL_TLV_ID; + tlv->length = 1; + tlv->bcast_ssid_ctl = (t_u8)atoi(args[1]); + endian_convert_tlv_header_out(tlv); + } + if (strcmp(args[0], "RTSThreshold") == 0) { + if (is_input_valid(RTSTHRESH, arg_num - 1, args + 1) != + UAP_SUCCESS) { + ret = UAP_FAILURE; + goto done; + } + tlvbuf_rts_threshold *tlv = NULL; + /* Append a new TLV */ + tlv_len = sizeof(tlvbuf_rts_threshold); + tmp_buffer = realloc(buffer, cmd_len + tlv_len); + if (!tmp_buffer) { + printf("ERR:Cannot append RTS threshold TLV!\n"); + ret = UAP_FAILURE; + goto done; + } else { + buffer = tmp_buffer; + tmp_buffer = NULL; + } + cmd_buf = (apcmdbuf_sys_configure *)buffer; + tlv = (tlvbuf_rts_threshold *)(buffer + cmd_len); + cmd_len += tlv_len; + /* Set TLV fields */ + tlv->tag = MRVL_RTS_THRESHOLD_TLV_ID; + tlv->length = 2; + tlv->rts_threshold = (t_u16)atoi(args[1]); + endian_convert_tlv_header_out(tlv); + tlv->rts_threshold = + uap_cpu_to_le16(tlv->rts_threshold); + } + if (strcmp(args[0], "FragThreshold") == 0) { + if (is_input_valid(FRAGTHRESH, arg_num - 1, args + 1) != + UAP_SUCCESS) { + ret = UAP_FAILURE; + goto done; + } + tlvbuf_frag_threshold *tlv = NULL; + /* Append a new TLV */ + tlv_len = sizeof(tlvbuf_frag_threshold); + tmp_buffer = realloc(buffer, cmd_len + tlv_len); + if (!tmp_buffer) { + printf("ERR:Cannot append Fragmentation threshold TLV!\n"); + ret = UAP_FAILURE; + goto done; + } else { + buffer = tmp_buffer; + tmp_buffer = NULL; + } + cmd_buf = (apcmdbuf_sys_configure *)buffer; + tlv = (tlvbuf_frag_threshold *)(buffer + cmd_len); + cmd_len += tlv_len; + /* Set TLV fields */ + tlv->tag = MRVL_FRAG_THRESHOLD_TLV_ID; + tlv->length = 2; + tlv->frag_threshold = (t_u16)atoi(args[1]); + endian_convert_tlv_header_out(tlv); + tlv->frag_threshold = + uap_cpu_to_le16(tlv->frag_threshold); + } + if (strcmp(args[0], "DTIMPeriod") == 0) { + if (is_input_valid(DTIMPERIOD, arg_num - 1, args + 1) != + UAP_SUCCESS) { + ret = UAP_FAILURE; + goto done; + } + tlvbuf_dtim_period *tlv = NULL; + /* Append a new TLV */ + tlv_len = sizeof(tlvbuf_dtim_period); + tmp_buffer = realloc(buffer, cmd_len + tlv_len); + if (!tmp_buffer) { + printf("ERR:Cannot append DTIM period TLV!\n"); + ret = UAP_FAILURE; + goto done; + } else { + buffer = tmp_buffer; + tmp_buffer = NULL; + } + cmd_buf = (apcmdbuf_sys_configure *)buffer; + tlv = (tlvbuf_dtim_period *)(buffer + cmd_len); + cmd_len += tlv_len; + /* Set TLV fields */ + tlv->tag = MRVL_DTIM_PERIOD_TLV_ID; + tlv->length = 1; + tlv->dtim_period = (t_u8)atoi(args[1]); + endian_convert_tlv_header_out(tlv); + } + if (strcmp(args[0], "RSNReplayProtection") == 0) { + if (is_input_valid(RSNREPLAYPROT, arg_num - 1, args + 1) + != UAP_SUCCESS) { + ret = UAP_FAILURE; + goto done; + } + tlvbuf_rsn_replay_prot *tlv = NULL; + /* Append a new TLV */ + tlv_len = sizeof(tlvbuf_rsn_replay_prot); + tmp_buffer = realloc(buffer, cmd_len + tlv_len); + if (!tmp_buffer) { + printf("ERR:Cannot append RSN replay protection TLV!\n"); + ret = UAP_FAILURE; + goto done; + } else { + buffer = tmp_buffer; + tmp_buffer = NULL; + } + cmd_buf = (apcmdbuf_sys_configure *)buffer; + tlv = (tlvbuf_rsn_replay_prot *)(buffer + cmd_len); + cmd_len += tlv_len; + /* Set TLV fields */ + tlv->tag = MRVL_RSN_REPLAY_PROT_TLV_ID; + tlv->length = 1; + tlv->rsn_replay_prot = (t_u8)atoi(args[1]); + endian_convert_tlv_header_out(tlv); + } + if (strcmp(args[0], "TxBeaconRate") == 0) { + if (is_input_valid(TXBEACONRATE, arg_num - 1, args + 1) + != UAP_SUCCESS) { + ret = UAP_FAILURE; + goto done; + } + tx_beacon_rate = (t_u16)A2HEXDECIMAL(args[1]); + } + if (strcmp(args[0], "MCBCdataRate") == 0) { + if (is_input_valid(MCBCDATARATE, arg_num - 1, args + 1) + != UAP_SUCCESS) { + ret = UAP_FAILURE; + goto done; + } + mcbc_data_rate = (t_u16)A2HEXDECIMAL(args[1]); + } + if (strcmp(args[0], "PktFwdCtl") == 0) { + if (is_input_valid(PKTFWD, arg_num - 1, args + 1) != + UAP_SUCCESS) { + ret = UAP_FAILURE; + goto done; + } + tlvbuf_pkt_fwd_ctl *tlv = NULL; + /* Append a new TLV */ + tlv_len = sizeof(tlvbuf_pkt_fwd_ctl); + tmp_buffer = realloc(buffer, cmd_len + tlv_len); + if (!tmp_buffer) { + printf("ERR:Cannot append packet forwarding control TLV!\n"); + ret = UAP_FAILURE; + goto done; + } else { + buffer = tmp_buffer; + tmp_buffer = NULL; + } + cmd_buf = (apcmdbuf_sys_configure *)buffer; + tlv = (tlvbuf_pkt_fwd_ctl *)(buffer + cmd_len); + cmd_len += tlv_len; + /* Set TLV fields */ + tlv->tag = MRVL_PKT_FWD_CTL_TLV_ID; + tlv->length = 1; + tlv->pkt_fwd_ctl = (t_u8)atoi(args[1]); + endian_convert_tlv_header_out(tlv); + } + if (strcmp(args[0], "StaAgeoutTimer") == 0) { + if (is_input_valid + (STAAGEOUTTIMER, arg_num - 1, + args + 1) != UAP_SUCCESS) { + ret = UAP_FAILURE; + goto done; + } + tlvbuf_sta_ageout_timer *tlv = NULL; + /* Append a new TLV */ + tlv_len = sizeof(tlvbuf_sta_ageout_timer); + tmp_buffer = realloc(buffer, cmd_len + tlv_len); + if (!tmp_buffer) { + printf("ERR:Cannot append STA ageout timer TLV!\n"); + ret = UAP_FAILURE; + goto done; + } else { + buffer = tmp_buffer; + tmp_buffer = NULL; + } + cmd_buf = (apcmdbuf_sys_configure *)buffer; + tlv = (tlvbuf_sta_ageout_timer *)(buffer + cmd_len); + cmd_len += tlv_len; + /* Set TLV fields */ + tlv->tag = MRVL_STA_AGEOUT_TIMER_TLV_ID; + tlv->length = 4; + tlv->sta_ageout_timer_ms = (t_u32)atoi(args[1]); + endian_convert_tlv_header_out(tlv); + tlv->sta_ageout_timer_ms = + uap_cpu_to_le32(tlv->sta_ageout_timer_ms); + } + if (strcmp(args[0], "PSStaAgeoutTimer") == 0) { + if (is_input_valid + (PSSTAAGEOUTTIMER, arg_num - 1, + args + 1) != UAP_SUCCESS) { + ret = UAP_FAILURE; + goto done; + } + tlvbuf_ps_sta_ageout_timer *tlv = NULL; + /* Append a new TLV */ + tlv_len = sizeof(tlvbuf_ps_sta_ageout_timer); + tmp_buffer = realloc(buffer, cmd_len + tlv_len); + if (!tmp_buffer) { + printf("ERR:Cannot append PS STA ageout timer TLV!\n"); + ret = UAP_FAILURE; + goto done; + } else { + buffer = tmp_buffer; + tmp_buffer = NULL; + } + cmd_buf = (apcmdbuf_sys_configure *)buffer; + tlv = (tlvbuf_ps_sta_ageout_timer *)(buffer + cmd_len); + cmd_len += tlv_len; + /* Set TLV fields */ + tlv->tag = MRVL_PS_STA_AGEOUT_TIMER_TLV_ID; + tlv->length = 4; + tlv->ps_sta_ageout_timer_ms = (t_u32)atoi(args[1]); + endian_convert_tlv_header_out(tlv); + tlv->ps_sta_ageout_timer_ms = + uap_cpu_to_le32(tlv->ps_sta_ageout_timer_ms); + } + if (strcmp(args[0], "AuthMode") == 0) { + if (is_input_valid(AUTHMODE, arg_num - 1, args + 1) != + UAP_SUCCESS) { + ret = UAP_FAILURE; + goto done; + } + tlvbuf_auth_mode *tlv = NULL; + /* Append a new TLV */ + tlv_len = sizeof(tlvbuf_auth_mode); + tmp_buffer = realloc(buffer, cmd_len + tlv_len); + if (!tmp_buffer) { + printf("ERR:Cannot append auth mode TLV!\n"); + ret = UAP_FAILURE; + goto done; + } else { + buffer = tmp_buffer; + tmp_buffer = NULL; + } + cmd_buf = (apcmdbuf_sys_configure *)buffer; + tlv = (tlvbuf_auth_mode *)(buffer + cmd_len); + cmd_len += tlv_len; + /* Set TLV fields */ + tlv->tag = MRVL_AUTH_TLV_ID; + tlv->length = 1; + tlv->auth_mode = (t_u8)atoi(args[1]); + endian_convert_tlv_header_out(tlv); + } + if (strcmp(args[0], "KeyIndex") == 0) { + if (arg_num == 1) { + printf("KeyIndex is blank!\n"); + ret = UAP_FAILURE; + goto done; + } else { + if (ISDIGIT(args[1]) == 0) { + printf("ERR:Illegal KeyIndex parameter. Must be either '0', '1', '2', or '3'.\n"); + ret = UAP_FAILURE; + goto done; + } + keyindex = atoi(args[1]); + if ((keyindex < 0) || (keyindex > 3)) { + printf("ERR:Illegal KeyIndex parameter. Must be either '0', '1', '2', or '3'.\n"); + ret = UAP_FAILURE; + goto done; + } + } + } + if (strncmp(args[0], "Key_", 4) == 0) { + if (arg_num == 1) { + printf("ERR:%s is blank!\n", args[0]); + ret = UAP_FAILURE; + goto done; + } else { + tlvbuf_wep_key *tlv = NULL; + int key_len = 0; + if (args[1][0] == '"') { + if ((strlen(args[1]) != 2) && + (strlen(args[1]) != 7) && + (strlen(args[1]) != 15)) { + printf("ERR:Wrong key length!\n"); + ret = UAP_FAILURE; + goto done; + } + key_len = strlen(args[1]) - 2; + } else { + if ((strlen(args[1]) != 0) && + (strlen(args[1]) != 10) && + (strlen(args[1]) != 26)) { + printf("ERR:Wrong key length!\n"); + ret = UAP_FAILURE; + goto done; + } + if (UAP_FAILURE == ishexstring(args[1])) { + printf("ERR:Only hex digits are allowed when key length is 10 or 26\n"); + ret = UAP_FAILURE; + goto done; + } + key_len = strlen(args[1]) / 2; + } + + /* Append a new TLV */ + tlv_len = sizeof(tlvbuf_wep_key) + key_len; + tmp_buffer = realloc(buffer, cmd_len + tlv_len); + if (!tmp_buffer) { + printf("ERR:Cannot append WEP key configurations TLV!\n"); + ret = UAP_FAILURE; + goto done; + } else { + buffer = tmp_buffer; + tmp_buffer = NULL; + } + cmd_buf = (apcmdbuf_sys_configure *)buffer; + tlv = (tlvbuf_wep_key *)(buffer + cmd_len); + cmd_len += tlv_len; + /* Set TLV fields */ + tlv->tag = MRVL_WEP_KEY_TLV_ID; + tlv->length = key_len + 2; + if (strcmp(args[0], "Key_0") == 0) { + tlv->key_index = 0; + } else if (strcmp(args[0], "Key_1") == 0) { + tlv->key_index = 1; + } else if (strcmp(args[0], "Key_2") == 0) { + tlv->key_index = 2; + } else if (strcmp(args[0], "Key_3") == 0) { + tlv->key_index = 3; + } + if (keyindex == tlv->key_index) { + tlv->is_default = 1; + } else { + tlv->is_default = 0; + } + if (args[1][0] == '"') { + memcpy(tlv->key, &args[1][1], + strlen(args[1]) - 2); + } else { + string2raw(args[1], tlv->key); + } + endian_convert_tlv_header_out(tlv); + } + } + if (strcmp(args[0], "PSK") == 0) { + if (arg_num == 1) { + printf("ERR:PSK is blank!\n"); + ret = UAP_FAILURE; + goto done; + } else { + tlvbuf_wpa_passphrase *tlv = NULL; + if (args[1][0] == '"') { + args[1]++; + } + if (args[1][strlen(args[1]) - 1] == '"') { + args[1][strlen(args[1]) - 1] = '\0'; + } + tlv_len = + sizeof(tlvbuf_wpa_passphrase) + + strlen(args[1]); + if (strlen(args[1]) > MAX_WPA_PASSPHRASE_LENGTH) { + printf("ERR:PSK too long.\n"); + ret = UAP_FAILURE; + goto done; + } + if (strlen(args[1]) < MIN_WPA_PASSPHRASE_LENGTH) { + printf("ERR:PSK too short.\n"); + ret = UAP_FAILURE; + goto done; + } + if (strlen(args[1]) == + MAX_WPA_PASSPHRASE_LENGTH) { + if (UAP_FAILURE == ishexstring(args[1])) { + printf("ERR:Only hex digits are allowed when passphrase's length is 64\n"); + ret = UAP_FAILURE; + goto done; + } + } + /* Append a new TLV */ + tmp_buffer = realloc(buffer, cmd_len + tlv_len); + if (!tmp_buffer) { + printf("ERR:Cannot append WPA passphrase TLV!\n"); + ret = UAP_FAILURE; + goto done; + } else { + buffer = tmp_buffer; + tmp_buffer = NULL; + } + cmd_buf = (apcmdbuf_sys_configure *)buffer; + tlv = (tlvbuf_wpa_passphrase *)(buffer + + cmd_len); + cmd_len += tlv_len; + /* Set TLV fields */ + tlv->tag = MRVL_WPA_PASSPHRASE_TLV_ID; + tlv->length = strlen(args[1]); + memcpy(tlv->passphrase, args[1], tlv->length); + endian_convert_tlv_header_out(tlv); + } + } + if (strcmp(args[0], "Protocol") == 0) { + if (is_input_valid(PROTOCOL, arg_num - 1, args + 1) != + UAP_SUCCESS) { + ret = UAP_FAILURE; + goto done; + } + protocol = (t_u16)atoi(args[1]); + } + if ((strcmp(args[0], "PairwiseCipher") == 0) || + (strcmp(args[0], "GroupCipher") == 0)) { + printf("ERR:PairwiseCipher and GroupCipher are not supported.\n" " Please configure pairwise cipher using parameters PwkCipherWPA or PwkCipherWPA2\n" " and group cipher using GwkCipher in the config file.\n"); + ret = UAP_FAILURE; + goto done; + } + + if ((protocol == PROTOCOL_NO_SECURITY) || + (protocol == PROTOCOL_STATIC_WEP)) { + if ((strcmp(args[0], "PwkCipherWPA") == 0) || + (strcmp(args[0], "PwkCipherWPA2") == 0) + || (strcmp(args[0], "GwkCipher") == 0)) { + printf("ERR:Pairwise cipher and group cipher should not be defined for Open and WEP mode.\n"); + ret = UAP_FAILURE; + goto done; + } + } + + if (strcmp(args[0], "PwkCipherWPA") == 0) { + if (arg_num == 1) { + printf("ERR:PwkCipherWPA is blank!\n"); + ret = UAP_FAILURE; + goto done; + } else { + if (ISDIGIT(args[1]) == 0) { + printf("ERR:Illegal PwkCipherWPA parameter. Must be either bit '2' or '3'.\n"); + ret = UAP_FAILURE; + goto done; + } + if (atoi(args[1]) & ~CIPHER_BITMAP) { + printf("ERR:Illegal PwkCipherWPA parameter. Must be either bit '2' or '3'.\n"); + ret = UAP_FAILURE; + goto done; + } + pwkcipher_wpa = atoi(args[1]); + if (enable_11n && + protocol != PROTOCOL_WPA2_MIXED) { + memset(&htcap, 0, sizeof(htcap)); + if (UAP_SUCCESS == + get_sys_cfg_11n(&htcap)) { + if (htcap.supported_mcs_set[0] + && (atoi(args[1]) == + CIPHER_TKIP)) { + printf("ERR: WPA/TKIP cannot be used when AP operates in 802.11n mode.\n"); + ret = UAP_FAILURE; + goto done; + } + } + } + } + } + + if (strcmp(args[0], "PwkCipherWPA2") == 0) { + if (arg_num == 1) { + printf("ERR:PwkCipherWPA2 is blank!\n"); + ret = UAP_FAILURE; + goto done; + } else { + if (ISDIGIT(args[1]) == 0) { + printf("ERR:Illegal PwkCipherWPA2 parameter. Must be either bit '2' or '3'.\n"); + ret = UAP_FAILURE; + goto done; + } + if (atoi(args[1]) & ~CIPHER_BITMAP) { + printf("ERR:Illegal PwkCipherWPA2 parameter. Must be either bit '2' or '3'.\n"); + ret = UAP_FAILURE; + goto done; + } + pwkcipher_wpa2 = atoi(args[1]); + if (enable_11n && + protocol != PROTOCOL_WPA2_MIXED) { + memset(&htcap, 0, sizeof(htcap)); + if (UAP_SUCCESS == + get_sys_cfg_11n(&htcap)) { + if (htcap.supported_mcs_set[0] + && (atoi(args[1]) == + CIPHER_TKIP)) { + printf("ERR: WPA/TKIP cannot be used when AP operates in 802.11n mode.\n"); + ret = UAP_FAILURE; + goto done; + } + } + } + } + } + if (strcmp(args[0], "GwkCipher") == 0) { + if (is_input_valid(GWK_CIPHER, arg_num - 1, args + 1) != + UAP_SUCCESS) { + ret = UAP_FAILURE; + goto done; + } + gwkcipher = atoi(args[1]); + } + if (strcmp(args[0], "GroupRekeyTime") == 0) { + if (is_input_valid + (GROUPREKEYTIMER, arg_num - 1, + args + 1) != UAP_SUCCESS) { + ret = UAP_FAILURE; + goto done; + } + tlvbuf_group_rekey_timer *tlv = NULL; + + /* Append a new TLV */ + tlv_len = sizeof(tlvbuf_group_rekey_timer); + tmp_buffer = realloc(buffer, cmd_len + tlv_len); + if (!tmp_buffer) { + printf("ERR:Cannot append group rekey timer TLV!\n"); + ret = UAP_FAILURE; + goto done; + } else { + buffer = tmp_buffer; + tmp_buffer = NULL; + } + cmd_buf = (apcmdbuf_sys_configure *)buffer; + tlv = (tlvbuf_group_rekey_timer *)(buffer + cmd_len); + cmd_len += tlv_len; + /* Set TLV fields */ + tlv->tag = MRVL_GRP_REKEY_TIME_TLV_ID; + tlv->length = 4; + tlv->group_rekey_time_sec = (t_u32)atoi(args[1]); + endian_convert_tlv_header_out(tlv); + tlv->group_rekey_time_sec = + uap_cpu_to_le32(tlv->group_rekey_time_sec); + } + if (strcmp(args[0], "MaxStaNum") == 0) { + if (is_input_valid(MAXSTANUM, arg_num - 1, args + 1) != + UAP_SUCCESS) { + ret = UAP_FAILURE; + goto done; + } + if (get_max_sta_num_supported(&max_sta_num_supported) == + UAP_FAILURE) { + ret = UAP_FAILURE; + goto done; + } + if (atoi(args[1]) > max_sta_num_supported) { + printf("ERR: MAX_STA_NUM must be less than %d\n", max_sta_num_supported); + ret = UAP_FAILURE; + goto done; + } + tlvbuf_max_sta_num *tlv = NULL; + + /* Append a new TLV */ + tlv_len = + sizeof(tlvbuf_max_sta_num) - + sizeof(tlv->max_sta_num_supported); + tmp_buffer = realloc(buffer, cmd_len + tlv_len); + if (!tmp_buffer) { + printf("ERR:Cannot realloc max station number TLV!\n"); + ret = UAP_FAILURE; + goto done; + } else { + buffer = tmp_buffer; + tmp_buffer = NULL; + } + cmd_buf = (apcmdbuf_sys_configure *)buffer; + tlv = (tlvbuf_max_sta_num *)(buffer + cmd_len); + cmd_len += tlv_len; + /* Set TLV fields */ + tlv->tag = MRVL_MAX_STA_CNT_TLV_ID; + tlv->length = 2; + tlv->max_sta_num_configured = (t_u16)atoi(args[1]); + endian_convert_tlv_header_out(tlv); + tlv->max_sta_num_configured = + uap_cpu_to_le16(tlv->max_sta_num_configured); + } + if (strcmp(args[0], "Retrylimit") == 0) { + if (is_input_valid(RETRYLIMIT, arg_num - 1, args + 1) != + UAP_SUCCESS) { + ret = UAP_FAILURE; + goto done; + } + tlvbuf_retry_limit *tlv = NULL; + + /* Append a new TLV */ + tlv_len = sizeof(tlvbuf_retry_limit); + tmp_buffer = realloc(buffer, cmd_len + tlv_len); + if (!tmp_buffer) { + printf("ERR:Cannot realloc retry limit TLV!\n"); + ret = UAP_FAILURE; + goto done; + } else { + buffer = tmp_buffer; + tmp_buffer = NULL; + } + cmd_buf = (apcmdbuf_sys_configure *)buffer; + tlv = (tlvbuf_retry_limit *)(buffer + cmd_len); + cmd_len += tlv_len; + /* Set TLV fields */ + tlv->tag = MRVL_RETRY_LIMIT_TLV_ID; + tlv->length = 1; + tlv->retry_limit = (t_u8)atoi(args[1]); + endian_convert_tlv_header_out(tlv); + } + if (strcmp(args[0], "PairwiseUpdateTimeout") == 0) { + if ((ISDIGIT(args[1]) == 0) || (atoi(args[1]) < 0)) { + ret = UAP_FAILURE; + goto done; + } + tlvbuf_eapol_pwk_hsk_timeout *tlv = NULL; + + /* Append a new TLV */ + tlv_len = sizeof(tlvbuf_eapol_pwk_hsk_timeout); + tmp_buffer = realloc(buffer, cmd_len + tlv_len); + if (!tmp_buffer) { + printf("ERR:Cannot append pairwise update timeout TLV!\n"); + ret = UAP_FAILURE; + goto done; + } else { + buffer = tmp_buffer; + tmp_buffer = NULL; + } + cmd_buf = (apcmdbuf_sys_configure *)buffer; + tlv = (tlvbuf_eapol_pwk_hsk_timeout *)(buffer + + cmd_len); + cmd_len += tlv_len; + /* Set TLV fields */ + tlv->tag = MRVL_EAPOL_PWK_HSK_TIMEOUT_TLV_ID; + tlv->length = 4; + tlv->pairwise_update_timeout = (t_u32)atoi(args[1]); + endian_convert_tlv_header_out(tlv); + tlv->pairwise_update_timeout = + uap_cpu_to_le32(tlv->pairwise_update_timeout); + } + if (strcmp(args[0], "PairwiseHandshakeRetries") == 0) { + if ((ISDIGIT(args[1]) == 0) || (atoi(args[1]) < 0)) { + ret = UAP_FAILURE; + goto done; + } + tlvbuf_eapol_pwk_hsk_retries *tlv = NULL; + + /* Append a new TLV */ + tlv_len = sizeof(tlvbuf_eapol_pwk_hsk_retries); + tmp_buffer = realloc(buffer, cmd_len + tlv_len); + if (!tmp_buffer) { + printf("ERR:Cannot append pairwise handshake retries TLV!\n"); + ret = UAP_FAILURE; + goto done; + } else { + buffer = tmp_buffer; + tmp_buffer = NULL; + } + cmd_buf = (apcmdbuf_sys_configure *)buffer; + tlv = (tlvbuf_eapol_pwk_hsk_retries *)(buffer + + cmd_len); + cmd_len += tlv_len; + /* Set TLV fields */ + tlv->tag = MRVL_EAPOL_PWK_HSK_RETRIES_TLV_ID; + tlv->length = 4; + tlv->pwk_retries = (t_u32)atoi(args[1]); + endian_convert_tlv_header_out(tlv); + tlv->pwk_retries = uap_cpu_to_le32(tlv->pwk_retries); + } + if (strcmp(args[0], "GroupwiseUpdateTimeout") == 0) { + if ((ISDIGIT(args[1]) == 0) || (atoi(args[1]) < 0)) { + ret = UAP_FAILURE; + goto done; + } + tlvbuf_eapol_gwk_hsk_timeout *tlv = NULL; + + /* Append a new TLV */ + tlv_len = sizeof(tlvbuf_eapol_gwk_hsk_timeout); + tmp_buffer = realloc(buffer, cmd_len + tlv_len); + if (!tmp_buffer) { + printf("ERR:Cannot append groupwise update timeout TLV!\n"); + ret = UAP_FAILURE; + goto done; + } else { + buffer = tmp_buffer; + tmp_buffer = NULL; + } + cmd_buf = (apcmdbuf_sys_configure *)buffer; + tlv = (tlvbuf_eapol_gwk_hsk_timeout *)(buffer + + cmd_len); + cmd_len += tlv_len; + /* Set TLV fields */ + tlv->tag = MRVL_EAPOL_GWK_HSK_TIMEOUT_TLV_ID; + tlv->length = 4; + tlv->groupwise_update_timeout = (t_u32)atoi(args[1]); + endian_convert_tlv_header_out(tlv); + tlv->groupwise_update_timeout = + uap_cpu_to_le32(tlv->groupwise_update_timeout); + } + if (strcmp(args[0], "GroupwiseHandshakeRetries") == 0) { + if ((ISDIGIT(args[1]) == 0) || (atoi(args[1]) < 0)) { + ret = UAP_FAILURE; + goto done; + } + tlvbuf_eapol_gwk_hsk_retries *tlv = NULL; + + /* Append a new TLV */ + tlv_len = sizeof(tlvbuf_eapol_gwk_hsk_retries); + tmp_buffer = realloc(buffer, cmd_len + tlv_len); + if (!tmp_buffer) { + printf("ERR:Cannot append groupwise handshake retries TLV!\n"); + ret = UAP_FAILURE; + goto done; + } else { + buffer = tmp_buffer; + tmp_buffer = NULL; + } + cmd_buf = (apcmdbuf_sys_configure *)buffer; + tlv = (tlvbuf_eapol_gwk_hsk_retries *)(buffer + + cmd_len); + cmd_len += tlv_len; + /* Set TLV fields */ + tlv->tag = MRVL_EAPOL_GWK_HSK_RETRIES_TLV_ID; + tlv->length = 4; + tlv->gwk_retries = (t_u32)atoi(args[1]); + endian_convert_tlv_header_out(tlv); + tlv->gwk_retries = uap_cpu_to_le32(tlv->gwk_retries); + } + + if (strcmp(args[0], "Enable11n") == 0) { + if ((ISDIGIT(args[1]) != UAP_SUCCESS) || + (atoi(args[1]) < 0) || (atoi(args[1]) > 1)) { + printf("ERR: Invalid Enable11n value\n"); + ret = UAP_FAILURE; + goto done; + } + tlvbuf_htcap_t *tlv = NULL; + enable_11n = atoi(args[1]); + + memset(&htcap, 0, sizeof(htcap)); + if (UAP_SUCCESS != get_sys_cfg_11n(&htcap)) { + printf("ERR: Reading current 11n configuration.\n"); + ret = UAP_FAILURE; + goto done; + } + + /* Append a new TLV */ + tlv_len = sizeof(tlvbuf_htcap_t); + tmp_buffer = realloc(buffer, cmd_len + tlv_len); + if (!tmp_buffer) { + printf("ERR:Cannot append HT Cap TLV!\n"); + ret = UAP_FAILURE; + goto done; + } else { + buffer = tmp_buffer; + tmp_buffer = NULL; + } + cmd_buf = (apcmdbuf_sys_configure *)buffer; + tlv = (tlvbuf_htcap_t *)(buffer + cmd_len); + tlv_offset_11n = cmd_len; + cmd_len += tlv_len; + /* Set TLV fields */ + tlv->tag = HT_CAPABILITY_TLV_ID; + tlv->length = sizeof(HTCap_t); + memcpy(&tlv->ht_cap, &htcap, sizeof(HTCap_t)); + if (enable_11n == 1) { + /* enable mcs rate */ + tlv->ht_cap.supported_mcs_set[0] = + DEFAULT_MCS_SET_0; + tlv->ht_cap.supported_mcs_set[4] = + DEFAULT_MCS_SET_4; + if (0 == get_fw_info(&fw)) { + if ((fw.hw_dev_mcs_support & 0x0f) >= 2) + tlv->ht_cap. + supported_mcs_set[1] = + DEFAULT_MCS_SET_1; + } + } else { + /* disable mcs rate */ + tlv->ht_cap.supported_mcs_set[0] = 0; + tlv->ht_cap.supported_mcs_set[4] = 0; + tlv->ht_cap.supported_mcs_set[1] = 0; + } + endian_convert_tlv_header_out(tlv); + } + if (strcmp(args[0], "HTCapInfo") == 0) { + if (enable_11n <= 0) { + printf("ERR: Enable11n parameter should be set before HTCapInfo.\n"); + ret = UAP_FAILURE; + goto done; + } + if ((IS_HEX_OR_DIGIT(args[1]) == UAP_FAILURE) || + ((((t_u16)A2HEXDECIMAL(args[1])) & + (~HT_CAP_CONFIG_MASK)) != HT_CAP_CHECK_MASK)) { + printf("ERR: Invalid HTCapInfo value\n"); + ret = UAP_FAILURE; + goto done; + } + + /* Find HT tlv pointer in buffer and set HTCapInfo */ + tlvbuf_htcap_t *tlv = NULL; + tlv = (tlvbuf_htcap_t *)(buffer + tlv_offset_11n); + tlv->ht_cap.ht_cap_info = + DEFAULT_HT_CAP_VALUE & ~HT_CAP_CONFIG_MASK; + tlv->ht_cap.ht_cap_info |= + (t_u16)A2HEXDECIMAL(args[1]) & + HT_CAP_CONFIG_MASK; + tlv->ht_cap.ht_cap_info = + uap_cpu_to_le16(tlv->ht_cap.ht_cap_info); + } + if (strcmp(args[0], "AMPDU") == 0) { + if (enable_11n <= 0) { + printf("ERR: Enable11n parameter should be set before AMPDU.\n"); + ret = UAP_FAILURE; + goto done; + } + if ((IS_HEX_OR_DIGIT(args[1]) == UAP_FAILURE) || + ((A2HEXDECIMAL(args[1])) > AMPDU_CONFIG_MASK)) { + printf("ERR: Invalid AMPDU value\n"); + ret = UAP_FAILURE; + goto done; + } + + /* Find HT tlv pointer in buffer and set AMPDU */ + tlvbuf_htcap_t *tlv = NULL; + tlv = (tlvbuf_htcap_t *)(buffer + tlv_offset_11n); + tlv->ht_cap.ampdu_param = + (t_u8)A2HEXDECIMAL(args[1]) & AMPDU_CONFIG_MASK; + } + if (strcmp(args[0], "HT_MCS_MAP") == 0) { + if (enable_11n <= 0) { + printf("ERR: Enable11n parameter should be set before HT_MCS_MAP.\n"); + ret = UAP_FAILURE; + goto done; + } + if (0 == get_fw_info(&fw)) { + /* Check upper nibble of MCS support value + * and block MCS_SET_1 when 2X2 is not supported + * by the underlying hardware */ + if (((fw.hw_dev_mcs_support & 0xf0) < + STREAM_2X2_MASK) && + (A2HEXDECIMAL(args[1]) & MCS_SET_1_MASK)) { + printf("ERR: Invalid HT_MCS_MAP\n"); + goto done; + } + } + + /* Find HT tlv pointer in buffer and set supported MCS set */ + tlvbuf_htcap_t *tlv = NULL; + tlv = (tlvbuf_htcap_t *)(buffer + tlv_offset_11n); + supported_mcs_set = (t_u32)A2HEXDECIMAL(args[1]); + supported_mcs_set = uap_cpu_to_le32(supported_mcs_set); + memcpy(tlv->ht_cap.supported_mcs_set, + &supported_mcs_set, sizeof(t_u32)); + } + if (strcmp(args[0], "Enable2040Coex") == 0) { + if ((ISDIGIT(args[1]) == 0) || (atoi(args[1]) < 0) || + (atoi(args[1]) > 1)) { + printf("ERR: Invalid Enable2040Coex value\n"); + ret = UAP_FAILURE; + goto done; + } + tlvbuf_2040_coex *tlv = NULL; + /* Append a new TLV */ + tlv_len = sizeof(tlvbuf_2040_coex); + tmp_buffer = realloc(buffer, cmd_len + tlv_len); + if (!tmp_buffer) { + printf("ERR:Cannot append 2040 coex TLV!\n"); + ret = UAP_FAILURE; + goto done; + } else { + buffer = tmp_buffer; + tmp_buffer = NULL; + } + cmd_buf = (apcmdbuf_sys_configure *)buffer; + tlv = (tlvbuf_2040_coex *)(buffer + cmd_len); + cmd_len += tlv_len; + /* Set TLV fields */ + tlv->tag = MRVL_2040_BSS_COEX_CONTROL_TLV_ID; + tlv->length = 1; + tlv->enable = (t_u8)atoi(args[1]); + endian_convert_tlv_header_out(tlv); + } + if (strcmp(args[0], "PreambleType") == 0) { + if ((ISDIGIT(args[1]) == 0) || (atoi(args[1]) < 0) || + (atoi(args[1]) > 2)) { + printf("ERR: Invalid PreambleType value\n"); + ret = UAP_FAILURE; + goto done; + } + + /* Append a new TLV */ + tlvbuf_preamble_ctl *tlv = NULL; + tlv_len = sizeof(tlvbuf_preamble_ctl); + tmp_buffer = realloc(buffer, cmd_len + tlv_len); + if (!tmp_buffer) { + printf("ERR:Cannot append preamble type TLV!\n"); + ret = UAP_FAILURE; + goto done; + } else { + buffer = tmp_buffer; + tmp_buffer = NULL; + } + cmd_buf = (apcmdbuf_sys_configure *)buffer; + tlv = (tlvbuf_preamble_ctl *)(buffer + cmd_len); + cmd_len += tlv_len; + /* Set TLV fields */ + tlv->tag = MRVL_PREAMBLE_CTL_TLV_ID; + tlv->length = 1; + tlv->preamble_type = (t_u8)atoi(args[1]); + endian_convert_tlv_header_out(tlv); + } +#if DEBUG + if (cmd_len != 0) { + hexdump("Command Buffer", (void *)cmd_buf, cmd_len, + ' '); + } +#endif + } +done: + fclose(config_file); + if (buffer) + free(buffer); + if (line) + free(line); + return ret; +} + +/** + * @brief Get band from current channel + * @param band + * @return UAP_SUCCESS/UAP_FAILURE + */ +static int +get_band(int *band) +{ + apcmdbuf_sys_configure *cmd_buf = NULL; + tlvbuf_channel_config *tlv = NULL; + t_u8 *buffer = NULL; + t_u16 cmd_len; + int ret = UAP_SUCCESS; + + /* Initialize the command length */ + cmd_len = + sizeof(apcmdbuf_sys_configure) + sizeof(tlvbuf_channel_config); + + /* Initialize the command buffer */ + buffer = (t_u8 *)malloc(cmd_len); + + if (!buffer) { + printf("ERR:Cannot allocate buffer for command!\n"); + ret = UAP_FAILURE; + goto done; + } + memset(buffer, 0, cmd_len); + + /* Locate headers */ + cmd_buf = (apcmdbuf_sys_configure *)buffer; + tlv = (tlvbuf_channel_config *)(buffer + + sizeof(apcmdbuf_sys_configure)); + + /* Fill the command buffer */ + cmd_buf->cmd_code = APCMD_SYS_CONFIGURE; + cmd_buf->size = cmd_len; + cmd_buf->seq_num = 0; + cmd_buf->result = 0; + tlv->tag = MRVL_CHANNELCONFIG_TLV_ID; + tlv->length = sizeof(tlvbuf_channel_config) - TLVHEADER_LEN; + cmd_buf->action = ACTION_GET; + + endian_convert_tlv_header_out(tlv); + /* Send the command */ + ret = uap_ioctl((t_u8 *)cmd_buf, &cmd_len, cmd_len); + endian_convert_tlv_header_in(tlv); + + if (ret == UAP_SUCCESS) { + /* Verify response */ + if ((cmd_buf->cmd_code != + (APCMD_SYS_CONFIGURE | APCMD_RESP_CHECK)) || + (tlv->tag != MRVL_CHANNELCONFIG_TLV_ID)) { + printf("ERR:Corrupted response! cmd_code=%x, Tlv->tag=%x\n", cmd_buf->cmd_code, tlv->tag); + ret = UAP_FAILURE; + goto done; + } + if (cmd_buf->result == CMD_SUCCESS) { + if (tlv->chan_number > MAX_CHANNELS_BG) + *band = BAND_A; + else + *band = BAND_B | BAND_G; + } else { + printf("ERR:Could not get band!\n"); + ret = UAP_FAILURE; + goto done; + } + } else { + printf("ERR:Command sending failed!\n"); + ret = UAP_FAILURE; + goto done; + } +done: + if (buffer) + free(buffer); + return ret; +} + +/** + * @brief Show usage information for the cfg_80211d command + * + * $return N/A + */ +void +print_apcmd_cfg_80211d_usage(void) +{ + printf("\nUsage: cfg_80211d \n"); + return; +} + +/** + * @brief Show usage information for the uap_stats command + * + * $return N/A + */ +void +print_apcmd_uap_stats(void) +{ + printf("Usage: uap_stats \n"); + return; +} + +/** + * SNMP MIB OIDs Table + */ +static oids_table snmp_oids[] = { + {0x0b, 4, "dot11LocalTKIPMICFailures"}, + {0x0c, 4, "dot11CCMPDecryptErrors"}, + {0x0d, 4, "dot11WEPUndecryptableCount"}, + {0x0e, 4, "dot11WEPICVErrorCount"}, + {0x0f, 4, "dot11DecryptFailureCount"}, + {0x12, 4, "dot11FailedCount"}, + {0x13, 4, "dot11RetryCount"}, + {0x14, 4, "dot11MultipleRetryCount"}, + {0x15, 4, "dot11FrameDuplicateCount"}, + {0x16, 4, "dot11RTSSuccessCount"}, + {0x17, 4, "dot11RTSFailureCount"}, + {0x18, 4, "dot11ACKFailureCount"}, + {0x19, 4, "dot11ReceivedFragmentCount"}, + {0x1a, 4, "dot11MulticastReceivedFrameCount"}, + {0x1b, 4, "dot11FCSErrorCount"}, + {0x1c, 4, "dot11TransmittedFrameCount"}, + {0x1d, 4, "dot11RSNATKIPCounterMeasuresInvoked"}, + {0x1e, 4, "dot11RSNA4WayHandshakeFailures"}, + {0x1f, 4, "dot11MulticastTransmittedFrameCount"} +}; + +/** + * @brief Get uAP stats + * + * @param argc Number of arguments + * @param argv Pointer to the arguments + * + * @return UAP_SUCCESS/UAP_FAILURE + */ +int +apcmd_uap_stats(int argc, char *argv[]) +{ + t_u8 no_of_oids = sizeof(snmp_oids) / sizeof(snmp_oids[0]); + t_u16 i, j; + int size; + apcmdbuf_snmp_mib *cmd_buf = NULL; + t_u8 *buf = NULL; + tlvbuf_header *tlv = NULL; + t_u16 cmd_len = 0; + t_u16 buf_len = MRVDRV_SIZE_OF_CMD_BUFFER; + int opt; + t_u16 oid_size, byte2 = 0; + t_u32 byte4 = 0; + int ret = UAP_SUCCESS; + + while ((opt = getopt_long(argc, argv, "+", cmd_options, NULL)) != -1) { + switch (opt) { + default: + print_apcmd_uap_stats(); + return UAP_SUCCESS; + } + } + + argc -= optind; + argv += optind; + if (argc) { + printf("Error: Invalid Input\n"); + print_apcmd_uap_stats(); + return UAP_FAILURE; + } + + /** Command Header */ + cmd_len += sizeof(apcmdbuf_snmp_mib); + + for (i = 0; i < no_of_oids; i++) { + /** + * Size of Oid + Oid_value + Oid_size + */ + cmd_len += snmp_oids[i].len + sizeof(tlvbuf_header); + } + buf = (t_u8 *)malloc(buf_len); + if (!buf) { + printf("ERR:Cannot allocate buffer from command!\n"); + return UAP_FAILURE; + } + memset(buf, 0, buf_len); + + /* Locate Headers */ + cmd_buf = (apcmdbuf_snmp_mib *)buf; + cmd_buf->size = cmd_len - BUF_HEADER_SIZE; + cmd_buf->result = 0; + cmd_buf->seq_num = 0; + cmd_buf->cmd_code = HostCmd_SNMP_MIB; + cmd_buf->action = uap_cpu_to_le16(ACTION_GET); + + tlv = (tlvbuf_header *)((t_u8 *)cmd_buf + sizeof(apcmdbuf_snmp_mib)); + /* Add oid, oid_size and oid_value for each OID */ + for (i = 0; i < no_of_oids; i++) { + /** Copy Index as Oid */ + tlv->type = uap_cpu_to_le16(snmp_oids[i].type); + /** Copy its size */ + tlv->len = uap_cpu_to_le16(snmp_oids[i].len); + /** Next TLV */ + tlv = (tlvbuf_header *)&(tlv->data[snmp_oids[i].len]); + } + ret = uap_ioctl((t_u8 *)cmd_buf, &cmd_len, buf_len); + if (ret == UAP_SUCCESS) { + if (cmd_buf->result == CMD_SUCCESS) { + tlv = (tlvbuf_header *)((t_u8 *)cmd_buf + + sizeof(apcmdbuf_snmp_mib)); + + size = cmd_buf->size - (sizeof(apcmdbuf_snmp_mib) - + BUF_HEADER_SIZE); + + while ((unsigned int)size >= sizeof(tlvbuf_header)) { + tlv->type = uap_le16_to_cpu(tlv->type); + for (i = 0; i < no_of_oids; i++) { + if (snmp_oids[i].type == tlv->type) { + printf("%s: ", + snmp_oids[i].name); + break; + } + } + oid_size = uap_le16_to_cpu(tlv->len); + switch (oid_size) { + case 1: + printf("%d", + (unsigned int)tlv->data[0]); + break; + case 2: + memcpy(&byte2, &tlv->data[0], + sizeof(oid_size)); + printf("%d", + (unsigned int) + uap_le16_to_cpu(byte2)); + break; + case 4: + memcpy(&byte4, &tlv->data[0], + sizeof(oid_size)); + printf("%d", + (unsigned int) + uap_le32_to_cpu(byte4)); + break; + default: + for (j = 0; j < oid_size; j++) { + printf("%d ", + (t_u8)tlv->data[j]); + } + break; + } + /** Next TLV */ + tlv = (tlvbuf_header *)&(tlv->data[oid_size]); + size -= (sizeof(tlvbuf_header) + oid_size); + size = (size > 0) ? size : 0; + printf("\n"); + } + + } else { + printf("ERR:Command Response incorrect!\n"); + ret = UAP_FAILURE; + } + } else { + printf("ERR:Command sending failed!\n"); + } + free(buf); + return ret; +} + +/** + * @brief parser for sys_cfg_80211d input + * + * @param argc Number of arguments + * @param argv Pointer to the arguments + * @param output Stores indexes for "state, country" + * arguments + * + * @return NA + * + */ +static void +parse_input_80211d(int argc, char **argv, int output[2][2]) +{ + int i, j, k = 0; + char *keywords[2] = { "state", "country" }; + + for (i = 0; i < 2; i++) + output[i][0] = -1; + + for (i = 0; i < argc; i++) { + for (j = 0; j < 2; j++) { + if (strcmp(argv[i], keywords[j]) == 0) { + output[j][1] = output[j][0] = i; + k = j; + break; + } + } + output[k][1] += 1; + } +} + +/** + * @brief Set/Get 802.11D country information + * + * Usage: cfg_80211d state country_code + * + * State 0 or 1 + * + * @param argc Number of arguments + * @param argv Pointer to the arguments + * @return UAP_SUCCESS/UAP_FAILURE + */ +int +apcmd_cfg_80211d(int argc, char *argv[]) +{ + apcmdbuf_cfg_80211d *cmd_buf = NULL; + ieeetypes_subband_set_t *subband = NULL; + t_u8 *buf = NULL; + t_u16 cmd_len = 0; + t_u16 buf_len = MRVDRV_SIZE_OF_CMD_BUFFER; + int output[2][2]; + int ret = UAP_SUCCESS; + int opt; + int status = 0; + int i, j; + t_u8 state = 0; + char country[4] = { ' ', ' ', 0, 0 }; + t_u8 sflag = 0, cflag = 0; + ieeetypes_subband_set_t sub_bands[MAX_SUB_BANDS]; + t_u8 no_of_sub_band = 0; + int band; + + while ((opt = getopt_long(argc, argv, "+", cmd_options, NULL)) != -1) { + switch (opt) { + default: + print_apcmd_cfg_80211d_usage(); + return UAP_SUCCESS; + } + } + argc -= optind; + argv += optind; + + if (argc) { + if (strcmp(argv[0], "state") && strcmp(argv[0], "country")) { + printf("ERR: Incorrect input. Either state or country is needed."); + print_apcmd_cfg_80211d_usage(); + return UAP_FAILURE; + } + /** SET */ + parse_input_80211d(argc, argv, output); + + /** State */ + if ((output[0][0] != -1) && (output[0][1] > output[0][0])) { + if ((output[0][1] - output[0][0]) != 2) { + printf("ERR: Invalid state inputs\n"); + print_apcmd_cfg_80211d_usage(); + return UAP_FAILURE; + } + + if (IS_HEX_OR_DIGIT(argv[output[0][0] + 1]) == + UAP_FAILURE) { + printf("ERR: valid input for state are 0 or 1\n"); + print_apcmd_cfg_80211d_usage(); + return UAP_FAILURE; + } + state = (t_u8)A2HEXDECIMAL(argv[output[0][0] + 1]); + + if ((state != 0) && (state != 1)) { + printf("ERR: valid input for state are 0 or 1 \n"); + print_apcmd_cfg_80211d_usage(); + return UAP_FAILURE; + } + sflag = 1; + } + + /** Country */ + if ((output[1][0] != -1) && (output[1][1] > output[1][0])) { + if ((output[1][1] - output[1][0]) != 2) { + printf("ERR: Invalid country inputs\n"); + print_apcmd_cfg_80211d_usage(); + return UAP_FAILURE; + } + if ((strlen(argv[output[1][0] + 1]) > 3) || + (strlen(argv[output[1][0] + 1]) == 0)) { + print_apcmd_cfg_80211d_usage(); + return UAP_FAILURE; + } + /* Only 2 characters of country code are copied here as indoor/outdoor + * conditions are not handled in domain file */ + strncpy(country, argv[output[1][0] + 1], 2); + + for (i = 0; (unsigned int)i < strlen(country); i++) { + if ((country[i] < 'A') || (country[i] > 'z')) { + printf("Invalid Country Code\n"); + print_apcmd_cfg_80211d_usage(); + return UAP_FAILURE; + } + if (country[i] > 'Z') + country[i] = country[i] - 'a' + 'A'; + } + + cflag = 1; + if (!get_band(&band)) { + printf("ERR:couldn't get band from channel!\n"); + return UAP_FAILURE; + } + /** Get domain information from the file */ + no_of_sub_band = + parse_domain_file(country, band, sub_bands, + NULL); + if (no_of_sub_band == UAP_FAILURE) { + printf("Parsing Failed\n"); + return UAP_FAILURE; + } + } + if (get_bss_status(&status) != UAP_SUCCESS) { + printf("ERR:Cannot get current bss status!\n"); + return UAP_FAILURE; + } + if (status == UAP_BSS_START) { + printf("ERR: 11d status can not be changed after BSS start!\n"); + return UAP_FAILURE; + } + } + + if (argc && !cflag && !sflag) { + printf("ERR: Invalid input\n"); + print_apcmd_cfg_80211d_usage(); + return UAP_FAILURE; + } + + if (sflag && !cflag) { + /** + * Update MIB only and return + */ + if (sg_snmp_mib + (ACTION_SET, OID_80211D_ENABLE, sizeof(state), + &state) == UAP_SUCCESS) { + printf("802.11d %sd \n", state ? "enable" : "disable"); + return UAP_SUCCESS; + } else { + return UAP_FAILURE; + } + } + + cmd_len = sizeof(apcmdbuf_cfg_80211d); + + if (cflag) { + cmd_len += no_of_sub_band * sizeof(ieeetypes_subband_set_t); + } else { + /** Get */ + cmd_len += MAX_SUB_BANDS * sizeof(ieeetypes_subband_set_t); + } + + buf = (t_u8 *)malloc(buf_len); + if (!buf) { + printf("ERR:Cannot allocate buffer from command!\n"); + return UAP_FAILURE; + } + memset(buf, 0, buf_len); + /* Locate headers */ + cmd_buf = (apcmdbuf_cfg_80211d *)buf; + cmd_len = argc ? cmd_len : + /** Set */ + (sizeof(apcmdbuf_cfg_80211d) - sizeof(domain_param_t)); + /** Get */ + + cmd_buf->size = cmd_len - BUF_HEADER_SIZE; + cmd_buf->result = 0; + cmd_buf->seq_num = 0; + cmd_buf->action = argc ? ACTION_SET : ACTION_GET; + cmd_buf->action = uap_cpu_to_le16(cmd_buf->action); + cmd_buf->cmd_code = HostCmd_CMD_802_11D_DOMAIN_INFO; + + if (cflag) { + /* third character of country code is copied here as indoor/outdoor + * condition is not supported in domain file*/ + strncpy(country, argv[output[1][0] + 1], sizeof(country) - 1); + for (i = 0; (unsigned int)i < strlen(country); i++) { + if ((country[i] < 'A') || (country[i] > 'z')) { + printf("Invalid Country Code\n"); + print_apcmd_cfg_80211d_usage(); + free(buf); + return UAP_FAILURE; + } + if (country[i] > 'Z') + country[i] = country[i] - 'a' + 'A'; + } + cmd_buf->domain.tag = uap_cpu_to_le16(TLV_TYPE_DOMAIN); + cmd_buf->domain.length = uap_cpu_to_le16(sizeof(domain_param_t) + - BUF_HEADER_SIZE + + + (no_of_sub_band * + sizeof + (ieeetypes_subband_set_t))); + + memset(cmd_buf->domain.country_code, ' ', + sizeof(cmd_buf->domain.country_code)); + memcpy(cmd_buf->domain.country_code, country, strlen(country)); + memcpy(cmd_buf->domain.subband, sub_bands, + no_of_sub_band * sizeof(ieeetypes_subband_set_t)); + } + + /* Send the command */ + ret = uap_ioctl((t_u8 *)cmd_buf, &cmd_len, buf_len); + if (ret == UAP_SUCCESS) { + if (cmd_buf->result == CMD_SUCCESS) { + if (argc) { + printf("Set executed successfully\n"); + if (sflag) { + if (sg_snmp_mib + (ACTION_SET, OID_80211D_ENABLE, + sizeof(state), + &state) == UAP_SUCCESS) { + printf("802.11d %sd \n", + state ? "enable" : + "disable"); + } + } + } else { + j = uap_le16_to_cpu(cmd_buf->domain.length); + if (sg_snmp_mib + (ACTION_GET, OID_80211D_ENABLE, + sizeof(state), &state) + == UAP_SUCCESS) { + printf("State = %sd\n", + state ? "enable" : "disable"); + } + + if (cmd_buf->domain.country_code[0] || + cmd_buf->domain.country_code[1] || + cmd_buf->domain.country_code[2]) { + printf("Country string = %c%c%c", + cmd_buf->domain.country_code[0], + cmd_buf->domain.country_code[1], + cmd_buf->domain.country_code[2]); + j -= sizeof(cmd_buf->domain. + country_code); + subband = + (ieeetypes_subband_set_t *) + cmd_buf->domain.subband; + printf("\nSub-band info="); + printf("\t(1st, #chan, MAX-power) \n"); + for (i = 0; i < (j / 3); i++) { + printf("\t\t(%d, \t%d, \t%d dbm)\n", subband->first_chan, subband->no_of_chan, subband->max_tx_pwr); + subband++; + } + } + } + } else { + printf("ERR:Command Response incorrect!\n"); + if (argc) + printf("11d info is allowed to set only before bss start.\n"); + ret = UAP_FAILURE; + } + } else { + printf("ERR:Command sending failed!\n"); + } + free(buf); + return ret; +} + +/** + * @brief Creates a sys_config request and sends to the driver + * + * Usage: "Usage : sys_config [CONFIG_FILE]" + * + * @param argc Number of arguments + * @param argv Pointer to the arguments + * @return UAP_SUCCESS/UAP_FAILURE + */ +int +apcmd_sys_config(int argc, char *argv[]) +{ + apcmdbuf_sys_configure *cmd_buf = NULL; + t_u8 *buf = NULL; + t_u16 cmd_len; + t_u16 buf_len; + int ret = UAP_SUCCESS; + int opt; + char **argv_dummy = NULL; + ps_mgmt pm; + + while ((opt = getopt_long(argc, argv, "+", cmd_options, NULL)) != -1) { + switch (opt) { + default: + print_sys_config_usage(); + return UAP_SUCCESS; + } + } + argc -= optind; + argv += optind; + + /* Check arguments */ + if (argc > 1) { + printf("ERR:Too many arguments.\n"); + print_sys_config_usage(); + return UAP_FAILURE; + } + if (argc == 1) { + /* Read profile and send command to firmware */ + ret = apcmd_sys_config_profile(argc, argv); + return ret; + } + + /** Query AP's setting */ + buf_len = MRVDRV_SIZE_OF_CMD_BUFFER; + + /* Alloc buf for command */ + buf = (t_u8 *)malloc(buf_len); + + if (!buf) { + printf("ERR:Cannot allocate buffer from command!\n"); + return UAP_FAILURE; + } + memset(buf, 0, buf_len); + + /* Reset custom_ie_present flag */ + custom_ie_present = 0; + + /* Reset max_mgmt_ie_print flag */ + max_mgmt_ie_print = 0; + + /* Locate headers */ + cmd_len = sizeof(apcmdbuf_sys_configure); + cmd_buf = (apcmdbuf_sys_configure *)buf; + + /* Fill the command buffer */ + cmd_buf->cmd_code = APCMD_SYS_CONFIGURE; + cmd_buf->size = cmd_len - BUF_HEADER_SIZE; + cmd_buf->seq_num = 0; + cmd_buf->result = 0; + + /* Send the command */ + ret = uap_ioctl((t_u8 *)cmd_buf, &cmd_len, buf_len); + + /* Process response */ + if (ret == UAP_SUCCESS) { + /* Verify response */ + if (cmd_buf->cmd_code != + (APCMD_SYS_CONFIGURE | APCMD_RESP_CHECK)) { + printf("ERR:Corrupted response!\n"); + free(buf); + return UAP_FAILURE; + } + /* Print response */ + if (cmd_buf->result == CMD_SUCCESS) { + printf("AP settings:\n"); + print_tlv(buf + sizeof(apcmdbuf_sys_configure), + cmd_buf->size - + sizeof(apcmdbuf_sys_configure) + + BUF_HEADER_SIZE); + if (apcmd_addbapara(1, argv_dummy) == UAP_FAILURE) { + printf("Couldn't get ADDBA parameters\n"); + free(buf); + return UAP_FAILURE; + } + if (apcmd_aggrpriotbl(1, argv_dummy) == UAP_FAILURE) { + printf("Couldn't get AMSDU/AMPDU priority table\n"); + free(buf); + return UAP_FAILURE; + } + if (apcmd_addbareject(1, argv_dummy) == UAP_FAILURE) { + printf("Couldn't get ADDBA reject table\n"); + free(buf); + return UAP_FAILURE; + } + printf("\n802.11D setting:\n"); + if (apcmd_cfg_80211d(1, argv_dummy) == UAP_FAILURE) { + free(buf); + return UAP_FAILURE; + } + if (!custom_ie_present) { + printf("\nCustom IE settings:\n"); + if (apcmd_sys_cfg_custom_ie(1, argv_dummy) == + UAP_FAILURE) { + free(buf); + return UAP_FAILURE; + } + } + } else { + printf("ERR:Could not retrieve system configure\n"); + ret = UAP_FAILURE; + } + } else { + printf("ERR:Command sending failed!\n"); + } + free(buf); + memset(&pm, 0, sizeof(ps_mgmt)); + ret = send_power_mode_ioctl(&pm, 0); + return ret; +} + +/** Update domain info with given country and band + * + * @param country_80211d country to be set + * @param band band of operation + * @return UAP_SUCCESS/UAP_FAILURE + */ +static int +update_domain_info(char *country_80211d, int band) +{ + apcmdbuf_cfg_80211d *cmd_buf = NULL; + t_u8 *buf = NULL; + t_u16 cmd_len = 0; + t_u16 buf_len = MRVDRV_SIZE_OF_CMD_BUFFER; + ieeetypes_subband_set_t sub_bands[MAX_SUB_BANDS]; + t_u8 no_of_sub_band = 0; + char country[4] = { ' ', ' ', 0, 0 }; + int ret = UAP_SUCCESS; + t_u8 domain_code = 0; + rgn_dom_code_t *prgn_dom_code = NULL; + + /* Get currently set country code from FW */ + buf = (t_u8 *)malloc(buf_len); + if (!buf) { + printf("ERR:Cannot allocate buffer from command!\n"); + return UAP_FAILURE; + } + memset(buf, 0, buf_len); + /* Locate headers */ + cmd_buf = (apcmdbuf_cfg_80211d *)buf; + cmd_len = (sizeof(apcmdbuf_cfg_80211d) - sizeof(domain_param_t)); + + cmd_buf->size = cmd_len - BUF_HEADER_SIZE; + cmd_buf->result = 0; + cmd_buf->seq_num = 0; + cmd_buf->action = ACTION_GET; + cmd_buf->action = uap_cpu_to_le16(cmd_buf->action); + cmd_buf->cmd_code = HostCmd_CMD_802_11D_DOMAIN_INFO; + + ret = uap_ioctl((t_u8 *)cmd_buf, &cmd_len, buf_len); + if ((ret == UAP_SUCCESS) && (cmd_buf->result == CMD_SUCCESS) && + (cmd_buf->domain.country_code[0] || + cmd_buf->domain.country_code[1] || + cmd_buf->domain.country_code[2])) { + country[0] = cmd_buf->domain.country_code[0]; + country[1] = cmd_buf->domain.country_code[1]; + } else { + /* country_80211d will only be used if country code is not already set */ + country[0] = country_80211d[0]; + country[1] = country_80211d[1]; + } + + if (band == BAND_A) + printf("Enabling 11d for 11h operation and setting country code to %s\n", country); + cmd_len = sizeof(apcmdbuf_cfg_80211d); + /** Get domain information from the file */ + no_of_sub_band = + parse_domain_file(country, band, sub_bands, &domain_code); + if (no_of_sub_band == UAP_FAILURE) { + printf("Parsing Failed\n"); + ret = UAP_FAILURE; + goto done; + } + /* Copy third character of country code here */ + if (cmd_buf->domain.country_code[2]) { + country[2] = cmd_buf->domain.country_code[2]; + } else { + country[2] = country_80211d[2]; + } + + /* Set domain for this country code */ + memset(buf, 0, buf_len); + cmd_len += no_of_sub_band * sizeof(ieeetypes_subband_set_t); + /* Locate headers */ + cmd_buf = (apcmdbuf_cfg_80211d *)buf; + cmd_buf->size = cmd_len - BUF_HEADER_SIZE; + cmd_buf->result = 0; + cmd_buf->seq_num = 0; + cmd_buf->action = ACTION_SET; + cmd_buf->action = uap_cpu_to_le16(cmd_buf->action); + cmd_buf->cmd_code = HostCmd_CMD_802_11D_DOMAIN_INFO; + + cmd_buf->domain.tag = uap_cpu_to_le16(TLV_TYPE_DOMAIN); + cmd_buf->domain.length = uap_cpu_to_le16(sizeof(domain_param_t) + - BUF_HEADER_SIZE + + + (no_of_sub_band * + sizeof + (ieeetypes_subband_set_t))); + + memset(cmd_buf->domain.country_code, ' ', + sizeof(cmd_buf->domain.country_code)); + memcpy(cmd_buf->domain.country_code, country, strlen(country)); + memcpy(cmd_buf->domain.subband, sub_bands, + no_of_sub_band * sizeof(ieeetypes_subband_set_t)); + + /* Send the command */ + ret = uap_ioctl((t_u8 *)cmd_buf, &cmd_len, buf_len); + if (ret == UAP_SUCCESS) { + if (cmd_buf->result != CMD_SUCCESS) { + printf("ERR:Command Response incorrect!\n"); + printf("11d info is allowed to set only before bss start.\n"); + ret = UAP_FAILURE; + goto done; + } + } else { + printf("ERR:Command sending failed!\n"); + } + + if ((band == BAND_A) && domain_code) { + /* Send 11D_CMD a second time, with reg_dom_code TLV appended. + * Use hostcmd instead of re-route. */ + cmd_len = cmd_buf->size + BUF_HEADER_SIZE; + prgn_dom_code = (rgn_dom_code_t *)((t_u8 *)cmd_buf + cmd_len); + cmd_len += sizeof(rgn_dom_code_t); + cmd_buf->size += sizeof(rgn_dom_code_t); +#if DEBUG + uap_printf(MSG_DEBUG, + "Adding Region Domain Code TLV. Domain_code=%d\n", + domain_code); +#endif + prgn_dom_code->tag = + uap_cpu_to_le16(MRVL_REGION_DOMAIN_CODE_TLV_ID); + prgn_dom_code->length = uap_cpu_to_le16(sizeof(rgn_dom_code_t) + - BUF_HEADER_SIZE); + prgn_dom_code->domain_code = domain_code; + + /* Send the command */ + uap_ioctl_no_reroute = 1; + ret = uap_ioctl((t_u8 *)cmd_buf, &cmd_len, buf_len); + uap_ioctl_no_reroute = 0; + + if (ret == UAP_SUCCESS) { + if (cmd_buf->result != CMD_SUCCESS) { + printf("ERR:Command Response incorrect!\n"); + printf("11d info is allowed to set only before bss start.\n"); + ret = UAP_FAILURE; + goto done; + } + } else { + printf("ERR:Command sending failed!\n"); + } + } + +done: + if (buf) + free(buf); + return ret; +} + +/** + * @brief Covert MCS Rate Bitmap to MCS Rate index + * + * @param rate_bitmap Pointer to rate bitmap + * @param size Size of the bitmap array + * + * @return Rate index + */ +int +get_rate_index_from_bitmap(t_u16 *rate_bitmap, int size) +{ + int i; + + for (i = 0; i < size * 8; i++) { + if (rate_bitmap[i / 16] & (1 << (i % 16))) { + return i; + } + } + return 0; +} + +/** + * @brief Checks current system configuration + * + * @param buf pointer to TLV buffer + * @param len TLV buffer length + * @return UAP_SUCCESS/UAP_FAILURE + */ +int +check_sys_config(t_u8 *buf, t_u16 len) +{ + tlvbuf_header *pcurrent_tlv = (tlvbuf_header *)buf; + int tlv_buf_left = len; + t_u16 tlv_type; + t_u16 tlv_len; + tlvbuf_channel_config *channel_tlv = NULL; + tlvbuf_channel_list *chnlist_tlv = NULL; + tlvbuf_pwk_cipher *pwk_cipher_tlv = NULL; + tlvbuf_gwk_cipher *gwk_cipher_tlv = NULL; + tlvbuf_auth_mode *auth_tlv = NULL; + tlvbuf_protocol *protocol_tlv = NULL; + tlvbuf_wep_key *wep_key_tlv = NULL; + tlvbuf_wpa_passphrase *passphrase_tlv = NULL; + tlvbuf_rates *rates_tlv = NULL; + tlvbuf_mcbc_data_rate *mcbc_data_rate_tlv = NULL; + t_u16 protocol = 0; + t_u16 mcbc_data_rate = 0; + t_u16 op_rates_len = 0; + t_u8 acs_mode_enabled = 0; + t_u8 *cbuf = NULL; + apcmdbuf_cfg_80211d *cmd_buf = NULL; + t_u16 buf_len, cmd_len; + char country_80211d[4] = { 'U', 'S', ' ', 0 }; + t_u8 state_80211h = 0; + int channel_tlv_band = BAND_B | BAND_G; + t_u8 secondary_ch_set = 0; + int scan_channels_band = BAND_B | BAND_G; + t_u8 state_80211d = 0; + t_u8 rate = 0; + t_u32 rate_bitmap = 0; + tlvbuf_htcap_t *ht_cap_tlv = NULL; + t_u16 enable_40Mhz = 0; + t_u16 enable_20Mhz_sgi = 0; + t_u16 enable_gf = 0; + t_u8 enable_11n = 0; + int flag = 0; + fw_info fw; + channel_list *pchan_list; + tlvbuf_tx_power *txpower_tlv = NULL; + int i = 0, ret = UAP_SUCCESS; + int pairwise_cipher_wpa = -1; + int pairwise_cipher_wpa2 = -1; + int group_cipher = -1; + int chan_list_len = 0; + int key_set = 0; + t_u8 channel = 0; + tx_rate_cfg_t tx_rate_config; + t_u32 mcs_rate_index = 0; + struct eth_priv_vhtcfg vhtcfg = { 0 }; + +#define BITMAP_RATE_1M 0x01 +#define BITMAP_RATE_2M 0x02 +#define BITMAP_RATE_5_5M 0x04 +#define BITMAP_RATE_11M 0x8 +#define B_RATE_MANDATORY 0x0f + + if (pcurrent_tlv == NULL) { + printf("ERR: No TLV buffer available!\n"); + return UAP_FAILURE; + } + + ret = sg_snmp_mib(ACTION_GET, OID_80211D_ENABLE, sizeof(state_80211d), + &state_80211d); + + buf_len = MRVDRV_SIZE_OF_CMD_BUFFER; + cbuf = (t_u8 *)malloc(buf_len); + if (!cbuf) { + printf("ERR:Cannot allocate buffer from command!\n"); + return UAP_FAILURE; + } + memset(cbuf, 0, buf_len); + /* Locate headers */ + cmd_buf = (apcmdbuf_cfg_80211d *)cbuf; + cmd_len = (sizeof(apcmdbuf_cfg_80211d) - sizeof(domain_param_t)); + cmd_buf->size = cmd_len - BUF_HEADER_SIZE; + cmd_buf->action = uap_cpu_to_le16(ACTION_GET); + cmd_buf->cmd_code = HostCmd_CMD_802_11D_DOMAIN_INFO; + ret = uap_ioctl((t_u8 *)cmd_buf, &cmd_len, buf_len); + if (ret == UAP_SUCCESS && cmd_buf->result == CMD_SUCCESS) { + if (cmd_buf->domain.country_code[0] || + cmd_buf->domain.country_code[1] || + cmd_buf->domain.country_code[2]) { + strncpy(country_80211d, + (char *)cmd_buf->domain.country_code, + COUNTRY_CODE_LEN); + } + } + free(cbuf); + + /* get region code to handle special cases */ + memset(&fw, 0, sizeof(fw)); + if (get_fw_info(&fw)) { + printf("Could not get fw info!\n"); + return UAP_FAILURE; + } + + if (get_tx_rate_cfg(&tx_rate_config) == UAP_FAILURE) { + printf("Could not get tx_rate_cfg!\n"); + return UAP_FAILURE; + } + while (tlv_buf_left >= (int)sizeof(tlvbuf_header) && + (ret != UAP_FAILURE)) { + tlv_type = *(t_u8 *)&pcurrent_tlv->type; + tlv_type |= (*((t_u8 *)&pcurrent_tlv->type + 1) << 8); + tlv_len = *(t_u8 *)&pcurrent_tlv->len; + tlv_len |= (*((t_u8 *)&pcurrent_tlv->len + 1) << 8); + if ((sizeof(tlvbuf_header) + tlv_len) > + (unsigned int)tlv_buf_left) { + printf("wrong tlv: tlv_len=%d, tlv_buf_left=%d\n", + tlv_len, tlv_buf_left); + break; + } + switch (tlv_type) { + case MRVL_CHANNELCONFIG_TLV_ID: + channel_tlv = (tlvbuf_channel_config *)pcurrent_tlv; + channel = channel_tlv->chan_number; + + if ((!state_80211d) && + (channel_tlv->chan_number == MAX_CHANNELS_BG) + && + (strncmp(country_80211d, "JP", COUNTRY_CODE_LEN - 1) + == 0) + ) { + printf("ERR: Invalid channel 14, 802.11d disabled, country code JP!\n"); + return UAP_FAILURE; + } + if (channel_tlv->bandcfg.chanBand == BAND_5GHZ) + channel_tlv_band = BAND_A; + secondary_ch_set = channel_tlv->bandcfg.chan2Offset; + if (channel_tlv_band != BAND_A) { + /* When country code is not Japan, allow channels 5-11 for US and 5-13 for non-US + * only for secondary channel below */ + if (secondary_ch_set == SEC_CHAN_BELOW) { + if (!strncmp + (country_80211d, "US", + COUNTRY_CODE_LEN - 1)) { + if (channel_tlv->chan_number > + DEFAULT_MAX_CHANNEL_BELOW) { + printf("ERR: Only channels 5-11 are allowed with secondary channel below for the US\n"); + return UAP_FAILURE; + } + } else if (strncmp + (country_80211d, "JP", + COUNTRY_CODE_LEN - 1)) { + if (channel_tlv->chan_number > + DEFAULT_MAX_CHANNEL_BELOW_NON_US) + { + printf("ERR: Only channels 5-13 are allowed with secondary channel below for" "non-Japan countries!\n"); + return UAP_FAILURE; + } + } + } + + /* When country code is not Japan, allow channels 1-7 for US and 1-9 for non-US + * only for secondary channel above */ + if (secondary_ch_set == SEC_CHAN_ABOVE) { + if (!strncmp + (country_80211d, "US", + COUNTRY_CODE_LEN - 1)) { + if (channel_tlv->chan_number > + DEFAULT_MAX_CHANNEL_ABOVE) { + printf("ERR: Only channels 1-7 are allowed with secondary channel above for the US\n"); + return UAP_FAILURE; + } + } else if (strncmp + (country_80211d, "JP", + COUNTRY_CODE_LEN - 1)) { + if (channel_tlv->chan_number > + DEFAULT_MAX_CHANNEL_ABOVE_NON_US) + { + printf("ERR: Only channels 1-9 are allowed with secondary channel above for" "non-Japan countries!\n"); + return UAP_FAILURE; + } + } + } + } + if (!(channel_tlv->bandcfg.scanMode == SCAN_MODE_ACS)) { + if (check_channel_validity_11d + (channel_tlv->chan_number, channel_tlv_band, + 1) == UAP_FAILURE) + return UAP_FAILURE; + if (state_80211d) { + /* Set country code to JP if channel is 8 or 12 and band is 5GHZ */ + if ((channel_tlv->chan_number < + MAX_CHANNELS_BG) && + (channel_tlv_band == BAND_A)) + strncpy(country_80211d, "JP ", + sizeof(country_80211d) - + 1); + } else { + if ((channel_tlv_band == BAND_A) && + ((channel_tlv->chan_number == 8) || + (channel_tlv->chan_number == + 12))) { + printf("ERR:Invalid band for given channel\n"); + return UAP_FAILURE; + } + } + } else { + acs_mode_enabled = 1; + } +#define JP_REGION_0xFE 0xFE + if (fw.region_code == JP_REGION_0xFE && + ((channel_tlv->chan_number == 12) || + (channel_tlv->chan_number == 13))) { + printf("ERR:Channel 12 or 13 is not allowed for region code 0xFE\n"); + return UAP_FAILURE; + } + break; + case MRVL_CHANNELLIST_TLV_ID: + chnlist_tlv = (tlvbuf_channel_list *)pcurrent_tlv; + pchan_list = + (channel_list *) & (chnlist_tlv->chan_list); + if (tlv_len % sizeof(channel_list)) { + printf("ERR:Invalid Scan channel list TLV!\n"); + return UAP_FAILURE; + } + chan_list_len = tlv_len / sizeof(channel_list); + + for (i = 0; i < chan_list_len; i++) { + scan_channels_band = BAND_B | BAND_G; + if ((scan_channels_band != BAND_A) && + (pchan_list->bandcfg.chanBand == + BAND_5GHZ)) { + scan_channels_band = BAND_A; + } + if (check_channel_validity_11d + (pchan_list->chan_number, + scan_channels_band, 0) == UAP_FAILURE) + return UAP_FAILURE; + pchan_list++; + } + break; + case MRVL_TX_POWER_TLV_ID: + txpower_tlv = (tlvbuf_tx_power *)pcurrent_tlv; + if (state_80211d) { + if (check_tx_pwr_validity_11d + (txpower_tlv->tx_power_dbm) == UAP_FAILURE) + return UAP_FAILURE; + } + break; + case MRVL_CIPHER_PWK_TLV_ID: + pwk_cipher_tlv = (tlvbuf_pwk_cipher *)pcurrent_tlv; + pwk_cipher_tlv->protocol = + uap_le16_to_cpu(pwk_cipher_tlv->protocol); + if (pwk_cipher_tlv->protocol == PROTOCOL_WPA) + pairwise_cipher_wpa = + pwk_cipher_tlv->pairwise_cipher; + else if (pwk_cipher_tlv->protocol == PROTOCOL_WPA2) + pairwise_cipher_wpa2 = + pwk_cipher_tlv->pairwise_cipher; + break; + case MRVL_CIPHER_GWK_TLV_ID: + gwk_cipher_tlv = (tlvbuf_gwk_cipher *)pcurrent_tlv; + group_cipher = gwk_cipher_tlv->group_cipher; + break; + case MRVL_AUTH_TLV_ID: + auth_tlv = (tlvbuf_auth_mode *)pcurrent_tlv; + break; + case MRVL_PROTOCOL_TLV_ID: + protocol_tlv = (tlvbuf_protocol *)pcurrent_tlv; + protocol = uap_le16_to_cpu(protocol_tlv->protocol); + break; + case MRVL_WPA_PASSPHRASE_TLV_ID: + passphrase_tlv = (tlvbuf_wpa_passphrase *)pcurrent_tlv; + break; + case MRVL_WEP_KEY_TLV_ID: + wep_key_tlv = (tlvbuf_wep_key *)pcurrent_tlv; + if (wep_key_tlv->is_default) { + key_set = 1; + } + break; + case HT_CAPABILITY_TLV_ID: + ht_cap_tlv = (tlvbuf_htcap_t *)pcurrent_tlv; + ht_cap_tlv->ht_cap.ht_cap_info = + uap_le16_to_cpu(ht_cap_tlv->ht_cap.ht_cap_info); + if (ht_cap_tlv->ht_cap.supported_mcs_set[0]) { + enable_11n = 1; + enable_40Mhz = + IS_11N_40MHZ_ENABLED(ht_cap_tlv->ht_cap. + ht_cap_info); + enable_20Mhz_sgi = + IS_11N_20MHZ_SHORTGI_ENABLED + (ht_cap_tlv->ht_cap.ht_cap_info); + enable_gf = + IS_11N_GF_ENABLED(ht_cap_tlv->ht_cap. + ht_cap_info); + } + break; + case MRVL_RATES_TLV_ID: + rates_tlv = (tlvbuf_rates *)pcurrent_tlv; + op_rates_len = tlv_len; + break; + case MRVL_MCBC_DATA_RATE_TLV_ID: + mcbc_data_rate_tlv = + (tlvbuf_mcbc_data_rate *)pcurrent_tlv; + mcbc_data_rate = + uap_le16_to_cpu(mcbc_data_rate_tlv-> + mcbc_datarate); + if (mcbc_data_rate && + (is_mcbc_rate_valid((t_u8)mcbc_data_rate) != + UAP_SUCCESS)) { + printf("ERR: Invalid MCBC Data Rate \n"); + return UAP_FAILURE; + } + break; + } + tlv_buf_left -= (sizeof(tlvbuf_header) + tlv_len); + pcurrent_tlv = (tlvbuf_header *)(pcurrent_tlv->data + tlv_len); + } + + if ((protocol == PROTOCOL_STATIC_WEP) && !key_set) { + printf("ERR:WEP keys not set!\n"); + return UAP_FAILURE; + } + if (auth_tlv == NULL) { + printf("ERR: No authentication found\n"); + return UAP_FAILURE; + } + if ((auth_tlv->auth_mode == 1) && (protocol != PROTOCOL_STATIC_WEP)) { + printf("ERR:Shared key authentication is not allowed for Open/WPA/WPA2/Mixed mode\n"); + return UAP_FAILURE; + } + + if (passphrase_tlv == NULL) { + printf("ERR: No passphrase found\n"); + return UAP_FAILURE; + } + if (((protocol == PROTOCOL_WPA) || (protocol == PROTOCOL_WPA2) + || (protocol == PROTOCOL_WPA3_SAE) + || (protocol == PROTOCOL_WPA2_MIXED)) + && !(passphrase_tlv->length)) { + printf("ERR:Passphrase must be set for WPA/WPA2/Mixed/WPA3 SAE mode\n"); + return UAP_FAILURE; + } + if ((protocol == PROTOCOL_WPA) || (protocol == PROTOCOL_WPA2_MIXED)) { + if (is_cipher_valid(pairwise_cipher_wpa, group_cipher) != + UAP_SUCCESS) { + printf("ERR:Wrong group cipher and WPA pairwise cipher combination!\n"); + return UAP_FAILURE; + } + } + if ((protocol == PROTOCOL_WPA2) || (protocol == PROTOCOL_WPA2_MIXED) + || (protocol == PROTOCOL_WPA3_SAE) + ) { + if (is_cipher_valid(pairwise_cipher_wpa2, group_cipher) != + UAP_SUCCESS) { + printf("ERR:Wrong group cipher and WPA2 pairwise cipher combination!\n"); + return UAP_FAILURE; + } + } + + if (chnlist_tlv == NULL) { + printf("ERR: No channel list found\n"); + return UAP_FAILURE; + } + if (acs_mode_enabled) { + pchan_list = (channel_list *) & (chnlist_tlv->chan_list); + for (i = 0; i < chan_list_len; i++) { + if ((!state_80211d) && + (pchan_list->chan_number == MAX_CHANNELS_BG) + && + (strncmp(country_80211d, "JP", COUNTRY_CODE_LEN - 1) + == 0) + ) { + printf("ERR: Invalid scan channel 14, 802.11d disabled, country code JP!\n"); + return UAP_FAILURE; + } + + if (fw.region_code == JP_REGION_0xFE && + ((pchan_list->chan_number == 12) || + (pchan_list->chan_number == 13))) { + printf("ERR:Scan Channel 12 or 13 is not allowed for region code 0xFE\n"); + return UAP_FAILURE; + } + pchan_list++; + } + + if (!state_80211d) { + /* Block scan channels 8 and 12 in 5GHz band if 11d is not enabled and country code not set to JP */ + pchan_list = + (channel_list *) & (chnlist_tlv->chan_list); + for (i = 0; i < chan_list_len; i++) { + if ((pchan_list->bandcfg.chanBand == BAND_5GHZ) + && ((pchan_list->chan_number == 8) || + (pchan_list->chan_number == 12))) { + printf("ERR: Invalid band for scan channel %d\n", pchan_list->chan_number); + return UAP_FAILURE; + } + pchan_list++; + } + } + if (state_80211d) { + /* Set default country code to US */ + strncpy(country_80211d, "US ", + sizeof(country_80211d) - 1); + pchan_list = + (channel_list *) & (chnlist_tlv->chan_list); + for (i = 0; i < chan_list_len; i++) { + /* Set country code to JP if channel is 8 or 12 and band is 5GHZ */ + if ((pchan_list->chan_number < MAX_CHANNELS_BG) + && (scan_channels_band == BAND_A)) { + strncpy(country_80211d, "JP ", + sizeof(country_80211d) - 1); + } + if (check_channel_validity_11d + (pchan_list->chan_number, + scan_channels_band, 0) == UAP_FAILURE) + return UAP_FAILURE; + pchan_list++; + } + if (update_domain_info + (country_80211d, + scan_channels_band) == UAP_FAILURE) { + return UAP_FAILURE; + } + } + } +#ifdef WIFI_DIRECT_SUPPORT + if (strncmp(dev_name, "wfd", 3)) +#endif + if ((!acs_mode_enabled && + (channel_tlv_band == (BAND_B | BAND_G))) + || (acs_mode_enabled && + (scan_channels_band == (BAND_B | BAND_G)))) { + if (rates_tlv == NULL) { + printf("ERR: No rates found\n"); + return UAP_FAILURE; + } + for (i = 0; i < op_rates_len; i++) { + rate = rates_tlv-> + operational_rates[i] & + ~BASIC_RATE_SET_BIT; + switch (rate) { + case 2: + rate_bitmap |= BITMAP_RATE_1M; + break; + case 4: + rate_bitmap |= BITMAP_RATE_2M; + break; + case 11: + rate_bitmap |= BITMAP_RATE_5_5M; + break; + case 22: + rate_bitmap |= BITMAP_RATE_11M; + break; + } + } + if ((rate_bitmap & B_RATE_MANDATORY) != + B_RATE_MANDATORY) { + if (acs_mode_enabled) + printf("ERR: Rates/Scan channels do not match!\n"); + else + printf("ERR: Rates/Channel do not match!\n"); + return UAP_FAILURE; + } + } + if ((!acs_mode_enabled && (channel_tlv_band == BAND_A)) + || (acs_mode_enabled && (scan_channels_band == BAND_A))) { + if (rates_tlv == NULL) { + printf("ERR: No rates found\n"); + return UAP_FAILURE; + } + for (i = 0; i < op_rates_len; i++) { + rate = rates_tlv-> + operational_rates[i] & ~BASIC_RATE_SET_BIT; + switch (rate) { + case 2: + case 4: + case 11: + case 22: + if (acs_mode_enabled) + printf("ERR: Rates/Scan channels do not match!\n"); + else + printf("ERR: Rates/Channel do not match!\n"); + return UAP_FAILURE; + } + } + state_80211h = 1; + if (sg_snmp_mib + (ACTION_SET, OID_80211H_ENABLE, sizeof(state_80211h), + &state_80211h) + == UAP_FAILURE) { + return UAP_FAILURE; + } + if (update_domain_info(country_80211d, BAND_A) == UAP_FAILURE) { + return UAP_FAILURE; + } + } +#define ISSUPP_CHANWIDTH40(Dot11nDevCap) (Dot11nDevCap & MBIT(17)) +#define ISSUPP_SHORTGI40(Dot11nDevCap) (Dot11nDevCap & MBIT(24)) + + if (enable_40Mhz) { + if (!ISSUPP_CHANWIDTH40(fw.hw_dot_11n_dev_cap)) { + printf("ERR: It's not support HT40 from Hardware Cap\n"); + return UAP_FAILURE; + } + } + + if (enable_11n) { + /*For protocol = Mixed, 11n enabled, only allow TKIP cipher for WPA protocol, not for WPA2 */ + if ((protocol == PROTOCOL_WPA2_MIXED) && + (pairwise_cipher_wpa2 == CIPHER_TKIP)) { + printf("ERR: WPA2 pairwise cipher cannot be TKIP when AP operates in 802.11n Mixed mode.\n"); + return UAP_FAILURE; + } else if (protocol == PROTOCOL_STATIC_WEP) { + printf("ERR: WEP cannot be used when AP operates in 802.11n mode.\n"); + return UAP_FAILURE; + } + } + if ((tx_rate_config.rate == UAP_RATE_INDEX_MCS32) && !enable_40Mhz) { + printf("ERR:uAP must be configured to operate in 40MHz if tx_rate is MCS32\n"); + return UAP_FAILURE; + } + if (enable_20Mhz_sgi && enable_gf) { + if ((tx_rate_config.rate >= UAP_RATE_INDEX_MCS0) && + (tx_rate_config.rate <= UAP_RATE_INDEX_MCS7)) { + printf("ERR: Invalid tx_rate for uAP in (20MHz Short GI + Green Field) mode\n"); + return UAP_FAILURE; + } + } + mcs_rate_index = + get_rate_index_from_bitmap(tx_rate_config.bitmap_rates, + sizeof(tx_rate_config.bitmap_rates)); + if ((mcs_rate_index >= UAP_RATE_BITMAP_MCS0) && + (mcs_rate_index <= UAP_RATE_BITMAP_MCS127)) { + mcs_rate_index -= (UAP_RATE_BITMAP_MCS0 - UAP_RATE_INDEX_MCS0); + if ((mcs_rate_index == UAP_RATE_INDEX_MCS32) & !enable_40Mhz) { + printf("ERR:uAP must be configured to operate in 40MHz if rate_bitmap contains MCS32\n"); + return UAP_FAILURE; + } + if (enable_20Mhz_sgi && enable_gf) { + if ((mcs_rate_index >= UAP_RATE_INDEX_MCS0) && + (mcs_rate_index <= UAP_RATE_INDEX_MCS7)) { + printf("ERR: Invalid tx_rate for uAP in (20MHz Short GI + Green Field) mode\n"); + return UAP_FAILURE; + } + } + } + + /* if 11d enabled, Channel 14, country code "JP", only B rates are allowed */ + if ((channel == 14) && state_80211d && + (strncmp(country_80211d, "JP", COUNTRY_CODE_LEN - 1) == 0)) { + if (rates_tlv == NULL) { + printf("ERR:No rates found\n"); + return UAP_FAILURE; + } + if (enable_11n) { + printf("ERR:11n must be disabled and the only B rates are allowed if 11d enabled and country code is JP with channel 14.\n"); + return UAP_FAILURE; + } + for (i = 0; i < op_rates_len; i++) { + rate = rates_tlv-> + operational_rates[i] & ~BASIC_RATE_SET_BIT; + switch (rate) { + case 2: + case 4: + case 11: + case 22: + break; + default: + printf("ERR:If 11d enabled, channel 14 and country code is JP, the only B rates are allowed.\n"); + return UAP_FAILURE; + } + } + } + + /* Channels 14, 165 are not allowed to operate in 40MHz mode */ + if (!acs_mode_enabled && enable_40Mhz) { + if ((channel == 14) + || (channel == 165) + ) { + printf("ERR:Invalid channel %d for 40MHz operation\n", + channel); + return UAP_FAILURE; + } else if (!secondary_ch_set) { + printf("ERR:Secondary channel should be set when 40Mhz is enabled!\n"); + return UAP_FAILURE; + } + } + /* Channels 14, 140, 165 are not allowed to operate in 40MHz mode */ + if (acs_mode_enabled && enable_40Mhz) { + if (chnlist_tlv == NULL) { + printf("ERR: No channel list found\n"); + return UAP_FAILURE; + } + pchan_list = (channel_list *) & (chnlist_tlv->chan_list); + for (i = 0; i < chan_list_len; i++) { + if ((pchan_list->chan_number != 14) + && (pchan_list->chan_number != 140) && + (pchan_list->chan_number != 165) + ) { + flag = 1; + break; + } + pchan_list++; + } + if (!flag) { + printf("ERR:Invalid channels in scan channel list for 40MHz operation\n"); + return UAP_FAILURE; + } + } + + if (0 == get_fw_info(&fw)) { + /*check whether support 802.11AC through BAND_AAC bit */ + if (fw.fw_bands & BAND_AAC) { + ret = get_802_11ac_cfg(&vhtcfg); + if (UAP_SUCCESS == ret) { + /* Note: When 11AC is disabled, FW sets vht_rx_mcs to 0xffff */ + if ((vhtcfg.vht_rx_mcs != 0xffff) && + (!enable_11n)) { + printf("ERR: 11ac enable while 11n disable, it is forbidden! \n"); + return UAP_FAILURE; + } + } else { + printf("Don't support 802.11AC \n"); + return UAP_SUCCESS; + } + } else + printf("No support 802 11AC.\n"); + } else { + printf("ERR: get_fw_info fail\n"); + return UAP_FAILURE; + } + + return ret; +} + +/** + * @brief Checks current bss configuration + * + * @param buf pointer to bss_config_t + * @return UAP_SUCCESS/UAP_FAILURE + */ +int +check_bss_config(t_u8 *buf) +{ + bss_config_t *bss_config = NULL;; + t_u8 acs_mode_enabled = 0; + t_u8 *cbuf = NULL; + apcmdbuf_cfg_80211d *cmd_buf = NULL; + t_u16 buf_len, cmd_len; + char country_80211d[4] = { 'U', 'S', ' ', 0 }; + t_u8 state_80211h = 0; + int channel_tlv_band = BAND_B | BAND_G; + t_u8 secondary_ch_set = 0; + int scan_channels_band = BAND_B | BAND_G; + t_u8 state_80211d = 0; + t_u8 rate = 0; + t_u32 rate_bitmap = 0; + t_u16 enable_40Mhz = 0; + t_u16 enable_20Mhz_sgi = 0; + t_u16 enable_gf = 0; + t_u8 enable_11n = 0; + int flag = 0; + fw_info fw; + int i = 0, ret = UAP_SUCCESS; + tx_rate_cfg_t tx_rate_config; + t_u32 mcs_rate_index = 0; + struct eth_priv_vhtcfg vhtcfg = { 0 }; + +#define BITMAP_RATE_1M 0x01 +#define BITMAP_RATE_2M 0x02 +#define BITMAP_RATE_5_5M 0x04 +#define BITMAP_RATE_11M 0x8 +#define B_RATE_MANDATORY 0x0f + + if (NULL == buf) { + printf("ERR: No buffer for bss_configure!\n"); + return UAP_FAILURE; + } + + bss_config = (bss_config_t *)buf; + + ret = sg_snmp_mib(ACTION_GET, OID_80211D_ENABLE, sizeof(state_80211d), + &state_80211d); + + buf_len = MRVDRV_SIZE_OF_CMD_BUFFER; + cbuf = (t_u8 *)malloc(buf_len); + if (!cbuf) { + printf("ERR:Cannot allocate buffer from command!\n"); + return UAP_FAILURE; + } + memset(cbuf, 0, buf_len); + /* Locate headers */ + cmd_buf = (apcmdbuf_cfg_80211d *)cbuf; + cmd_len = (sizeof(apcmdbuf_cfg_80211d) - sizeof(domain_param_t)); + cmd_buf->size = cmd_len - BUF_HEADER_SIZE; + cmd_buf->action = uap_cpu_to_le16(ACTION_GET); + cmd_buf->cmd_code = HostCmd_CMD_802_11D_DOMAIN_INFO; + ret = uap_ioctl((t_u8 *)cmd_buf, &cmd_len, buf_len); + if (ret == UAP_SUCCESS && cmd_buf->result == CMD_SUCCESS) { + if (cmd_buf->domain.country_code[0] || + cmd_buf->domain.country_code[1] || + cmd_buf->domain.country_code[2]) { + strncpy(country_80211d, + (char *)cmd_buf->domain.country_code, + COUNTRY_CODE_LEN); + } + } + free(cbuf); + + /* get region code to handle special cases */ + memset(&fw, 0, sizeof(fw)); + if (get_fw_info(&fw)) { + printf("Could not get fw info!\n"); + return UAP_FAILURE; + } + + if (get_tx_rate_cfg(&tx_rate_config) == UAP_FAILURE) { + printf("Could not get tx_rate_cfg!\n"); + return UAP_FAILURE; + } + + if ((!state_80211d) && (bss_config->channel == MAX_CHANNELS_BG) + && (strncmp(country_80211d, "JP", COUNTRY_CODE_LEN - 1) == 0) + ) { + printf("ERR: Invalid channel 14, 802.11d disabled, country code JP!\n"); + return UAP_FAILURE; + } + + if ((fw.fw_bands & (BAND_B | BAND_G | BAND_GN | BAND_GAC)) + && !(fw.fw_bands & (BAND_A | BAND_AAC)) + ) { + if (bss_config->channel > MAX_CHANNELS_BG) { + printf("ERR: Invalid channel in 2.4GHz band!\n"); + return UAP_FAILURE; + } + } + + if (!(fw.fw_bands & (BAND_B | BAND_G | BAND_GN + | BAND_GAC)) && (fw.fw_bands & (BAND_A + | BAND_AAC))) { + if (bss_config->channel < 36 || + bss_config->channel > MAX_CHANNELS) { + printf("ERR: Invalid channel in 5GHz band!\n"); + return UAP_FAILURE; + } + } + if (bss_config->bandcfg.chanBand == BAND_5GHZ) + channel_tlv_band = BAND_A; + secondary_ch_set = bss_config->bandcfg.chan2Offset; + if (channel_tlv_band != BAND_A) { + /* When country code is not Japan, allow channels 5-11 for US and 5-13 for non-US + * only for secondary channel below */ + if (secondary_ch_set == SEC_CHAN_BELOW) { + if (!strncmp + (country_80211d, "US", COUNTRY_CODE_LEN - 1)) { + if (bss_config->channel > + DEFAULT_MAX_CHANNEL_BELOW) { + printf("ERR: Only channels 5-11 are allowed with secondary channel below for the US\n"); + return UAP_FAILURE; + } + } else if (strncmp + (country_80211d, "JP", + COUNTRY_CODE_LEN - 1)) { + if (bss_config->channel > + DEFAULT_MAX_CHANNEL_BELOW_NON_US) { + printf("ERR: Only channels 5-13 are allowed with secondary channel below for" "non-Japan countries!\n"); + return UAP_FAILURE; + } + } + } + + /* When country code is not Japan, allow channels 1-7 for US and 1-9 for non-US + * only for secondary channel above */ + if (secondary_ch_set == SEC_CHAN_ABOVE) { + if (!strncmp + (country_80211d, "US", COUNTRY_CODE_LEN - 1)) { + if (bss_config->channel > + DEFAULT_MAX_CHANNEL_ABOVE) { + printf("ERR: Only channels 1-7 are allowed with secondary channel above for the US\n"); + return UAP_FAILURE; + } + } else if (strncmp + (country_80211d, "JP", + COUNTRY_CODE_LEN - 1)) { + if (bss_config->channel > + DEFAULT_MAX_CHANNEL_ABOVE_NON_US) { + printf("ERR: Only channels 1-9 are allowed with secondary channel above for" "non-Japan countries!\n"); + return UAP_FAILURE; + } + } + } + } + + if (!(bss_config->bandcfg.scanMode == SCAN_MODE_ACS)) { + if (check_channel_validity_11d + (bss_config->channel, channel_tlv_band, 1) == UAP_FAILURE) + return UAP_FAILURE; + if (state_80211d) { + /* Set country code to JP if channel is 8 or 12 and band is 5GHZ */ + if ((bss_config->channel < MAX_CHANNELS_BG) && + (channel_tlv_band == BAND_A)) + strncpy(country_80211d, "JP ", + sizeof(country_80211d) - 1); + } else { + if ((channel_tlv_band == BAND_A) && + ((bss_config->channel == 8) || + (bss_config->channel == 12))) { + printf("ERR:Invalid band for given channel\n"); + return UAP_FAILURE; + } + } + } else { + acs_mode_enabled = 1; + } + +#define JP_REGION_0xFE 0xFE + if (fw.region_code == JP_REGION_0xFE && + ((bss_config->channel == 12) || (bss_config->channel == 13))) { + printf("ERR:Channel 12 or 13 is not allowed for region code 0xFE\n"); + return UAP_FAILURE; + } + + for (i = 0; i < bss_config->num_of_chan; i++) { + scan_channels_band = BAND_B | BAND_G; + if ((scan_channels_band != BAND_A) && + (bss_config->chan_list[i].bandcfg.chanBand == BAND_5GHZ)) { + scan_channels_band = BAND_A; + } + if (check_channel_validity_11d + (bss_config->chan_list[i].chan_number, scan_channels_band, + 0) == UAP_FAILURE) + return UAP_FAILURE; + } + + if (state_80211d) { + if (check_tx_pwr_validity_11d(bss_config->tx_power_level) == + UAP_FAILURE) + return UAP_FAILURE; + } + + if (bss_config->supported_mcs_set[0]) { + enable_11n = 1; + enable_40Mhz = IS_11N_40MHZ_ENABLED(bss_config->ht_cap_info); + enable_20Mhz_sgi = + IS_11N_20MHZ_SHORTGI_ENABLED(bss_config->ht_cap_info); + enable_gf = IS_11N_GF_ENABLED(bss_config->ht_cap_info); + } + + if (bss_config->mcbc_data_rate && + (is_mcbc_rate_valid(bss_config->mcbc_data_rate) != UAP_SUCCESS)) { + printf("ERR: Invalid MCBC Data Rate \n"); + return UAP_FAILURE; + } + + if ((bss_config->protocol == PROTOCOL_STATIC_WEP) + && (0 == bss_config->wep_cfg.key0.is_default) + && (0 == bss_config->wep_cfg.key1.is_default) + && (0 == bss_config->wep_cfg.key2.is_default) + && (0 == bss_config->wep_cfg.key3.is_default)) { + printf("ERR:WEP keys not set!\n"); + return UAP_FAILURE; + } + + if ((bss_config->auth_mode == 1) && + (bss_config->protocol != PROTOCOL_STATIC_WEP)) { + printf("ERR:Shared key authentication is not allowed for Open/WPA/WPA2/Mixed mode\n"); + return UAP_FAILURE; + } + + if (((bss_config->protocol == PROTOCOL_WPA) || + (bss_config->protocol == PROTOCOL_WPA2) + || (bss_config->protocol == PROTOCOL_WPA3_SAE) + || (bss_config->protocol == PROTOCOL_WPA2_MIXED)) && + !(bss_config->wpa_cfg.length)) { + printf("ERR:Passphrase must be set for WPA/WPA2/Mixed/WPA3 SAE mode\n"); + return UAP_FAILURE; + } + + if ((bss_config->protocol == PROTOCOL_WPA) || + (bss_config->protocol == PROTOCOL_WPA2_MIXED)) { + if (is_cipher_valid + (bss_config->wpa_cfg.pairwise_cipher_wpa, + bss_config->wpa_cfg.group_cipher) != UAP_SUCCESS) { + printf("ERR:Wrong group cipher and WPA pairwise cipher combination!\n"); + return UAP_FAILURE; + } + } + if ((bss_config->protocol == PROTOCOL_WPA2) || + (bss_config->protocol == PROTOCOL_WPA2_MIXED) + || (bss_config->protocol == PROTOCOL_WPA3_SAE) + ) { + if (is_cipher_valid + (bss_config->wpa_cfg.pairwise_cipher_wpa2, + bss_config->wpa_cfg.group_cipher) != UAP_SUCCESS) { + printf("ERR:Wrong group cipher and WPA2 pairwise cipher combination!\n"); + return UAP_FAILURE; + } + } + + if (0 == bss_config->num_of_chan) { + printf("ERR: No channel list found\n"); + return UAP_FAILURE; + } + + if (acs_mode_enabled) { + for (i = 0; i < bss_config->num_of_chan; i++) { + if ((!state_80211d) && + (bss_config->chan_list[i].chan_number == + MAX_CHANNELS_BG) + && + (strncmp(country_80211d, "JP", COUNTRY_CODE_LEN - 1) + == 0) + ) { + printf("ERR: Invalid scan channel 14, 802.11d disabled, country code JP!\n"); + return UAP_FAILURE; + } + + if (fw.region_code == JP_REGION_0xFE && + ((bss_config->chan_list[i].chan_number == 12) || + (bss_config->chan_list[i].chan_number == 13))) { + printf("ERR:Scan Channel 12 or 13 is not allowed for region code 0xFE\n"); + return UAP_FAILURE; + } + } + + if (!state_80211d) { + /* Block scan channels 8 and 12 in 5GHz band if 11d is not enabled and country code not set to JP */ + for (i = 0; i < bss_config->num_of_chan; i++) { + if ((bss_config->chan_list[i].bandcfg. + chanBand == BAND_5GHZ) + && + ((bss_config->chan_list[i].chan_number == 8) + || (bss_config->chan_list[i].chan_number == + 12))) { + printf("ERR: Invalid band for scan channel %d\n", bss_config->chan_list[i].chan_number); + return UAP_FAILURE; + } + } + } + + if (state_80211d) { + /* Set default country code to US */ + strncpy(country_80211d, "US ", + sizeof(country_80211d) - 1); + for (i = 0; i < bss_config->num_of_chan; i++) { + /* Set country code to JP if channel is 8 or 12 and band is 5GHZ */ + if ((bss_config->chan_list[i].chan_number < + MAX_CHANNELS_BG) && + (scan_channels_band == BAND_A)) { + strncpy(country_80211d, "JP ", + sizeof(country_80211d) - 1); + } + if (check_channel_validity_11d + (bss_config->chan_list[i].chan_number, + scan_channels_band, 0) == UAP_FAILURE) + return UAP_FAILURE; + } + if (update_domain_info + (country_80211d, + scan_channels_band) == UAP_FAILURE) { + return UAP_FAILURE; + } + } + } +#ifdef WIFI_DIRECT_SUPPORT + if (strncmp(dev_name, "wfd", 3)) +#endif + if ((!acs_mode_enabled && + (channel_tlv_band == (BAND_B | BAND_G))) + || (acs_mode_enabled && + (scan_channels_band == (BAND_B | BAND_G)))) { + if (0 == bss_config->rates[0]) { + printf("ERR: No rates found\n"); + return UAP_FAILURE; + } + for (i = 0; i < MAX_DATA_RATES && bss_config->rates[i]; + i++) { + rate = bss_config-> + rates[i] & ~BASIC_RATE_SET_BIT; + switch (rate) { + case 2: + rate_bitmap |= BITMAP_RATE_1M; + break; + case 4: + rate_bitmap |= BITMAP_RATE_2M; + break; + case 11: + rate_bitmap |= BITMAP_RATE_5_5M; + break; + case 22: + rate_bitmap |= BITMAP_RATE_11M; + break; + } + } + if ((rate_bitmap & B_RATE_MANDATORY) != + B_RATE_MANDATORY) { + if (acs_mode_enabled) + printf("ERR: Rates/Scan channels do not match!\n"); + else + printf("ERR: Rates/Channel do not match!\n"); + return UAP_FAILURE; + } + } + if ((!acs_mode_enabled && (channel_tlv_band == BAND_A)) + || (acs_mode_enabled && (scan_channels_band == BAND_A))) { + if (0 == bss_config->rates[0]) { + printf("ERR: No rates found\n"); + return UAP_FAILURE; + } + for (i = 0; i < MAX_DATA_RATES && bss_config->rates[i]; i++) { + rate = bss_config->rates[i] & ~BASIC_RATE_SET_BIT; + switch (rate) { + case 2: + case 4: + case 11: + case 22: + if (acs_mode_enabled) + printf("ERR: Rates/Scan channels do not match!\n"); + else + printf("ERR: Rates/Channel do not match!\n"); + return UAP_FAILURE; + } + } + state_80211h = 1; + if (sg_snmp_mib + (ACTION_SET, OID_80211H_ENABLE, sizeof(state_80211h), + &state_80211h) + == UAP_FAILURE) { + return UAP_FAILURE; + } + if (update_domain_info(country_80211d, BAND_A) == UAP_FAILURE) { + return UAP_FAILURE; + } + } +#define ISSUPP_CHANWIDTH40(Dot11nDevCap) (Dot11nDevCap & MBIT(17)) +#define ISSUPP_SHORTGI40(Dot11nDevCap) (Dot11nDevCap & MBIT(24)) + + if (enable_40Mhz) { + if (!ISSUPP_CHANWIDTH40(fw.hw_dot_11n_dev_cap)) { + printf("ERR: It's not support HT40 from Hardware Cap\n"); + return UAP_FAILURE; + } + } + + if (enable_11n) { + /*For protocol = Mixed, 11n enabled, only allow TKIP cipher for WPA protocol, not for WPA2 */ + if ((bss_config->protocol == PROTOCOL_WPA2_MIXED) && + (bss_config->wpa_cfg.pairwise_cipher_wpa2 == CIPHER_TKIP)) { + printf("ERR: WPA2 pairwise cipher cannot be TKIP when AP operates in 802.11n Mixed mode.\n"); + return UAP_FAILURE; + } else if (bss_config->protocol == PROTOCOL_STATIC_WEP) { + printf("ERR: WEP cannot be used when AP operates in 802.11n mode.\n"); + return UAP_FAILURE; + } + } + if ((tx_rate_config.rate == UAP_RATE_INDEX_MCS32) && !enable_40Mhz) { + printf("ERR:uAP must be configured to operate in 40MHz if tx_rate is MCS32\n"); + return UAP_FAILURE; + } + if (enable_20Mhz_sgi && enable_gf) { + if ((tx_rate_config.rate >= UAP_RATE_INDEX_MCS0) && + (tx_rate_config.rate <= UAP_RATE_INDEX_MCS7)) { + printf("ERR: Invalid tx_rate for uAP in (20MHz Short GI + Green Field) mode\n"); + return UAP_FAILURE; + } + } + mcs_rate_index = + get_rate_index_from_bitmap(tx_rate_config.bitmap_rates, + sizeof(tx_rate_config.bitmap_rates)); + if ((mcs_rate_index >= UAP_RATE_BITMAP_MCS0) && + (mcs_rate_index <= UAP_RATE_BITMAP_MCS127)) { + mcs_rate_index -= (UAP_RATE_BITMAP_MCS0 - UAP_RATE_INDEX_MCS0); + if ((mcs_rate_index == UAP_RATE_INDEX_MCS32) & !enable_40Mhz) { + printf("ERR:uAP must be configured to operate in 40MHz if rate_bitmap contains MCS32\n"); + return UAP_FAILURE; + } + if (enable_20Mhz_sgi && enable_gf) { + if ((mcs_rate_index >= UAP_RATE_INDEX_MCS0) && + (mcs_rate_index <= UAP_RATE_INDEX_MCS7)) { + printf("ERR: Invalid tx_rate for uAP in (20MHz Short GI + Green Field) mode\n"); + return UAP_FAILURE; + } + } + } + +/* if 11d enabled, Channel 14, country code "JP", only B rates are allowed*/ + if ((bss_config->channel == 14) && state_80211d && + (strncmp(country_80211d, "JP", COUNTRY_CODE_LEN - 1) == 0)) { + if (0 == bss_config->rates[0]) { + printf("ERR:No rates found\n"); + return UAP_FAILURE; + } + if (enable_11n) { + printf("ERR:11n must be disabled and the only B rates are allowed if 11d enabled and country code is JP with channel 14.\n"); + return UAP_FAILURE; + } + for (i = 0; i < MAX_DATA_RATES && bss_config->rates[i]; i++) { + rate = bss_config->rates[i] & ~BASIC_RATE_SET_BIT; + switch (rate) { + case 2: + case 4: + case 11: + case 22: + break; + default: + printf("ERR:If 11d enabled, channel 14 and country code is JP, the only B rates are allowed.\n"); + return UAP_FAILURE; + } + } + } + + /* Channels 14, 165 are not allowed to operate in 40MHz mode */ + if (!acs_mode_enabled && enable_40Mhz) { + if ((bss_config->channel == 14) + || (bss_config->channel == 165) + ) { + printf("ERR:Invalid channel %d for 40MHz operation\n", + bss_config->channel); + return UAP_FAILURE; + } else if (!secondary_ch_set) { + printf("ERR:Secondary channel should be set when 40Mhz is enabled!\n"); + return UAP_FAILURE; + } + } +/* Channels 14, 140, 165 are not allowed to operate in 40MHz mode */ + if (acs_mode_enabled && enable_40Mhz) { + if (bss_config->num_of_chan == 0) { + printf("ERR: No channel list found\n"); + return UAP_FAILURE; + } + for (i = 0; i < bss_config->num_of_chan; i++) { + if ((bss_config->chan_list[i].chan_number != 14) + && (bss_config->chan_list[i].chan_number != 140) && + (bss_config->chan_list[i].chan_number != 165) + ) { + flag = 1; + break; + } + } + if (!flag) { + printf("ERR:Invalid channels in scan channel list for 40MHz operation\n"); + return UAP_FAILURE; + } + } + + if (0 == get_fw_info(&fw)) { + /*check whether support 802.11AC through BAND_AAC bit */ + if (fw.fw_bands & BAND_AAC) { + ret = get_802_11ac_cfg(&vhtcfg); + if (UAP_SUCCESS == ret) { + /* Note: When 11AC is disabled, FW sets vht_rx_mcs to 0xffff */ + if ((vhtcfg.vht_rx_mcs != 0xffff) && + (!enable_11n)) { + printf("ERR: 11ac enable while 11n disable, it is forbidden! \n"); + return UAP_FAILURE; + } + } else { + printf("Don't support 802.11AC \n"); + return UAP_SUCCESS; + } + } else + printf("No support 802 11AC.\n"); + } else { + printf("ERR: get_fw_info fail\n"); + return UAP_FAILURE; + } + + return ret; +} + +/** + * @brief Send read/write command along with register details to the driver + * @param reg Reg type + * @param offset Pointer to register offset string + * @param strvalue Pointer to value string + * @return UAP_SUCCESS or UAP_FAILURE + */ +int +apcmd_regrdwr_process(int reg, char *offset, char *strvalue) +{ + apcmdbuf_reg_rdwr *cmd_buf = NULL; + t_u8 *buf = NULL; + t_u16 cmd_len = 0; + t_u16 buf_len = MRVDRV_SIZE_OF_CMD_BUFFER; + int ret = UAP_SUCCESS; + char *whichreg; + + /* Alloc buf for command */ + buf = (t_u8 *)malloc(buf_len); + if (!buf) { + printf("ERR:Cannot allocate buffer for command!\n"); + return UAP_FAILURE; + } + memset(buf, 0, buf_len); + + /* Locate headers */ + cmd_len = sizeof(apcmdbuf_reg_rdwr); + cmd_buf = (apcmdbuf_reg_rdwr *)buf; + + /* Fill the command buffer */ + cmd_buf->size = cmd_len - BUF_HEADER_SIZE; + cmd_buf->seq_num = 0; + cmd_buf->result = 0; + + switch (reg) { + case CMD_MAC: + whichreg = "MAC"; + cmd_buf->cmd_code = HostCmd_CMD_MAC_REG_ACCESS; + break; + case CMD_BBP: + whichreg = "BBP"; + cmd_buf->cmd_code = HostCmd_CMD_BBP_REG_ACCESS; + break; + case CMD_RF: + cmd_buf->cmd_code = HostCmd_CMD_RF_REG_ACCESS; + whichreg = "RF"; + break; + default: + printf("Invalid register set specified.\n"); + free(buf); + return UAP_FAILURE; + } + if (strvalue) { + cmd_buf->action = 1; // WRITE + } else { + cmd_buf->action = 0; // READ + } + cmd_buf->action = uap_cpu_to_le16(cmd_buf->action); + cmd_buf->offset = A2HEXDECIMAL(offset); + cmd_buf->offset = uap_cpu_to_le16(cmd_buf->offset); + if (strvalue) { + cmd_buf->value = A2HEXDECIMAL(strvalue); + cmd_buf->value = uap_cpu_to_le32(cmd_buf->value); + } + + /* Send the command */ + ret = uap_ioctl((t_u8 *)cmd_buf, &cmd_len, buf_len); + + /* Process response */ + if (ret == UAP_SUCCESS) { + if (cmd_buf->result == CMD_SUCCESS) { + printf("Successfully executed the command\n"); + printf("%s[0x%04hx] = 0x%08x\n", + whichreg, uap_le16_to_cpu(cmd_buf->offset), + uap_le32_to_cpu(cmd_buf->value)); + } else { + printf("ERR:Command sending failed!\n"); + free(buf); + return UAP_FAILURE; + } + } else { + printf("ERR:Command sending failed!\n"); + free(buf); + return UAP_FAILURE; + } + + free(buf); + return UAP_SUCCESS; +} + +/** + * @brief Send read command for EEPROM + * + * Usage: "Usage : rdeeprom " + * + * @param argc Number of arguments + * @param argv Pointer to the arguments + * @return UAP_SUCCESS/UAP_FAILURE + */ +int +apcmd_read_eeprom(int argc, char *argv[]) +{ + apcmdbuf_eeprom_access *cmd_buf = NULL; + t_u8 *buf = NULL; + t_u16 cmd_len = 0; + t_u16 buf_len = MRVDRV_SIZE_OF_CMD_BUFFER; + t_u16 byte_count, offset; + int ret = UAP_SUCCESS; + int opt; + while ((opt = getopt_long(argc, argv, "+", cmd_options, NULL)) != -1) { + switch (opt) { + default: + print_apcmd_read_eeprom_usage(); + return UAP_FAILURE; + } + } + argc -= optind; + argv += optind; + + /* Check arguments */ + if (!argc || + (argc && is_input_valid(RDEEPROM, argc, argv) != UAP_SUCCESS)) { + print_apcmd_read_eeprom_usage(); + return UAP_FAILURE; + } + offset = A2HEXDECIMAL(argv[0]); + byte_count = A2HEXDECIMAL(argv[1]); + + buf = (t_u8 *)malloc(buf_len); + if (!buf) { + printf("ERR:Cannot allocate buffer from command!\n"); + return UAP_FAILURE; + } + memset(buf, 0, buf_len); + + /* Locate headers */ + cmd_buf = (apcmdbuf_eeprom_access *)buf; + cmd_len = sizeof(apcmdbuf_eeprom_access); + + cmd_buf->size = sizeof(apcmdbuf_eeprom_access) - BUF_HEADER_SIZE; + cmd_buf->result = 0; + cmd_buf->seq_num = 0; + cmd_buf->action = 0; + + cmd_buf->cmd_code = HostCmd_EEPROM_ACCESS; + cmd_buf->offset = uap_cpu_to_le16(offset); + cmd_buf->byte_count = uap_cpu_to_le16(byte_count); + + /* Send the command */ + ret = uap_ioctl((t_u8 *)cmd_buf, &cmd_len, buf_len); + + /* Process response */ + if (ret == UAP_SUCCESS) { + if (cmd_buf->result == CMD_SUCCESS) { + printf("Successfully executed the command\n"); + byte_count = uap_le16_to_cpu(cmd_buf->byte_count); + offset = uap_le16_to_cpu(cmd_buf->offset); + hexdump_data("EEPROM", (void *)cmd_buf->value, + byte_count, ' '); + } else { + printf("ERR:Command Response incorrect!\n"); + ret = UAP_FAILURE; + } + } else { + printf("ERR:Command sending failed!\n"); + } + + free(buf); + return ret; +} + +/** + * @brief Show usage information for the regrdwr command + * command + * + * $return N/A + */ +void +print_regrdwr_usage(void) +{ + printf("\nUsage : uaputl.exe regrdwr [value]\n"); + printf("\nTYPE Options: 1 - read/write MAC register"); + printf("\n 2 - read/write BBP register"); + printf("\n 3 - read/write RF register"); + printf("\n"); + return; + +} + +/** + * @brief Provides interface to perform read/write operations on regsiters + * @param argc Number of arguments + * @param argv Pointer to the arguments + * @return UAP_SUCCESS/UAP_FAILURE + */ +int +apcmd_regrdwr(int argc, char *argv[]) +{ + int opt; + t_s32 reg; + int ret = UAP_SUCCESS; + while ((opt = getopt_long(argc, argv, "+", cmd_options, NULL)) != -1) { + switch (opt) { + default: + print_regrdwr_usage(); + return UAP_SUCCESS; + } + } + argc -= optind; + argv += optind; + + /* Check arguments */ + if ((argc < 2) || (argc > 3)) { + printf("ERR:wrong arguments.\n"); + print_regrdwr_usage(); + return UAP_FAILURE; + } + if ((atoi(argv[0]) != 1) && (atoi(argv[0]) != 2) && + (atoi(argv[0]) != 3)) { + printf("ERR:Illegal register type %s. Must be either '1','2' or '3'.\n", argv[0]); + print_regrdwr_usage(); + return UAP_FAILURE; + } + reg = atoi(argv[0]); + ret = apcmd_regrdwr_process(reg, argv[1], argc > 2 ? argv[2] : NULL); + return ret; +} + +/** + * @brief Show usage information for the memaccess command + * command + * + * $return N/A + */ +void +print_memaccess_usage(void) +{ + printf("\nUsage : uaputl.exe memaccess
[value]\n"); + printf("\nRead/Write memory location"); + printf("\nADDRESS: Address of the memory location to be read/written"); + printf("\nValue : Value to be written at that address\n"); + return; +} + +/** + * @brief Provides interface to perform read/write memory location + * @param argc Number of arguments + * @param argv Pointer to the arguments + * @return UAP_SUCCESS/UAP_FAILURE + */ +int +apcmd_memaccess(int argc, char *argv[]) +{ + int opt; + apcmdbuf_mem_access *cmd_buf = NULL; + t_u8 *buf = NULL; + t_u16 cmd_len = 0; + t_u16 buf_len = MRVDRV_SIZE_OF_CMD_BUFFER; + int ret = UAP_SUCCESS; + char *address = NULL; + char *value = NULL; + + while ((opt = getopt_long(argc, argv, "+", cmd_options, NULL)) != -1) { + switch (opt) { + default: + print_memaccess_usage(); + return UAP_SUCCESS; + } + } + argc -= optind; + argv += optind; + + /* Check arguments */ + if ((argc < 1) || (argc > 2)) { + printf("ERR:wrong arguments.\n"); + print_memaccess_usage(); + return UAP_FAILURE; + } + + address = argv[0]; + if (argc == 2) + value = argv[1]; + + /* Alloc buf for command */ + buf = (t_u8 *)malloc(buf_len); + + if (!buf) { + printf("ERR:Cannot allocate buffer from command!\n"); + return UAP_FAILURE; + } + memset(buf, 0, buf_len); + /* Locate headers */ + cmd_len = sizeof(apcmdbuf_mem_access); + cmd_buf = (apcmdbuf_mem_access *)buf; + + /* Fill the command buffer */ + cmd_buf->size = cmd_len - BUF_HEADER_SIZE; + cmd_buf->seq_num = 0; + cmd_buf->result = 0; + cmd_buf->cmd_code = HostCmd_CMD_MEM_ACCESS; + + if (value) + cmd_buf->action = 1; // WRITE + else + cmd_buf->action = 0; // READ + + cmd_buf->action = uap_cpu_to_le16(cmd_buf->action); + cmd_buf->address = A2HEXDECIMAL(address); + cmd_buf->address = uap_cpu_to_le32(cmd_buf->address); + + if (value) { + cmd_buf->value = A2HEXDECIMAL(value); + cmd_buf->value = uap_cpu_to_le32(cmd_buf->value); + } + + /* Send the command */ + ret = uap_ioctl((t_u8 *)cmd_buf, &cmd_len, buf_len); + + /* Process response */ + if (ret == UAP_SUCCESS) { + if (cmd_buf->result == CMD_SUCCESS) { + printf("Successfully executed the command\n"); + printf("[0x%04x] = 0x%08x\n", + uap_le32_to_cpu(cmd_buf->address), + uap_le32_to_cpu(cmd_buf->value)); + } else { + printf("ERR:Command sending failed!\n"); + free(buf); + return UAP_FAILURE; + } + } else { + printf("ERR:Command sending failed!\n"); + free(buf); + return UAP_FAILURE; + } + free(buf); + return UAP_SUCCESS; +} + +/** + * @brief Creates a sys_debug request to send data packet directly to driver + * @param pkt_type packet type 0 or 5. + * @param control management packet tx control field. + * @param file packet data file. + * @return UAP_SUCCESS/UAP_FAILURE + */ +int +apcmd_debug_data_packet_inject(int pkt_type, int control, char *file) +{ + struct ifreq ifr; + t_s32 sockfd; + t_u8 *buf = NULL; + t_u32 data_len; + FILE *fp = NULL; + pkt_header *header = NULL; + + /* Check if file exists */ + fp = fopen(file, "r"); + if (fp == NULL) { + printf("\nERR:Data file can not be opened %s.\n", file); + return UAP_FAILURE; + } + buf = (t_u8 *)malloc(MRVDRV_SIZE_OF_PKT_BUFFER); + if (buf == NULL) { + printf("Error: allocate memory for packet buffer failed\n"); + fclose(fp); + return UAP_FAILURE; + } + memset(buf, 0, MRVDRV_SIZE_OF_PKT_BUFFER); + header = (pkt_header *)buf; + data_len = fparse_for_hex(fp, buf + sizeof(pkt_header)); + fclose(fp); + if (data_len > (MRVDRV_SIZE_OF_PKT_BUFFER - sizeof(pkt_header))) { + printf("ERR: Config file is too big %d\n", data_len); + free(buf); + return UAP_FAILURE; + } + header->tx_pkt_type = pkt_type; + header->tx_control = control; + header->pkt_len = data_len; + + /* Open socket */ + if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) { + printf("ERR:Cannot open socket\n"); + free(buf); + return UAP_FAILURE; + } + + /* Initialize the ifr structure */ + memset(&ifr, 0, sizeof(ifr)); + strncpy(ifr.ifr_ifrn.ifrn_name, dev_name, IFNAMSIZ - 1); + ifr.ifr_ifru.ifru_data = (void *)buf; + /* Perform ioctl */ + errno = 0; + if (ioctl(sockfd, UAPHOSTPKTINJECT, &ifr)) { + perror(""); + printf("ERR:ioctl is not supported by %s\n", dev_name); + close(sockfd); + free(buf); + return UAP_FAILURE; + } + /* Close socket */ + close(sockfd); + + if (buf) + free(buf); + return UAP_SUCCESS; +} + +/** + * @brief Show usage information for the bss_config command + * + * $return N/A + */ +void +print_bss_config_usage(void) +{ + printf("\nUsage : bss_config [CONFIG_FILE]\n"); + printf("\nIf CONFIG_FILE is provided, a 'set' is performed, else a 'get' is performed.\n"); + printf("CONFIG_FILE is file containing all the BSS settings.\n"); + return; +} + +/** + * @brief Read the BSS profile and populate structure + * + * @param argc Number of arguments + * @param argv Pointer to the arguments + * @param bss Pointer to BSS configuration buffer + * @return UAP_SUCCESS or UAP_FAILURE + */ +int +parse_bss_config(int argc, char *argv[], bss_config_t *bss) +{ + FILE *config_file = NULL; + char *line = NULL; + int li = 0; + char *pos = NULL; + int arg_num = 0; + char *args[30]; + int i; + int is_ap_config = 0; + int is_ap_mac_filter = 0; + int keyindex = -1; + int pwkcipher_wpa = -1; + int pwkcipher_wpa2 = -1; + int gwkcipher = -1; + int protocol = -1; + int tx_beacon_rate = -1; + int tx_data_rate = -1; + int mcbc_data_rate = -1; + int num_rates = 0; + int found = 0; + int filter_mac_count = -1; + int retval = UAP_SUCCESS; + int chan_mode = 0; + int band_flag = 0; + int chan_number = 0; + t_u16 max_sta_num_supported = 0; + fw_info fw; + HTCap_t htcap; + int enable_11n = -1; + t_u32 supported_mcs_set = 0; + int ac = 0; + int is_wmm_parameters = 0; + char oui_type[4] = { 0x00, 0x50, 0xf2, 0x02 }; + struct eth_priv_vhtcfg vhtcfg = { 0 }; + + /* Check if file exists */ + config_file = fopen(argv[0], "r"); + if (config_file == NULL) { + printf("\nERR:Config file can not open.\n"); + return UAP_FAILURE; + } + line = (char *)malloc(MAX_CONFIG_LINE); + if (!line) { + printf("ERR:Cannot allocate memory for line\n"); + retval = UAP_FAILURE; + goto done; + } + memset(line, 0, MAX_CONFIG_LINE); + + /* Parse file and process */ + while (config_get_line(line, MAX_CONFIG_LINE, config_file, &li, &pos)) { +#if DEBUG + uap_printf(MSG_DEBUG, "DBG:Received config line (%d) = %s\n", + li, line); +#endif + arg_num = parse_line(line, args); +#if DEBUG + uap_printf(MSG_DEBUG, "DBG:Number of arguments = %d\n", + arg_num); + for (i = 0; i < arg_num; i++) { + uap_printf(MSG_DEBUG, "\tDBG:Argument %d. %s\n", i + 1, + args[i]); + } +#endif + /* Check for end of AP configurations */ + if (is_ap_config == 1) { + if (strcmp(args[0], "}") == 0) { + is_ap_config = 0; + if (tx_data_rate != -1) { + if ((!bss->rates[0]) && (tx_data_rate) + && + (is_tx_rate_valid + ((t_u8)tx_data_rate) != + UAP_SUCCESS)) { + printf("ERR: Invalid Tx Data Rate \n"); + retval = UAP_FAILURE; + goto done; + } + if (bss->rates[0] && tx_data_rate) { + for (i = 0; bss->rates[i] != 0; + i++) { + if ((bss-> + rates[i] & + ~BASIC_RATE_SET_BIT) + == tx_data_rate) { + found = 1; + break; + } + } + if (!found) { + printf("ERR: Invalid Tx Data Rate \n"); + retval = UAP_FAILURE; + goto done; + } + } + + /* Set Tx data rate field */ + bss->tx_data_rate = tx_data_rate; + } + if (tx_beacon_rate != -1) { + if ((!bss->rates[0]) && (tx_beacon_rate) + && + (is_tx_rate_valid + ((t_u8)tx_beacon_rate) != + UAP_SUCCESS)) { + printf("ERR: Invalid Tx Beacon Rate \n"); + retval = UAP_FAILURE; + goto done; + } + if (bss->rates[0] && tx_beacon_rate) { + for (i = 0; bss->rates[i] != 0; + i++) { + if ((bss-> + rates[i] & + ~BASIC_RATE_SET_BIT) + == tx_beacon_rate) { + found = 1; + break; + } + } + if (!found) { + printf("ERR: Invalid Tx Beacon Rate \n"); + retval = UAP_FAILURE; + goto done; + } + } + + /* Set Tx beacon rate field */ + bss->tx_beacon_rate = tx_beacon_rate; + } + if (mcbc_data_rate != -1) { + if ((!bss->rates[0]) && (mcbc_data_rate) + && + (is_mcbc_rate_valid + ((t_u8)mcbc_data_rate) != + UAP_SUCCESS)) { + printf("ERR: Invalid Tx Data Rate \n"); + retval = UAP_FAILURE; + goto done; + } + if (bss->rates[0] && mcbc_data_rate) { + for (i = 0; bss->rates[i] != 0; + i++) { + if (bss-> + rates[i] & + BASIC_RATE_SET_BIT) + { + if ((bss-> + rates[i] & + ~BASIC_RATE_SET_BIT) + == + mcbc_data_rate) + { + found = 1; + break; + } + } + } + if (!found) { + printf("ERR: Invalid MCBC Data Rate \n"); + retval = UAP_FAILURE; + goto done; + } + } + + /* Set MCBC data rate field */ + bss->mcbc_data_rate = mcbc_data_rate; + } + if ((protocol == PROTOCOL_STATIC_WEP) && + (enable_11n == 1)) { + printf("ERR:WEP cannot be used when AP operates in 802.11n mode.\n"); + goto done; + } + if (0 == get_fw_info(&fw)) { + /*check whether support 802.11AC through BAND_AAC bit */ + if (fw.fw_bands & BAND_AAC) { + retval = get_802_11ac_cfg + (&vhtcfg); + if (retval != UAP_SUCCESS) + goto done; + if ((enable_11n == 1) && + (vhtcfg.vht_rx_mcs != + 0xffff)) { + printf("ERR: 11n must be enabled when AP operates in 11ac mode.\n"); + retval = UAP_FAILURE; + goto done; + } + } else + printf("No support 802 11AC.\n"); + } else { + printf("ERR: get_fw_info fail\n"); + retval = UAP_FAILURE; + goto done; + } + if ((protocol == PROTOCOL_WPA2_MIXED) && + ((pwkcipher_wpa < 0) || + (pwkcipher_wpa2 < 0))) { + printf("ERR:Both PwkCipherWPA and PwkCipherWPA2 should be defined for Mixed mode.\n"); + retval = UAP_FAILURE; + goto done; + } + if (protocol != -1) { + bss->protocol = protocol; + if (protocol & + (PROTOCOL_WPA | PROTOCOL_WPA2)) { + /* Set key management field */ + bss->key_mgmt = KEY_MGMT_PSK; + bss->key_mgmt_operation = 0; + } + } + if (((pwkcipher_wpa >= 0) || + (pwkcipher_wpa2 >= 0)) && + (gwkcipher >= 0)) { + if ((protocol == PROTOCOL_WPA) || + (protocol == PROTOCOL_WPA2_MIXED)) { + if (enable_11n != -1) { + if (is_cipher_valid_with_11n(pwkcipher_wpa, gwkcipher, protocol, enable_11n) != UAP_SUCCESS) { + printf("ERR:Wrong group cipher and WPA pairwise cipher combination!\n"); + retval = UAP_FAILURE; + goto done; + } + } else if + (is_cipher_valid_with_proto + (pwkcipher_wpa, + gwkcipher, + protocol) != + UAP_SUCCESS) { + printf("ERR:Wrong group cipher and WPA pairwise cipher combination!\n"); + retval = UAP_FAILURE; + goto done; + } + } + if ((protocol == PROTOCOL_WPA2) || + (protocol == PROTOCOL_WPA2_MIXED) + || (protocol == PROTOCOL_WPA3_SAE) + ) { + if (enable_11n != -1) { + if (is_cipher_valid_with_11n(pwkcipher_wpa2, gwkcipher, protocol, enable_11n) != UAP_SUCCESS) { + printf("ERR:Wrong group cipher and WPA2 pairwise cipher combination!\n"); + retval = UAP_FAILURE; + goto done; + } + } else if + (is_cipher_valid_with_proto + (pwkcipher_wpa2, + gwkcipher, + protocol) != + UAP_SUCCESS) { + printf("ERR:Wrong group cipher and WPA2 pairwise cipher combination!\n"); + retval = UAP_FAILURE; + goto done; + } + } + /* Set pairwise and group cipher fields */ + bss->wpa_cfg.pairwise_cipher_wpa = + pwkcipher_wpa; + bss->wpa_cfg.pairwise_cipher_wpa2 = + pwkcipher_wpa2; + bss->wpa_cfg.group_cipher = gwkcipher; + } + continue; + } + } + + /* Check for beginning of AP configurations */ + if (strcmp(args[0], "ap_config") == 0) { + is_ap_config = 1; + continue; + } + + /* Check for end of AP MAC address filter configurations */ + if (is_ap_mac_filter == 1) { + if (strcmp(args[0], "}") == 0) { + is_ap_mac_filter = 0; + if (bss->filter.mac_count != filter_mac_count) { + printf("ERR:Number of MAC address provided does not match 'Count'\n"); + retval = UAP_FAILURE; + goto done; + } + if (bss->filter.filter_mode && + (bss->filter.mac_count == 0)) { + printf("ERR:Filter list can not be empty for %s Filter mode\n", (bss->filter.filter_mode == 1) ? "'Allow'" : "'Block'"); + retval = UAP_FAILURE; + goto done; + } + continue; + } + } + + /* Check for beginning of AP MAC address filter configurations */ + if (strcmp(args[0], "ap_mac_filter") == 0) { + is_ap_mac_filter = 1; + bss->filter.mac_count = 0; + filter_mac_count = 0; + continue; + } + if ((strcmp(args[0], "FilterMode") == 0) && is_ap_mac_filter) { + if ((ISDIGIT(args[1]) == 0) || (atoi(args[1]) < 0) || + (atoi(args[1]) > 2)) { + printf("ERR:Illegal FilterMode paramter %d. Must be either '0', '1', or '2'.\n", atoi(args[1])); + retval = UAP_FAILURE; + goto done; + } + bss->filter.filter_mode = atoi(args[1]); + continue; + } + if ((strcmp(args[0], "Count") == 0) && is_ap_mac_filter) { + bss->filter.mac_count = atoi(args[1]); + if ((ISDIGIT(args[1]) == 0) || + (bss->filter.mac_count > MAX_MAC_ONESHOT_FILTER)) { + printf("ERR: Illegal Count parameter.\n"); + retval = UAP_FAILURE; + goto done; + } + } + if ((strncmp(args[0], "mac_", 4) == 0) && is_ap_mac_filter) { + if (filter_mac_count < MAX_MAC_ONESHOT_FILTER) { + if (mac2raw + (args[1], + bss->filter.mac_list[filter_mac_count]) != + UAP_SUCCESS) { + printf("ERR: Invalid MAC address %s \n", + args[1]); + retval = UAP_FAILURE; + goto done; + } + filter_mac_count++; + } else { + printf("ERR: Filter table can not have more than %d MAC addresses\n", MAX_MAC_ONESHOT_FILTER); + retval = UAP_FAILURE; + goto done; + } + } + + /* Check for end of Wmm Parameters configurations */ + if (is_wmm_parameters == 1) { + if (strcmp(args[0], "}") == 0) { + is_wmm_parameters = 0; + continue; + } + } + /* Check for beginning of Sticky Tim Sta MAC address Configurations */ + if (strcmp(args[0], "Wmm_parameters") == 0) { + is_wmm_parameters = 1; + memset(&(bss->wmm_para), 0, sizeof(bss->wmm_para)); + memcpy(bss->wmm_para.ouitype, oui_type, + sizeof(oui_type)); + bss->wmm_para.ouisubtype = 1; + bss->wmm_para.version = 1; + continue; + } + if ((strcmp(args[0], "Qos_info") == 0) && is_wmm_parameters) { + bss->wmm_para.qos_info = A2HEXDECIMAL(args[1]); + printf("wmm_para.qos_info = %2x\n", + bss->wmm_para.qos_info); + if ((bss->wmm_para.qos_info != ENABLE_WMM_PS) && + (bss->wmm_para.qos_info != DISABLE_WMM_PS)) { + printf("ERR:qos_info must be either 0x80 or 0x00.\n"); + retval = UAP_FAILURE; + goto done; + } + } + if ((strcmp(args[0], "AC_BE") == 0) && is_wmm_parameters) { + ac = 0; + } + if ((strcmp(args[0], "AC_BK") == 0) && is_wmm_parameters) { + ac = 1; + } + if ((strcmp(args[0], "AC_VI") == 0) && is_wmm_parameters) { + ac = 2; + } + if ((strcmp(args[0], "AC_VO") == 0) && is_wmm_parameters) { + ac = 3; + } + if ((strcmp(args[0], "Aifsn") == 0) && is_wmm_parameters) { + bss->wmm_para.ac_params[ac].aci_aifsn.aifsn = + (t_u8)A2HEXDECIMAL(args[1]); + printf("wmm_para.ac_params[%d].aci_aifsn.aifsn = %x\n", + ac, bss->wmm_para.ac_params[ac].aci_aifsn.aifsn); + bss->wmm_para.ac_params[ac].aci_aifsn.aci = (t_u8)ac; + printf("wmm_para.ac_params[%d].aci_aifsn.aci = %x\n", + ac, bss->wmm_para.ac_params[ac].aci_aifsn.aci); + } + if ((strcmp(args[0], "Ecw_max") == 0) && is_wmm_parameters) { + bss->wmm_para.ac_params[ac].ecw.ecw_max = + (t_u8)A2HEXDECIMAL(args[1]); + printf("wmm_para.ac_params[%d].ecw.ecw_max = %x\n", ac, + bss->wmm_para.ac_params[ac].ecw.ecw_max); + } + if ((strcmp(args[0], "Ecw_min") == 0) && is_wmm_parameters) { + bss->wmm_para.ac_params[ac].ecw.ecw_min = + (t_u8)A2HEXDECIMAL(args[1]); + printf("wmm_para.ac_params[%d].ecw.ecw_min = %x\n", ac, + bss->wmm_para.ac_params[ac].ecw.ecw_min); + } + if ((strcmp(args[0], "Tx_op") == 0) && is_wmm_parameters) { + bss->wmm_para.ac_params[ac].tx_op_limit = + (t_u8)A2HEXDECIMAL(args[1]); + printf("wmm_para.ac_params[%d].tx_op_limit = %x\n", ac, + bss->wmm_para.ac_params[ac].tx_op_limit); + } + + if (strcmp(args[0], "SSID") == 0) { + if (arg_num == 1) { + printf("ERR:SSID field is blank!\n"); + retval = UAP_FAILURE; + goto done; + } else { + if (args[1][0] == '"') { + args[1]++; + } + if (args[1][strlen(args[1]) - 1] == '"') { + args[1][strlen(args[1]) - 1] = '\0'; + } + if ((strlen(args[1]) > MAX_SSID_LENGTH) || + (strlen(args[1]) == 0)) { + printf("ERR:SSID length out of range (%d to %d).\n", MIN_SSID_LENGTH, MAX_SSID_LENGTH); + retval = UAP_FAILURE; + goto done; + } + /* Set SSID field */ + bss->ssid.ssid_len = strlen(args[1]); + memcpy(bss->ssid.ssid, args[1], + bss->ssid.ssid_len); + } + } + if (strcmp(args[0], "BeaconPeriod") == 0) { + if (is_input_valid(BEACONPERIOD, arg_num - 1, args + 1) + != UAP_SUCCESS) { + retval = UAP_FAILURE; + goto done; + } + /* Set beacon period field */ + bss->beacon_period = (t_u16)atoi(args[1]); + } + if (strcmp(args[0], "ChanList") == 0) { + if (is_input_valid(SCANCHANNELS, arg_num - 1, args + 1) + != UAP_SUCCESS) { + retval = UAP_FAILURE; + goto done; + } + + /* Set channel list field */ + if ((arg_num - 1) < MAX_CHANNELS) { + bss->num_of_chan = arg_num - 1; + } else { + bss->num_of_chan = MAX_CHANNELS; + } + for (i = 0; (unsigned int)i < bss->num_of_chan; i++) { + sscanf(args[i + 1], "%d.%d", &chan_number, + &band_flag); + bss->chan_list[i].chan_number = chan_number; + bss->chan_list[i].bandcfg.chanBand = BAND_2GHZ; + if (((band_flag != -1) && (band_flag)) || + (chan_number > MAX_CHANNELS_BG)) { + bss->chan_list[i].bandcfg.chanBand = + BAND_5GHZ; + } + } + } + if (strcmp(args[0], "Channel") == 0) { + if (is_input_valid(CHANNEL, arg_num - 1, args + 1) != + UAP_SUCCESS) { + retval = UAP_FAILURE; + goto done; + } + /* Set channel field */ + bss->channel = (t_u8)atoi(args[1]); + if ((arg_num - 1) == 2) { + chan_mode = atoi(args[2]); + memset(&(bss->bandcfg), 0, + sizeof(bss->bandcfg)); + if (chan_mode & BITMAP_ACS_MODE) { + int mode; + + if (uap_ioctl_dfs_repeater_mode(&mode) + == UAP_SUCCESS) { + if (mode) { + printf("ERR: ACS in DFS Repeater mode" " is not allowed\n"); + retval = UAP_FAILURE; + goto done; + } + } + + bss->bandcfg.scanMode = SCAN_MODE_ACS; + } + if (chan_mode & BITMAP_CHANNEL_ABOVE) + bss->bandcfg.chan2Offset = + SEC_CHAN_ABOVE; + if (chan_mode & BITMAP_CHANNEL_BELOW) + bss->bandcfg.chan2Offset = + SEC_CHAN_BELOW; + } else + memset(&(bss->bandcfg), 0, + sizeof(bss->bandcfg)); + if (bss->channel > MAX_CHANNELS_BG) + bss->bandcfg.chanBand = BAND_5GHZ; + } + if (strcmp(args[0], "Band") == 0) { + if (is_input_valid(BAND, arg_num - 1, args + 1) != + UAP_SUCCESS) { + retval = UAP_FAILURE; + goto done; + } + /* Clear previously set band */ + bss->bandcfg.chanBand = BAND_2GHZ; + if (atoi(args[1]) == 1) + bss->bandcfg.chanBand = BAND_5GHZ; + } + if (strcmp(args[0], "AP_MAC") == 0) { + int ret; + if ((ret = + mac2raw(args[1], bss->mac_addr)) != UAP_SUCCESS) { + printf("ERR: %s Address \n", + ret == + UAP_FAILURE ? "Invalid MAC" : ret == + UAP_RET_MAC_BROADCAST ? "Broadcast" : + "Multicast"); + retval = UAP_FAILURE; + goto done; + } + } + + if (strcmp(args[0], "Rate") == 0) { + if (is_input_valid(RATE, arg_num - 1, args + 1) != + UAP_SUCCESS) { + printf("ERR: Invalid Rate input\n"); + retval = UAP_FAILURE; + goto done; + } + /* Set rates field */ + if ((arg_num - 1) < MAX_DATA_RATES) { + num_rates = arg_num - 1; + } else { + num_rates = MAX_DATA_RATES; + } + for (i = 0; i < num_rates; i++) { + bss->rates[i] = (t_u8)A2HEXDECIMAL(args[i + 1]); + } + } + if (strcmp(args[0], "TxPowerLevel") == 0) { + if (is_input_valid(TXPOWER, arg_num - 1, args + 1) != + UAP_SUCCESS) { + printf("ERR:Invalid TxPowerLevel \n"); + retval = UAP_FAILURE; + goto done; + } + /* Set Tx power level field */ + bss->tx_power_level = (t_u8)atoi(args[1]); + } + if (strcmp(args[0], "BroadcastSSID") == 0) { + if (is_input_valid(BROADCASTSSID, arg_num - 1, args + 1) + != UAP_SUCCESS) { + retval = UAP_FAILURE; + goto done; + } + /* Set broadcast SSID control field */ + bss->bcast_ssid_ctl = (t_u8)atoi(args[1]); + } + if (strcmp(args[0], "RTSThreshold") == 0) { + if (is_input_valid(RTSTHRESH, arg_num - 1, args + 1) != + UAP_SUCCESS) { + retval = UAP_FAILURE; + goto done; + } + /* Set RTS threshold field */ + bss->rts_threshold = (t_u16)atoi(args[1]); + } + if (strcmp(args[0], "FragThreshold") == 0) { + if (is_input_valid(FRAGTHRESH, arg_num - 1, args + 1) != + UAP_SUCCESS) { + retval = UAP_FAILURE; + goto done; + } + /* Set Frag threshold field */ + bss->frag_threshold = (t_u16)atoi(args[1]); + } + if (strcmp(args[0], "DTIMPeriod") == 0) { + if (is_input_valid(DTIMPERIOD, arg_num - 1, args + 1) != + UAP_SUCCESS) { + retval = UAP_FAILURE; + goto done; + } + /* Set DTIM period field */ + bss->dtim_period = (t_u8)atoi(args[1]); + } + if (strcmp(args[0], "RSNReplayProtection") == 0) { + if (is_input_valid(RSNREPLAYPROT, arg_num - 1, args + 1) + != UAP_SUCCESS) { + retval = UAP_FAILURE; + goto done; + } + /* Set RSN replay protection field */ + bss->wpa_cfg.rsn_protection = (t_u8)atoi(args[1]); + } + if (strcmp(args[0], "PairwiseUpdateTimeout") == 0) { + if ((ISDIGIT(args[1]) == 0) || (atoi(args[1]) < 0)) { + retval = UAP_FAILURE; + goto done; + } + /* Set Pairwise Update Timeout field */ + bss->pairwise_update_timeout = (t_u32)atoi(args[1]); + } + if (strcmp(args[0], "PairwiseHandshakeRetries") == 0) { + if ((ISDIGIT(args[1]) == 0) || (atoi(args[1]) < 0)) { + retval = UAP_FAILURE; + goto done; + } + /* Set Pairwise Hanshake Retries */ + bss->pwk_retries = (t_u32)atoi(args[1]); + } + if (strcmp(args[0], "GroupwiseUpdateTimeout") == 0) { + if ((ISDIGIT(args[1]) == 0) || (atoi(args[1]) < 0)) { + retval = UAP_FAILURE; + goto done; + } + /* Set Groupwise Update Timeout field */ + bss->groupwise_update_timeout = (t_u32)atoi(args[1]); + } + if (strcmp(args[0], "GroupwiseHandshakeRetries") == 0) { + if ((ISDIGIT(args[1]) == 0) || (atoi(args[1]) < 0)) { + retval = UAP_FAILURE; + goto done; + } + /* Set Groupwise Hanshake Retries */ + bss->gwk_retries = (t_u32)atoi(args[1]); + } + if (strcmp(args[0], "TxBeaconRate") == 0) { + if (is_input_valid(TXBEACONRATE, arg_num - 1, args + 1) + != UAP_SUCCESS) { + retval = UAP_FAILURE; + goto done; + } + tx_beacon_rate = (t_u16)A2HEXDECIMAL(args[1]); + } + if (strcmp(args[0], "MCBCdataRate") == 0) { + if (is_input_valid(MCBCDATARATE, arg_num - 1, args + 1) + != UAP_SUCCESS) { + retval = UAP_FAILURE; + goto done; + } + mcbc_data_rate = (t_u16)A2HEXDECIMAL(args[1]); + } + if (strcmp(args[0], "PktFwdCtl") == 0) { + if (is_input_valid(PKTFWD, arg_num - 1, args + 1) != + UAP_SUCCESS) { + retval = UAP_FAILURE; + goto done; + } + /* Set packet forward control field */ + bss->pkt_forward_ctl = (t_u8)atoi(args[1]); + } + if (strcmp(args[0], "StaAgeoutTimer") == 0) { + if (is_input_valid + (STAAGEOUTTIMER, arg_num - 1, + args + 1) != UAP_SUCCESS) { + retval = UAP_FAILURE; + goto done; + } + /* Set STA ageout timer field */ + bss->sta_ageout_timer = (t_u32)atoi(args[1]); + } + if (strcmp(args[0], "PSStaAgeoutTimer") == 0) { + if (is_input_valid + (PSSTAAGEOUTTIMER, arg_num - 1, + args + 1) != UAP_SUCCESS) { + retval = UAP_FAILURE; + goto done; + } + /* Set PS STA ageout timer field */ + bss->ps_sta_ageout_timer = (t_u32)atoi(args[1]); + } + if (strcmp(args[0], "AuthMode") == 0) { + if (is_input_valid(AUTHMODE, arg_num - 1, args + 1) != + UAP_SUCCESS) { + retval = UAP_FAILURE; + goto done; + } + /* Set auth mode field */ + bss->auth_mode = (t_u16)atoi(args[1]); + } + if (strcmp(args[0], "KeyIndex") == 0) { + if (arg_num == 1) { + printf("KeyIndex is blank!\n"); + retval = UAP_FAILURE; + goto done; + } else { + if (ISDIGIT(args[1]) == 0) { + printf("ERR:Illegal KeyIndex parameter. Must be either '0', '1', '2', or '3'.\n"); + retval = UAP_FAILURE; + goto done; + } + keyindex = atoi(args[1]); + if ((keyindex < 0) || (keyindex > 3)) { + printf("ERR:Illegal KeyIndex parameter. Must be either '0', '1', '2', or '3'.\n"); + retval = UAP_FAILURE; + goto done; + } + switch (keyindex) { + case 0: + bss->wep_cfg.key0.is_default = 1; + break; + case 1: + bss->wep_cfg.key1.is_default = 1; + break; + case 2: + bss->wep_cfg.key2.is_default = 1; + break; + case 3: + bss->wep_cfg.key3.is_default = 1; + break; + } + } + } + if (strncmp(args[0], "Key_", 4) == 0) { + if (arg_num == 1) { + printf("ERR:%s is blank!\n", args[0]); + retval = UAP_FAILURE; + goto done; + } else { + int key_len = 0; + if (args[1][0] == '"') { + if ((strlen(args[1]) != 2) && + (strlen(args[1]) != 7) && + (strlen(args[1]) != 15)) { + printf("ERR:Wrong key length!\n"); + retval = UAP_FAILURE; + goto done; + } + key_len = strlen(args[1]) - 2; + } else { + if ((strlen(args[1]) != 0) && + (strlen(args[1]) != 10) && + (strlen(args[1]) != 26)) { + printf("ERR:Wrong key length!\n"); + retval = UAP_FAILURE; + goto done; + } + if (UAP_FAILURE == ishexstring(args[1])) { + printf("ERR:Only hex digits are allowed when key length is 10 or 26\n"); + retval = UAP_FAILURE; + goto done; + } + key_len = strlen(args[1]) / 2; + } + /* Set WEP key fields */ + if (strcmp(args[0], "Key_0") == 0) { + bss->wep_cfg.key0.key_index = 0; + bss->wep_cfg.key0.length = key_len; + if (args[1][0] == '"') { + memcpy(bss->wep_cfg.key0.key, + &args[1][1], + strlen(args[1]) - 2); + } else { + string2raw(args[1], + bss->wep_cfg.key0. + key); + } + } else if (strcmp(args[0], "Key_1") == 0) { + bss->wep_cfg.key1.key_index = 1; + bss->wep_cfg.key1.length = key_len; + if (args[1][0] == '"') { + memcpy(bss->wep_cfg.key1.key, + &args[1][1], + strlen(args[1]) - 2); + } else { + string2raw(args[1], + bss->wep_cfg.key1. + key); + } + } else if (strcmp(args[0], "Key_2") == 0) { + bss->wep_cfg.key2.key_index = 2; + bss->wep_cfg.key2.length = key_len; + if (args[1][0] == '"') { + memcpy(bss->wep_cfg.key2.key, + &args[1][1], + strlen(args[1]) - 2); + } else { + string2raw(args[1], + bss->wep_cfg.key2. + key); + } + } else if (strcmp(args[0], "Key_3") == 0) { + bss->wep_cfg.key3.key_index = 3; + bss->wep_cfg.key3.length = key_len; + if (args[1][0] == '"') { + memcpy(bss->wep_cfg.key3.key, + &args[1][1], + strlen(args[1]) - 2); + } else { + string2raw(args[1], + bss->wep_cfg.key3. + key); + } + } + } + } + if (strcmp(args[0], "PSK") == 0) { + if (arg_num == 1) { + printf("ERR:PSK is blank!\n"); + retval = UAP_FAILURE; + goto done; + } else { + if (args[1][0] == '"') { + args[1]++; + } + if (args[1][strlen(args[1]) - 1] == '"') { + args[1][strlen(args[1]) - 1] = '\0'; + } + if (strlen(args[1]) > MAX_WPA_PASSPHRASE_LENGTH) { + printf("ERR:PSK too long.\n"); + retval = UAP_FAILURE; + goto done; + } + if (strlen(args[1]) < MIN_WPA_PASSPHRASE_LENGTH) { + printf("ERR:PSK too short.\n"); + retval = UAP_FAILURE; + goto done; + } + if (strlen(args[1]) == + MAX_WPA_PASSPHRASE_LENGTH) { + if (UAP_FAILURE == ishexstring(args[1])) { + printf("ERR:Only hex digits are allowed when passphrase's length is 64\n"); + retval = UAP_FAILURE; + goto done; + } + } + /* Set WPA passphrase field */ + bss->wpa_cfg.length = strlen(args[1]); + memcpy(bss->wpa_cfg.passphrase, args[1], + bss->wpa_cfg.length); + } + } + if (strcmp(args[0], "Protocol") == 0) { + if (is_input_valid(PROTOCOL, arg_num - 1, args + 1) != + UAP_SUCCESS) { + retval = UAP_FAILURE; + goto done; + } + /* Set protocol field */ + protocol = (t_u16)atoi(args[1]); + } + if ((strcmp(args[0], "PairwiseCipher") == 0) || + (strcmp(args[0], "GroupCipher") == 0)) { + printf("ERR:PairwiseCipher and GroupCipher are not supported.\n" " Please configure pairwise cipher using parameters PwkCipherWPA or PwkCipherWPA2\n" " and group cipher using GwkCipher in the config file.\n"); + goto done; + } + + if ((protocol == PROTOCOL_NO_SECURITY) || + (protocol == PROTOCOL_STATIC_WEP)) { + if ((strcmp(args[0], "PwkCipherWPA") == 0) || + (strcmp(args[0], "PwkCipherWPA2") == 0) + || (strcmp(args[0], "GwkCipher") == 0)) { + printf("ERR:Pairwise cipher and group cipher should not be defined for Open and WEP mode.\n"); + goto done; + } + } + + if (strcmp(args[0], "PwkCipherWPA") == 0) { + if (arg_num == 1) { + printf("ERR:PwkCipherWPA is blank!\n"); + goto done; + } else { + if (ISDIGIT(args[1]) == 0) { + printf("ERR:Illegal PwkCipherWPA parameter. Must be either bit '2' or '3'.\n"); + goto done; + } + if (atoi(args[1]) & ~CIPHER_BITMAP) { + printf("ERR:Illegal PwkCipherWPA parameter. Must be either bit '2' or '3'.\n"); + goto done; + } + pwkcipher_wpa = atoi(args[1]); + if (enable_11n && + protocol != PROTOCOL_WPA2_MIXED) { + memset(&htcap, 0, sizeof(htcap)); + if (UAP_SUCCESS == + get_sys_cfg_11n(&htcap)) { + if (htcap.supported_mcs_set[0] + && (atoi(args[1]) == + CIPHER_TKIP)) { + printf("ERR: WPA/TKIP cannot be used when AP operates in 802.11n mode.\n"); + return UAP_FAILURE; + } + } + } + } + } + if (strcmp(args[0], "PwkCipherWPA2") == 0) { + if (arg_num == 1) { + printf("ERR:PwkCipherWPA2 is blank!\n"); + goto done; + } else { + if (ISDIGIT(args[1]) == 0) { + printf("ERR:Illegal PwkCipherWPA2 parameter. Must be either bit '2' or '3'.\n"); + goto done; + } + if (atoi(args[1]) & ~CIPHER_BITMAP) { + printf("ERR:Illegal PwkCipherWPA2 parameter. Must be either bit '2' or '3'.\n"); + goto done; + } + pwkcipher_wpa2 = atoi(args[1]); + if (enable_11n && + protocol != PROTOCOL_WPA2_MIXED) { + memset(&htcap, 0, sizeof(htcap)); + if (UAP_SUCCESS == + get_sys_cfg_11n(&htcap)) { + if (htcap.supported_mcs_set[0] + && (atoi(args[1]) == + CIPHER_TKIP)) { + printf("ERR: WPA/TKIP cannot be used when AP operates in 802.11n mode.\n"); + return UAP_FAILURE; + } + } + } + } + } + if (strcmp(args[0], "GwkCipher") == 0) { + if (is_input_valid(GWK_CIPHER, arg_num - 1, args + 1) != + UAP_SUCCESS) { + goto done; + } + gwkcipher = atoi(args[1]); + } + if (strcmp(args[0], "GroupRekeyTime") == 0) { + if (is_input_valid + (GROUPREKEYTIMER, arg_num - 1, + args + 1) != UAP_SUCCESS) { + retval = UAP_FAILURE; + goto done; + } + + /* Set group rekey time field */ + bss->wpa_cfg.gk_rekey_time = (t_u32)atoi(args[1]); + } + if (strcmp(args[0], "MaxStaNum") == 0) { + if (is_input_valid(MAXSTANUM, arg_num - 1, args + 1) != + UAP_SUCCESS) { + retval = UAP_FAILURE; + goto done; + } + if (get_max_sta_num_supported(&max_sta_num_supported) == + UAP_FAILURE) { + retval = UAP_FAILURE; + goto done; + } + if (atoi(args[1]) > max_sta_num_supported) { + printf("ERR: MAX_STA_NUM must be less than %d\n", max_sta_num_supported); + retval = UAP_FAILURE; + goto done; + } + /* Set max STA number field */ + bss->max_sta_count = (t_u16)atoi(args[1]); + } + if (strcmp(args[0], "Retrylimit") == 0) { + if (is_input_valid(RETRYLIMIT, arg_num - 1, args + 1) != + UAP_SUCCESS) { + retval = UAP_FAILURE; + goto done; + } + + /* Set retry limit field */ + bss->retry_limit = (t_u16)atoi(args[1]); + } + if (strcmp(args[0], "PreambleType") == 0) { + if (is_input_valid(PREAMBLETYPE, arg_num - 1, args + 1) + != UAP_SUCCESS) { + retval = UAP_FAILURE; + goto done; + } + + /* Set preamble type field */ + bss->preamble_type = (t_u8)atoi(args[1]); + } + if (strcmp(args[0], "Enable11n") == 0) { + if ((ISDIGIT(args[1]) != UAP_SUCCESS) || + (atoi(args[1]) < 0) || (atoi(args[1]) > 1)) { + printf("ERR: Invalid Enable11n value\n"); + goto done; + } + enable_11n = atoi(args[1]); + + memset(&htcap, 0, sizeof(htcap)); + if (UAP_SUCCESS != get_sys_cfg_11n(&htcap)) { + printf("ERR: Reading current 11n configuration.\n"); + goto done; + } + bss->ht_cap_info = htcap.ht_cap_info; + bss->ampdu_param = htcap.ampdu_param; + memcpy(bss->supported_mcs_set, htcap.supported_mcs_set, + 16); + bss->ht_ext_cap = htcap.ht_ext_cap; + bss->tx_bf_cap = htcap.tx_bf_cap; + bss->asel = htcap.asel; + if (enable_11n == 1) { + /* enable mcs rate */ + bss->supported_mcs_set[0] = DEFAULT_MCS_SET_0; + bss->supported_mcs_set[4] = DEFAULT_MCS_SET_4; + if (0 == get_fw_info(&fw)) { + if ((fw.hw_dev_mcs_support & 0x0f) >= 2) + bss->supported_mcs_set[1] = + DEFAULT_MCS_SET_1; + } + } else { + /* disable mcs rate */ + bss->supported_mcs_set[0] = 0; + bss->supported_mcs_set[4] = 0; + bss->supported_mcs_set[1] = 0; + } + } + if (strcmp(args[0], "HTCapInfo") == 0) { + if (enable_11n <= 0) { + printf("ERR: Enable11n parameter should be set before HTCapInfo.\n"); + goto done; + } + if ((IS_HEX_OR_DIGIT(args[1]) == UAP_FAILURE) || + ((((t_u16)A2HEXDECIMAL(args[1])) & + (~HT_CAP_CONFIG_MASK)) != HT_CAP_CHECK_MASK)) { + printf("ERR: Invalid HTCapInfo value\n"); + goto done; + } + bss->ht_cap_info = + DEFAULT_HT_CAP_VALUE & ~HT_CAP_CONFIG_MASK; + bss->ht_cap_info |= + (t_u16)A2HEXDECIMAL(args[1]) & + HT_CAP_CONFIG_MASK; + bss->ht_cap_info = uap_cpu_to_le16(bss->ht_cap_info); + } + if (strcmp(args[0], "AMPDU") == 0) { + if (enable_11n <= 0) { + printf("ERR: Enable11n parameter should be set before AMPDU.\n"); + goto done; + } + if ((IS_HEX_OR_DIGIT(args[1]) == UAP_FAILURE) || + ((A2HEXDECIMAL(args[1])) > AMPDU_CONFIG_MASK)) { + printf("ERR: Invalid AMPDU value\n"); + goto done; + } + /* Find HT tlv pointer in buffer and set AMPDU */ + bss->ampdu_param = + (t_u8)A2HEXDECIMAL(args[1]) & AMPDU_CONFIG_MASK; + } + if (strcmp(args[0], "HT_MCS_MAP") == 0) { + if (enable_11n <= 0) { + printf("ERR: Enable11n parameter should be set before HT_MCS_MAP.\n"); + goto done; + } + if ((IS_HEX_OR_DIGIT(args[1]) == UAP_FAILURE)) { + printf("ERR: Invalid HT_MCS_MAP value\n"); + goto done; + } + if (0 == get_fw_info(&fw)) { + /* Check upper nibble of MCS support value + * and block MCS_SET_1 when 2X2 is not supported + * by the underlying hardware */ + if (((fw.hw_dev_mcs_support & 0xf0) < + STREAM_2X2_MASK) && + (A2HEXDECIMAL(args[1]) & MCS_SET_1_MASK)) { + printf("ERR: Invalid HT_MCS_MAP\n"); + goto done; + } + } + supported_mcs_set = (t_u32)A2HEXDECIMAL(args[1]); + supported_mcs_set = uap_cpu_to_le32(supported_mcs_set); + memcpy(bss->supported_mcs_set, &supported_mcs_set, + sizeof(t_u32)); + } + if (strcmp(args[0], "Enable2040Coex") == 0) { + if ((ISDIGIT(args[1]) == 0) || (atoi(args[1]) < 0) || + (atoi(args[1]) > 1)) { + printf("ERR:Invalid Enable2040Coex value.\n"); + goto done; + } + bss->enable_2040coex = (t_u8)atoi(args[1]); + } + } +done: + fclose(config_file); + if (line) + free(line); + return retval; +} + +/** + * @brief Show all the BSS configuration in the buffer + * + * @param buf Pointer to BSS configuration buffer + * + * $return N/A + */ +void +print_bss_config(bss_config_t *buf) +{ + int i = 0; + int flag = 0; + + if (!buf) { + printf("ERR:Empty BSS config!\n"); + return; + } + + /* Print AP MAC address */ + printf("AP MAC address = "); + print_mac(buf->mac_addr); + printf("\n"); + + /* Print SSID */ + if (buf->ssid.ssid_len) { + printf("SSID = %s\n", buf->ssid.ssid); + } + + /* Print broadcast SSID control */ + printf("SSID broadcast = %s\n", + (buf->bcast_ssid_ctl == 1) ? "enabled" : "disabled"); + + /* Print DTIM period */ + printf("DTIM period = %d\n", buf->dtim_period); + + /* Print beacon period */ + printf("Beacon period = %d\n", buf->beacon_period); + + /* Print rates */ + printf("Basic Rates ="); + for (i = 0; i < MAX_DATA_RATES; i++) { + if (!buf->rates[i]) + break; + if (buf->rates[i] > (BASIC_RATE_SET_BIT - 1)) { + flag = flag ? : 1; + printf(" 0x%x", buf->rates[i]); + } + } + printf("%s\nNon-Basic Rates =", flag ? "" : " ( none ) "); + for (flag = 0, i = 0; i < MAX_DATA_RATES; i++) { + if (!buf->rates[i]) + break; + if (buf->rates[i] < BASIC_RATE_SET_BIT) { + flag = flag ? : 1; + printf(" 0x%x", buf->rates[i]); + } + } + printf("%s\n", flag ? "" : " ( none ) "); + + /* Print Tx data rate */ + printf("Tx data rate = "); + if (buf->tx_data_rate == 0) + printf("auto\n"); + else + printf("0x%x\n", buf->tx_data_rate); + + /* Print MCBC data rate */ + printf("MCBC data rate = "); + if (buf->mcbc_data_rate == 0) + printf("auto\n"); + else + printf("0x%x\n", buf->mcbc_data_rate); + + /* Print Tx power level */ + printf("Tx power = %d dBm\n", buf->tx_power_level); + + /* Print Tx antenna */ + printf("Tx antenna = %s\n", (buf->tx_antenna) ? "B" : "A"); + + /* Print Rx antenna */ + printf("Rx antenna = %s\n", (buf->rx_antenna) ? "B" : "A"); + + /* Print packet forward control */ + printf("%s handles packet forwarding -\n", + ((buf->pkt_forward_ctl & PKT_FWD_FW_BIT) == + 0) ? "Host" : "Firmware"); + printf("\tIntra-BSS broadcast packets are %s\n", + ((buf->pkt_forward_ctl & PKT_FWD_INTRA_BCAST) == + 0) ? "allowed" : "denied"); + printf("\tIntra-BSS unicast packets are %s\n", + ((buf->pkt_forward_ctl & PKT_FWD_INTRA_UCAST) == + 0) ? "allowed" : "denied"); + printf("\tInter-BSS unicast packets are %s\n", + ((buf->pkt_forward_ctl & PKT_FWD_INTER_UCAST) == + 0) ? "allowed" : "denied"); + + /* Print maximum STA count */ + printf("Max Station Number configured = %d\n", buf->max_sta_count); + + /* Print mgmt frame FWD control */ + printf("MGMT frame Fwd Control = 0x%x\n", buf->mgmt_ie_passthru_mask); + + /* Print MAC filter */ + if (buf->filter.filter_mode == 0) { + printf("Filter Mode = Filter table is disabled\n"); + } else { + if (buf->filter.filter_mode == 1) { + printf("Filter Mode = Allow MAC addresses specified in the allowed list\n"); + } else if (buf->filter.filter_mode == 2) { + printf("Filter Mode = Block MAC addresses specified in the banned list\n"); + } else { + printf("Filter Mode = Unknown\n"); + } + for (i = 0; i < buf->filter.mac_count; i++) { + printf("MAC_%d = ", i); + print_mac(buf->filter.mac_list[i]); + printf("\n"); + } + } + + /* Print STA ageout timer */ + printf("STA ageout timer = %d\n", buf->sta_ageout_timer); + + /* Print PS STA ageout timer */ + printf("PS STA ageout timer = %d\n", buf->ps_sta_ageout_timer); + + /* Print RTS threshold */ + printf("RTS threshold = %d\n", buf->rts_threshold); + + /* Print Fragmentation threshold */ + printf("Fragmentation threshold = %d\n", buf->frag_threshold); + + /* Print retry limit */ + printf("Retry Limit = %d\n", buf->retry_limit); + + /* Print preamble type */ + printf("Preamble type = %s\n", (buf->preamble_type == 0) ? + "auto" : ((buf->preamble_type == 1) ? "short" : "long")); + + /* Print channel */ + printf("Channel = %d\n", buf->channel); + printf("Band = %s\n", + (buf->bandcfg.chanBand == BAND_5GHZ) ? "5GHz" : "2.4GHz"); + printf("Channel Select Mode = %s\n", + (buf->bandcfg.scanMode == SCAN_MODE_ACS) ? "ACS" : "Manual"); + if (buf->bandcfg.chan2Offset == SEC_CHAN_NONE) + printf("no secondary channel\n"); + else if (buf->bandcfg.chan2Offset == SEC_CHAN_ABOVE) + printf("secondary channel is above primary channel\n"); + else if (buf->bandcfg.chan2Offset == SEC_CHAN_BELOW) + printf("secondary channel is below primary channel\n"); + + /* Print channel list */ + printf("Channels List = "); + for (i = 0; (unsigned int)i < buf->num_of_chan; i++) { + printf("\n%d\t%sGHz", buf->chan_list[i].chan_number, + (buf->chan_list[i].bandcfg.chanBand == + BAND_5GHZ) ? "5" : "2.4"); + } + printf("\n"); + + /* Print auth mode */ + switch (buf->auth_mode) { + case 0: + printf("AUTHMODE = Open authentication\n"); + break; + case 1: + printf("AUTHMODE = Shared key authentication\n"); + break; + case 3: + printf("AUTHMODE = WPA3 SAE\n"); + break; + case 255: + printf("AUTHMODE = Auto (open and shared key)\n"); + break; + default: + printf("ERR: Invalid authmode=%d\n", buf->auth_mode); + break; + } + + /* Print protocol */ + switch (buf->protocol) { + case 0: + case PROTOCOL_NO_SECURITY: + printf("PROTOCOL = No security\n"); + break; + case PROTOCOL_STATIC_WEP: + printf("PROTOCOL = Static WEP\n"); + break; + case PROTOCOL_WPA: + printf("PROTOCOL = WPA \n"); + break; + case PROTOCOL_WPA2: + printf("PROTOCOL = WPA2 \n"); + break; + case PROTOCOL_WPA | PROTOCOL_WPA2: + printf("PROTOCOL = WPA/WPA2 \n"); + break; + case PROTOCOL_WPA3_SAE: + printf("PROTOCOL = WPA3 SAE \n"); + break; + default: + printf("Unknown PROTOCOL: 0x%x \n", buf->protocol); + break; + } + + /* Print key management */ + if (buf->key_mgmt == KEY_MGMT_PSK) + printf("KeyMgmt = PSK\n"); + else + printf("KeyMgmt = NONE\n"); + + /* Print WEP configurations */ + if (buf->wep_cfg.key0.length) { + printf("WEP KEY_0 = "); + for (i = 0; i < buf->wep_cfg.key0.length; i++) { + printf("%02x ", buf->wep_cfg.key0.key[i]); + } + (buf->wep_cfg.key0. + is_default) ? (printf("\n")) : (printf("\n")); + } else { + printf("WEP KEY_0 = NONE\n"); + } + if (buf->wep_cfg.key1.length) { + printf("WEP KEY_1 = "); + for (i = 0; i < buf->wep_cfg.key1.length; i++) { + printf("%02x ", buf->wep_cfg.key1.key[i]); + } + (buf->wep_cfg.key1. + is_default) ? (printf("\n")) : (printf("\n")); + } else { + printf("WEP KEY_1 = NONE\n"); + } + if (buf->wep_cfg.key2.length) { + printf("WEP KEY_2 = "); + for (i = 0; i < buf->wep_cfg.key2.length; i++) { + printf("%02x ", buf->wep_cfg.key2.key[i]); + } + (buf->wep_cfg.key2. + is_default) ? (printf("\n")) : (printf("\n")); + } else { + printf("WEP KEY_2 = NONE\n"); + } + if (buf->wep_cfg.key3.length) { + printf("WEP KEY_3 = "); + for (i = 0; i < buf->wep_cfg.key3.length; i++) { + printf("%02x ", buf->wep_cfg.key3.key[i]); + } + (buf->wep_cfg.key3. + is_default) ? (printf("\n")) : (printf("\n")); + } else { + printf("WEP KEY_3 = NONE\n"); + } + + /* Print WPA configurations */ + if (buf->protocol & PROTOCOL_WPA) { + switch (buf->wpa_cfg.pairwise_cipher_wpa) { + case CIPHER_TKIP: + printf("PwkCipherWPA = TKIP\n"); + break; + case CIPHER_AES_CCMP: + printf("PwkCipherWPA = AES CCMP\n"); + break; + case CIPHER_TKIP | CIPHER_AES_CCMP: + printf("PwkCipherWPA = TKIP + AES CCMP\n"); + break; + case CIPHER_NONE: + printf("PwkCipherWPA = None\n"); + break; + default: + printf("Unknown PwkCipherWPA 0x%x\n", + buf->wpa_cfg.pairwise_cipher_wpa); + break; + } + } + if (buf->protocol & (PROTOCOL_WPA2 | PROTOCOL_WPA3_SAE)) { + switch (buf->wpa_cfg.pairwise_cipher_wpa2) { + case CIPHER_TKIP: + printf("PwkCipherWPA2 = TKIP\n"); + break; + case CIPHER_AES_CCMP: + printf("PwkCipherWPA2 = AES CCMP\n"); + break; + case CIPHER_TKIP | CIPHER_AES_CCMP: + printf("PwkCipherWPA2 = TKIP + AES CCMP\n"); + break; + case CIPHER_NONE: + printf("PwkCipherWPA2 = None\n"); + break; + default: + printf("Unknown PwkCipherWPA2 0x%x\n", + buf->wpa_cfg.pairwise_cipher_wpa2); + break; + } + } + switch (buf->wpa_cfg.group_cipher) { + case CIPHER_TKIP: + printf("GroupCipher = TKIP\n"); + break; + case CIPHER_AES_CCMP: + printf("GroupCipher = AES CCMP\n"); + break; + case CIPHER_NONE: + printf("GroupCipher = None\n"); + break; + default: + printf("Unknown Group cipher 0x%x\n", + buf->wpa_cfg.group_cipher); + break; + } + printf("RSN replay protection = %s\n", + (buf->wpa_cfg.rsn_protection) ? "enabled" : "disabled"); + printf("Pairwise Handshake timeout = %d\n", + buf->pairwise_update_timeout); + printf("Pairwise Handshake Retries = %d\n", buf->pwk_retries); + printf("Groupwise Handshake timeout = %d\n", + buf->groupwise_update_timeout); + printf("Groupwise Handshake Retries = %d\n", buf->gwk_retries); + if (buf->wpa_cfg.length > 0) { + printf("WPA passphrase = "); + for (i = 0; (unsigned int)i < buf->wpa_cfg.length; i++) + printf("%c", buf->wpa_cfg.passphrase[i]); + printf("\n"); + } else { + printf("WPA passphrase = None\n"); + } + if (buf->wpa_cfg.gk_rekey_time == 0) + printf("Group re-key time = disabled\n"); + else + printf("Group re-key time = %d second\n", + buf->wpa_cfg.gk_rekey_time); + printf("20/40 coex = %s\n", + (buf->enable_2040coex) ? "enabled" : "disabled"); + printf("wmm parameters:\n"); + printf("\tqos_info = 0x%x\n", buf->wmm_para.qos_info); + printf("\tBE: AIFSN=%d, CW_MAX=%d CW_MIN=%d, TXOP=%d\n", + buf->wmm_para.ac_params[AC_BE].aci_aifsn.aifsn, + buf->wmm_para.ac_params[AC_BE].ecw.ecw_max, + buf->wmm_para.ac_params[AC_BE].ecw.ecw_min, + buf->wmm_para.ac_params[AC_BE].tx_op_limit); + printf("\tBK: AIFSN=%d, CW_MAX=%d CW_MIN=%d, TXOP=%d\n", + buf->wmm_para.ac_params[AC_BK].aci_aifsn.aifsn, + buf->wmm_para.ac_params[AC_BK].ecw.ecw_max, + buf->wmm_para.ac_params[AC_BK].ecw.ecw_min, + buf->wmm_para.ac_params[AC_BK].tx_op_limit); + printf("\tVI: AIFSN=%d, CW_MAX=%d CW_MIN=%d, TXOP=%d\n", + buf->wmm_para.ac_params[AC_VI].aci_aifsn.aifsn, + buf->wmm_para.ac_params[AC_VI].ecw.ecw_max, + buf->wmm_para.ac_params[AC_VI].ecw.ecw_min, + buf->wmm_para.ac_params[AC_VI].tx_op_limit); + printf("\tVO: AIFSN=%d, CW_MAX=%d CW_MIN=%d, TXOP=%d\n", + buf->wmm_para.ac_params[AC_VO].aci_aifsn.aifsn, + buf->wmm_para.ac_params[AC_VO].ecw.ecw_max, + buf->wmm_para.ac_params[AC_VO].ecw.ecw_min, + buf->wmm_para.ac_params[AC_VO].tx_op_limit); + + return; +} + +/** + * @brief Send command to Read the BSS profile + * + * @param buf Pointer to bss command buffer for get + * @return UAP_SUCCESS or UAP_FAILURE + */ +static int +get_bss_config(t_u8 *buf) +{ + apcmdbuf_bss_configure *cmd_buf = NULL; + t_s32 sockfd; + struct ifreq ifr; + + cmd_buf = (apcmdbuf_bss_configure *)buf; + cmd_buf->action = ACTION_GET; + + /* Open socket */ + if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) { + printf("ERR:Cannot open socket\n"); + return UAP_FAILURE; + } +#if DEBUG + /* Dump request buffer */ + hexdump("Get Request buffer", (void *)buf, + sizeof(apcmdbuf_bss_configure) + + sizeof(bss_config_t), ' '); +#endif + /* Initialize the ifr structure */ + memset(&ifr, 0, sizeof(ifr)); + strncpy(ifr.ifr_ifrn.ifrn_name, dev_name, IFNAMSIZ - 1); + ifr.ifr_ifru.ifru_data = (void *)cmd_buf; + if (ioctl(sockfd, UAP_BSS_CONFIG, &ifr)) { + printf("ERR:UAP_BSS_CONFIG is not supported by %s\n", dev_name); + close(sockfd); + return UAP_FAILURE; + } +#if DEBUG + /* Dump request buffer */ + hexdump("Get Response buffer", (void *)buf, + sizeof(apcmdbuf_bss_configure) + + sizeof(bss_config_t), ' '); +#endif + close(sockfd); + return UAP_SUCCESS; +} + +/** + * @brief Creates a bss_config request and sends to the driver + * + * Usage: "Usage : bss_config [CONFIG_FILE]" + * + * @param argc Number of arguments + * @param argv Pointer to the arguments + * @return UAP_SUCCESS/UAP_FAILURE + */ +int +apcmd_bss_config(int argc, char *argv[]) +{ + apcmdbuf_bss_configure *cmd_buf = NULL; + bss_config_t *bss = NULL; + t_u8 *buf = NULL; + t_u16 cmd_len; + t_u16 buf_len; + int ret = UAP_SUCCESS; + int opt; + t_s32 sockfd; + struct ifreq ifr; + + while ((opt = getopt_long(argc, argv, "+", cmd_options, NULL)) != -1) { + switch (opt) { + default: + print_bss_config_usage(); + return UAP_SUCCESS; + } + } + argc -= optind; + argv += optind; + + /* Check arguments */ + if (argc > 1) { + printf("ERR:Too many arguments.\n"); + print_bss_config_usage(); + return UAP_FAILURE; + } + + /* Query BSS settings */ + + /* Alloc buf for command */ + buf_len = sizeof(apcmdbuf_bss_configure) + sizeof(bss_config_t); + buf = (t_u8 *)malloc(buf_len); + if (!buf) { + printf("ERR:Cannot allocate buffer from command!\n"); + return UAP_FAILURE; + } + memset((char *)buf, 0, buf_len); + + /* Locate headers */ + cmd_len = sizeof(apcmdbuf_bss_configure); + cmd_buf = (apcmdbuf_bss_configure *)buf; + bss = (bss_config_t *)(buf + cmd_len); + + /* Get all parametes first */ + if (get_bss_config(buf) == UAP_FAILURE) { + printf("ERR:Reading current parameters\n"); + free(buf); + return UAP_FAILURE; + } + + if (argc == 1) { + /* Parse config file and populate structure */ + ret = parse_bss_config(argc, argv, bss); + if (ret == UAP_FAILURE) { + free(buf); + return ret; + } + cmd_len += sizeof(bss_config_t); + cmd_buf->action = ACTION_SET; + + /* Send the command */ + /* Open socket */ + if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) { + printf("ERR:Cannot open socket\n"); + free(buf); + return UAP_FAILURE; + } + + /* Initialize the ifr structure */ + memset(&ifr, 0, sizeof(ifr)); + strncpy(ifr.ifr_ifrn.ifrn_name, dev_name, IFNAMSIZ - 1); + ifr.ifr_ifru.ifru_data = (void *)cmd_buf; +#if DEBUG + /* Dump request buffer */ + hexdump("Request buffer", (void *)buf, buf_len, ' '); +#endif + if (ioctl(sockfd, UAP_BSS_CONFIG, &ifr)) { + perror(""); + printf("ERR:UAP_BSS_CONFIG is not supported by %s\n", + dev_name); + close(sockfd); + free(buf); + return UAP_FAILURE; + } +#if DEBUG + /* Dump respond buffer */ + hexdump("Respond buffer", (void *)buf, buf_len, ' '); +#endif + close(sockfd); + } else { + /* Print response */ + printf("BSS settings:\n"); + print_bss_config(bss); + } + + free(buf); + return ret; +} + +/** + * @brief Read the profile and sends to the driver + * + * @param argc Number of arguments + * @param argv Pointer to the arguments + * @return UAP_SUCCESS or UAP_FAILURE + */ +int +apcmd_coex_config_profile(int argc, char *argv[]) +{ + FILE *config_file = NULL; + char *line = NULL; + int i, index, li = 0; + int ret = UAP_SUCCESS; + char *pos = NULL; + int arg_num = 0; + char *args[30]; + int is_coex_config = 0; + int is_coex_common_config = 0; + int is_coex_sco_config = 0; + int is_coex_acl_config = 0; + t_u8 *buf = NULL; + apcmdbuf_coex_config *cmd_buf = NULL; + tlvbuf_coex_common_cfg *coex_common_tlv; + tlvbuf_coex_sco_cfg *coex_sco_tlv; + tlvbuf_coex_acl_cfg *coex_acl_tlv; + t_u16 acl_enabled = 0; + t_u32 conf_bitmap = 0; + t_u32 ap_coex_enable = 0; + t_u16 cmd_len = 0, tlv_len = 0; + t_u16 sco_prot_qtime[4] = { 0, 0, 0, 0 }, sco_prot_rate = + 0, sco_acl_freq = 0; + t_u16 acl_bt_time = 0, acl_wlan_time = 0, acl_prot_rate = 0; + + /* Check if file exists */ + config_file = fopen(argv[0], "r"); + if (config_file == NULL) { + printf("\nERR:Config file can not open.\n"); + return UAP_FAILURE; + } + line = (char *)malloc(MAX_CONFIG_LINE); + if (!line) { + printf("ERR:Cannot allocate memory for line\n"); + ret = UAP_FAILURE; + goto done; + } + bzero(line, MAX_CONFIG_LINE); + + /* fixed command length */ + cmd_len = sizeof(apcmdbuf_coex_config) + sizeof(tlvbuf_coex_common_cfg) + + sizeof(tlvbuf_coex_sco_cfg) + sizeof(tlvbuf_coex_acl_cfg); + /* alloc buf for command */ + buf = (t_u8 *)malloc(cmd_len); + if (!buf) { + printf("ERR:Cannot allocate buffer from command!\n"); + ret = UAP_FAILURE; + goto done; + } + bzero((char *)buf, cmd_len); + + cmd_buf = (apcmdbuf_coex_config *)buf; + + /* Fill the command buffer */ + cmd_buf->cmd_code = HostCmd_ROBUST_COEX; + cmd_buf->size = cmd_len - BUF_HEADER_SIZE; + cmd_buf->seq_num = 0; + cmd_buf->result = 0; + cmd_buf->action = uap_cpu_to_le16(ACTION_SET); + + /* Parse file and process */ + while (config_get_line(line, MAX_CONFIG_LINE, config_file, &li, &pos)) { +#if DEBUG + uap_printf(MSG_DEBUG, "DBG:Received config line (%d) = %s\n", + li, line); +#endif + arg_num = parse_line(line, args); +#if DEBUG + uap_printf(MSG_DEBUG, "DBG:Number of arguments = %d\n", + arg_num); + for (i = 0; i < arg_num; i++) { + uap_printf(MSG_DEBUG, "\tDBG:Argument %d. %s\n", i + 1, + args[i]); + } +#endif + /* Check for end of Coex configurations */ + if (is_coex_acl_config == 1) { + if (strcmp(args[0], "}") == 0) { + coex_acl_tlv = + (tlvbuf_coex_acl_cfg *)(cmd_buf-> + tlv_buffer + + tlv_len); + coex_acl_tlv->tag = MRVL_BT_COEX_ACL_CFG_TLV_ID; + coex_acl_tlv->length = + sizeof(tlvbuf_coex_acl_cfg) - + sizeof(tlvbuf_header); + endian_convert_tlv_header_out(coex_acl_tlv); + coex_acl_tlv->enabled = + uap_cpu_to_le16(acl_enabled); + coex_acl_tlv->bt_time = + uap_cpu_to_le16(acl_bt_time); + coex_acl_tlv->wlan_time = + uap_cpu_to_le16(acl_wlan_time); + coex_acl_tlv->protection_rate = + uap_cpu_to_le16(acl_prot_rate); + tlv_len += sizeof(tlvbuf_coex_acl_cfg); + is_coex_acl_config = 0; + } + } else if (is_coex_sco_config == 1) { + if (strcmp(args[0], "}") == 0) { + coex_sco_tlv = + (tlvbuf_coex_sco_cfg *)(cmd_buf-> + tlv_buffer + + tlv_len); + coex_sco_tlv->tag = MRVL_BT_COEX_SCO_CFG_TLV_ID; + coex_sco_tlv->length = + sizeof(tlvbuf_coex_sco_cfg) - + sizeof(tlvbuf_header); + endian_convert_tlv_header_out(coex_sco_tlv); + for (i = 0; i < 4; i++) + coex_sco_tlv->protection_qtime[i] = + uap_cpu_to_le16(sco_prot_qtime + [i]); + coex_sco_tlv->protection_rate = + uap_cpu_to_le16(sco_prot_rate); + coex_sco_tlv->acl_frequency = + uap_cpu_to_le16(sco_acl_freq); + tlv_len += sizeof(tlvbuf_coex_sco_cfg); + is_coex_sco_config = 0; + } + } else if (is_coex_common_config == 1) { + if (strcmp(args[0], "}") == 0) { + coex_common_tlv = + (tlvbuf_coex_common_cfg *)(cmd_buf-> + tlv_buffer + + tlv_len); + coex_common_tlv->tag = + MRVL_BT_COEX_COMMON_CFG_TLV_ID; + coex_common_tlv->length = + sizeof(tlvbuf_coex_common_cfg) - + sizeof(tlvbuf_header); + endian_convert_tlv_header_out(coex_common_tlv); + coex_common_tlv->config_bitmap = + uap_cpu_to_le32(conf_bitmap); + coex_common_tlv->ap_bt_coex = + uap_cpu_to_le32(ap_coex_enable); + tlv_len += sizeof(tlvbuf_coex_common_cfg); + is_coex_common_config = 0; + } + } else if (is_coex_config == 1) { + if (strcmp(args[0], "}") == 0) + is_coex_config = 0; + } + if (strcmp(args[0], "coex_config") == 0) { + is_coex_config = 1; + } else if (strcmp(args[0], "common_config") == 0) { + is_coex_common_config = 1; + } else if (strcmp(args[0], "sco_config") == 0) { + is_coex_sco_config = 1; + } else if (strcmp(args[0], "acl_config") == 0) { + is_coex_acl_config = 1; + } + if ((strcmp(args[0], "bitmap") == 0) && is_coex_common_config) { + if (is_input_valid + (COEX_COMM_BITMAP, arg_num - 1, + args + 1) != UAP_SUCCESS) { + ret = UAP_FAILURE; + goto done; + } + conf_bitmap = (t_u32)A2HEXDECIMAL(args[1]); + } else if ((strcmp(args[0], "APBTCoex") == 0) && + is_coex_common_config) { + if (is_input_valid + (COEX_COMM_AP_COEX, arg_num - 1, + args + 1) != UAP_SUCCESS) { + ret = UAP_FAILURE; + goto done; + } + ap_coex_enable = (t_u32)A2HEXDECIMAL(args[1]); + } else if ((strncmp(args[0], "protectionFromQTime", 19) == 0) && + is_coex_sco_config) { + index = atoi(args[0] + strlen("protectionFromQTime")); + if (index < 0 || index > 3) { + printf("ERR:Incorrect index %d.\n", index); + ret = UAP_FAILURE; + goto done; + } + if (is_input_valid(COEX_PROTECTION, arg_num, args) != + UAP_SUCCESS) { + ret = UAP_FAILURE; + goto done; + } + sco_prot_qtime[index] = (t_u16)atoi(args[1]); + } else if ((strcmp(args[0], "scoProtectionFromRate") == 0) && + is_coex_sco_config) { + if (is_input_valid(COEX_PROTECTION, arg_num, args) != + UAP_SUCCESS) { + ret = UAP_FAILURE; + goto done; + } + sco_prot_rate = (t_u16)atoi(args[1]); + } else if ((strcmp(args[0], "aclFrequency") == 0) && + is_coex_sco_config) { + if (is_input_valid + (COEX_SCO_ACL_FREQ, arg_num - 1, + args + 1) != UAP_SUCCESS) { + ret = UAP_FAILURE; + goto done; + } + sco_acl_freq = (t_u16)atoi(args[1]); + } else if ((strcmp(args[0], "enabled") == 0) && + is_coex_acl_config) { + if (is_input_valid + (COEX_ACL_ENABLED, arg_num - 1, + args + 1) != UAP_SUCCESS) { + ret = UAP_FAILURE; + goto done; + } + acl_enabled = (t_u16)atoi(args[1]); + } else if ((strcmp(args[0], "btTime") == 0) && + is_coex_acl_config) { + if (is_input_valid + (COEX_ACL_BT_TIME, arg_num - 1, + args + 1) != UAP_SUCCESS) { + ret = UAP_FAILURE; + goto done; + } + acl_bt_time = (t_u16)atoi(args[1]); + } else if ((strcmp(args[0], "wlanTime") == 0) && + is_coex_acl_config) { + if (is_input_valid + (COEX_ACL_WLAN_TIME, arg_num - 1, + args + 1) != UAP_SUCCESS) { + ret = UAP_FAILURE; + goto done; + } + acl_wlan_time = (t_u16)atoi(args[1]); + } else if ((strcmp(args[0], "aclProtectionFromRate") == 0) && + is_coex_acl_config) { + if (is_input_valid(COEX_PROTECTION, arg_num, args) != + UAP_SUCCESS) { + ret = UAP_FAILURE; + goto done; + } + acl_prot_rate = (t_u16)atoi(args[1]); + } + } + /* Send the command */ + ret = uap_ioctl((t_u8 *)cmd_buf, &cmd_len, cmd_len); + + /* Process response */ + if (ret == UAP_SUCCESS) { + /* Verify response */ + if (cmd_buf->cmd_code != + (HostCmd_ROBUST_COEX | APCMD_RESP_CHECK)) { + printf("ERR:Corrupted response!\n"); + ret = UAP_FAILURE; + goto done; + } + /* Print response */ + if (cmd_buf->result == CMD_SUCCESS) { + printf("BT Coex settings sucessfully set.\n"); + } else { + printf("ERR:Could not set coex configuration.\n"); + } + } else { + printf("ERR:Command sending failed!\n"); + } +done: + fclose(config_file); + if (buf) + free(buf); + if (line) + free(line); + return ret; +} + +/** + * @brief Show usage information for the coex_config command + * + * $return N/A + */ +void +print_coex_config_usage(void) +{ + printf("\nUsage : coex_config [CONFIG_FILE]\n"); + printf("\nIf CONFIG_FILE is provided, a 'set' is performed, else a 'get' is performed.\n"); + return; +} + +/** + * @brief Creates a coex_config request and sends to the driver + * + * Usage: "Usage : coex_config [CONFIG_FILE]" + * + * @param argc Number of arguments + * @param argv Pointer to the arguments + * @return UAP_SUCCESS or UAP_FAILURE + */ +int +apcmd_coex_config(int argc, char *argv[]) +{ + apcmdbuf_coex_config *cmd_buf = NULL; + tlvbuf_coex_common_cfg *coex_common_tlv; + tlvbuf_coex_sco_cfg *coex_sco_tlv; + tlvbuf_coex_acl_cfg *coex_acl_tlv; + tlvbuf_coex_stats *coex_stats_tlv; + t_u8 *buf = NULL; + t_u16 cmd_len = 0; + t_u16 buf_len = MRVDRV_SIZE_OF_CMD_BUFFER; + int ret = UAP_SUCCESS; + int opt; + + while ((opt = getopt_long(argc, argv, "+", cmd_options, NULL)) != -1) { + switch (opt) { + default: + print_coex_config_usage(); + return UAP_SUCCESS; + } + } + argc -= optind; + argv += optind; + + /* Check arguments */ + if (argc > 1) { + printf("ERR:Too many arguments.\n"); + print_coex_config_usage(); + return UAP_FAILURE; + } + if (argc == 1) { + /* Read profile and send command to firmware */ + ret = apcmd_coex_config_profile(argc, argv); + return ret; + } + + /* fixed command length */ + cmd_len = sizeof(apcmdbuf_coex_config) + sizeof(tlvbuf_coex_common_cfg) + + sizeof(tlvbuf_coex_sco_cfg) + sizeof(tlvbuf_coex_acl_cfg) + + sizeof(tlvbuf_coex_stats); + /* alloc buf for command */ + buf = (t_u8 *)malloc(buf_len); + if (!buf) { + printf("ERR:Cannot allocate buffer from command!\n"); + return UAP_FAILURE; + } + bzero((char *)buf, buf_len); + + cmd_buf = (apcmdbuf_coex_config *)buf; + + coex_common_tlv = (tlvbuf_coex_common_cfg *)cmd_buf->tlv_buffer; + coex_common_tlv->tag = MRVL_BT_COEX_COMMON_CFG_TLV_ID; + coex_common_tlv->length = + sizeof(tlvbuf_coex_common_cfg) - sizeof(tlvbuf_header); + endian_convert_tlv_header_out(coex_common_tlv); + + coex_sco_tlv = (tlvbuf_coex_sco_cfg *)(cmd_buf->tlv_buffer + + sizeof(tlvbuf_coex_common_cfg)); + coex_sco_tlv->tag = MRVL_BT_COEX_SCO_CFG_TLV_ID; + coex_sco_tlv->length = + sizeof(tlvbuf_coex_sco_cfg) - sizeof(tlvbuf_header); + endian_convert_tlv_header_out(coex_sco_tlv); + + coex_acl_tlv = (tlvbuf_coex_acl_cfg *)(cmd_buf->tlv_buffer + + sizeof(tlvbuf_coex_common_cfg) + + sizeof(tlvbuf_coex_sco_cfg)); + coex_acl_tlv->tag = MRVL_BT_COEX_ACL_CFG_TLV_ID; + coex_acl_tlv->length = + sizeof(tlvbuf_coex_acl_cfg) - sizeof(tlvbuf_header); + endian_convert_tlv_header_out(coex_acl_tlv); + + coex_stats_tlv = (tlvbuf_coex_stats *)(cmd_buf->tlv_buffer + + sizeof(tlvbuf_coex_common_cfg) + + sizeof(tlvbuf_coex_sco_cfg) + + sizeof(tlvbuf_coex_acl_cfg)); + coex_stats_tlv->tag = MRVL_BT_COEX_STATS_TLV_ID; + coex_stats_tlv->length = + sizeof(tlvbuf_coex_stats) - sizeof(tlvbuf_header); + endian_convert_tlv_header_out(coex_stats_tlv); + + /* Fill the command buffer */ + cmd_buf->cmd_code = HostCmd_ROBUST_COEX; + cmd_buf->size = cmd_len - BUF_HEADER_SIZE; + cmd_buf->seq_num = 0; + cmd_buf->result = 0; + cmd_buf->action = uap_cpu_to_le16(ACTION_GET); + + /* Send the command */ + ret = uap_ioctl((t_u8 *)cmd_buf, &cmd_len, buf_len); + + /* Process response */ + if (ret == UAP_SUCCESS) { + /* Verify response */ + if (cmd_buf->cmd_code != + (HostCmd_ROBUST_COEX | APCMD_RESP_CHECK)) { + printf("ERR:Corrupted response!\n"); + free(buf); + return UAP_FAILURE; + } + /* Print response */ + if (cmd_buf->result == CMD_SUCCESS) { + printf("BT Coex settings:\n"); + print_tlv(buf + sizeof(apcmdbuf_coex_config), + cmd_buf->size - sizeof(apcmdbuf_coex_config) + + BUF_HEADER_SIZE); + } else { + printf("ERR:Could not retrieve coex configuration.\n"); + ret = UAP_FAILURE; + } + } else { + printf("ERR:Command sending failed!\n"); + } + free(buf); + return ret; +} + +/** + * @brief Show usage information for the mic_err command + * + * $return N/A + */ +void +print_mic_err_usage(void) +{ + printf("\nUsage : mic_err \n"); + return; +} + +/** + * @brief report station mic error to the driver + * + * Usage: "mic_err " + * + * @param argc Number of arguments + * @param argv Pointer to the arguments + * @return UAP_SUCCESS/UAP_FAILURE + */ +int +apcmd_mic_err(int argc, char *argv[]) +{ + int ret = UAP_SUCCESS; + int opt; + struct ifreq ifr; + t_s32 sockfd; + t_u8 mac_addr[ETH_ALEN]; + + while ((opt = getopt_long(argc, argv, "+", cmd_options, NULL)) != -1) { + switch (opt) { + default: + print_mic_err_usage(); + return UAP_SUCCESS; + } + } + argc -= optind; + argv += optind; + + /* Check arguments */ + if (argc != 1) { + printf("ERR:wrong arguments! Must provide STA_MAC_ADDRESS.\n"); + print_mic_err_usage(); + return UAP_FAILURE; + } + memset(mac_addr, 0, ETH_ALEN); + + if ((ret = mac2raw(argv[0], mac_addr)) != UAP_SUCCESS) { + printf("ERR: %s Address\n", ret == UAP_FAILURE ? "Invalid MAC" : + ret == + UAP_RET_MAC_BROADCAST ? "Broadcast" : "Multicast"); + return UAP_FAILURE; + } +#if DEBUG + /* Dump mac address */ + hexdump("report mic error", (void *)mac_addr, ETH_ALEN, ' '); +#endif + /* Open socket */ + if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) { + printf("ERR:Cannot open socket\n"); + return UAP_FAILURE; + } + /* Initialize the ifr structure */ + memset(&ifr, 0, sizeof(ifr)); + strncpy(ifr.ifr_ifrn.ifrn_name, dev_name, IFNAMSIZ - 1); + ifr.ifr_ifru.ifru_data = (void *)mac_addr; + /* Perform ioctl */ + errno = 0; + if (ioctl(sockfd, UAP_REPORT_MIC_ERR, &ifr)) { + perror(""); + printf("ERR:UAP_REPORT_MIC_ERR is not supported by %s\n", + dev_name); + close(sockfd); + return UAP_FAILURE; + } + printf("MIC error reporting successful!\n"); + /* Close socket */ + close(sockfd); + return UAP_SUCCESS; +} + +/** + * @brief Show usage information for the sta_deauth_ext command + * + * $return N/A + */ +void +print_set_key_usage(void) +{ + printf("\nUsage : key_material [KEY_ID]\n"); + printf("\n MAC_ADDRESS: station mac address or ff:ff:ff:ff:ff:ff"); + printf("\n KEY: hex string, valid length 32 or 64\n"); + return; +} + +/** + * @brief Creates a set key request and sends to the driver + * + * Usage: "set_key [KEY_ID]" + * + * @param argc Number of arguments + * @param argv Pointer to the arguments + * @return UAP_SUCCESS/UAP_FAILURE + */ +int +apcmd_set_key(int argc, char *argv[]) +{ + int ret = UAP_SUCCESS; + int opt; + struct ifreq ifr; + t_s32 sockfd; + encrypt_key key; + int key_id = 0; + + while ((opt = getopt_long(argc, argv, "+", cmd_options, NULL)) != -1) { + switch (opt) { + default: + print_set_key_usage(); + return UAP_SUCCESS; + } + } + argc -= optind; + argv += optind; + + /* Check arguments */ + if (argc < 2 || argc > 3) { + print_set_key_usage(); + return UAP_FAILURE; + } + memset(&key, 0, sizeof(encrypt_key)); + + ret = mac2raw(argv[0], key.mac_addr); + + if ((ret != UAP_SUCCESS) && (ret != UAP_RET_MAC_BROADCAST)) { + printf("ERR: %s Address\n", + ret == UAP_FAILURE ? "Invalid MAC" : "Multicast"); + return UAP_FAILURE; + } + if ((strlen(argv[1]) != 32) && (strlen(argv[1]) != 64)) { + printf("ERR: key must be hex string with length 32 or 64"); + print_set_key_usage(); + return UAP_FAILURE; + } + if (UAP_FAILURE == ishexstring(argv[1])) { + printf("ERR:Only hex digits are allowed\n"); + print_set_key_usage(); + return UAP_FAILURE; + } + if (argc == 3) { + if ((ISDIGIT(argv[2]) == 0) || (atoi(argv[2]) < 0) || + (atoi(argv[2]) > 3)) { + printf("ERR:Illegal key id %s. Must be either '0', '1', '2', or '3'.\n", argv[2]); + print_set_key_usage(); + return UAP_FAILURE; + } + key_id = atoi(argv[2]); + } + + key.key_len = strlen(argv[1]) / 2; + string2raw(argv[1], key.key_material); + key.key_index = key_id; + +#if DEBUG + /* dump key buffer */ + hexdump("set key", (void *)&key, sizeof(encrypt_key), ' '); +#endif + + /* Open socket */ + if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) { + printf("ERR:Cannot open socket\n"); + return UAP_FAILURE; + } + /* Initialize the ifr structure */ + memset(&ifr, 0, sizeof(ifr)); + strncpy(ifr.ifr_ifrn.ifrn_name, dev_name, IFNAMSIZ - 1); + ifr.ifr_ifru.ifru_data = (void *)&key; + /* Perform ioctl */ + errno = 0; + if (ioctl(sockfd, UAP_SET_KEY, &ifr)) { + perror(""); + printf("ERR:UAP_SET_KEY is not supported by %s\n", dev_name); + close(sockfd); + return UAP_FAILURE; + } + printf("Key setting successful.\n"); + /* Close socket */ + close(sockfd); + return UAP_SUCCESS; +} + +/** + * @brief Show usage information for the sys_cfg_custom_ie + * command + * + * $return N/A + */ +void +print_sys_cfg_custom_ie_usage(void) +{ + printf("\nUsage : sys_cfg_custom_ie [INDEX] [MASK] [IEBuffer]"); + printf("\n empty - Get all IE settings\n"); + printf("\n INDEX: 0 - Get/Set IE index 0 setting"); + printf("\n 1 - Get/Set IE index 1 setting"); + printf("\n 2 - Get/Set IE index 2 setting"); + printf("\n 3 - Get/Set IE index 3 setting"); + printf("\n . "); + printf("\n . "); + printf("\n . "); + printf("\n -1 - Append/Delete IE automatically"); + printf("\n Delete will delete the IE from the matching IE buffer"); + printf("\n Append will append the IE to the buffer with the same mask"); + printf("\n MASK : Management subtype mask value as per bit defintions"); + printf("\n : Bit 0 - Association request."); + printf("\n : Bit 1 - Association response."); + printf("\n : Bit 2 - Reassociation request."); + printf("\n : Bit 3 - Reassociation response."); + printf("\n : Bit 4 - Probe request."); + printf("\n : Bit 5 - Probe response."); + printf("\n : Bit 8 - Beacon."); + printf("\n MASK : MASK = 0 to clear the mask and the IE buffer"); + printf("\n IEBuffer : IE Buffer in hex (max 256 bytes)\n\n"); + return; +} + +/** custom IE, auto mask value */ +#define UAP_CUSTOM_IE_AUTO_MASK 0xffff + +/** + * @brief Get max management IE index + * @param max_mgmt_ie + * @param print flag + * @return UAP_SUCCESS/UAP_FAILURE + */ +static int +get_max_mgmt_ie(int *max_mgmt_ie, int flag) +{ + apcmdbuf_sys_configure *cmd_buf = NULL; + tlvbuf_max_mgmt_ie *tlv = NULL; + t_u8 *buffer = NULL; + t_u16 cmd_len = 0, i = 0; + t_u16 buf_len = MRVDRV_SIZE_OF_CMD_BUFFER; + int ret = UAP_SUCCESS; + + *max_mgmt_ie = 0; + /* Initialize the command length */ + cmd_len = sizeof(apcmdbuf_sys_configure) + sizeof(tlvbuf_max_mgmt_ie); + + /* Initialize the command buffer */ + buffer = (t_u8 *)malloc(buf_len); + if (!buffer) { + printf("ERR:Cannot allocate buffer for command!\n"); + return UAP_FAILURE; + } + memset(buffer, 0, buf_len); + + /* Locate headers */ + cmd_buf = (apcmdbuf_sys_configure *)buffer; + tlv = (tlvbuf_max_mgmt_ie *)(buffer + sizeof(apcmdbuf_sys_configure)); + + /* Fill the command buffer */ + cmd_buf->cmd_code = APCMD_SYS_CONFIGURE; + cmd_buf->size = cmd_len; + cmd_buf->seq_num = 0; + cmd_buf->result = 0; + tlv->tag = MRVL_MAX_MGMT_IE_TLV_ID; + tlv->length = 0; + cmd_buf->action = ACTION_GET; + endian_convert_tlv_header_out(tlv); + /* Send the command */ + ret = uap_ioctl((t_u8 *)cmd_buf, &cmd_len, buf_len); + endian_convert_tlv_header_in(tlv); + + /* Process response */ + if (ret == UAP_SUCCESS) { + /* Verify response */ + if ((cmd_buf->cmd_code != + (APCMD_SYS_CONFIGURE | APCMD_RESP_CHECK)) || + (tlv->tag != MRVL_MAX_MGMT_IE_TLV_ID)) { + printf("ERR:Corrupted response! cmd_code=%x, Tlv->tag=%x\n", cmd_buf->cmd_code, tlv->tag); + free(buffer); + return UAP_FAILURE; + } + /* Print response */ + if (cmd_buf->result == CMD_SUCCESS) { + tlv->count = uap_le16_to_cpu(tlv->count); + for (i = 0; i < tlv->count; i++) { + tlv->info[i].buf_size = + uap_le16_to_cpu(tlv->info[i].buf_size); + tlv->info[i].buf_count = + uap_le16_to_cpu(tlv->info[i].buf_count); + *max_mgmt_ie += tlv->info[i].buf_count; + if (flag) { + printf("buf%d_size = %d\n", i, + tlv->info[i].buf_size); + printf("number of buffers = %d\n", + tlv->info[i].buf_count); + printf("\n"); + } + } + } else { + printf("ERR:Could not get max_mgmt_ie_index!\n"); + ret = UAP_FAILURE; + } + } else { + printf("ERR:Command sending failed!\n"); + } + if (buffer) + free(buffer); + return UAP_SUCCESS; +} + +/** + * @brief Creates a sys_cfg request for custom IE settings + * and sends to the driver + * + * Usage: "sys_cfg_custom_ie [INDEX] [MASK] [IEBuffer]" + * + * Options: INDEX : 0 - Get/Set IE index 0 setting + * 1 - Get/Set IE index 1 setting + * 2 - Get/Set IE index 2 setting + * 3 - Get/Set IE index 3 setting + * . + * . + * . + * MASK : Management subtype mask value + * IEBuffer: IE Buffer in hex + * empty - Get all IE settings + * + * @param argc Number of arguments + * @param argv Pointer to the arguments + * @return UAP_SUCCESS/UAP_FAILURE + */ +int +apcmd_sys_cfg_custom_ie(int argc, char *argv[]) +{ + tlvbuf_custom_ie *tlv = NULL; + tlvbuf_max_mgmt_ie *max_mgmt_ie_tlv = NULL; + custom_ie *ie_ptr = NULL; + t_u8 *buffer = NULL; + t_u16 buf_len = 0; + t_u16 mgmt_subtype_mask = 0; + int ie_buf_len = 0, ie_len = 0, i = 0, max_mgmt_ie = 0, print_flag = 0; + struct ifreq ifr; + t_s32 sockfd; + + if (argc == 1 && max_mgmt_ie_print == 0) { + /* Print buffer sizes only if (argc == 1) i.e. get all indices one by one + * && (max_mgmt_ie_print == 0) i.e. max mgmt IE is not printed via sys_config cmd */ + print_flag = 1; + } + + /* Reset the max_mgmt_ie_print for successive cmds */ + max_mgmt_ie_print = 0; + + if (!get_max_mgmt_ie(&max_mgmt_ie, print_flag)) { + printf("ERR:couldn't get max_mgmt_ie!\n"); + return UAP_FAILURE; + } + if (max_mgmt_ie == 0) { + max_mgmt_ie = MAX_MGMT_IE_INDEX; +#if DEBUG + uap_printf(MSG_DEBUG, + "WARN: max_mgmt_ie=0, defaulting to MAX_MGMT_IE_INDEX\n"); +#endif + } + + /* Check arguments */ + if (argc > 4) { + printf("ERR:Too many arguments.\n"); + print_sys_cfg_custom_ie_usage(); + return UAP_FAILURE; + } + + /* Error checks and initialize the command length */ + if (argc >= 2) { + if (((IS_HEX_OR_DIGIT(argv[1]) == UAP_FAILURE) && + (atoi(argv[1]) != -1)) || (atoi(argv[1]) < -1)) { + printf("ERR:Illegal index %s\n", argv[1]); + print_sys_cfg_custom_ie_usage(); + return UAP_FAILURE; + } + } + switch (argc) { + case 1: + buf_len = MRVDRV_SIZE_OF_CMD_BUFFER; + break; + case 2: + if ((atoi(argv[1]) < 0) || (atoi(argv[1]) >= max_mgmt_ie)) { + printf("ERR:Illegal index %s. Must be either greater than or equal to 0 and less than %d for Get Operation \n", argv[1], max_mgmt_ie); + print_sys_cfg_custom_ie_usage(); + return UAP_FAILURE; + } + buf_len = MRVDRV_SIZE_OF_CMD_BUFFER; + break; + case 3: + if (UAP_FAILURE == ishexstring(argv[2]) || + A2HEXDECIMAL(argv[2]) != 0) { + printf("ERR: Mask value should be 0 to clear IEBuffers.\n"); + print_sys_cfg_custom_ie_usage(); + return UAP_FAILURE; + } + if (atoi(argv[1]) == -1) { + printf("ERR: Buffer should be provided for automatic deletion.\n"); + print_sys_cfg_custom_ie_usage(); + return UAP_FAILURE; + } + buf_len = sizeof(tlvbuf_custom_ie) + sizeof(custom_ie); + break; + case 4: + /* This is to check negative numbers and special symbols */ + if (UAP_FAILURE == IS_HEX_OR_DIGIT(argv[2])) { + printf("ERR:Mask value must be 0 or hex digits\n"); + print_sys_cfg_custom_ie_usage(); + return UAP_FAILURE; + } + /* If above check is passed and mask is not hex, then it must be 0 */ + if ((ISDIGIT(argv[2]) == UAP_SUCCESS) && atoi(argv[2])) { + printf("ERR:Mask value must be 0 or hex digits\n "); + print_sys_cfg_custom_ie_usage(); + return UAP_FAILURE; + } + if (UAP_FAILURE == ishexstring(argv[3])) { + printf("ERR:Only hex digits are allowed\n"); + print_sys_cfg_custom_ie_usage(); + return UAP_FAILURE; + } + ie_buf_len = strlen(argv[3]); + if (!strncasecmp("0x", argv[3], 2)) { + ie_len = (ie_buf_len - 2 + 1) / 2; + argv[3] += 2; + } else + ie_len = (ie_buf_len + 1) / 2; + if (ie_len > MAX_IE_BUFFER_LEN) { + printf("ERR:Incorrect IE length %d\n", ie_buf_len); + print_sys_cfg_custom_ie_usage(); + return UAP_FAILURE; + } + mgmt_subtype_mask = (t_u16)A2HEXDECIMAL(argv[2]); + buf_len = sizeof(tlvbuf_custom_ie) + sizeof(custom_ie) + ie_len; + break; + } + + /* Initialize the command buffer */ + buffer = (t_u8 *)malloc(buf_len); + if (!buffer) { + printf("ERR:Cannot allocate buffer for command!\n"); + return UAP_FAILURE; + } + memset(buffer, 0, buf_len); + tlv = (tlvbuf_custom_ie *)buffer; + tlv->tag = MRVL_MGMT_IE_LIST_TLV_ID; + if (argc == 1 || argc == 2) { + if (argc == 1) + tlv->length = 0; + else { + tlv->length = sizeof(t_u16); + ie_ptr = (custom_ie *)(tlv->ie_data); + ie_ptr->ie_index = (t_u16)(atoi(argv[1])); + } + } else { + /* Locate headers */ + ie_ptr = (custom_ie *)(tlv->ie_data); + /* Set TLV fields */ + tlv->length = sizeof(custom_ie) + ie_len; + ie_ptr->ie_index = atoi(argv[1]); + ie_ptr->mgmt_subtype_mask = mgmt_subtype_mask; + ie_ptr->ie_length = ie_len; + if (argc == 4) + string2raw(argv[3], ie_ptr->ie_buffer); + } + /* Open socket */ + if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) { + printf("ERR:Cannot open socket\n"); + if (buffer) + free(buffer); + return UAP_FAILURE; + } + if (argc != 1) { + /* Initialize the ifr structure */ + memset(&ifr, 0, sizeof(ifr)); + strncpy(ifr.ifr_ifrn.ifrn_name, dev_name, IFNAMSIZ - 1); + ifr.ifr_ifru.ifru_data = (void *)buffer; + /* Perform ioctl */ + if (ioctl(sockfd, UAP_CUSTOM_IE, &ifr)) { + if (errno < 0) { + perror("ioctl[UAP_CUSTOM_IE]"); + printf("ERR:Command sending failed!\n"); + } else { + printf("custom IE configuration failed!\n"); + } + close(sockfd); + if (buffer) + free(buffer); + return UAP_FAILURE; + } + /* Print response */ + if (argc > 2) { + printf("custom IE setting successful\n"); + } else { + printf("Querying custom IE successful\n"); + tlv = (tlvbuf_custom_ie *)buffer; + ie_len = tlv->length; + ie_ptr = (custom_ie *)(tlv->ie_data); + if (tlv->tag == MRVL_MGMT_IE_LIST_TLV_ID) { + while ((unsigned int)ie_len >= + sizeof(custom_ie)) { + printf("Index [%d]\n", + ie_ptr->ie_index); + if (ie_ptr->ie_length) + printf("Management Subtype Mask = 0x%02x\n", ie_ptr->mgmt_subtype_mask == 0 ? UAP_CUSTOM_IE_AUTO_MASK : ie_ptr->mgmt_subtype_mask); + else + printf("Management Subtype Mask = 0x%02x\n", ie_ptr->mgmt_subtype_mask); + hexdump_data("IE Buffer", + (void *)ie_ptr->ie_buffer, + (ie_ptr->ie_length), ' '); + ie_len -= + sizeof(custom_ie) + + ie_ptr->ie_length; + ie_ptr = (custom_ie *)((t_u8 *)ie_ptr + + sizeof(custom_ie) + + + ie_ptr-> + ie_length); + } + } + max_mgmt_ie_tlv = + (tlvbuf_max_mgmt_ie *)(buffer + + sizeof(tlvbuf_custom_ie) + + tlv->length); + if (max_mgmt_ie_tlv) { + if (max_mgmt_ie_tlv->tag == + MRVL_MAX_MGMT_IE_TLV_ID) { + for (i = 0; i < max_mgmt_ie_tlv->count; + i++) { + printf("buf%d_size = %d\n", i, + max_mgmt_ie_tlv->info[i]. + buf_size); + printf("number of buffers = %d\n", max_mgmt_ie_tlv->info[i].buf_count); + printf("\n"); + } + } + } + } + } + + /* Special handling for all indices: Get all IEs one-by-one */ + if (argc == 1) { + for (i = 0; i < max_mgmt_ie; i++) { + + tlv->length = sizeof(t_u16); + ie_ptr = (custom_ie *)(tlv->ie_data); + ie_ptr->ie_index = (t_u16)(i); + + /* Initialize the ifr structure */ + memset(&ifr, 0, sizeof(ifr)); + strncpy(ifr.ifr_ifrn.ifrn_name, dev_name, IFNAMSIZ - 1); + ifr.ifr_ifru.ifru_data = (void *)buffer; + /* Perform ioctl */ + if (ioctl(sockfd, UAP_CUSTOM_IE, &ifr)) { + if (errno < 0) { + perror("ioctl[UAP_CUSTOM_IE]"); + printf("ERR:Command sending failed!\n"); + } else { + printf("custom IE configuration failed!\n"); + } + close(sockfd); + if (buffer) + free(buffer); + return UAP_FAILURE; + } + /* Print response */ + tlv = (tlvbuf_custom_ie *)buffer; + ie_len = tlv->length; + ie_ptr = (custom_ie *)(tlv->ie_data); + if (tlv->tag == MRVL_MGMT_IE_LIST_TLV_ID) { + while ((unsigned int)ie_len >= + sizeof(custom_ie)) { + printf("Index [%d]\n", + ie_ptr->ie_index); + if (ie_ptr->ie_length) + printf("Management Subtype Mask = 0x%02x\n", ie_ptr->mgmt_subtype_mask == 0 ? UAP_CUSTOM_IE_AUTO_MASK : ie_ptr->mgmt_subtype_mask); + else + printf("Management Subtype Mask = 0x%02x\n", ie_ptr->mgmt_subtype_mask); + hexdump_data("IE Buffer", + (void *)ie_ptr->ie_buffer, + (ie_ptr->ie_length), ' '); + ie_len -= + sizeof(custom_ie) + + ie_ptr->ie_length; + ie_ptr = (custom_ie *)((t_u8 *)ie_ptr + + sizeof(custom_ie) + + + ie_ptr-> + ie_length); + } + } + } + printf("Querying custom IE successful\n"); + } + + if (buffer) + free(buffer); + + close(sockfd); + return UAP_SUCCESS; +} + +/** + * @brief Show usage information for the dfstesting command + * + * $return N/A + */ +void +print_dfstesting_usage(void) +{ + printf("\nUsage : dfstesting [USER_CAC_PD USER_NOP_PD NO_CHAN_CHANGE FIXED_CHAN_NUM]\n"); + printf("\n empty - Get all dfstesting settings\n"); + printf("\n USER_CAC_PD: user configured Channel Availability Check period"); + printf("\n 0 - disable, use default (60000)"); + printf("\n 1-65535 - CAC period in msec"); + printf("\n USER_NOP_PD: user configured Non-Occupancy Period"); + printf("\n 0 - disable, use default (1800)"); + printf("\n 1-65535 - NOP period in sec"); + printf("\n NO_CHAN_CHANGE: user setting, don't change channel on radar"); + printf("\n 0 - disable, default behavior"); + printf("\n non-zero - enable, overrides below setting"); + printf("\n FIXED_CHAN_NUM: user fixed channel to change to on radar"); + printf("\n 0 - disable, use random channel [default]"); + printf("\n 1-255 - set fixed channel (not checked for validity)\n"); + return; +} + +/** + * @brief user configuration of dfs testing settings + * + * Usage: "dfstesting [USER_CAC_PD USER_NOP_PD NO_CHAN_CHANGE FIXED_CHAN_NUM]" + * + * @param argc Number of arguments + * @param argv Pointer to the arguments + * @return UAP_SUCCESS/UAP_FAILURE + */ +int +apcmd_dfstesting(int argc, char *argv[]) +{ + int opt; + struct ifreq ifr; + t_s32 sockfd; + t_u32 val; + dfs_testing_para dfs_test; + + while ((opt = getopt_long(argc, argv, "+", cmd_options, NULL)) != -1) { + switch (opt) { + default: + print_dfstesting_usage(); + return UAP_SUCCESS; + } + } + argc -= optind; + argv += optind; + + memset(&dfs_test, 0x00, sizeof(dfs_test)); + + /* Check arguments */ + if (argc == 0) { + dfs_test.action = ACTION_GET; + } else if (argc == 4) { + if ((IS_HEX_OR_DIGIT(argv[0]) == UAP_FAILURE) || + (IS_HEX_OR_DIGIT(argv[1]) == UAP_FAILURE) || + (IS_HEX_OR_DIGIT(argv[2]) == UAP_FAILURE) || + (IS_HEX_OR_DIGIT(argv[3]) == UAP_FAILURE)) { + printf("ERR: Only Number values are allowed\n"); + print_dfstesting_usage(); + return UAP_FAILURE; + } + + val = A2HEXDECIMAL(argv[0]); + if (val > 0xfffff) { + printf("ERR: invalid user_cac_pd value!\n"); + return UAP_FAILURE; + } + dfs_test.usr_cac_period = (t_u32)val; + + val = A2HEXDECIMAL(argv[1]); + if (val > 0xffff) { + printf("ERR: invalid user_nop_pd value!\n"); + return UAP_FAILURE; + } + dfs_test.usr_nop_period = (t_u16)val; + + val = A2HEXDECIMAL(argv[2]); + dfs_test.no_chan_change = (t_u8)(val ? 1 : 0); + + val = A2HEXDECIMAL(argv[3]); + if (val > 0xff) { + printf("ERR: invalid fixed_chan_num value!\n"); + return UAP_FAILURE; + } + dfs_test.fixed_new_chan = (t_u8)val; + dfs_test.action = ACTION_SET; + } else { + printf("ERR: invalid number of arguments! Must be 0 or 4.\n"); + print_dfstesting_usage(); + return UAP_FAILURE; + } + dfs_test.subcmd = UAP_DFS_TESTING; + + /* Open socket */ + if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) { + printf("ERR:Cannot open socket\n"); + return UAP_FAILURE; + } + /* Initialize the ifr structure */ + memset(&ifr, 0, sizeof(ifr)); + strncpy(ifr.ifr_ifrn.ifrn_name, dev_name, IFNAMSIZ - 1); + ifr.ifr_ifru.ifru_data = (void *)&dfs_test; + /* Perform ioctl */ + errno = 0; + if (ioctl(sockfd, UAP_IOCTL_CMD, &ifr)) { + perror(""); + printf("ERR: UAP_DFS_TESTING is not supported by %s\n", + dev_name); + close(sockfd); + return UAP_FAILURE; + } + + if (argc) + printf("DFS testing setting successful!\n"); + else + printf("DFS testing settings:\n" + " user_cac_period = %d msec\n" + " user_nop_period = %d sec\n" + " no_channel_change = %d\n" + " fixed_channel_num = %d\n", + dfs_test.usr_cac_period, dfs_test.usr_nop_period, + dfs_test.no_chan_change, dfs_test.fixed_new_chan); + /* Close socket */ + close(sockfd); + return UAP_SUCCESS; +} + +/** + * @brief Show usage information for the cscount_cfg + * command + * + * $return N/A + */ +void +print_cscount_cfg_usage(void) +{ + printf("\nUsage : cscount []"); + printf("\n Where "); + printf("\n 5-20: No of beacons with Channel Switch Count IE\n"); + return; +} + +/** + * @brief Set/get cs_count configuration + * @param argc Number of arguments + * @param argv Pointer to the arguments + * @return UAP_SUCCESS/UAP_FAILURE + */ +int +apcmd_cscount_cfg(int argc, char *argv[]) +{ + int opt; + cscount_cfg_t cscount_cfg; + struct ifreq ifr; + t_s32 sockfd; + + while ((opt = getopt_long(argc, argv, "+", cmd_options, NULL)) != -1) { + switch (opt) { + default: + print_cscount_cfg_usage(); + return UAP_SUCCESS; + } + } + argc -= optind; + argv += optind; + + /* Check arguments */ + + memset(&cscount_cfg, 0, sizeof(cscount_cfg)); + if (argc == 0) { + cscount_cfg.action = ACTION_GET; + } else if (argc == 1) { + if ((t_u32)A2HEXDECIMAL(argv[0]) < 5 + && (t_u32)A2HEXDECIMAL(argv[0]) > 20) { + printf("ERR:Invalid Channel switch count value\n"); + return UAP_FAILURE; + } + cscount_cfg.action = ACTION_SET; + cscount_cfg.cs_count = (t_u32)A2HEXDECIMAL(argv[0]); + } else { + print_cscount_cfg_usage(); + return UAP_FAILURE; + } + cscount_cfg.subcmd = UAP_CHAN_SWITCH_COUNT_CFG; + + /* Open socket */ + if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) { + printf("ERR:Cannot open socket\n"); + return UAP_FAILURE; + } + /* Initialize the ifr structure */ + memset(&ifr, 0, sizeof(ifr)); + strncpy(ifr.ifr_ifrn.ifrn_name, dev_name, IFNAMSIZ - 1); + ifr.ifr_ifru.ifru_data = (void *)&cscount_cfg; + /* Perform ioctl */ + errno = 0; + if (ioctl(sockfd, UAP_IOCTL_CMD, &ifr)) { + perror(""); + printf("ERR: Channel switch count configuration failed\n"); + close(sockfd); + return UAP_FAILURE; + } + + /* Handle response */ + if (cscount_cfg.action == ACTION_GET) { + printf("Channel Switch count = %d\n", cscount_cfg.cs_count); + } + + /* Close socket */ + close(sockfd); + return UAP_SUCCESS; +} + +/** + * @brief Show usage information for the mgmtframectrl command + * + * $return N/A + */ +void +print_mgmtframectrl_usage(void) +{ + printf("\nUsage : mgmtframectrl [MASK]\n"); + printf(" empty - Get management frame control mask\n"); + printf(" MASK - Set management frame control mask\n"); +} + +/** + * @brief Creates management frame control request and send to driver + * + * @param argc Number of arguments + * @param argv Pointer to the arguments + * @return UAP_SUCCESS/UAP_FAILURE + */ +int +apcmd_mgmt_frame_control(int argc, char *argv[]) +{ + int opt; + mgmt_frame_ctrl param; /* Action =0, Mask =0 */ + struct ifreq ifr; + t_s32 sockfd; + + while ((opt = getopt_long(argc, argv, "+", cmd_options, NULL)) != -1) { + switch (opt) { + default: + print_mgmtframectrl_usage(); + return UAP_SUCCESS; + } + } + argc -= optind; + argv += optind; + + /* Check arguments */ + if (argc > 1) { + printf("ERR:wrong arguments.\n"); + print_mgmtframectrl_usage(); + return UAP_FAILURE; + } + + if ((argc) && (IS_HEX_OR_DIGIT(argv[0]) == UAP_FAILURE)) { + printf("ERR: Invalid argument %s\n", argv[0]); + print_mgmtframectrl_usage(); + return UAP_FAILURE; + } + + memset(¶m, 0, sizeof(mgmt_frame_ctrl)); + param.subcmd = UAP_MGMT_FRAME_CONTROL; + if (argc) { + param.action = ACTION_SET; + param.mask = (t_u16)A2HEXDECIMAL(argv[0]); + } else { + param.action = ACTION_GET; + } + /* Open socket */ + if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) { + printf("ERR:Cannot open socket\n"); + return UAP_FAILURE; + } + /* Initialize the ifr structure */ + memset(&ifr, 0, sizeof(ifr)); + strncpy(ifr.ifr_ifrn.ifrn_name, dev_name, strlen(dev_name)); + ifr.ifr_ifru.ifru_data = (void *)¶m; + /* Perform ioctl */ + errno = 0; + if (ioctl(sockfd, UAP_IOCTL_CMD, &ifr)) { + perror(""); + printf("ERR:UAP_IOCTL_CMD failed\n"); + close(sockfd); + return UAP_FAILURE; + } + if (!argc) { + printf("Management Frame control mask = 0x%02x\n", + (int)param.mask); + } + /* Close socket */ + close(sockfd); + return UAP_SUCCESS; +} + +/** + * @brief Show usage information for the sys_cfg_pmf command + * command + * + * $return N/A + */ +void +print_sys_cfg_pmf(void) +{ + printf("\nUsage : uaputl.exe sys_cfg_pmf [MFPC] [MFPR]\n"); + printf("\nSet/Get PMF capabilities"); + printf("\n empty - Get PMF capabilites\n"); + printf("\n MFPC: Management frames protection capable"); + printf("\n 0 - Not capable"); + printf("\n 1 - capable"); + printf("\n MFPR: Management frames protection required"); + printf("\n don't care if MFPC is set to 0"); + printf("\n 0 - Not required"); + printf("\n 1 - required\n"); + return; +} + +int +apcmd_sys_cfg_pmf(int argc, char *argv[]) +{ + int opt; + apcmdbuf_pmf_params *cmd_buf = NULL; + t_u8 *buf = NULL; + t_u16 cmd_len = 0; + t_u16 buf_len = MRVDRV_SIZE_OF_CMD_BUFFER; + int ret = UAP_SUCCESS; + t_u8 mfpc = 0; + t_u8 mfpr = 0; + + while ((opt = getopt_long(argc, argv, "+", cmd_options, NULL)) != -1) { + switch (opt) { + default: + print_sys_cfg_pmf(); + return UAP_SUCCESS; + } + } + argc -= optind; + argv += optind; + + /* Check arguments */ + if ((argc > 2)) { + printf("ERR:wrong arguments.\n"); + print_sys_cfg_pmf(); + return UAP_FAILURE; + } + + if (argc > 0) + mfpc = atoi(argv[0]); + + if (mfpc && (argc == 1)) { + printf("ERR:wrong arguments.\n"); + print_sys_cfg_pmf(); + return UAP_FAILURE; + } + + if (mfpc && (argc == 2)) + mfpr = atoi(argv[1]); + + /* Alloc buf for command */ + buf = (t_u8 *)malloc(buf_len); + + if (!buf) { + printf("ERR:Cannot allocate buffer from command!\n"); + return UAP_FAILURE; + } + memset(buf, 0, buf_len); + + /* Locate headers */ + cmd_len = sizeof(apcmdbuf_pmf_params); + cmd_buf = (apcmdbuf_pmf_params *) buf; + + /* Fill the command buffer */ + cmd_buf->size = cmd_len - BUF_HEADER_SIZE; + cmd_buf->seq_num = 0; + cmd_buf->result = 0; + cmd_buf->cmd_code = HostCmd_CMD_PMF_PARAMS; + if (argc == 0) + cmd_buf->action = ACTION_GET; + else + cmd_buf->action = ACTION_SET; + cmd_buf->action = uap_cpu_to_le16(cmd_buf->action); + cmd_buf->params.mfpc = mfpc; + cmd_buf->params.mfpr = mfpr; + + /* Send the command */ + ret = uap_ioctl((t_u8 *)cmd_buf, &cmd_len, buf_len); + + /* Process response */ + if (ret == UAP_SUCCESS) { + if (cmd_buf->result == CMD_SUCCESS) { + printf("Successfully executed the command\n"); + printf("mfpc: %d, mfpr: %d\n", + cmd_buf->params.mfpc, cmd_buf->params.mfpr); + } else { + printf("ERR:Command sending failed!\n"); + free(buf); + return UAP_FAILURE; + } + } else { + printf("ERR:Command sending failed!\n"); + free(buf); + return UAP_FAILURE; + } + free(buf); + return UAP_SUCCESS; +} + +/** + * @brief Show usage information for uap operation control command + * + * $return N/A + */ +void +print_uap_oper_ctrl_usage(void) +{ + printf("\nUsage : uap_oper_ctrl "); + printf("\n set/get uap operation when in-STA disconnected from ext-AP if multi channel is disabled"); + printf("\n control: 0: default, do nothing"); + printf("\n 2: uap stops and restart automatically"); + printf("\n chanopt : specify which channel should be used when uap restarts automatically"); + printf("\n 1: uap restarts on default 2.4G/channel 6"); + printf("\n 2: uap restart on band/channel configured by driver previously"); + printf("\n 3: uap restart on band/channel configured by parameter bandcfg/channel"); + printf("\n bandcfg : This parameter specifies the bandwidth (BW)"); + printf("\n 0: 20Mhz"); + printf("\n 2: 40Mhz"); + printf("\n 3: 80Mhz"); + printf("\n channel : This parameter specifies the channel will be used when chanopt is 3."); + return; +} + +/** + * @brief Set/Get uap operation when in-STA disconnected from ext-AP + * @param argc Number of arguments + * @param argv A pointer to arguments array + * @return MLAN_STATUS_SUCCESS--success, otherwise--fail + */ +int +apcmd_uap_oper_ctrl(int argc, char *argv[]) +{ + int opt; + uap_operation_ctrl param; + struct eth_priv_uap_oper_ctrl *uap_oper = NULL; + struct ifreq ifr; + t_s32 sockfd; + t_u8 *respbuf = NULL; + + memset(¶m, 0, sizeof(param)); + while ((opt = getopt_long(argc, argv, "+", cmd_options, NULL)) != -1) { + switch (opt) { + default: + print_uap_oper_ctrl_usage(); + return UAP_SUCCESS; + } + } + argc -= optind; + argv += optind; + + respbuf = (t_u8 *)malloc(MRVDRV_SIZE_OF_CMD_BUFFER); + if (!respbuf) { + printf("ERR:Cannot allocate buffer for command!\n"); + return UAP_FAILURE; + } + memset(respbuf, 0, MRVDRV_SIZE_OF_CMD_BUFFER); + + /* Check arguments */ + if (argc > 4) { + printf("ERR: Invalid number of arguments.\n"); + print_uap_oper_ctrl_usage(); + free(respbuf); + return UAP_FAILURE; + } + + if (argc > 0) { + param.uap_oper.ctrl = (t_u16)A2HEXDECIMAL(argv[0]); + if (param.uap_oper.ctrl == 2) + param.uap_oper.chan_opt = (t_u16)A2HEXDECIMAL(argv[1]); + + if (argc == 4 && param.uap_oper.chan_opt == 3) { + param.uap_oper.bandcfg = (t_u8)A2HEXDECIMAL(argv[2]); + param.uap_oper.channel = (t_u8)A2HEXDECIMAL(argv[3]); + } + param.action = ACTION_SET; + } else { + param.action = ACTION_GET; + } + param.subcmd = UAP_OPERATION_CTRL; + + memcpy(respbuf, ¶m, sizeof(uap_operation_ctrl)); + + /* Open socket */ + if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) { + printf("ERR:Cannot open socket\n"); + free(respbuf); + return UAP_FAILURE; + } + /* Initialize the ifr structure */ + memset(&ifr, 0, sizeof(ifr)); + strncpy(ifr.ifr_ifrn.ifrn_name, dev_name, IFNAMSIZ - 1); + ifr.ifr_ifru.ifru_data = (void *)respbuf; + /* Perform ioctl */ + errno = 0; + if (ioctl(sockfd, UAP_IOCTL_CMD, &ifr)) { + perror(""); + printf("ERR: uap operation control set/get failed\n"); + close(sockfd); + free(respbuf); + return UAP_FAILURE; + } + + /* Handle response */ + if (param.action == ACTION_GET) { + /* Process result */ + uap_oper = + (struct eth_priv_uap_oper_ctrl *)(respbuf + + 2 * sizeof(t_u32)); + printf(" uap operation control %x\n", uap_oper->ctrl); + printf(" uap channel operation %x\n", uap_oper->chan_opt); + if (uap_oper->chan_opt == 3) { + printf(" uap bandwidth %s\n", + uap_oper-> + bandcfg ? ((uap_oper->bandcfg == 2) ? "40Mhz" : + "80Mhz") : "20Mhz"); + printf(" uap channel %d\n", uap_oper->channel); + } + } else + printf("uap operation control set success!\n"); + /* Close socket */ + close(sockfd); + if (respbuf) + free(respbuf); + return UAP_SUCCESS; +} + +/** Structure of command table*/ +typedef struct { + /** Command name */ + char *cmd; + /** Command function pointer */ + int (*func) (int argc, char *argv[]); + /** Command usuage */ + char *help; +} command_table; + +/** AP command table */ +static command_table ap_command[] = { + {"sys_config", apcmd_sys_config, "\tSet/get uAP's profile"}, + {"sys_info", apcmd_sys_info, "\tDisplay system info"}, + {"sys_reset", apcmd_sys_reset, "\tReset uAP"}, + {"bss_start", apcmd_bss_start, "\tStart the BSS"}, + {"bss_stop", apcmd_bss_stop, "\tStop the BSS"}, + {"skip_cac", apcmd_skip_cac, "\tSkip the CAC"}, + {"sta_deauth", apcmd_sta_deauth, "\tDeauth client"}, + {"sta_list", apcmd_sta_list, "\tDisplay list of clients"}, + {"sys_cfg_ap_mac_address", apcmd_sys_cfg_ap_mac_address, + "Set/get uAP mac address"}, + {"sys_cfg_ssid", apcmd_sys_cfg_ssid, "\tSet/get uAP ssid"}, + {"sys_cfg_beacon_period", apcmd_sys_cfg_beacon_period, + "Set/get uAP beacon period"}, + {"sys_cfg_dtim_period", apcmd_sys_cfg_dtim_period, + "Set/get uAP dtim period"}, + {"sys_cfg_bss_status", apcmd_sys_cfg_bss_status, "Get BSS status"}, + {"sys_cfg_channel", apcmd_sys_cfg_channel, + "\tSet/get uAP radio channel"}, + {"sys_cfg_channel_ext", apcmd_sys_cfg_channel_ext, + "\tSet/get uAP radio channel, band and mode"}, + {"sys_cfg_scan_channels", apcmd_sys_cfg_scan_channels, + "Set/get uAP radio channel list"}, + {"sys_cfg_rates", apcmd_sys_cfg_rates, "\tSet/get uAP rates"}, + {"sys_cfg_rates_ext", apcmd_sys_cfg_rates_ext, "\tSet/get uAP rates"}, + {"sys_cfg_tx_power", apcmd_sys_cfg_tx_power, "Set/get uAP tx power"}, + {"sys_cfg_bcast_ssid_ctl", apcmd_sys_cfg_bcast_ssid_ctl, + "Set/get uAP broadcast ssid"}, + {"sys_cfg_preamble_ctl", apcmd_sys_cfg_preamble_ctl, + "Get uAP preamble"}, + {"antcfg", apcmd_antcfg, "Set/get uAP tx/rx antenna"}, + {"htstreamcfg", apcmd_htstreamcfg, + "Set/get uAP HT stream configurations"}, + {"sys_cfg_rts_threshold", apcmd_sys_cfg_rts_threshold, + "Set/get uAP rts threshold"}, + {"sys_cfg_frag_threshold", apcmd_sys_cfg_frag_threshold, + "Set/get uAP frag threshold"}, + {"radioctrl", apcmd_radio_ctl, "Set/get uAP radio on/off"}, + {"sys_cfg_tx_beacon_rate", apcmd_sys_cfg_tx_beacon_rate, + "Set/get uAP tx beacon rate"}, + {"txratecfg", apcmd_tx_rate_cfg, "Set/get trasnmit data rate"}, + {"sys_cfg_mcbc_data_rate", apcmd_sys_cfg_mcbc_data_rate, + "Set/get uAP MCBC rate"}, + {"sys_cfg_rsn_replay_prot", apcmd_sys_cfg_rsn_replay_prot, + "Set/get RSN replay protection"}, + {"sys_cfg_pkt_fwd_ctl", apcmd_sys_cfg_pkt_fwd_ctl, + "Set/get uAP packet forwarding"}, + {"sys_cfg_sta_ageout_timer", apcmd_sys_cfg_sta_ageout_timer, + "Set/get station ageout timer"}, + {"sys_cfg_ps_sta_ageout_timer", apcmd_sys_cfg_ps_sta_ageout_timer, + "Set/get PS station ageout timer"}, + {"sys_cfg_auth", apcmd_sys_cfg_auth, + "\tSet/get uAP authentication mode"}, + {"sys_cfg_protocol", apcmd_sys_cfg_protocol, + "Set/get uAP security protocol"}, + {"sys_cfg_wep_key", apcmd_sys_cfg_wep_key, "\tSet/get uAP wep key"}, + {"sys_cfg_cipher", apcmd_sys_cfg_cipher, + "\tSet/get uAP WPA/WPA2 cipher"}, + {"sys_cfg_pwk_cipher", apcmd_sys_cfg_pwk_cipher, + "\tSet/get uAP WPA/WPA2 pairwise cipher"}, + {"sys_cfg_gwk_cipher", apcmd_sys_cfg_gwk_cipher, + "\tSet/get uAP WPA/WPA2 group cipher"}, + {"sys_cfg_wpa_passphrase", apcmd_sys_cfg_wpa_passphrase, + "Set/get uAP WPA or WPA2 passphrase"}, + {"sys_cfg_wpa3_sae_password", apcmd_sys_cfg_wpa3_sae_password, + "Set/get uAP WPA3 SAE password"}, + {"sys_cfg_group_rekey_timer", apcmd_sys_cfg_group_rekey_timer, + "Set/get uAP group re-key time"}, + {"sys_cfg_max_sta_num", apcmd_sys_cfg_max_sta_num, + "Set/get uAP max station number"}, + {"sys_cfg_retry_limit", apcmd_sys_cfg_retry_limit, + "Set/get uAP retry limit number"}, + {"sys_cfg_sticky_tim_config", apcmd_sys_cfg_sticky_tim_config, + "Set/get uAP sticky TIM configuration"}, + {"sys_cfg_sticky_tim_sta_mac_addr", + apcmd_sys_cfg_sticky_tim_sta_mac_addr, + "Set/get uAP sticky TIM sta MAC address"}, + {"sys_cfg_eapol_pwk_hsk", apcmd_sys_cfg_eapol_pwk_hsk, + "Set/getuAP pairwise Handshake timeout value and retries"}, + {"sys_cfg_eapol_gwk_hsk", apcmd_sys_cfg_eapol_gwk_hsk, + "Set/getuAP groupwise Handshake timeout value and retries"}, + {"sys_cfg_custom_ie", apcmd_sys_cfg_custom_ie, + "\tSet/get custom IE configuration"}, + {"sta_filter_table", apcmd_sta_filter_table, "Set/get uAP mac filter"}, + {"regrdwr", apcmd_regrdwr, "\t\tRead/Write register command"}, + {"memaccess", apcmd_memaccess, + "\tRead/Write to a memory address command"}, + {"rdeeprom", apcmd_read_eeprom, "\tRead EEPROM "}, + {"cfg_data", apcmd_cfg_data, + "\tGet/Set configuration file from/to firmware"}, + {"sys_cfg_80211d", apcmd_cfg_80211d, "\tSet/Get 802.11D info"}, + {"uap_stats", apcmd_uap_stats, "\tGet uAP stats"}, + {"pscfg", apcmd_pscfg, "\t\tSet/get uAP power mode"}, + {"bss_config", apcmd_bss_config, "\tSet/get BSS configuration"}, + {"sta_deauth_ext", apcmd_sta_deauth_ext, "\tDeauth client"}, + {"mic_err", apcmd_mic_err, "\t\tReport station mic error"}, + {"key_material", apcmd_set_key, "\tSet key"}, + {"coex_config", apcmd_coex_config, + "\tSet/get uAP BT coex configuration"}, + {"hscfg", apcmd_hscfg, "\t\tSet/get uAP host sleep parameters."}, + {"hssetpara", apcmd_hssetpara, + "\t\tSet/get uAP host sleep parameters."}, + {"addbapara", apcmd_addbapara, "\tSet/get uAP ADDBA parameters."}, + {"aggrpriotbl", apcmd_aggrpriotbl, + "\tSet/get uAP priority table for AMPDU/AMSDU."}, + {"addbareject", apcmd_addbareject, "\tSet/get uAP addbareject table."}, + {"sys_cfg_11n", apcmd_sys_cfg_11n, "\tSet/get uAP 802.11n parameters."}, +#ifdef RX_PACKET_COALESCE + {"rxpktcoal_cfg", apcmd_rx_pkt_coalesce, + "\tSet/get RX Packet coalesing paramterts."}, +#endif + {"httxbfcfg", apcmd_sys_cfg_tx_bf, "\tSet/get uAP TX BF parameters."}, + {"httxcfg", apcmd_sys_cfg_ht_tx, "\t\tSet/get uAP HT Tx parameters."}, + {"vhtcfg", apcmd_sys_cfg_vht, "\t\tSet/get uAP VHT parameters."}, + {"sys_cfg_wmm", apcmd_sys_cfg_wmm, + "\tSet/get uAP beacon wmm parameters."}, + {"sys_cfg_ap_wmm", apcmd_sys_cfg_ap_wmm, + "\tSet/get uAP hardware wmm parameters."}, + {"deepsleep", apcmd_deepsleep, "\tSet/get deepsleep mode."}, + {"hostcmd", apcmd_hostcmd, "\t\tSet/get hostcmd"}, + {"tx_data_pause", apcmd_txdatapause, + "\tSet/get Tx data pause settings."}, +#ifdef SDIO + {"sdcmd52rw", apcmd_cmd52_readwrite, + "\tRead or write using sdio command 52."}, +#endif + {"sys_cfg_2040_coex", apcmd_sys_cfg_2040_coex, + "\tSet/get 20/40 coex settings."}, + {"dfstesting", apcmd_dfstesting, "\tConfigure DFS Testing settings."}, + {"cscount", apcmd_cscount_cfg, "\tConfigure DFS Channel Switch Count."}, + {"mgmtframectrl", apcmd_mgmt_frame_control, + "\tSpecifies mask indicating management frames to be sent from host."}, + {"sys_cfg_restrict_client_mode", apcmd_sys_cfg_restrict_client_mode, + "\tSet/get the mode in which client stations can connect to the uAP."}, + {"sys_cfg_pmf", apcmd_sys_cfg_pmf, "\tSet/get PMF capabilities."}, + {"uap_oper_ctrl", apcmd_uap_oper_ctrl, + "\tSet/get uap operation control value."}, + {"band_steering_cfg", apcmd_band_steering, + "\tConfigure Band Steering."}, + {NULL, NULL, 0} +}; + +/** + * @brief Prints usage information of uaputl + * + * @return N/A + */ +static void +print_tool_usage(void) +{ + int i; + printf("uaputl.exe - uAP utility ver %s\n", UAP_VERSION); + printf("Usage:\n" + "\tuaputl.exe [options] [command parameters]\n"); + printf("Options:\n" + "\t--help\tDisplay help\n" + "\t-v\tDisplay version\n" + "\t-i \n" "\t-d \n"); + printf("Commands:\n"); + for (i = 0; ap_command[i].cmd; i++) + printf("\t%-4s\t\t%s\n", ap_command[i].cmd, ap_command[i].help); + printf("\n" + "For more information on the usage of each command use:\n" + "\tuaputl.exe --help\n"); +} + +/**************************************************************************** + Global functions +****************************************************************************/ +/** Option parameter*/ +static struct option ap_options[] = { + {"help", 0, NULL, 'h'}, + {"interface", 1, NULL, 'i'}, + {"debug", 1, NULL, 'd'}, + {"version", 0, NULL, 'v'}, + {NULL, 0, NULL, '\0'} +}; + +/** + * @brief Checks if given channel in 'a' band is valid or not. + * + * @param channel Channel number + * @return UAP_SUCCESS or UAP_FAILURE + */ +int +is_valid_a_band_channel(int channel) +{ + int ret = UAP_SUCCESS; + switch (channel) { + case 16: + case 34: + case 36: + case 38: + case 40: + case 42: + case 44: + case 46: + case 48: + case 52: + case 56: + case 60: + case 64: + case 100: + case 104: + case 108: + case 112: + case 116: + case 120: + case 124: + case 128: + case 132: + case 136: + case 140: + case 144: + case 149: + case 153: + case 157: + case 161: + case 165: + break; + default: + ret = UAP_FAILURE; + break; + } + return ret; +} + +/** + * @brief Checks if secondary channel can be set above given primary channel in 'a' band or not. + * + * @param channel Channel number + * @return UAP_SUCCESS or UAP_FAILURE + */ +int +is_valid_a_band_channel_above(int channel) +{ + int ret = UAP_SUCCESS; + switch (channel) { + case 36: + case 44: + case 52: + case 60: + case 100: + case 108: + case 116: + case 124: + case 132: + case 140: + case 149: + case 157: + break; + default: + ret = UAP_FAILURE; + break; + } + return ret; +} + +/** + * @brief Checks if secondary channel can be set below given primary channel in 'a' band or not. + * + * @param channel Channel number + * @return UAP_SUCCESS or UAP_FAILURE + */ +int +is_valid_a_band_channel_below(int channel) +{ + int ret = UAP_SUCCESS; + switch (channel) { + case 40: + case 48: + case 56: + case 64: + case 104: + case 112: + case 120: + case 128: + case 136: + case 153: + case 161: + break; + default: + ret = UAP_FAILURE; + break; + } + return ret; +} + +/** + * @brief Checkes a particular input for validatation. + * + * @param cmd Type of input + * @param argc Number of arguments + * @param argv Pointer to the arguments + * @return UAP_SUCCESS or UAP_FAILURE + */ +int +is_input_valid(valid_inputs cmd, int argc, char *argv[]) +{ + int i; + int chan_number = 0; + int band = 0; + int ch; + int ret = UAP_SUCCESS; + if (argc == 0) + return UAP_FAILURE; + switch (cmd) { + case RDEEPROM: + if (argc != 2) { + printf(" ERR: Argument count mismatch\n"); + ret = UAP_FAILURE; + } else { + if ((ISDIGIT(argv[0]) == 0) || (ISDIGIT(argv[1]) == 0) + || (A2HEXDECIMAL(argv[0]) & 0x03) || + ((int)(A2HEXDECIMAL(argv[0])) < 0) || + (A2HEXDECIMAL(argv[1]) & 0x03) || + (A2HEXDECIMAL(argv[1]) < 4) || + (A2HEXDECIMAL(argv[1]) > 20)) { + printf(" ERR: Invalid inputs for Read EEPROM\n"); + ret = UAP_FAILURE; + } + } + break; + case SCANCHANNELS: + if (argc > MAX_CHANNELS) { + printf("ERR: Invalid List of Channels\n"); + ret = UAP_FAILURE; + } else { + for (i = 0; i < argc; i++) { + chan_number = -1; + band = -1; + sscanf(argv[i], "%d.%d", &chan_number, &band); + if ((chan_number == -1) || (chan_number < 1) || + (chan_number > MAX_CHANNELS)) { + printf("ERR: Channel must be in the range of 1 to %d\n", MAX_CHANNELS); + ret = UAP_FAILURE; + break; + } + if ((chan_number > MAX_CHANNELS_BG) && + !(is_valid_a_band_channel(chan_number))) { + printf("ERR: Invalid Channel in 'a' band!\n"); + ret = UAP_FAILURE; + break; + } + if ((band < -1) || (band > 1)) { + printf("ERR:Band must be either 0 or 1\n"); + ret = UAP_FAILURE; + break; + } else { + if (((chan_number < MAX_CHANNELS_BG) && + (chan_number != 8) && + (chan_number != 12) && (band == 1)) + || ((chan_number > MAX_CHANNELS_BG) + && (band == 0))) { + printf("ERR:Invalid band for given channel\n"); + ret = UAP_FAILURE; + break; + } + } + } + if ((ret != UAP_FAILURE) && + (has_dup_channel(argc, argv) != UAP_SUCCESS)) { + printf("ERR: Duplicate channel values entered\n"); + ret = UAP_FAILURE; + } + if ((ret != UAP_FAILURE) && + (has_diff_band(argc, argv) != UAP_SUCCESS)) { + printf("ERR: Scan channel list should contain channels from only one band\n"); + ret = UAP_FAILURE; + } + } + break; + case TXPOWER: + if ((argc > 1) || (ISDIGIT(argv[0]) == 0)) { + printf("ERR:Invalid Transmit power\n"); + ret = UAP_FAILURE; + } else { + if ((atoi(argv[0]) < MIN_TX_POWER) || + (atoi(argv[0]) > MAX_TX_POWER)) { + printf("ERR: TX Powar must be in the rage of %d to %d. \n", MIN_TX_POWER, MAX_TX_POWER); + ret = UAP_FAILURE; + } + } + break; + case PROTOCOL: + if ((argc > 2) || (ISDIGIT(argv[0]) == 0)) { + printf("ERR:Invalid Protocol\n"); + ret = UAP_FAILURE; + } else + ret = is_protocol_valid(atoi(argv[0])); + break; + case AKM_SUITE: + if (argc == 2) { + if (A2HEXDECIMAL(argv[1]) & + ~(KEY_MGMT_PSK | KEY_MGMT_PSK_SHA256 | KEY_MGMT_EAP + | KEY_MGMT_NONE | KEY_MGMT_SAE)) { + printf("ERR: Invalid AKM suite\n"); + ret = UAP_FAILURE; + } + } + break; + case CHANNEL: + if ((argc != 1) && (argc != 2)) { + printf("ERR: Incorrect arguments for channel.\n"); + ret = UAP_FAILURE; + } else { + if (argc == 2) { + if ((ISDIGIT(argv[1]) == 0) || + (atoi(argv[1]) & ~CHANNEL_MODE_MASK)) { + printf("ERR: Invalid Mode\n"); + ret = UAP_FAILURE; + } + if ((atoi(argv[1]) & BITMAP_ACS_MODE) && + (atoi(argv[0]) != 0)) { + printf("ERR: Channel must be 0 for ACS; MODE = 1.\n"); + ret = UAP_FAILURE; + } + if ((atoi(argv[1]) & BITMAP_CHANNEL_ABOVE) && + (atoi(argv[1]) & BITMAP_CHANNEL_BELOW)) { + printf("ERR: secondary channel above and below both are enabled\n"); + ret = UAP_FAILURE; + } + } + if ((argc == 1) || (!(atoi(argv[1]) & BITMAP_ACS_MODE))) { + if ((ISDIGIT(argv[0]) == 0) || + (atoi(argv[0]) < 1) || + (atoi(argv[0]) > MAX_CHANNELS)) { + printf("ERR: Channel must be in the range of 1 to %d\n", MAX_CHANNELS); + ret = UAP_FAILURE; + } + if ((atoi(argv[0]) > MAX_CHANNELS_BG) && + !(is_valid_a_band_channel(atoi(argv[0])))) { + printf("ERR: Invalid Channel in 'a' band!\n"); + ret = UAP_FAILURE; + } + ch = atoi(argv[0]); + if (ch <= MAX_CHANNELS_BG) { + if ((argc == 2) && + (atoi(argv[1]) & + BITMAP_CHANNEL_ABOVE) && + (atoi(argv[0]) > + MAX_CHANNEL_ABOVE)) { + printf("ERR: only allow channel 1-9 for secondary channel above\n"); + ret = UAP_FAILURE; + } + if ((argc == 2) && + (atoi(argv[1]) & + BITMAP_CHANNEL_BELOW) && + ((atoi(argv[0]) < MIN_CHANNEL_BELOW) + || (atoi(argv[0]) == 14))) { + printf("ERR: only allow channel 5-13 for secondary channel below\n"); + ret = UAP_FAILURE; + } + } else { + if (argc == 2) { + if ((atoi(argv[1]) & + BITMAP_CHANNEL_BELOW) && + !is_valid_a_band_channel_below + (atoi(argv[0]))) { + printf("ERR: For given primary channel secondary channel can not be set below\n"); + ret = UAP_FAILURE; + } + if ((atoi(argv[1]) & + BITMAP_CHANNEL_ABOVE) && + !is_valid_a_band_channel_above + (atoi(argv[0]))) { + printf("ERR: For given primary channel secondary channel can not be set above\n"); + ret = UAP_FAILURE; + } + } + } + } + } + break; + case CHANNEL_EXT: + if (argc > 3) { + printf("ERR: Incorrect arguments for channel_ext.\n"); + ret = UAP_FAILURE; + } else { + if (argc == 3) { + if ((ISDIGIT(argv[2]) == 0) || + (atoi(argv[2]) & ~CHANNEL_MODE_MASK)) { + printf("ERR: Invalid Mode\n"); + ret = UAP_FAILURE; + } + if ((atoi(argv[2]) & BITMAP_ACS_MODE) && + (atoi(argv[0]) != 0)) { + printf("ERR: Channel must be 0 for ACS; MODE = 1.\n"); + ret = UAP_FAILURE; + } + if ((atoi(argv[2]) & BITMAP_CHANNEL_ABOVE) && + (atoi(argv[2]) & BITMAP_CHANNEL_BELOW)) { + printf("ERR: secondary channel above and below both are enabled\n"); + ret = UAP_FAILURE; + } + } + if ((argc == 2) && + ((ISDIGIT(argv[1]) == 0) || (atoi(argv[1]) < 0) || + atoi(argv[1]) > 1)) { + printf("ERR:Invalid band\n"); + ret = UAP_FAILURE; + } + if ((argc == 1) || + ((argc == 3) && + !(atoi(argv[2]) & BITMAP_ACS_MODE))) { + if ((ISDIGIT(argv[0]) == 0) || + (atoi(argv[0]) < 1) || + (atoi(argv[0]) > MAX_CHANNELS)) { + printf("ERR: Channel must be in the range of 1 to %d\n", MAX_CHANNELS); + ret = UAP_FAILURE; + } + if ((atoi(argv[0]) > MAX_CHANNELS_BG) && + !(is_valid_a_band_channel(atoi(argv[0])))) { + printf("ERR: Invalid Channel in 'a' band!\n"); + ret = UAP_FAILURE; + } + ch = atoi(argv[0]); + if (ch <= MAX_CHANNELS_BG) { + if ((argc == 3) && + (atoi(argv[2]) & + BITMAP_CHANNEL_ABOVE) && + (atoi(argv[0]) > + MAX_CHANNEL_ABOVE)) { + printf("ERR: only allow channel 1-9 for secondary channel above\n"); + ret = UAP_FAILURE; + } + if ((argc == 3) && + (atoi(argv[2]) & + BITMAP_CHANNEL_BELOW) && + ((atoi(argv[0]) < MIN_CHANNEL_BELOW) + || (atoi(argv[0]) == 14))) { + printf("ERR: only allow channel 5-13 for secondary channel below\n"); + ret = UAP_FAILURE; + } + } else { + if (argc == 3) { + if ((atoi(argv[2]) & + BITMAP_CHANNEL_BELOW) && + !is_valid_a_band_channel_below + (atoi(argv[0]))) { + printf("ERR: For given primary channel secondary channel can not be set below\n"); + ret = UAP_FAILURE; + } + if ((atoi(argv[2]) & + BITMAP_CHANNEL_ABOVE) && + !is_valid_a_band_channel_above + (atoi(argv[0]))) { + printf("ERR: For given primary channel secondary channel can not be set above\n"); + ret = UAP_FAILURE; + } + } + } + } + } + break; + case BAND: + if (argc > 1) { + printf("ERR: Incorrect number of BAND arguments.\n"); + ret = UAP_FAILURE; + } else { + if ((ISDIGIT(argv[0]) == 0) || (atoi(argv[0]) < 0) || + (atoi(argv[0]) > 1)) { + printf("ERR: Invalid band.\n"); + ret = UAP_FAILURE; + } + } + break; + case RATE: + if (argc > MAX_RATES) { + printf("ERR: Incorrect number of RATES arguments.\n"); + ret = UAP_FAILURE; + } else { + for (i = 0; i < argc; i++) { + if ((IS_HEX_OR_DIGIT(argv[i]) == UAP_FAILURE) || + (is_rate_valid + (A2HEXDECIMAL(argv[i]) & + ~BASIC_RATE_SET_BIT) + != UAP_SUCCESS)) { + printf("ERR:Unsupported rate.\n"); + ret = UAP_FAILURE; + break; + } + } + if ((ret != UAP_FAILURE) && + (has_dup_rate(argc, argv) != UAP_SUCCESS)) { + printf("ERR: Duplicate rate values entered\n"); + ret = UAP_FAILURE; + } + if (check_mandatory_rates(argc, argv) != UAP_SUCCESS) { + ret = UAP_FAILURE; + } + } + break; + case BROADCASTSSID: + if (argc != 1) { + printf("ERR:wrong BROADCASTSSID arguments.\n"); + ret = UAP_FAILURE; + } else { + if ((ISDIGIT(argv[0]) == 0) || + ((atoi(argv[0]) != 0) && (atoi(argv[0]) != 1) && + (atoi(argv[0]) != 2))) { + printf("ERR:Illegal parameter %s for BROADCASTSSID. Must be either '0', '1' or '2'.\n", argv[0]); + ret = UAP_FAILURE; + } + } + break; + case RTSTHRESH: + if (argc != 1) { + printf("ERR:Incorrect number of arguments for RTSTHRESHOLD\n"); + ret = UAP_FAILURE; + } else if ((ISDIGIT(argv[0]) == 0) || (atoi(argv[0]) < 0) || + (atoi(argv[0]) > MAX_RTS_THRESHOLD)) { + printf("ERR:Illegal RTSTHRESHOLD %s. The value must between 0 and %d\n", argv[0], MAX_RTS_THRESHOLD); + ret = UAP_FAILURE; + } + break; + case FRAGTHRESH: + if (argc != 1) { + printf("ERR:Incorrect number of arguments for FRAGTHRESH\n"); + ret = UAP_FAILURE; + } else if ((ISDIGIT(argv[0]) == 0) || + (atoi(argv[0]) < MIN_FRAG_THRESHOLD) || + (atoi(argv[0]) > MAX_FRAG_THRESHOLD)) { + printf("ERR:Illegal FRAGTHRESH %s. The value must between %d and %d\n", argv[0], MIN_FRAG_THRESHOLD, MAX_FRAG_THRESHOLD); + ret = UAP_FAILURE; + } + break; + case DTIMPERIOD: + if (argc != 1) { + printf("ERR:Incorrect number of arguments for DTIMPERIOD\n"); + ret = UAP_FAILURE; + } else if ((ISDIGIT(argv[0]) == 0) || (atoi(argv[0]) < 1) || + (atoi(argv[0]) > MAX_DTIM_PERIOD)) { + printf("ERR: DTIMPERIOD Value must be in range of 1 to %d\n", MAX_DTIM_PERIOD); + ret = UAP_FAILURE; + } + break; + case RSNREPLAYPROT: + if (argc != 1) { + printf("ERR:Incorrect number of arguments for RSNREPLAYPROT\n"); + ret = UAP_FAILURE; + } else { + if ((ISDIGIT(argv[0]) == 0) || (atoi(argv[0]) < 0) || + (atoi(argv[0]) > 1)) { + printf("ERR:Illegal RSNREPLAYPROT parameter %s. Must be either '0' or '1'.\n", argv[0]); + ret = UAP_FAILURE; + } + } + break; + case RADIOCONTROL: + if (argc != 1) { + printf("ERR:Incorrect number of arguments for RADIOCONTROL\n"); + ret = UAP_FAILURE; + } else { + if ((ISDIGIT(argv[0]) == 0) || (atoi(argv[0]) < 0) || + (atoi(argv[0]) > 1)) { + printf("ERR:Illegal RADIOCONTROL parameter %s. Must be either '0' or '1'.\n", argv[0]); + ret = UAP_FAILURE; + } + } + break; + case TXRATECFG: + if (argc > 3) { + printf("ERR:Incorrect number of arguments for DATARATE\n"); + ret = UAP_FAILURE; + } else { + if (((argc >= 1) && + (IS_HEX_OR_DIGIT(argv[0]) == UAP_FAILURE)) || + ((argc >= 2) && + (IS_HEX_OR_DIGIT(argv[1]) == UAP_FAILURE)) + || ((argc >= 3) && + (IS_HEX_OR_DIGIT(argv[2]) == UAP_FAILURE)) + ) { + printf("ERR: invalid Tx data rate\n"); + ret = UAP_FAILURE; + } else if (argc >= 1) { + if (A2HEXDECIMAL(argv[0]) == 0xFF) { + if (argc != 1) { + printf("ERR: invalid auto rate input\n"); + ret = UAP_FAILURE; + } + } else { + if ((A2HEXDECIMAL(argv[0]) > 3) + ) { + printf("ERR: invalid format\n"); + ret = UAP_FAILURE; + } + if (argc >= 2) { + if (((A2HEXDECIMAL(argv[0]) == + 0) && + (A2HEXDECIMAL(argv[1]) > + 11)) || + ((A2HEXDECIMAL(argv[0]) == + 1) && + (A2HEXDECIMAL(argv[1]) != + 32) && + (A2HEXDECIMAL(argv[1]) > + 15) + )) { + printf("ERR:Incorrect TxRate %s.\n", argv[1]); + ret = UAP_FAILURE; + } + } + if (argc == 3) { + if (((A2HEXDECIMAL(argv[0]) != + 2) && + (A2HEXDECIMAL(argv[0]) != + 3)) || + ((A2HEXDECIMAL(argv[2]) < 1) + || (A2HEXDECIMAL(argv[2]) > + 2))) { + printf("ERR:Incorrect nss.\n"); + ret = UAP_FAILURE; + } + } + } + } + } + break; + case MCBCDATARATE: + case TXBEACONRATE: + if (argc != 1) { + printf("ERR:Incorrect number of arguments for DATARATE\n"); + ret = UAP_FAILURE; + } else { + if (IS_HEX_OR_DIGIT(argv[0]) == UAP_FAILURE) { + printf("ERR: invalid data rate\n"); + ret = UAP_FAILURE; + } else if ((A2HEXDECIMAL(argv[0]) != 0) && + (is_rate_valid + (A2HEXDECIMAL(argv[0]) & + ~BASIC_RATE_SET_BIT) != UAP_SUCCESS)) { + printf("ERR: invalid data rate\n"); + ret = UAP_FAILURE; + } + } + break; + case PKTFWD: + if (argc != 1) { + printf("ERR:Incorrect number of arguments for PKTFWD.\n"); + ret = UAP_FAILURE; + } else if ((ISDIGIT(argv[0]) == 0) || + ((atoi(argv[0]) < 0) || (atoi(argv[0]) > 15))) { + printf("ERR:Illegal PKTFWD parameter %s. Must be within '0' and '15'.\n", argv[0]); + ret = UAP_FAILURE; + } + break; + case STAAGEOUTTIMER: + if (argc != 1) { + printf("ERR:Incorrect number of arguments for STAAGEOUTTIMER.\n"); + ret = UAP_FAILURE; + } else { + if ((ISDIGIT(argv[0]) == 0) || ((atoi(argv[0]) != 0) && + ((atoi(argv[0]) < + MIN_STAGE_OUT_TIME) || + (atoi(argv[0]) > + MAX_STAGE_OUT_TIME)))) + { + printf("ERR:Illegal STAAGEOUTTIMER %s. Must be between %d and %d.\n", argv[0], MIN_STAGE_OUT_TIME, MAX_STAGE_OUT_TIME); + ret = UAP_FAILURE; + } + } + break; + case PSSTAAGEOUTTIMER: + if (argc != 1) { + printf("ERR:Incorrect number of arguments for PSSTAAGEOUTTIMER.\n"); + ret = UAP_FAILURE; + } else { + if ((ISDIGIT(argv[0]) == 0) || ((atoi(argv[0]) != 0) && + ((atoi(argv[0]) < + MIN_STAGE_OUT_TIME) || + (atoi(argv[0]) > + MAX_STAGE_OUT_TIME)))) + { + printf("ERR:Illegal PSSTAAGEOUTTIMER %s. Must be between %d and %d.\n", argv[0], MIN_STAGE_OUT_TIME, MAX_STAGE_OUT_TIME); + ret = UAP_FAILURE; + } + } + break; + case AUTHMODE: + if (argc != 1) { + printf("ERR:Incorrect number of arguments for AUTHMODE\n"); + ret = UAP_FAILURE; + } else { + if ((ISDIGIT(argv[0]) == 0) || ((atoi(argv[0]) != 0) && + (atoi(argv[0]) != 1) + && (atoi(argv[0]) != 3) + && (atoi(argv[0]) != + 255))) { + printf("ERR:Illegal AUTHMODE parameter %s. Must be either '0','1','3' or 255''.\n", argv[0]); + ret = UAP_FAILURE; + } + } + break; + case GROUPREKEYTIMER: + if (argc != 1) { + printf("ERR:Incorrect number of arguments for GROUPREKEYTIMER.\n"); + ret = UAP_FAILURE; + } else { + if ((ISDIGIT(argv[0]) == 0) || (atoi(argv[0]) < 0) || + (atoi(argv[0]) > MAX_GRP_TIMER)) { + printf("ERR: GROUPREKEYTIMER range is [0:%d] (0 for disable)\n", MAX_GRP_TIMER); + ret = UAP_FAILURE; + } + } + break; + case MAXSTANUM: + if (argc != 1) { + printf("ERR:Incorrect number of arguments for MAXSTANUM\n"); + ret = UAP_FAILURE; + } else { + if ((ISDIGIT(argv[0]) == 0) || (atoi(argv[0]) <= 0)) { + printf("ERR:Invalid STA_NUM argument %s.\n", + argv[0]); + ret = UAP_FAILURE; + } + } + break; + case BEACONPERIOD: + if (argc != 1) { + printf("ERR:Incorrect number of argument for BEACONPERIOD.\n"); + ret = UAP_FAILURE; + } else { + if ((ISDIGIT(argv[0]) == 0) || + (atoi(argv[0]) < MIN_BEACON_PERIOD) + || (atoi(argv[0]) > MAX_BEACON_PERIOD)) { + printf("ERR: BEACONPERIOD must be in range of %d to %d.\n", MIN_BEACON_PERIOD, MAX_BEACON_PERIOD); + ret = UAP_FAILURE; + } + } + break; + case RETRYLIMIT: + if (argc != 1) { + printf("ERR:Incorrect number of arguments for RETRY LIMIT\n"); + ret = UAP_FAILURE; + } else { + if ((ISDIGIT(argv[0]) == 0) || + (atoi(argv[0]) > MAX_RETRY_LIMIT) || + (atoi(argv[0]) < 0)) { + printf("ERR:RETRY_LIMIT must be in the range of [0:%d]. The input was %s.\n", MAX_RETRY_LIMIT, argv[0]); + ret = UAP_FAILURE; + } + } + break; + case STICKYTIMCONFIG: + if ((argc != 1) && (argc != 3)) { + printf("ERR:Incorrect number of arguments for STICKY_TIM_CONFIG\n"); + ret = UAP_FAILURE; + } else { + if ((ISDIGIT(argv[0]) == 0) || (atoi(argv[0]) < 0) || + (atoi(argv[0]) > 2)) { + printf("ERR:Enable parameter must be 0, 1 or 2\n"); + ret = UAP_FAILURE; + break; + } + if (((atoi(argv[0]) != 1) && (argc > 1))) { + printf("ERR: Invalid arguments\n"); + ret = UAP_FAILURE; + break; + } + if ((atoi(argv[0]) == 1) && (argc != 3)) { + printf("ERR: Both duration and sticky bit mask must be provided for ENABLE = 1\n"); + ret = UAP_FAILURE; + break; + } + if (argc > 1) { + if ((ISDIGIT(argv[1]) == 0)) { + printf("ERR: Invalid duration\n"); + ret = UAP_FAILURE; + break; + } + if ((ISDIGIT(argv[2]) == 0) || + (atoi(argv[2]) < 1) || + (atoi(argv[2]) > 3)) { + printf("ERR:Invalid sticky bit mask\n"); + ret = UAP_FAILURE; + break; + } + } + } + break; + case STICKYTIMSTAMACADDR: + if ((argc != 1) && (argc != 2)) { + printf("ERR:Incorrect number of STICKY_TIM_STA_MAC_ADDR arguments\n"); + ret = UAP_FAILURE; + } else { + if ((argc == 2) && + ((ISDIGIT(argv[0]) == 0) || (atoi(argv[0]) < 0) || + (atoi(argv[0]) > 1))) { + printf("ERR:Invalid control parameter\n"); + ret = UAP_FAILURE; + break; + } + } + break; + case COEX2040CONFIG: + if (argc != 1) { + printf("ERR: Incorrect number of 2040 COEX CONFIG arguments\n"); + ret = UAP_FAILURE; + } else { + if ((ISDIGIT(argv[0]) == 0) || (atoi(argv[0]) < 0) || + (atoi(argv[0]) > 1)) { + printf("ERR:Invalid enable parameter\n"); + ret = UAP_FAILURE; + break; + } + } + break; + case EAPOL_PWK_HSK: + if (argc != 2) { + printf("ERR:Incorrect number of EAPOL_PWK_HSK arguments.\n"); + ret = UAP_FAILURE; + } else { + if ((ISDIGIT(argv[0]) == 0) || (ISDIGIT(argv[1]) == 0) + || (atoi(argv[0]) < 0) || (atoi(argv[1]) < 0)) { + printf("ERR:Illegal parameters for EAPOL_PWK_HSK. Must be digits greater than equal to zero.\n"); + } + } + break; + case EAPOL_GWK_HSK: + if (argc != 2) { + printf("ERR:Incorrect number of EAPOL_GWK_HSK arguments.\n"); + ret = UAP_FAILURE; + } else { + if ((ISDIGIT(argv[0]) == 0) || (ISDIGIT(argv[1]) == 0) + || (atoi(argv[0]) < 0) || (atoi(argv[1]) < 0)) { + printf("ERR:Illegal parameters for EAPOL_GWK_HSK. Must be digits greater than equal to zero.\n"); + } + } + break; + case PREAMBLETYPE: + if (argc != 1) { + printf("ERR:Incorrect number of arguments for PREAMBLE TYPE\n"); + ret = UAP_FAILURE; + } else { + if ((ISDIGIT(argv[0]) == 0) || + (atoi(argv[0]) > MAX_PREAMBLE_TYPE) || + (atoi(argv[0]) < 0)) { + printf("ERR:PREAMBLE TYPE must be in the range of [0:%d]. The input was %s.\n", MAX_PREAMBLE_TYPE, argv[0]); + ret = UAP_FAILURE; + } + } + break; + + case COEX_COMM_BITMAP: + if (argc != 1) { + printf("ERR:Incorrect number of argument for Bitmap.\n"); + ret = UAP_FAILURE; + } else { + /* Only bit 0 is supported now, hence check for 1 or 0 */ + if ((IS_HEX_OR_DIGIT(argv[0]) == 0) || + (atoi(argv[0]) < 0) || (atoi(argv[0]) > 1)) { + printf("ERR: Bitmap must have value of 1 or 0.\n"); + ret = UAP_FAILURE; + } + } + break; + case COEX_COMM_AP_COEX: + if (argc != 1) { + printf("ERR:Incorrect number of argument for APBTCoex.\n"); + ret = UAP_FAILURE; + } else { + if ((IS_HEX_OR_DIGIT(argv[0]) == 0) || + (atoi(argv[0]) < 0) || (atoi(argv[0]) > 1)) { + printf("ERR: APBTCoex must have value of 1 or 0.\n"); + ret = UAP_FAILURE; + } + } + break; + case COEX_SCO_ACL_FREQ: + if (argc != 1) { + printf("ERR:Incorrect number of arguments for aclFrequency.\n"); + ret = UAP_FAILURE; + } else { + if (ISDIGIT(argv[0]) == 0) { + printf("ERR: Incorrect value for aclFrequency.\n"); + ret = UAP_FAILURE; + } + } + break; + case COEX_ACL_ENABLED: + if (argc != 1) { + printf("ERR:Incorrect number of arguments for (acl) enabled.\n"); + ret = UAP_FAILURE; + } else { + if ((ISDIGIT(argv[0]) == 0) || (atoi(argv[0]) < 0) || + (atoi(argv[0]) > 1)) { + printf("ERR: (acl) enabled must have value of 1 or 0.\n"); + ret = UAP_FAILURE; + } + } + break; + case COEX_ACL_BT_TIME: + case COEX_ACL_WLAN_TIME: + if (argc != 1) { + printf("ERR:Incorrect number of arguments for bt/wlan time.\n"); + ret = UAP_FAILURE; + } else { + if (ISDIGIT(argv[0]) == 0) { + printf("ERR: Incorrect value for bt/wlan time.\n"); + ret = UAP_FAILURE; + } + } + break; + case COEX_PROTECTION: + if (argc != 2) { + printf("ERR:Incorrect number of arguments for %s.\n", + argv[0]); + ret = UAP_FAILURE; + } else { + if (ISDIGIT(argv[1]) == 0) { + printf("ERR: Incorrect value for %s.\n", + argv[0]); + ret = UAP_FAILURE; + } + } + break; + case PWK_CIPHER: + if ((argc != 1) && (argc != 2)) { + printf("ERR:Incorrect number of arguments for pwk_cipher.\n"); + ret = UAP_FAILURE; + } else { + if ((ISDIGIT(argv[0]) == 0) || + (atoi(argv[0]) & ~PROTOCOL_BITMAP)) { + printf("Invalid Protocol paramter.\n"); + ret = UAP_FAILURE; + } + if (argc == 2) { + if ((ISDIGIT(argv[1]) == 0) || + (atoi(argv[1]) & ~CIPHER_BITMAP)) { + printf("Invalid pairwise cipher.\n"); + ret = UAP_FAILURE; + } + } + } + break; + case GWK_CIPHER: + if (argc != 1) { + printf("ERR:Incorrect number of arguments for gwk_cipher.\n"); + ret = UAP_FAILURE; + } else { + if ((ISDIGIT(argv[0]) == 0) || + (atoi(argv[0]) & ~CIPHER_BITMAP) || + (atoi(argv[0]) == AES_CCMP_TKIP)) { + printf("Invalid group cipher.\n"); + ret = UAP_FAILURE; + } + } + break; + case RESTRICT_CLIENT_MODE: + if ((argc != 1) && (argc != 2)) { + printf("ERR: Incorrect number of arguments.\n"); + ret = UAP_FAILURE; + } else { + if ((ISDIGIT(argv[0]) == 0) || ((argc == 2) && + ((IS_HEX_OR_DIGIT + (argv[1]) == 0) || + ((atoi(argv[0]) < 0) || + (atoi(argv[0]) > + 1))))) { + printf("ERR: Invalid arguments\n"); + ret = UAP_FAILURE; + } + if ((atoi(argv[0]) == 1) && (argc == 1)) { + printf("ERR: Mode_config parameter must be provided to enable this feature.\n"); + ret = UAP_FAILURE; + } + if ((argc == 2) && + (((A2HEXDECIMAL(argv[1]) << 8) != B_ONLY_MASK) && + ((A2HEXDECIMAL(argv[1]) << 8) != G_ONLY_MASK) && + ((A2HEXDECIMAL(argv[1]) << 8) != A_ONLY_MASK) && + ((A2HEXDECIMAL(argv[1]) << 8) != N_ONLY_MASK) && + ((A2HEXDECIMAL(argv[1]) << 8) != AC_ONLY_MASK))) { + printf("ERR: Exactly one mode can be enabled at a time.\n"); + ret = UAP_FAILURE; + } + } + break; + default: + ret = UAP_FAILURE; + break; + } + return ret; +} + +/** + * @brief Converts colon separated MAC address to hex value + * + * @param mac A pointer to the colon separated MAC string + * @param raw A pointer to the hex data buffer + * @return UAP_SUCCESS or UAP_FAILURE + * UAP_RET_MAC_BROADCAST - if broadcast mac + * UAP_RET_MAC_MULTICAST - if multicast mac + */ +int +mac2raw(char *mac, t_u8 *raw) +{ + unsigned int temp_raw[ETH_ALEN]; + int num_tokens = 0; + int i; + if (strlen(mac) != ((2 * ETH_ALEN) + (ETH_ALEN - 1))) { + return UAP_FAILURE; + } + num_tokens = sscanf(mac, "%2x:%2x:%2x:%2x:%2x:%2x", + temp_raw + 0, temp_raw + 1, temp_raw + 2, + temp_raw + 3, temp_raw + 4, temp_raw + 5); + if (num_tokens != ETH_ALEN) { + return UAP_FAILURE; + } + for (i = 0; i < num_tokens; i++) + raw[i] = (t_u8)temp_raw[i]; + + if (memcmp(raw, "\xff\xff\xff\xff\xff\xff", ETH_ALEN) == 0) { + return UAP_RET_MAC_BROADCAST; + } else if (raw[0] & 0x01) { + return UAP_RET_MAC_MULTICAST; + } + return UAP_SUCCESS; +} + +/** + * @brief Converts a string to hex value + * + * @param str A pointer to the string + * @param raw A pointer to the raw data buffer + * @return Number of bytes read + */ +int +string2raw(char *str, unsigned char *raw) +{ + int len = (strlen(str) + 1) / 2; + + do { + if (!isxdigit(*str)) { + return -1; + } + *str = toupper(*str); + *raw = CHAR2INT(*str) << 4; + ++str; + *str = toupper(*str); + if (*str == '\0') + break; + *raw |= CHAR2INT(*str); + ++raw; + } while (*++str != '\0'); + return len; +} + +/** + * @brief Prints a MAC address in colon separated form from hex data + * + * @param raw A pointer to the hex data buffer + * @return N/A + */ +void +print_mac(t_u8 *raw) +{ + printf("%02x:%02x:%02x:%02x:%02x:%02x", (unsigned int)raw[0], + (unsigned int)raw[1], (unsigned int)raw[2], (unsigned int)raw[3], + (unsigned int)raw[4], (unsigned int)raw[5]); + return; +} + +/** + * @brief Check hex string + * + * @param hex A pointer to hex string + * @return UAP_SUCCESS or UAP_FAILURE + */ +int +ishexstring(void *hex) +{ + int i, a; + char *p = hex; + int len = strlen(p); + if (!strncasecmp("0x", p, 2)) { + p += 2; + len -= 2; + } + for (i = 0; i < len; i++) { + a = hex2num(*p); + if (a < 0) + return UAP_FAILURE; + p++; + } + return UAP_SUCCESS; +} + +/** + * @brief Show auth tlv + * + * @param tlv Pointer to auth tlv + * + * $return N/A + */ +void +print_auth(tlvbuf_auth_mode *tlv) +{ + switch (tlv->auth_mode) { + case 0: + printf("AUTHMODE = Open authentication\n"); + break; + case 1: + printf("AUTHMODE = Shared key authentication\n"); + break; + case 3: + printf("AUTHMODE = WPA3 SAE\n"); + break; + case 255: + printf("AUTHMODE = Auto (open and shared key)\n"); + break; + default: + printf("ERR: Invalid authmode=%d\n", tlv->auth_mode); + break; + } +} + +/** + * + * @brief Show cipher tlv + * + * @param tlv Pointer to cipher tlv + * + * $return N/A + */ +void +print_cipher(tlvbuf_cipher *tlv) +{ + switch (tlv->pairwise_cipher) { + case CIPHER_TKIP: + printf("PairwiseCipher = TKIP\n"); + break; + case CIPHER_AES_CCMP: + printf("PairwiseCipher = AES CCMP\n"); + break; + case CIPHER_TKIP | CIPHER_AES_CCMP: + printf("PairwiseCipher = TKIP + AES CCMP\n"); + break; + case CIPHER_NONE: + printf("PairwiseCipher = None\n"); + break; + default: + printf("Unknown Pairwise cipher 0x%x\n", tlv->pairwise_cipher); + break; + } + switch (tlv->group_cipher) { + case CIPHER_TKIP: + printf("GroupCipher = TKIP\n"); + break; + case CIPHER_AES_CCMP: + printf("GroupCipher = AES CCMP\n"); + break; + case CIPHER_NONE: + printf("GroupCipher = None\n"); + break; + default: + printf("Unknown Group cipher 0x%x\n", tlv->group_cipher); + break; + } +} + +/** + * @brief Show pairwise cipher tlv + * + * @param tlv Pointer to pairwise cipher tlv + * + * $return N/A + */ +void +print_pwk_cipher(tlvbuf_pwk_cipher *tlv) +{ + switch (tlv->protocol) { + case PROTOCOL_WPA: + printf("Protocol WPA : "); + break; + case PROTOCOL_WPA2: + printf("Protocol WPA2 : "); + break; + case PROTOCOL_WPA3_SAE: + printf("Protocol WPA3_SAE : "); + break; + default: + printf("Unknown Protocol 0x%x\n", tlv->protocol); + break; + } + + switch (tlv->pairwise_cipher) { + case CIPHER_TKIP: + printf("PairwiseCipher = TKIP\n"); + break; + case CIPHER_AES_CCMP: + printf("PairwiseCipher = AES CCMP\n"); + break; + case CIPHER_TKIP | CIPHER_AES_CCMP: + printf("PairwiseCipher = TKIP + AES CCMP\n"); + break; + case CIPHER_NONE: + printf("PairwiseCipher = None\n"); + break; + default: + printf("Unknown Pairwise cipher 0x%x\n", tlv->pairwise_cipher); + break; + } +} + +/** + * @brief Show group cipher tlv + * + * @param tlv Pointer to group cipher tlv + * + * $return N/A + */ +void +print_gwk_cipher(tlvbuf_gwk_cipher *tlv) +{ + switch (tlv->group_cipher) { + case CIPHER_TKIP: + printf("GroupCipher = TKIP\n"); + break; + case CIPHER_AES_CCMP: + printf("GroupCipher = AES CCMP\n"); + break; + case CIPHER_NONE: + printf("GroupCipher = None\n"); + break; + default: + printf("Unknown Group cipher 0x%x\n", tlv->group_cipher); + break; + } +} + +/** + * @brief Show mac filter tlv + * + * @param tlv Pointer to filter tlv + * + * $return N/A + */ +void +print_mac_filter(tlvbuf_sta_mac_addr_filter *tlv) +{ + int i; + switch (tlv->filter_mode) { + case 0: + printf("Filter Mode = Filter table is disabled\n"); + return; + case 1: + if (!tlv->count) { + printf("No mac address is allowed to connect\n"); + } else { + printf("Filter Mode = Allow mac address specified in the allowed list\n"); + } + break; + case 2: + if (!tlv->count) { + printf("No mac address is blocked\n"); + } else { + printf("Filter Mode = Block MAC addresses specified in the banned list\n"); + } + break; + } + for (i = 0; i < tlv->count; i++) { + printf("MAC_%d = ", i); + print_mac(&tlv->mac_address[i * ETH_ALEN]); + printf("\n"); + } +} + +/** + * @brief Show rate tlv + * + * @param tlv Pointer to rate tlv + * + * $return N/A + */ +void +print_rate(tlvbuf_rates *tlv) +{ + int flag = 0; + int i; + t_u16 tlv_len; + + tlv_len = *(t_u8 *)&tlv->length; + tlv_len |= (*((t_u8 *)&tlv->length + 1) << 8); + + printf("Basic Rates ="); + for (i = 0; i < tlv_len; i++) { + if (tlv->operational_rates[i] > (BASIC_RATE_SET_BIT - 1)) { + flag = flag ? : 1; + printf(" 0x%x", tlv->operational_rates[i]); + } + } + printf("%s\nNon-Basic Rates =", flag ? "" : " ( none ) "); + for (flag = 0, i = 0; i < tlv_len; i++) { + if (tlv->operational_rates[i] < BASIC_RATE_SET_BIT) { + flag = flag ? : 1; + printf(" 0x%x", tlv->operational_rates[i]); + } + } + printf("%s\n", flag ? "" : " ( none ) "); +} + +/** + * @brief Show all the tlv in the buf + * + * @param buf Pointer to tlv buffer + * @param len Tlv buffer len + * + * $return N/A + */ +void +print_tlv(t_u8 *buf, t_u16 len) +{ + tlvbuf_header *pcurrent_tlv = (tlvbuf_header *)buf; + int tlv_buf_left = len; + t_u16 tlv_type; + t_u16 tlv_len; + t_u16 tlv_val_16; + t_u32 tlv_val_32; + t_u8 ssid[33]; + int i = 0; + tlvbuf_ap_mac_address *mac_tlv; + tlvbuf_ssid *ssid_tlv; + tlvbuf_beacon_period *beacon_tlv; + tlvbuf_dtim_period *dtim_tlv; + tlvbuf_rates *rates_tlv; + tlvbuf_tx_power *txpower_tlv; + tlvbuf_bcast_ssid_ctl *bcast_tlv; + tlvbuf_preamble_ctl *preamble_tlv; + tlvbuf_bss_status *bss_status_tlv; + tlvbuf_rts_threshold *rts_tlv; + tlvbuf_mcbc_data_rate *mcbcrate_tlv; + tlvbuf_pkt_fwd_ctl *pkt_fwd_tlv; + tlvbuf_sta_ageout_timer *ageout_tlv; + tlvbuf_ps_sta_ageout_timer *ps_ageout_tlv; + tlvbuf_auth_mode *auth_tlv; + tlvbuf_protocol *proto_tlv; + tlvbuf_akmp *akmp_tlv; + tlvbuf_cipher *cipher_tlv; + tlvbuf_pwk_cipher *pwk_cipher_tlv; + tlvbuf_gwk_cipher *gwk_cipher_tlv; + tlvbuf_group_rekey_timer *rekey_tlv; + tlvbuf_wpa_passphrase *psk_tlv; + tlvbuf_coex_common_cfg *coex_common_tlv; + tlvbuf_coex_sco_cfg *coex_sco_tlv; + tlvbuf_coex_acl_cfg *coex_acl_tlv; + tlvbuf_coex_stats *coex_stats_tlv; + tlvbuf_wep_key *wep_tlv; + tlvbuf_frag_threshold *frag_tlv; + tlvbuf_sta_mac_addr_filter *filter_tlv; + tlvbuf_max_sta_num *max_sta_tlv; + tlvbuf_retry_limit *retry_limit_tlv; + tlvbuf_eapol_pwk_hsk_timeout *pwk_timeout_tlv; + tlvbuf_eapol_pwk_hsk_retries *pwk_retries_tlv; + tlvbuf_eapol_gwk_hsk_timeout *gwk_timeout_tlv; + tlvbuf_eapol_gwk_hsk_retries *gwk_retries_tlv; + tlvbuf_channel_config *channel_tlv; + tlvbuf_channel_list *chnlist_tlv; + channel_list *pchan_list; + t_u16 custom_ie_len; + tlvbuf_rsn_replay_prot *replay_prot_tlv; + tlvbuf_custom_ie *custom_ie_tlv; + custom_ie *custom_ie_ptr; + tlvbuf_max_mgmt_ie *max_mgmt_ie_tlv; + tlvbuf_wmm_para_t *wmm_para_tlv; + int flag = 0; + tlvbuf_htcap_t *ht_cap_tlv; + tlvbuf_htinfo_t *ht_info_tlv; + tlvbuf_2040_coex *coex_2040_tlv; + +#ifdef RX_PACKET_COALESCE + tlvbuf_rx_pkt_coal_t *rx_pkt_coal_tlv; +#endif + +#if DEBUG + uap_printf(MSG_DEBUG, "tlv total len=%d\n", len); +#endif + while (tlv_buf_left >= (int)sizeof(tlvbuf_header)) { + tlv_type = *(t_u8 *)&pcurrent_tlv->type; + tlv_type |= (*((t_u8 *)&pcurrent_tlv->type + 1) << 8); + tlv_len = *(t_u8 *)&pcurrent_tlv->len; + tlv_len |= (*((t_u8 *)&pcurrent_tlv->len + 1) << 8); + if ((sizeof(tlvbuf_header) + tlv_len) > + (unsigned int)tlv_buf_left) { + printf("wrong tlv: tlv_len=%d, tlv_buf_left=%d\n", + tlv_len, tlv_buf_left); + break; + } + switch (tlv_type) { + case MRVL_AP_MAC_ADDRESS_TLV_ID: + mac_tlv = (tlvbuf_ap_mac_address *)pcurrent_tlv; + printf("AP MAC address = "); + print_mac(mac_tlv->ap_mac_addr); + printf("\n"); + break; + case MRVL_SSID_TLV_ID: + memset(ssid, 0, sizeof(ssid)); + ssid_tlv = (tlvbuf_ssid *)pcurrent_tlv; + + strncpy((char *)ssid, (char *)ssid_tlv->ssid, + sizeof(ssid) - 1); + + printf("SSID = %s\n", ssid); + break; + case MRVL_BEACON_PERIOD_TLV_ID: + beacon_tlv = (tlvbuf_beacon_period *)pcurrent_tlv; + tlv_val_16 = *(t_u8 *)&beacon_tlv->beacon_period_ms; + tlv_val_16 |= + (*((t_u8 *)&beacon_tlv->beacon_period_ms + 1) << + 8); + printf("Beacon period = %d\n", tlv_val_16); + break; + case MRVL_DTIM_PERIOD_TLV_ID: + dtim_tlv = (tlvbuf_dtim_period *)pcurrent_tlv; + printf("DTIM period = %d\n", dtim_tlv->dtim_period); + break; + case MRVL_CHANNELCONFIG_TLV_ID: + channel_tlv = (tlvbuf_channel_config *)pcurrent_tlv; + printf("Channel = %d\n", channel_tlv->chan_number); + printf("Band = %s\n", + (channel_tlv->bandcfg.chanBand == + BAND_5GHZ) ? "5GHz" : "2.4GHz"); + printf("Channel Select Mode = %s\n", + (channel_tlv->bandcfg.scanMode == + SCAN_MODE_ACS) ? "ACS" : "Manual"); + if (channel_tlv->bandcfg.chan2Offset == SEC_CHAN_NONE) + printf("no secondary channel\n"); + else if (channel_tlv->bandcfg.chan2Offset == + SEC_CHAN_ABOVE) + printf("secondary channel is above primary channel\n"); + else if (channel_tlv->bandcfg.chan2Offset == + SEC_CHAN_BELOW) + printf("secondary channel is below primary channel\n"); + break; + case MRVL_CHANNELLIST_TLV_ID: + chnlist_tlv = (tlvbuf_channel_list *)pcurrent_tlv; + printf("Channels List = "); + pchan_list = + (channel_list *) & (chnlist_tlv->chan_list); + if (tlv_len % sizeof(channel_list)) { + break; + } + for (i = 0; + (unsigned int)i < (tlv_len / sizeof(channel_list)); + i++) { + printf("\n%d\t%sGHz", pchan_list->chan_number, + (pchan_list->bandcfg.chanBand == + BAND_5GHZ) ? "5" : "2.4"); + pchan_list++; + } + printf("\n"); + break; + case MRVL_RSN_REPLAY_PROT_TLV_ID: + replay_prot_tlv = + (tlvbuf_rsn_replay_prot *)pcurrent_tlv; + printf("RSN replay protection = %s\n", + replay_prot_tlv-> + rsn_replay_prot ? "enabled" : "disabled"); + break; + case MRVL_RATES_TLV_ID: + rates_tlv = (tlvbuf_rates *)pcurrent_tlv; + print_rate(rates_tlv); + break; + case MRVL_TX_POWER_TLV_ID: + txpower_tlv = (tlvbuf_tx_power *)pcurrent_tlv; + printf("Tx power = %d dBm\n", + txpower_tlv->tx_power_dbm); + break; + case MRVL_BCAST_SSID_CTL_TLV_ID: + bcast_tlv = (tlvbuf_bcast_ssid_ctl *)pcurrent_tlv; + printf("SSID broadcast = %s\n", + (bcast_tlv->bcast_ssid_ctl == + 1) ? "enabled" : "disabled"); + break; + case MRVL_PREAMBLE_CTL_TLV_ID: + preamble_tlv = (tlvbuf_preamble_ctl *)pcurrent_tlv; + printf("Preamble type = %s\n", + (preamble_tlv->preamble_type == + 0) ? "auto" : ((preamble_tlv->preamble_type == + 1) ? "short" : "long")); + break; + case MRVL_BSS_STATUS_TLV_ID: + bss_status_tlv = (tlvbuf_bss_status *)pcurrent_tlv; + printf("BSS status = %s\n", + (bss_status_tlv->bss_status == + 0) ? "stopped" : "started"); + break; + case MRVL_RTS_THRESHOLD_TLV_ID: + rts_tlv = (tlvbuf_rts_threshold *)pcurrent_tlv; + tlv_val_16 = *(t_u8 *)&rts_tlv->rts_threshold; + tlv_val_16 |= + (*((t_u8 *)&rts_tlv->rts_threshold + 1) << 8); + printf("RTS threshold = %d\n", tlv_val_16); + break; + case MRVL_FRAG_THRESHOLD_TLV_ID: + frag_tlv = (tlvbuf_frag_threshold *)pcurrent_tlv; + tlv_val_16 = *(t_u8 *)&frag_tlv->frag_threshold; + tlv_val_16 |= + (*((t_u8 *)&frag_tlv->frag_threshold + 1) << 8); + printf("Fragmentation threshold = %d\n", tlv_val_16); + break; + case MRVL_MCBC_DATA_RATE_TLV_ID: + mcbcrate_tlv = (tlvbuf_mcbc_data_rate *)pcurrent_tlv; + tlv_val_16 = *(t_u8 *)&mcbcrate_tlv->mcbc_datarate; + tlv_val_16 |= + (*((t_u8 *)&mcbcrate_tlv->mcbc_datarate + 1) << + 8); + if (mcbcrate_tlv->mcbc_datarate == 0) + printf("MCBC data rate = auto\n"); + else + printf("MCBC data rate = 0x%x\n", tlv_val_16); + break; + case MRVL_PKT_FWD_CTL_TLV_ID: + pkt_fwd_tlv = (tlvbuf_pkt_fwd_ctl *)pcurrent_tlv; + printf("%s handles packet forwarding -\n", + ((pkt_fwd_tlv->pkt_fwd_ctl & PKT_FWD_FW_BIT) == + 0) ? "Host" : "Firmware"); + printf("\tIntra-BSS broadcast packets are %s\n", + ((pkt_fwd_tlv-> + pkt_fwd_ctl & PKT_FWD_INTRA_BCAST) == + 0) ? "allowed" : "denied"); + printf("\tIntra-BSS unicast packets are %s\n", + ((pkt_fwd_tlv-> + pkt_fwd_ctl & PKT_FWD_INTRA_UCAST) == + 0) ? "allowed" : "denied"); + printf("\tInter-BSS unicast packets are %s\n", + ((pkt_fwd_tlv-> + pkt_fwd_ctl & PKT_FWD_INTER_UCAST) == + 0) ? "allowed" : "denied"); + break; + case MRVL_STA_AGEOUT_TIMER_TLV_ID: + ageout_tlv = (tlvbuf_sta_ageout_timer *)pcurrent_tlv; + tlv_val_32 = *(t_u8 *)&ageout_tlv->sta_ageout_timer_ms; + tlv_val_32 |= + (*((t_u8 *)&ageout_tlv->sta_ageout_timer_ms + 1) + << 8); + tlv_val_32 |= + (*((t_u8 *)&ageout_tlv->sta_ageout_timer_ms + 2) + << 16); + tlv_val_32 |= + (*((t_u8 *)&ageout_tlv->sta_ageout_timer_ms + 3) + << 24); + printf("STA ageout timer = %d\n", (int)tlv_val_32); + break; + case MRVL_PS_STA_AGEOUT_TIMER_TLV_ID: + ps_ageout_tlv = + (tlvbuf_ps_sta_ageout_timer *)pcurrent_tlv; + tlv_val_32 = + *(t_u8 *)&ps_ageout_tlv->ps_sta_ageout_timer_ms; + tlv_val_32 |= + (* + ((t_u8 *)&ps_ageout_tlv-> + ps_sta_ageout_timer_ms + 1) << 8); + tlv_val_32 |= + (* + ((t_u8 *)&ps_ageout_tlv-> + ps_sta_ageout_timer_ms + 2) << 16); + tlv_val_32 |= + (* + ((t_u8 *)&ps_ageout_tlv-> + ps_sta_ageout_timer_ms + 3) << 24); + printf("PS STA ageout timer = %d\n", (int)tlv_val_32); + break; + case MRVL_AUTH_TLV_ID: + auth_tlv = (tlvbuf_auth_mode *)pcurrent_tlv; + print_auth(auth_tlv); + break; + case MRVL_PROTOCOL_TLV_ID: + proto_tlv = (tlvbuf_protocol *)pcurrent_tlv; + tlv_val_16 = *(t_u8 *)&proto_tlv->protocol; + tlv_val_16 |= + (*((t_u8 *)&proto_tlv->protocol + 1) << 8); + print_protocol(tlv_val_16); + break; + case MRVL_AKMP_TLV_ID: + akmp_tlv = (tlvbuf_akmp *)pcurrent_tlv; + tlv_val_16 = *(t_u8 *)&akmp_tlv->key_mgmt; + tlv_val_16 |= (*((t_u8 *)&akmp_tlv->key_mgmt + 1) << 8); + if (tlv_val_16 & (KEY_MGMT_PSK | KEY_MGMT_PSK_SHA256)) { + if (tlv_val_16 & KEY_MGMT_PSK) + printf("KeyMgmt = PSK\n"); + if (tlv_val_16 & KEY_MGMT_PSK_SHA256) + printf("KeyMgmt = PSK_SHA256\n"); + tlv_val_16 = + *(t_u8 *)&akmp_tlv->key_mgmt_operation; + if (tlv_len > sizeof(t_u16)) { + tlv_val_16 |= + (* + ((t_u8 *)&akmp_tlv-> + key_mgmt_operation + 1) << 8); + printf("Key Exchange on : %s.\n", + (tlv_val_16 & 0x01) ? "Host" : + "Device"); + printf("1x Authentication on : %s.\n", + (tlv_val_16 & 0x10) ? "Host" : + "Device"); + } + } + if (tlv_val_16 & KEY_MGMT_EAP) + printf("KeyMgmt = EAP"); + if (tlv_val_16 & KEY_MGMT_NONE) + printf("KeyMgmt = NONE"); + break; + case MRVL_CIPHER_TLV_ID: + cipher_tlv = (tlvbuf_cipher *)pcurrent_tlv; + print_cipher(cipher_tlv); + break; + case MRVL_CIPHER_PWK_TLV_ID: + pwk_cipher_tlv = (tlvbuf_pwk_cipher *)pcurrent_tlv; + pwk_cipher_tlv->protocol = + uap_le16_to_cpu(pwk_cipher_tlv->protocol); + print_pwk_cipher(pwk_cipher_tlv); + break; + case MRVL_CIPHER_GWK_TLV_ID: + gwk_cipher_tlv = (tlvbuf_gwk_cipher *)pcurrent_tlv; + print_gwk_cipher(gwk_cipher_tlv); + break; + case MRVL_GRP_REKEY_TIME_TLV_ID: + rekey_tlv = (tlvbuf_group_rekey_timer *)pcurrent_tlv; + tlv_val_32 = *(t_u8 *)&rekey_tlv->group_rekey_time_sec; + tlv_val_32 |= + (*((t_u8 *)&rekey_tlv->group_rekey_time_sec + 1) + << 8); + tlv_val_32 |= + (*((t_u8 *)&rekey_tlv->group_rekey_time_sec + 2) + << 16); + tlv_val_32 |= + (*((t_u8 *)&rekey_tlv->group_rekey_time_sec + 3) + << 24); + if (tlv_val_32 == 0) + printf("Group re-key time = disabled\n"); + else + printf("Group re-key time = %d second\n", + tlv_val_32); + break; + case MRVL_WPA_PASSPHRASE_TLV_ID: + psk_tlv = (tlvbuf_wpa_passphrase *)pcurrent_tlv; + if (tlv_len > 0) { + printf("WPA passphrase = "); + for (i = 0; i < tlv_len; i++) + printf("%c", psk_tlv->passphrase[i]); + printf("\n"); + } else + printf("WPA passphrase = None\n"); + break; + case MRVL_WEP_KEY_TLV_ID: + wep_tlv = (tlvbuf_wep_key *)pcurrent_tlv; + print_wep_key(wep_tlv); + break; + case MRVL_STA_MAC_ADDR_FILTER_TLV_ID: + filter_tlv = (tlvbuf_sta_mac_addr_filter *)pcurrent_tlv; + print_mac_filter(filter_tlv); + break; + case MRVL_MAX_STA_CNT_TLV_ID: + max_sta_tlv = (tlvbuf_max_sta_num *)pcurrent_tlv; + tlv_val_16 = + *(t_u8 *)&max_sta_tlv->max_sta_num_configured; + tlv_val_16 |= + (* + ((t_u8 *)&max_sta_tlv->max_sta_num_configured + + 1) << 8); + printf("Max Station Number configured = %d\n", + tlv_val_16); + if (max_sta_tlv->length == 4) { + tlv_val_16 = + *(t_u8 *)&max_sta_tlv-> + max_sta_num_supported; + tlv_val_16 |= + (* + ((t_u8 *)&max_sta_tlv-> + max_sta_num_supported + 1) << 8); + printf("Max Station Number supported = %d\n", + tlv_val_16); + } + break; + case MRVL_RETRY_LIMIT_TLV_ID: + retry_limit_tlv = (tlvbuf_retry_limit *)pcurrent_tlv; + printf("Retry Limit = %d\n", + retry_limit_tlv->retry_limit); + break; + case MRVL_EAPOL_PWK_HSK_TIMEOUT_TLV_ID: + pwk_timeout_tlv = + (tlvbuf_eapol_pwk_hsk_timeout *)pcurrent_tlv; + pwk_timeout_tlv->pairwise_update_timeout = + uap_le32_to_cpu(pwk_timeout_tlv-> + pairwise_update_timeout); + printf("Pairwise handshake timeout = %d\n", + pwk_timeout_tlv->pairwise_update_timeout); + break; + case MRVL_EAPOL_PWK_HSK_RETRIES_TLV_ID: + pwk_retries_tlv = + (tlvbuf_eapol_pwk_hsk_retries *)pcurrent_tlv; + pwk_retries_tlv->pwk_retries = + uap_le32_to_cpu(pwk_retries_tlv->pwk_retries); + printf("Pairwise handshake retries = %d\n", + pwk_retries_tlv->pwk_retries); + break; + case MRVL_EAPOL_GWK_HSK_TIMEOUT_TLV_ID: + gwk_timeout_tlv = + (tlvbuf_eapol_gwk_hsk_timeout *)pcurrent_tlv; + gwk_timeout_tlv->groupwise_update_timeout = + uap_le32_to_cpu(gwk_timeout_tlv-> + groupwise_update_timeout); + printf("Groupwise handshake timeout = %d\n", + gwk_timeout_tlv->groupwise_update_timeout); + break; + case MRVL_EAPOL_GWK_HSK_RETRIES_TLV_ID: + gwk_retries_tlv = + (tlvbuf_eapol_gwk_hsk_retries *)pcurrent_tlv; + gwk_retries_tlv->gwk_retries = + uap_le32_to_cpu(gwk_retries_tlv->gwk_retries); + printf("Groupwise handshake retries = %d\n", + gwk_retries_tlv->gwk_retries); + break; + case MRVL_MGMT_IE_LIST_TLV_ID: + custom_ie_tlv = (tlvbuf_custom_ie *)pcurrent_tlv; + custom_ie_len = tlv_len; + custom_ie_ptr = (custom_ie *)(custom_ie_tlv->ie_data); + while (custom_ie_len >= sizeof(custom_ie)) { + custom_ie_ptr->ie_index = + uap_le16_to_cpu(custom_ie_ptr-> + ie_index); + custom_ie_ptr->ie_length = + uap_le16_to_cpu(custom_ie_ptr-> + ie_length); + custom_ie_ptr->mgmt_subtype_mask = + uap_le16_to_cpu(custom_ie_ptr-> + mgmt_subtype_mask); + printf("Index [%d]\n", custom_ie_ptr->ie_index); + if (custom_ie_ptr->ie_length) + printf("Management Subtype Mask = 0x%02x\n", custom_ie_ptr->mgmt_subtype_mask == 0 ? UAP_CUSTOM_IE_AUTO_MASK : custom_ie_ptr->mgmt_subtype_mask); + else + printf("Management Subtype Mask = 0x%02x\n", custom_ie_ptr->mgmt_subtype_mask); + hexdump_data("IE Buffer", + (void *)custom_ie_ptr->ie_buffer, + (custom_ie_ptr->ie_length), ' '); + custom_ie_len -= + sizeof(custom_ie) + + custom_ie_ptr->ie_length; + custom_ie_ptr = + (custom_ie *)((t_u8 *)custom_ie_ptr + + sizeof(custom_ie) + + custom_ie_ptr->ie_length); + } + custom_ie_present = 1; + break; + case MRVL_MAX_MGMT_IE_TLV_ID: + max_mgmt_ie_tlv = (tlvbuf_max_mgmt_ie *)pcurrent_tlv; + max_mgmt_ie_tlv->count = + uap_le16_to_cpu(max_mgmt_ie_tlv->count); + for (i = 0; i < max_mgmt_ie_tlv->count; i++) { + max_mgmt_ie_tlv->info[i].buf_size = + uap_le16_to_cpu(max_mgmt_ie_tlv-> + info[i].buf_size); + max_mgmt_ie_tlv->info[i].buf_count = + uap_le16_to_cpu(max_mgmt_ie_tlv-> + info[i].buf_count); + printf("buf%d_size = %d\n", i, + max_mgmt_ie_tlv->info[i].buf_size); + printf("number of buffers = %d\n", + max_mgmt_ie_tlv->info[i].buf_count); + printf("\n"); + } + max_mgmt_ie_print = 1; + break; + case MRVL_BT_COEX_COMMON_CFG_TLV_ID: + printf("Coex common configuration:\n"); + coex_common_tlv = + (tlvbuf_coex_common_cfg *)pcurrent_tlv; + printf("\tConfig Bitmap = 0x%02x\n", + uap_le32_to_cpu(coex_common_tlv->config_bitmap)); + printf("\tAP Coex Enabled = %d\n", + uap_le32_to_cpu(coex_common_tlv->ap_bt_coex)); + break; + + case MRVL_BT_COEX_SCO_CFG_TLV_ID: + printf("Coex sco configuration:\n"); + coex_sco_tlv = (tlvbuf_coex_sco_cfg *)pcurrent_tlv; + for (i = 0; i < 4; i++) + printf("\tQtime protection [%d] = %d usecs\n", + i, + uap_le16_to_cpu(coex_sco_tlv-> + protection_qtime[i])); + printf("\tProtection frame rate = %d\n", + uap_le16_to_cpu(coex_sco_tlv->protection_rate)); + printf("\tACL frequency = %d\n", + uap_le16_to_cpu(coex_sco_tlv->acl_frequency)); + break; + + case MRVL_BT_COEX_ACL_CFG_TLV_ID: + printf("Coex acl configuration: "); + coex_acl_tlv = (tlvbuf_coex_acl_cfg *)pcurrent_tlv; + coex_acl_tlv->enabled = + uap_le16_to_cpu(coex_acl_tlv->enabled); + printf("%s\n", + (coex_acl_tlv-> + enabled) ? "enabled" : "disabled"); + if (coex_acl_tlv->enabled) { + printf("\tBT time = %d usecs\n", + uap_le16_to_cpu(coex_acl_tlv->bt_time)); + printf("\tWLan time = %d usecs\n", + uap_le16_to_cpu(coex_acl_tlv-> + wlan_time)); + printf("\tProtection frame rate = %d\n", + uap_le16_to_cpu(coex_acl_tlv-> + protection_rate)); + } + break; + + case MRVL_BT_COEX_STATS_TLV_ID: + printf("Coex statistics: \n"); + coex_stats_tlv = (tlvbuf_coex_stats *)pcurrent_tlv; + printf("\tNull not sent = %d\n", + uap_le32_to_cpu(coex_stats_tlv->null_not_sent)); + printf("\tNull queued = %d\n", + uap_le32_to_cpu(coex_stats_tlv->null_queued)); + printf("\tNull not queued = %d\n", + uap_le32_to_cpu(coex_stats_tlv-> + null_not_queued)); + printf("\tCF End queued = %d\n", + uap_le32_to_cpu(coex_stats_tlv->cf_end_queued)); + printf("\tCF End not queued = %d\n", + uap_le32_to_cpu(coex_stats_tlv-> + cf_end_not_queued)); + printf("\tNull allocation failures = %d\n", + uap_le32_to_cpu(coex_stats_tlv-> + null_alloc_fail)); + printf("\tCF End allocation failures = %d\n", + uap_le32_to_cpu(coex_stats_tlv-> + cf_end_alloc_fail)); + break; + case HT_CAPABILITY_TLV_ID: + printf("\nHT Capability Info: \n"); + ht_cap_tlv = (tlvbuf_htcap_t *)pcurrent_tlv; + if (!ht_cap_tlv->ht_cap.supported_mcs_set[0]) { + printf("802.11n is disabled\n"); + } else { + printf("802.11n is enabled\n"); + printf("ht_cap_info=0x%x, ampdu_param=0x%x tx_bf_cap=%#x\n", uap_le16_to_cpu(ht_cap_tlv->ht_cap.ht_cap_info), ht_cap_tlv->ht_cap.ampdu_param, uap_le32_to_cpu(ht_cap_tlv->ht_cap.tx_bf_cap)); + printf("supported MCS set:\n"); + for (i = 0; i < MCS_SET_LEN; i++) { + printf("0x%x ", + ht_cap_tlv->ht_cap. + supported_mcs_set[i]); + } + printf("\n"); + } + break; + case HT_INFO_TLV_ID: + ht_info_tlv = (tlvbuf_htinfo_t *)pcurrent_tlv; + if (ht_info_tlv->length) { + printf("\nHT Information Element: \n"); + printf("Primary channel = %d\n", + ht_info_tlv->ht_info.pri_chan); + printf("Secondary channel offset = %d\n", + (int)GET_SECONDARY_CHAN(ht_info_tlv-> + ht_info.field2)); + printf("STA channel width = %dMHz\n", + IS_CHANNEL_WIDTH_40(ht_info_tlv->ht_info. + field2) ? 40 : 20); + printf("RIFS %s\n", + IS_RIFS_ALLOWED(ht_info_tlv->ht_info. + field2) ? "Allowed" : + "Prohibited"); + ht_info_tlv->ht_info.field3 = + uap_le16_to_cpu(ht_info_tlv->ht_info. + field3); + ht_info_tlv->ht_info.field4 = + uap_le16_to_cpu(ht_info_tlv->ht_info. + field4); + printf("HT Protection = %d\n", + (int)GET_HT_PROTECTION(ht_info_tlv-> + ht_info.field3)); + printf("Non-Greenfield HT STAs present: %s\n", + NONGF_STA_PRESENT(ht_info_tlv->ht_info. + field3) ? "Yes" : + "No"); + printf("OBSS Non-HT STAs present: %s\n", + OBSS_NONHT_STA_PRESENT(ht_info_tlv-> + ht_info. + field3) ? "Yes" : + "No"); + for (i = 0; i < MCS_SET_LEN; i++) { + if (ht_info_tlv->ht_info. + basic_mcs_set[i]) { + printf("Basic_mcs_set: \n"); + flag = 1; + break; + } + } + if (flag) { + for (i = 0; i < MCS_SET_LEN; i++) + printf("%x ", + ht_info_tlv->ht_info. + basic_mcs_set[i]); + printf("\n"); + } + } + break; + case MRVL_2040_BSS_COEX_CONTROL_TLV_ID: + coex_2040_tlv = (tlvbuf_2040_coex *)pcurrent_tlv; + printf("20/40 coex = %s\n", + (coex_2040_tlv-> + enable) ? "enabled" : "disabled"); + break; + case VENDOR_SPECIFIC_IE_TLV_ID: + wmm_para_tlv = (tlvbuf_wmm_para_t *)pcurrent_tlv; + printf("wmm parameters:\n"); + printf("\tqos_info = 0x%x\n", + wmm_para_tlv->wmm_para.qos_info); + printf("\tBE: AIFSN=%d, CW_MAX=%d CW_MIN=%d, TXOP=%d\n", + wmm_para_tlv->wmm_para.ac_params[AC_BE]. + aci_aifsn.aifsn, + wmm_para_tlv->wmm_para.ac_params[AC_BE].ecw. + ecw_max, + wmm_para_tlv->wmm_para.ac_params[AC_BE].ecw. + ecw_min, + uap_le16_to_cpu(wmm_para_tlv->wmm_para. + ac_params[AC_BE].tx_op_limit)); + printf("\tBK: AIFSN=%d, CW_MAX=%d CW_MIN=%d, TXOP=%d\n", + wmm_para_tlv->wmm_para.ac_params[AC_BK]. + aci_aifsn.aifsn, + wmm_para_tlv->wmm_para.ac_params[AC_BK].ecw. + ecw_max, + wmm_para_tlv->wmm_para.ac_params[AC_BK].ecw. + ecw_min, + uap_le16_to_cpu(wmm_para_tlv->wmm_para. + ac_params[AC_BK].tx_op_limit)); + printf("\tVI: AIFSN=%d, CW_MAX=%d CW_MIN=%d, TXOP=%d\n", + wmm_para_tlv->wmm_para.ac_params[AC_VI]. + aci_aifsn.aifsn, + wmm_para_tlv->wmm_para.ac_params[AC_VI].ecw. + ecw_max, + wmm_para_tlv->wmm_para.ac_params[AC_VI].ecw. + ecw_min, + uap_le16_to_cpu(wmm_para_tlv->wmm_para. + ac_params[AC_VI].tx_op_limit)); + printf("\tVO: AIFSN=%d, CW_MAX=%d CW_MIN=%d, TXOP=%d\n", + wmm_para_tlv->wmm_para.ac_params[AC_VO]. + aci_aifsn.aifsn, + wmm_para_tlv->wmm_para.ac_params[AC_VO].ecw. + ecw_max, + wmm_para_tlv->wmm_para.ac_params[AC_VO].ecw. + ecw_min, + uap_le16_to_cpu(wmm_para_tlv->wmm_para. + ac_params[AC_VO].tx_op_limit)); + break; +#ifdef RX_PACKET_COALESCE + case MRVL_RX_PKT_COAL_TLV_ID: + rx_pkt_coal_tlv = (tlvbuf_rx_pkt_coal_t *)pcurrent_tlv; + printf("RX packet coalesce threshold=%d\n", + uap_le32_to_cpu(rx_pkt_coal_tlv->rx_pkt_count)); + printf("RX packet coalesce timeout in msec=%d\n", + uap_le16_to_cpu(rx_pkt_coal_tlv->delay)); + break; +#endif + default: + break; + } + tlv_buf_left -= (sizeof(tlvbuf_header) + tlv_len); + pcurrent_tlv = (tlvbuf_header *)(pcurrent_tlv->data + tlv_len); + } + return; +} + +/** + * @brief Checks if command requires driver handling, and if so, + * repackage and send as regular command, instead of hostcmd. + * + * @param cmd Pointer to the command buffer + * @param size Pointer to the command size. This value is + * overwritten by the function with the size of the + * received response. + * @param buf_size Size of the allocated command buffer + * @param reroute_ret Pointer to return value of rerouted command + * @return UAP_SUCCESS (handled here, further processing not needed) + * or UAP_FAILURE (not handled here, proceed as usual) + */ +static int +uap_ioctl_reroute(t_u8 *cmd, t_u16 *size, t_u16 buf_size, int *reroute_ret) +{ + t_u8 reroute = 0; + t_u16 cmd_code = 0; + t_u16 cmd_action = 0; + apcmdbuf_cfg_80211d *hcmd_domain = NULL; + apcmdbuf_snmp_mib *hcmd_snmp = NULL; + tlvbuf_header *tlv = NULL; + struct ifreq ifr; + t_s32 sockfd; + t_u8 *buf = NULL; + t_u16 buf_len = 0; + snmp_mib_param *snmp_param = NULL; + domain_info_param *domain_param = NULL; + + /* assume input is a hostcmd */ + cmd_code = ((apcmdbuf *)(cmd))->cmd_code; + + /* just check if we need to re-route right now */ + switch (cmd_code) { + case HostCmd_SNMP_MIB: + hcmd_snmp = (apcmdbuf_snmp_mib *)cmd; + tlv = (tlvbuf_header *)(cmd + sizeof(apcmdbuf_snmp_mib)); + cmd_action = uap_le16_to_cpu(hcmd_snmp->action); + /* reroute CMD_SNMP_MIB: SET */ + if (cmd_action == ACTION_SET) { + reroute = 1; + buf_len = + sizeof(snmp_mib_param) + + uap_le16_to_cpu(tlv->len); + } + break; + case HostCmd_CMD_802_11D_DOMAIN_INFO: + hcmd_domain = (apcmdbuf_cfg_80211d *)cmd; + cmd_action = uap_le16_to_cpu(hcmd_domain->action); + /* reroute CMD_DOMAIN_INFO: SET */ + if (cmd_action == ACTION_SET) { + reroute = 1; + buf_len = sizeof(domain_info_param) + (*size + - + sizeof + (apcmdbuf_cfg_80211d) + + + sizeof + (domain_param_t)); + } + break; + } + + /* Exit early if not re-routing */ + if (!reroute || uap_ioctl_no_reroute) + return UAP_FAILURE; + + /* Prepare buffer */ +#if DEBUG + uap_printf(MSG_DEBUG, "DBG: rerouting CMD 0x%04x\n", cmd_code); +#endif + buf = (t_u8 *)malloc(buf_len); + if (!buf) { + printf("ERR:Cannot allocate buffer for command!\n"); + goto done_no_socket; + } + memset(buf, 0, buf_len); + + /* Prepare param */ + switch (cmd_code) { + case HostCmd_SNMP_MIB: + snmp_param = (snmp_mib_param *)buf; + snmp_param->subcmd = UAP_SNMP_MIB; + snmp_param->action = cmd_action; + snmp_param->oid = uap_le16_to_cpu(tlv->type); + snmp_param->oid_val_len = uap_le16_to_cpu(tlv->len); + memcpy(snmp_param->oid_value, tlv->data, + MIN(sizeof(t_u32), snmp_param->oid_val_len)); + break; + case HostCmd_CMD_802_11D_DOMAIN_INFO: + domain_param = (domain_info_param *)buf; + domain_param->subcmd = UAP_DOMAIN_INFO; + domain_param->action = cmd_action; + memcpy(domain_param->tlv, &hcmd_domain->domain, + buf_len - sizeof(domain_info_param)); + tlv = (tlvbuf_header *)domain_param->tlv; + tlv->type = uap_le16_to_cpu(tlv->type); + tlv->len = uap_le16_to_cpu(tlv->len); + + break; + } +#if DEBUG + /* Dump request buffer */ + hexdump("Reroute Request buffer", buf, buf_len, ' '); +#endif + + /* Open socket */ + if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) { + printf("ERR:Cannot open socket\n"); + goto done_no_socket; + } + /* Initialize the ifr structure */ + memset(&ifr, 0, sizeof(ifr)); + strncpy(ifr.ifr_ifrn.ifrn_name, dev_name, IFNAMSIZ - 1); + ifr.ifr_ifru.ifru_data = (void *)buf; + /* Perform ioctl */ + errno = 0; + if (ioctl(sockfd, UAP_IOCTL_CMD, &ifr)) { + *reroute_ret = UAP_FAILURE; + perror(""); +#if DEBUG + uap_printf(MSG_DEBUG, "ERR: reroute of CMD 0x%04x failed\n", + cmd_code); +#endif + goto done; + } + *reroute_ret = UAP_SUCCESS; + +done: + /* Close socket */ + close(sockfd); +done_no_socket: + if (buf) + free(buf); + + return UAP_SUCCESS; +} + +/** + * @brief Performs the ioctl operation to send the command to + * the driver. + * + * @param cmd Pointer to the command buffer + * @param size Pointer to the command size. This value is + * overwritten by the function with the size of the + * received response. + * @param buf_size Size of the allocated command buffer + * @return UAP_SUCCESS or UAP_FAILURE + */ +int +uap_ioctl(t_u8 *cmd, t_u16 *size, t_u16 buf_size) +{ + struct ifreq ifr; + apcmdbuf *header = NULL; + t_s32 sockfd; + int reroute_ret = 0; + mrvl_priv_cmd *mrvl_cmd = NULL; + t_u8 *buf = NULL, *temp = NULL; + t_u16 mrvl_header_len = 0; + int ret = UAP_SUCCESS; + +#ifdef WIFI_DIRECT_SUPPORT + if (strncmp(dev_name, "wfd", 3)) +#endif + if (uap_ioctl_reroute(cmd, size, buf_size, &reroute_ret) == + UAP_SUCCESS) { + return reroute_ret; + } + + if (buf_size < *size) { + printf("buf_size should not less than cmd buffer size\n"); + return UAP_FAILURE; + } + + /* Open socket */ + if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) { + printf("ERR:Cannot open socket\n"); + return UAP_FAILURE; + } + *(t_u32 *)cmd = buf_size - BUF_HEADER_SIZE; + + mrvl_header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_HOSTCMD); + buf = (unsigned char *)malloc(buf_size + sizeof(mrvl_priv_cmd) + + mrvl_header_len); + if (buf == NULL) { + close(sockfd); + return UAP_FAILURE; + } + + memset(buf, 0, buf_size + sizeof(mrvl_priv_cmd) + mrvl_header_len); + /* Fill up buffer */ + mrvl_cmd = (mrvl_priv_cmd *)buf; + mrvl_cmd->buf = buf + sizeof(mrvl_priv_cmd); + mrvl_cmd->used_len = 0; + mrvl_cmd->total_len = buf_size + mrvl_header_len; + /* Copy NXP command string */ + temp = mrvl_cmd->buf; + strncpy((char *)temp, CMD_NXP, strlen(CMD_NXP)); + temp += (strlen(CMD_NXP)); + /* Insert command string */ + strncpy((char *)temp, PRIV_CMD_HOSTCMD, strlen(PRIV_CMD_HOSTCMD)); + temp += (strlen(PRIV_CMD_HOSTCMD)); + + memcpy(temp, (t_u8 *)cmd, *size); + + /* Initialize the ifr structure */ + memset(&ifr, 0, sizeof(ifr)); + strncpy(ifr.ifr_ifrn.ifrn_name, dev_name, IFNAMSIZ - 1); + ifr.ifr_ifru.ifru_data = (void *)mrvl_cmd; + header = (apcmdbuf *)(buf + sizeof(mrvl_priv_cmd) + mrvl_header_len); + header->size = *size - BUF_HEADER_SIZE; + if (header->cmd_code == APCMD_SYS_CONFIGURE) { + apcmdbuf_sys_configure *sys_cfg; + sys_cfg = (apcmdbuf_sys_configure *)header; + sys_cfg->action = uap_cpu_to_le16(sys_cfg->action); + } + endian_convert_request_header(header); +#if DEBUG + /* Dump request buffer */ + hexdump("Request buffer", mrvl_cmd, + *size + sizeof(mrvl_priv_cmd) + mrvl_header_len, ' '); +#endif + /* Perform ioctl */ + errno = 0; + if (ioctl(sockfd, MRVLPRIVCMD, &ifr)) { + perror(""); + printf("ERR:MRVLPRIVCMD is not supported by %s\n", dev_name); + ret = UAP_FAILURE; + goto done; + } + endian_convert_response_header(header); + header->cmd_code &= HostCmd_CMD_ID_MASK; + header->cmd_code |= APCMD_RESP_CHECK; + *size = header->size; + + /* Validate response size */ + if (*size > (buf_size - BUF_HEADER_SIZE)) { + printf("ERR:Response size (%d) greater than buffer size (%d)! Aborting!\n", *size, buf_size); + ret = UAP_FAILURE; + goto done; + } + memcpy(cmd, (t_u8 *)header, *size + BUF_HEADER_SIZE); +#if DEBUG + /* Dump respond buffer */ + hexdump("Respond buffer", mrvl_cmd, + *size + BUF_HEADER_SIZE + sizeof(mrvl_priv_cmd) + + mrvl_header_len, ' '); +#endif + +done: + /* Close socket */ + close(sockfd); + if (buf) + free(buf); + return ret; +} + +/** + * @brief Get protocol from the firmware + * + * @param proto A pointer to protocol var + * @return UAP_SUCCESS/UAP_FAILURE + */ +int +get_sys_cfg_protocol(t_u16 *proto) +{ + apcmdbuf_sys_configure *cmd_buf = NULL; + tlvbuf_protocol *tlv = NULL; + t_u8 *buffer = NULL; + t_u16 cmd_len; + int ret = UAP_FAILURE; + + cmd_len = sizeof(apcmdbuf_sys_configure) + sizeof(tlvbuf_protocol); + /* Initialize the command buffer */ + buffer = (t_u8 *)malloc(cmd_len); + if (!buffer) { + printf("ERR:Cannot allocate buffer for command!\n"); + return ret; + } + memset(buffer, 0, cmd_len); + /* Locate headers */ + cmd_buf = (apcmdbuf_sys_configure *)buffer; + tlv = (tlvbuf_protocol *)(buffer + sizeof(apcmdbuf_sys_configure)); + /* Fill the command buffer */ + cmd_buf->cmd_code = APCMD_SYS_CONFIGURE; + cmd_buf->size = cmd_len; + cmd_buf->seq_num = 0; + cmd_buf->result = 0; + cmd_buf->action = ACTION_GET; + tlv->tag = MRVL_PROTOCOL_TLV_ID; + tlv->length = 2; + endian_convert_tlv_header_out(tlv); + /* Send the command */ + ret = uap_ioctl((t_u8 *)cmd_buf, &cmd_len, cmd_len); + endian_convert_tlv_header_in(tlv); + + /* Process response */ + if (ret == UAP_SUCCESS) { + /* Verify response */ + if (cmd_buf->cmd_code != + (APCMD_SYS_CONFIGURE | APCMD_RESP_CHECK)) { + printf("ERR:Corrupted response! cmd_code=%x, Tlv->tag=%x\n", cmd_buf->cmd_code, tlv->tag); + free(buffer); + return UAP_FAILURE; + } + + if (cmd_buf->result == CMD_SUCCESS) { + tlv->protocol = uap_le16_to_cpu(tlv->protocol); + memcpy(proto, &tlv->protocol, sizeof(tlv->protocol)); + } else { + ret = UAP_FAILURE; + } + } + if (buffer) + free(buffer); + return ret; +} + +/** + * @brief Check cipher is valid or not + * + * @param pairwisecipher Pairwise cipher + * @param groupcipher Group cipher + * @param protocol Protocol + * @param enable_11n 11n enabled or not. + * @return UAP_SUCCESS or UAP_FAILURE + */ +int +is_cipher_valid_with_11n(int pairwisecipher, int groupcipher, + int protocol, int enable_11n) +{ + if ((pairwisecipher == CIPHER_NONE) && (groupcipher == CIPHER_NONE)) + return UAP_SUCCESS; + if (pairwisecipher == CIPHER_TKIP) { + /* Ok to have TKIP in mixed mode */ + if (enable_11n && protocol != PROTOCOL_WPA2_MIXED) { + printf("ERR: WPA/TKIP cannot be used when AP operates in 802.11n mode.\n"); + return UAP_FAILURE; + } + } + if ((pairwisecipher == CIPHER_TKIP) && (groupcipher == CIPHER_TKIP)) + return UAP_SUCCESS; + if ((pairwisecipher == CIPHER_AES_CCMP) && + (groupcipher == CIPHER_AES_CCMP)) + return UAP_SUCCESS; + if ((pairwisecipher == CIPHER_AES_CCMP) && (groupcipher == CIPHER_TKIP)) + return UAP_SUCCESS; + if ((pairwisecipher == CIPHER_BITMAP) && (groupcipher == CIPHER_TKIP)) + return UAP_SUCCESS; + return UAP_FAILURE; +} + +/** + * @brief Check cipher is valid or not based on proto + * + * @param pairwisecipher Pairwise cipher + * @param groupcipher Group cipher + * @param protocol Protocol + * @return UAP_SUCCESS or UAP_FAILURE + */ +int +is_cipher_valid_with_proto(int pairwisecipher, int groupcipher, int protocol) +{ + HTCap_t htcap; + + if ((pairwisecipher == CIPHER_NONE) && (groupcipher == CIPHER_NONE)) + return UAP_SUCCESS; + if (pairwisecipher == CIPHER_TKIP) { + /* Ok to have TKIP in mixed mode */ + if (protocol != PROTOCOL_WPA2_MIXED) { + memset(&htcap, 0, sizeof(htcap)); + if (UAP_SUCCESS == get_sys_cfg_11n(&htcap)) { + if (htcap.supported_mcs_set[0]) { + printf("ERR: WPA/TKIP cannot be used when AP operates in 802.11n mode.\n"); + return UAP_FAILURE; + } + } + } + } + if ((pairwisecipher == CIPHER_TKIP) && (groupcipher == CIPHER_TKIP)) + return UAP_SUCCESS; + if ((pairwisecipher == CIPHER_AES_CCMP) && + (groupcipher == CIPHER_AES_CCMP)) + return UAP_SUCCESS; + if ((pairwisecipher == CIPHER_AES_CCMP) && (groupcipher == CIPHER_TKIP)) + return UAP_SUCCESS; + if ((pairwisecipher == CIPHER_BITMAP) && (groupcipher == CIPHER_TKIP)) + return UAP_SUCCESS; + return UAP_FAILURE; +} + +/** + * @brief Check cipher is valid or not + * + * @param pairwisecipher Pairwise cipher + * @param groupcipher Group cipher + * @return UAP_SUCCESS or UAP_FAILURE + */ +int +is_cipher_valid(int pairwisecipher, int groupcipher) +{ + HTCap_t htcap; + t_u16 proto = 0; + + if ((pairwisecipher == CIPHER_NONE) && (groupcipher == CIPHER_NONE)) + return UAP_SUCCESS; + if (pairwisecipher == CIPHER_TKIP) { + if (UAP_SUCCESS == get_sys_cfg_protocol(&proto)) { + /* Ok to have TKIP in mixed mode */ + if (proto != PROTOCOL_WPA2_MIXED) { + memset(&htcap, 0, sizeof(htcap)); + if (UAP_SUCCESS == get_sys_cfg_11n(&htcap)) { + if (htcap.supported_mcs_set[0]) { + printf("ERR: WPA/TKIP cannot be used when AP operates in 802.11n mode.\n"); + return UAP_FAILURE; + } + } + } + } + } + if ((pairwisecipher == CIPHER_TKIP) && (groupcipher == CIPHER_TKIP)) + return UAP_SUCCESS; + if ((pairwisecipher == CIPHER_AES_CCMP) && + (groupcipher == CIPHER_AES_CCMP)) + return UAP_SUCCESS; + if ((pairwisecipher == CIPHER_AES_CCMP) && (groupcipher == CIPHER_TKIP)) + return UAP_SUCCESS; + if ((pairwisecipher == CIPHER_BITMAP) && (groupcipher == CIPHER_TKIP)) + return UAP_SUCCESS; + return UAP_FAILURE; +} + +/** + * @brief The main function + * + * @param argc Number of arguments + * @param argv Pointer to the arguments + * @return 0 or 1 + */ +int +main(int argc, char *argv[]) +{ + int opt, i; + int ret = 0; + memset(dev_name, 0, sizeof(dev_name)); + strcpy(dev_name, DEFAULT_DEV_NAME); + + /* Parse arguments */ + while ((opt = + getopt_long(argc, argv, "+hi:d:v", ap_options, NULL)) != -1) { + switch (opt) { + case 'i': + if (strlen(optarg) < IFNAMSIZ) { + memset(dev_name, 0, sizeof(dev_name)); + strncpy(dev_name, optarg, strlen(optarg)); + } + printf("dev_name:%s\n", dev_name); + break; + case 'v': + printf("uaputl.exe - uAP utility ver %s\n", + UAP_VERSION); + exit(0); + case 'd': + debug_level = strtoul(optarg, NULL, 10); +#if DEBUG + uap_printf(MSG_DEBUG, "debug_level=%x\n", debug_level); +#endif + break; + case 'h': + default: + print_tool_usage(); + exit(0); + } + } + + argc -= optind; + argv += optind; + optind = 0; + + if (argc < 1) { + print_tool_usage(); + exit(1); + } + + /* Process command */ + for (i = 0; ap_command[i].cmd; i++) { + if (strncmp + (ap_command[i].cmd, argv[0], strlen(ap_command[i].cmd))) + continue; + if (strlen(ap_command[i].cmd) != strlen(argv[0])) + continue; + ret = ap_command[i].func(argc, argv); + break; + } + if (!ap_command[i].cmd) { + printf("ERR: %s is not supported\n", argv[0]); + exit(1); + } + if (ret == UAP_FAILURE) + return -1; + else + return 0; +} diff --git a/mxm_wifiex/wlan_src/mapp/uaputl/uaputl.h b/mxm_wifiex/wlan_src/mapp/uaputl/uaputl.h new file mode 100644 index 0000000..7f8b0cf --- /dev/null +++ b/mxm_wifiex/wlan_src/mapp/uaputl/uaputl.h @@ -0,0 +1,2671 @@ +/** @file uaputl.h + * + * @brief Header file for uaputl application + * + * + * Copyright 2014-2020 NXP + * + * NXP CONFIDENTIAL + * The source code contained or described herein and all documents related to + * the source code (Materials) are owned by NXP, its + * suppliers and/or its licensors. Title to the Materials remains with NXP, + * its suppliers and/or its licensors. The Materials contain + * trade secrets and proprietary and confidential information of NXP, its + * suppliers and/or its licensors. The Materials are protected by worldwide copyright + * and trade secret laws and treaty provisions. No part of the Materials may be + * used, copied, reproduced, modified, published, uploaded, posted, + * transmitted, distributed, or disclosed in any way without NXP's prior + * express written permission. + * + * No license under any patent, copyright, trade secret or other intellectual + * property right is granted to or conferred upon you by disclosure or delivery + * of the Materials, either expressly, by implication, inducement, estoppel or + * otherwise. Any license under such intellectual property rights must be + * express and approved by NXP in writing. + * + */ +/************************************************************************ +Change log: + 03/01/08: Initial creation +************************************************************************/ + +#ifndef _UAP_H +#define _UAP_H + +/** uAP application version string */ +#define UAP_VERSION "4.10" + +/** Character, 1 byte */ +typedef signed char t_s8; +/** Unsigned character, 1 byte */ +typedef unsigned char t_u8; + +/** Short integer */ +typedef signed short t_s16; +/** Unsigned short integer */ +typedef unsigned short t_u16; + +/** Integer */ +typedef signed int t_s32; +/** Unsigned integer */ +typedef unsigned int t_u32; + +/** Long long integer */ +typedef signed long long t_s64; +/** Unsigned long integer */ +typedef unsigned long long t_u64; + +#if (BYTE_ORDER == LITTLE_ENDIAN) +#undef BIG_ENDIAN_SUPPORT +#endif + +/** 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 from 16 bit little endian format to CPU format */ +#define uap_le16_to_cpu(x) swap_byte_16(x) +/** Convert from 32 bit little endian format to CPU format */ +#define uap_le32_to_cpu(x) swap_byte_32(x) +/** Convert from 64 bit little endian format to CPU format */ +#define uap_le64_to_cpu(x) swap_byte_64(x) +/** Convert to 16 bit little endian format from CPU format */ +#define uap_cpu_to_le16(x) swap_byte_16(x) +/** Convert to 32 bit little endian format from CPU format */ +#define uap_cpu_to_le32(x) swap_byte_32(x) +/** Convert to 64 bit little endian format from CPU format */ +#define uap_cpu_to_le64(x) swap_byte_64(x) + +/** Convert APCMD header to little endian format from CPU format */ +#define endian_convert_request_header(x) \ + { \ + (x)->cmd_code = uap_cpu_to_le16((x)->cmd_code); \ + (x)->size = uap_cpu_to_le16((x)->size); \ + (x)->seq_num = uap_cpu_to_le16((x)->seq_num); \ + (x)->result = uap_cpu_to_le16((x)->result); \ + } + +/** Convert APCMD header from little endian format to CPU format */ +#define endian_convert_response_header(x) \ + { \ + (x)->cmd_code = uap_le16_to_cpu((x)->cmd_code); \ + (x)->size = uap_le16_to_cpu((x)->size); \ + (x)->seq_num = uap_le16_to_cpu((x)->seq_num); \ + (x)->result = uap_le16_to_cpu((x)->result); \ + } + +/** Convert TLV header to little endian format from CPU format */ +#define endian_convert_tlv_header_out(x) \ + { \ + (x)->tag = uap_cpu_to_le16((x)->tag); \ + (x)->length = uap_cpu_to_le16((x)->length); \ + } + +/** Convert TLV header from little endian format to CPU format */ +#define endian_convert_tlv_header_in(x) \ + { \ + (x)->tag = uap_le16_to_cpu((x)->tag); \ + (x)->length = uap_le16_to_cpu((x)->length); \ + } + +#else /* BIG_ENDIAN_SUPPORT */ +/** Do nothing */ +#define uap_le16_to_cpu(x) x +/** Do nothing */ +#define uap_le32_to_cpu(x) x +/** Do nothing */ +#define uap_le64_to_cpu(x) x +/** Do nothing */ +#define uap_cpu_to_le16(x) x +/** Do nothing */ +#define uap_cpu_to_le32(x) x +/** Do nothing */ +#define uap_cpu_to_le64(x) x + +/** Do nothing */ +#define endian_convert_request_header(x) +/** Do nothing */ +#define endian_convert_response_header(x) +/** Do nothing */ +#define endian_convert_tlv_header_out(x) +/** Do nothing */ +#define endian_convert_tlv_header_in(x) +#endif /* BIG_ENDIAN_SUPPORT */ + +/** MRVL private command ioctl number */ +#define MRVLPRIVCMD (SIOCDEVPRIVATE + 14) +/** 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 +/** deep sleep subcommand */ +#define UAP_DEEP_SLEEP 3 +/** Tx data pause subcommand */ +#define UAP_TX_DATA_PAUSE 5 +#ifdef SDIO +/** sdcmd52 read write subcommand */ +#define UAP_SDCMD52_RW 6 +#endif +/** snmp mib subcommand */ +#define UAP_SNMP_MIB 7 +/** domain info subcommand */ +#define UAP_DOMAIN_INFO 8 +/** dfs testing subcommand */ +#define UAP_DFS_TESTING 10 +/** TX beamforming configuration */ +#define UAP_TX_BF_CFG 9 +/** 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 +/** Tx rate configuration */ +#define UAP_TX_RATE_CFG 14 +/** Antenna configuration */ +#define UAP_ANTENNA_CFG 15 + +#define UAP_DFS_REPEATER_MODE 16 + +#define UAP_CAC_TIMER_STATUS 17 + +/** Skip CAC */ +#define UAP_SKIP_CAC 18 + +#define UAP_HT_TX_CFG 19 + +#define UAP_VHT_CFG 20 + +#define UAP_HT_STREAM_CFG 21 + +#define UAP_OPERATION_CTRL 22 + +/** Config DFS channel switch count subcommand */ +#define UAP_CHAN_SWITCH_COUNT_CFG 23 +#define UAP_BAND_STEER 24 + +/** 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 + +/** deauth station */ +#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) + +/** enable UAP report mic error */ +#define UAP_REPORT_MIC_ERR (SIOCDEVPRIVATE + 8) +/** uap set key */ +#define UAP_SET_KEY (SIOCDEVPRIVATE + 9) +/** Packet inject command ioctl number */ +#define UAPHOSTPKTINJECT (SIOCDEVPRIVATE + 12) + +/** 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) + +/** Max IE index per BSS */ +#define MAX_MGMT_IE_INDEX 12 + +/** HS_CFG: Get flag */ +#define HS_CFG_FLAG_GET 0 +/** HS_CFG: Set flag */ +#define HS_CFG_FLAG_SET 1 +/** HS_CFG: condition flag */ +#define HS_CFG_FLAG_CONDITION 2 +/** HS_CFG: gpio flag */ +#define HS_CFG_FLAG_GPIO 4 +/** HS_CFG: gap flag */ +#define HS_CFG_FLAG_GAP 8 +/** HS_CFG: all flags */ +#define HS_CFG_FLAG_ALL 0x0f +/** HS_CFG: condition mask */ +#define HS_CFG_CONDITION_MASK 0x4f + +/** Host sleep config conditions : Cancel */ +#define HS_CFG_CANCEL 0xffffffff + +/** 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; + +/** 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 + +/** sleep parameter */ +#define SLEEP_PARAMETER 1 +/** inactivity sleep parameter */ +#define INACTIVITY_SLEEP_PARAMETER 2 + +/** sleep parameter : lower limit in micro-sec */ +#define PS_SLEEP_PARAM_MIN 5000 +/** sleep parameter : upper limit in micro-sec */ +#define PS_SLEEP_PARAM_MAX 32000 +/** power save awake period minimum value in micro-sec */ +#define PS_AWAKE_PERIOD_MIN 2000 + +/** ps_mgmt */ +typedef struct _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; +} ps_mgmt; + +/** 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; + +/** Default block ACK timeout */ +#define DEFAULT_BLOCK_ACK_TIMEOUT 0xFFFF + +/** Default block ACK timeout */ +#define MAX_TXRX_WINDOW_SIZE 0x3FF + +/** MAXIMUM number of TID */ +#define MAX_NUM_TID 8 + +/** 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_bands*/ + t_u8 fw_bands; + /** Region Code */ + t_u16 region_code; + /** 802.11n device capabilities */ + t_u32 hw_dot_11n_dev_cap; +} fw_info; + +#ifndef ETH_ALEN +/** MAC address length */ +#define ETH_ALEN 6 +#endif + +/** 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 _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; +} bf_global_cfg_args; + +/** trigger sounding args */ +typedef struct _trigger_sound_args { + /** Peer MAC address */ + t_u8 peer_mac[ETH_ALEN]; + /** Status */ + t_u8 status; +} trigger_sound_args; + +/** bf periodicity args */ +typedef struct _bf_periodicity_args { + /** Peer MAC address */ + t_u8 peer_mac[ETH_ALEN]; + /** Current Tx BF Interval */ + t_u16 interval; + /** Status */ + t_u8 status; +} bf_periodicity_args; + +/** tx bf peer args */ +typedef struct _tx_bf_peer_args { + /** Peer MAC address */ + t_u8 peer_mac[ETH_ALEN]; + /** Reserved */ + t_u16 reserved; + /** Enable/Disable Beamforming */ + t_u8 bf_enbl; + /** Enable/Disable sounding */ + t_u8 sounding_enbl; + /** FB Type */ + t_u8 fb_type; +} tx_bf_peer_args; + +typedef struct _snr_thr_args { + /** Peer MAC address */ + t_u8 peer_mac[ETH_ALEN]; + /** SNR for peer */ + t_u8 snr; +} snr_thr_args; + +/** Type definition of tx_bf_cfg */ +typedef struct _tx_bf_cfg_para { + /** Sub command */ + t_u32 subcmd; + /** Action: Set/Get + * Will be eliminatied on moal */ + t_u32 action; + /** BF command id */ + t_u16 bf_action; + /** Action Set/Get - + * this will be pssed to DNLD_CMD*/ + t_u16 bf_cmd_action; + /** Number of peers */ + t_u32 no_of_peers; + union { + bf_global_cfg_args bf_global_cfg; + trigger_sound_args bf_sound[MAX_PEER_MAC_TUPLES]; + bf_periodicity_args bf_periodicity[MAX_PEER_MAC_TUPLES]; + tx_bf_peer_args tx_bf_peer[MAX_PEER_MAC_TUPLES]; + snr_thr_args bf_snr[MAX_PEER_MAC_TUPLES]; + } body; +} tx_bf_cfg_para; + +/** skip_cac parameters */ +typedef struct _skip_cac_para { + /** subcmd */ + t_u32 subcmd; + /** Set/Get */ + t_u32 action; + /** enable/disable deepsleep*/ + t_u16 skip_cac; +} skip_cac_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; +/** Default idle time for auto deep sleep */ +#define DEEP_SLEEP_IDLE_TIME 100 + +/** band_steering parameters */ +typedef struct _band_steer_para { + /** subcmd */ + t_u32 subcmd; + /** Set/Get */ + t_u8 action; + /** enable/disable band steering*/ + t_u8 state; + /** Probe Response will be blocked to 2G channel for first block_2g_prb_req probe requests*/ + t_u8 block_2g_prb_req; + /** When band steering is enabled, limit the btm request sent to STA at */ + t_u8 max_btm_req_allowed; +} band_steer_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; + +/** Tx data pause disable */ +#define TX_DATA_PAUSE_DISABLE 0 +/** Tx data pause enable */ +#define TX_DATA_PAUSE_ENABLE 1 +/** Default maximum Tx buffer for all PS clients */ +#define MAX_TX_BUF_CNT 2 + +/** snmp_mib parameters */ +typedef struct _snmp_mib_param { + /** 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[]; +} snmp_mib_param; + +/** 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[]; +} domain_info_param; + +/** dfs_testing parameters */ +typedef struct _dfs_testing_param { + /** subcmd */ + t_u32 subcmd; + /** Set/Get */ + t_u32 action; + /** user CAC period (msec) */ + t_u32 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; + +/** Channel switch count config */ +typedef struct _cscount_cfg_t { + /** subcmd */ + t_u32 subcmd; + /** Set/Get */ + t_u32 action; + /** user channel switch count */ + t_u8 cs_count; +} cscount_cfg_t; + +/** mgmt_frame_ctrl */ +typedef struct _mgmt_frame_ctrl { + /** subcmd */ + t_u32 subcmd; + /** Set/Get */ + t_u32 action; + /** mask */ + t_u32 mask; +} mgmt_frame_ctrl; + +/* dfs repeater mode */ +typedef struct _dfs_repeater_mode { + /** subcmd */ + t_u32 subcmd; + /** set/get */ + t_u32 action; + /** mode */ + t_u32 mode; +} dfs_repeater_mode; + +/* */ +typedef struct _cac_timer_status { + /** subcmd */ + t_u32 subcmd; + /** set/get */ + t_u32 action; + /** mode */ + t_u32 mode; +} cac_timer_status; + +/** Type definition of ht_tx_cfg */ +typedef struct _ht_tx_cfg { + /** HTTxCap */ + t_u16 httxcap; + /** HTTxInfo */ + t_u16 httxinfo; +} ht_tx_cfg; + +/** Type definition of ht_tx_cfg_para */ +typedef struct _ht_tx_cfg_para { + /** Sub command */ + t_u32 subcmd; + /** Action: Set/Get + * Will be eliminatied on moal */ + t_u32 action; + /* HT Tx configuration */ + ht_tx_cfg tx_cfg; +} ht_tx_cfg_para; + +/** Default device name */ +#define DEFAULT_DEV_NAME "uap0" + +/** Success */ +#define UAP_SUCCESS 1 +/** Failure */ +#define UAP_FAILURE 0 +/** MAC BROADCAST */ +#define UAP_RET_MAC_BROADCAST 0x1FF +/** MAC MULTICAST */ +#define UAP_RET_MAC_MULTICAST 0x1FE + +/** Command is successful */ +#define CMD_SUCCESS 0 +/** Command fails */ +#define CMD_FAILURE -1 + +/** BSS start error : Invalid parameters */ +#define BSS_FAILURE_START_INVAL 2 + +/** Maximum line length for config file */ +#define MAX_LINE_LENGTH 240 +/** Maximum command length */ +#define MAX_CMD_LENGTH 100 +/** Size of command buffer */ +#define MRVDRV_SIZE_OF_CMD_BUFFER (3 * 1024) +/** Size of packet inject buffer */ +#define MRVDRV_SIZE_OF_PKT_BUFFER (1500) + +/** Maximum number of clients supported by AP */ +#define MAX_NUM_CLIENTS MAX_STA_COUNT +/** Maximum number of MAC addresses for one-shot filter modifications */ +#define MAX_MAC_ONESHOT_FILTER 64 +/** Maximum SSID length */ +#define MAX_SSID_LENGTH 32 +/** Maximum SSID length */ +#define MIN_SSID_LENGTH 1 +/** Maximum WPA passphrase length */ +#define MAX_WPA_PASSPHRASE_LENGTH 64 +/** Minimum WPA passphrase length */ +#define MIN_WPA_PASSPHRASE_LENGTH 8 +/** Maximum WPA3 SAE password length */ +#define MAX_WPA3_SAE_PASSWORD_LENGTH 255 +/** Minimum WPA3 SAE password length */ +#define MIN_WPA3_SAE_PASSWORD_LENGTH 8 +/** Maximum data rates */ +#define MAX_DATA_RATES 14 +/** Maximum length of lines in configuration file */ +#define MAX_CONFIG_LINE 240 +/** MSB bit is set if its a basic rate */ +#define BASIC_RATE_SET_BIT 0x80 +/** Maximum group key timer */ +#define MAX_GRP_TIMER 86400 +/** Maximum Retry Limit */ +#define MAX_RETRY_LIMIT 14 +/** Maximum preamble type value */ +#define MAX_PREAMBLE_TYPE 2 + +/** Maximum TX Power Limit */ +#define MAX_TX_POWER 30 +/** Minimum TX Power Limit */ +#define MIN_TX_POWER 0 + +/** Maximum channel number in bg mode */ +#define MAX_CHANNELS_BG 14 +/** Maximum channels */ +#define MAX_CHANNELS 165 +#define DEFAULT_MAX_VALID_CHANNEL_BG 11 + +/** MAX station count */ +#define MAX_STA_COUNT 64 + +/** Maximum RTS threshold */ +#define MAX_RTS_THRESHOLD 2347 + +/** Maximum fragmentation threshold */ +#define MAX_FRAG_THRESHOLD 2346 +/** Minimum fragmentation threshold */ +#define MIN_FRAG_THRESHOLD 256 + +/** Maximum stage out time */ +#define MAX_STAGE_OUT_TIME 864000 +/** Minimum stage out time */ +#define MIN_STAGE_OUT_TIME 50 + +/** Maximum DTIM period */ +#define MAX_DTIM_PERIOD 100 + +/** Maximum BEACON period */ +#define MAX_BEACON_PERIOD 4000 + +/** Minimum BEACON period */ +#define MIN_BEACON_PERIOD 50 + +/** Maximum IE buffer length */ +#define MAX_IE_BUFFER_LEN 256 + +/** Maximum custom IE count */ +#define MAX_CUSTOM_IE_COUNT 4 + +/** Maximum number of rates allowed at a time */ +#define MAX_RATES 12 + +/** Default wait period in seconds */ +#define DEFAULT_WAIT_TIME 3 + +/** Maximum valid value of Deauth reason code */ +#define MAX_DEAUTH_REASON_CODE 0xFFFF + +#ifdef __GNUC__ +/** Structure packing begins */ +#define PACK_START +/** Structure packeing end */ +#define PACK_END __attribute__ ((packed)) +#else +/** Structure packing begins */ +#define PACK_START __packed +/** Structure packeing end */ +#define PACK_END +#endif + +/** Action field value : get */ +#define ACTION_GET 0 +/** Action field value : set */ +#define ACTION_SET 1 +/** + * Hex or Decimal to Integer + * @param num string to convert into decimal or hex + */ +#define A2HEXDECIMAL(num) \ + (strncasecmp("0x", (num), 2)?(unsigned int) strtoll((num),NULL,0):a2hex((num)))\ + +/** + * Check of decimal or hex string + * @param num string + */ +#define IS_HEX_OR_DIGIT(num) \ + (strncasecmp("0x", (num), 2)?ISDIGIT((num)):ishexstring((num)))\ + +/** Find minimum value */ +#ifndef MIN +#define MIN(a, b) ((a) < (b) ? (a) : (b)) +#endif /* MIN */ + +/** Valid Input Commands */ +typedef enum { + RDEEPROM, + SCANCHANNELS, + TXPOWER, + PROTOCOL, + CHANNEL, + CHANNEL_EXT, + BAND, + RATE, + BROADCASTSSID, + RTSTHRESH, + FRAGTHRESH, + DTIMPERIOD, + RADIOCONTROL, + TXBEACONRATE, + MCBCDATARATE, + PKTFWD, + STAAGEOUTTIMER, + PSSTAAGEOUTTIMER, + AUTHMODE, + GROUPREKEYTIMER, + MAXSTANUM, + BEACONPERIOD, + RETRYLIMIT, + STICKYTIMCONFIG, + STICKYTIMSTAMACADDR, + COEX2040CONFIG, + TXRATECFG, + RSNREPLAYPROT, + PREAMBLETYPE, + EAPOL_PWK_HSK, + EAPOL_GWK_HSK, + COEX_COMM_BITMAP, + COEX_COMM_AP_COEX, + COEX_PROTECTION, + COEX_SCO_ACL_FREQ, + COEX_ACL_ENABLED, + COEX_ACL_BT_TIME, + COEX_ACL_WLAN_TIME, + PWK_CIPHER, + GWK_CIPHER, + RESTRICT_CLIENT_MODE, + AKM_SUITE, +} valid_inputs; + +/** Message verbosity level */ +enum { MSG_NONE, MSG_DEBUG, MSG_ALL }; + +/** oids_table */ +typedef struct { + /** oid type */ + t_u16 type; + /** oid len */ + t_u16 len; + /** oid name */ + char *name; +} oids_table; + +/** NXP private command identifier */ +#define CMD_NXP "MRVL_CMD" +/** NXP private command for hostcmd */ +#define PRIV_CMD_HOSTCMD "hostcmd" + +/** 4 byte header to store buf len*/ +#define BUF_HEADER_SIZE 4 + +/** TLV header length */ +#define TLVHEADER_LEN 4 + +/** AP CMD header */ +#define APCMDHEADER /** Buf Size */ \ + t_u32 buf_size; \ + /** Command Code */ \ + t_u16 cmd_code; \ + /** Size */ \ + t_u16 size; \ + /** Sequence Number */ \ + t_u16 seq_num; \ + /** Result */ \ + t_s16 result + +/** TLV header */ +#define TLVHEADER /** Tag */ \ + t_u16 tag; \ + /** Length */ \ + t_u16 length + +/* TLV Definitions */ + +/** TLV buffer header*/ +typedef PACK_START struct _tlvbuf_header { + /** Header type */ + t_u16 type; + /** Header length */ + t_u16 len; + /** Data */ + t_u8 data[]; +} PACK_END tlvbuf_header; + +/** BITMAP for ACS mode */ +#define BITMAP_ACS_MODE 0x01 + +/* 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 + +/** BITMAP for secondary channel above */ +#define BITMAP_CHANNEL_ABOVE 0x02 +/** BITMAP for secondary channel below */ +#define BITMAP_CHANNEL_BELOW 0x04 +/** Channle mode mask */ +#define CHANNEL_MODE_MASK 0x07 +/** max primary channel support secondary channel above */ +#define MAX_CHANNEL_ABOVE 9 +/** Default max primary channel supporting secondary channel above when country code is not Japan */ +#define DEFAULT_MAX_CHANNEL_ABOVE 7 +/** min primary channel support secondary channel below */ +#define MIN_CHANNEL_BELOW 5 +/** Default max primary channel supporting secondary channel above when country code is not Japan and not US */ +#define DEFAULT_MAX_CHANNEL_ABOVE_NON_US 9 +/** Default max primary channel supporting secondary channel below when country code is not Japan */ +#define DEFAULT_MAX_CHANNEL_BELOW 11 +/** Default max primary channel supporting secondary channel below when country code is not Japan and not US */ +#define DEFAULT_MAX_CHANNEL_BELOW_NON_US 13 + +/** channel band */ +enum { + BAND_2GHZ = 0, + BAND_5GHZ = 1, + BAND_4GHZ = 2, +}; + +/** channel offset */ +enum { + SEC_CHAN_NONE = 0, + SEC_CHAN_ABOVE = 1, + SEC_CHAN_5MHZ = 2, + SEC_CHAN_BELOW = 3 +}; + +/** channel bandwidth */ +enum { + CHAN_BW_20MHZ = 0, + CHAN_BW_10MHZ, + CHAN_BW_40MHZ, + CHAN_BW_80MHZ, +}; + +/** scan mode */ +enum { + SCAN_MODE_MANUAL = 0, + SCAN_MODE_ACS, + SCAN_MODE_USER, +}; + +/** Band_Config_t */ +typedef PACK_START struct _Band_Config_t { +#ifdef BIG_ENDIAN_SUPPORT + /** Channel Selection Mode - (00)=manual, (01)=ACS, (02)=user*/ + t_u8 scanMode:2; + /** Secondary Channel Offset - (00)=None, (01)=Above, (11)=Below */ + t_u8 chan2Offset:2; + /** Channel Width - (00)=20MHz, (10)=40MHz, (11)=80MHz */ + t_u8 chanWidth:2; + /** Band Info - (00)=2.4GHz, (01)=5GHz */ + t_u8 chanBand:2; +#else + /** Band Info - (00)=2.4GHz, (01)=5GHz */ + t_u8 chanBand:2; + /** Channel Width - (00)=20MHz, (10)=40MHz, (11)=80MHz */ + t_u8 chanWidth:2; + /** Secondary Channel Offset - (00)=None, (01)=Above, (11)=Below */ + t_u8 chan2Offset:2; + /** Channel Selection Mode - (00)=manual, (01)=ACS, (02)=Adoption mode*/ + t_u8 scanMode:2; +#endif +} PACK_END Band_Config_t; + +/** TLV buffer : Channel Config */ +typedef PACK_START struct _tlvbuf_channel_config { + /** Header */ + TLVHEADER; + /** Band Configuration */ + Band_Config_t bandcfg; + /** Channel number */ + t_u8 chan_number; +} PACK_END tlvbuf_channel_config; + +/** Channel List Entry */ +typedef PACK_START struct _channel_list { + /** Band Config */ + Band_Config_t bandcfg; + /** Channel Number */ + t_u8 chan_number; + /** Reserved */ + t_u8 reserved1; + /** Reserved */ + t_u16 reserved2; + /** Reserved */ + t_u16 reserved3; +} PACK_END channel_list; + +/** TLV buffer : Channel List */ +typedef PACK_START struct _tlvbuf_channel_list { + /** Header */ + TLVHEADER; + /** Channel List */ + channel_list chan_list[]; +} PACK_END tlvbuf_channel_list; + +/** TLV buffer : AP MAC address */ +typedef PACK_START struct _tlvbuf_ap_mac_address { + /** Header */ + TLVHEADER; + /** AP MAC address */ + t_u8 ap_mac_addr[ETH_ALEN]; +} PACK_END tlvbuf_ap_mac_address; + +/** TLV buffer : SSID */ +typedef PACK_START struct _tlvbuf_ssid { + /** Header */ + TLVHEADER; + /** SSID */ + t_u8 ssid[]; +} PACK_END tlvbuf_ssid; + +/** TLV buffer : Beacon period */ +typedef PACK_START struct _tlvbuf_beacon_period { + /** Header */ + TLVHEADER; + /** Beacon period */ + t_u16 beacon_period_ms; +} PACK_END tlvbuf_beacon_period; + +/** TLV buffer : DTIM period */ +typedef PACK_START struct _tlvbuf_dtim_period { + /** Header */ + TLVHEADER; + /** DTIM period */ + t_u8 dtim_period; +} PACK_END tlvbuf_dtim_period; + +/** TLV buffer : BSS status */ +typedef PACK_START struct _tlvbuf_bss_status { + /** Header */ + TLVHEADER; + /** BSS status */ + t_u16 bss_status; +} PACK_END tlvbuf_bss_status; + +/** TLV buffer : Channel */ +typedef PACK_START struct _tlvbuf_phyparamdsset { + /** Header */ + TLVHEADER; + /** Channel */ + t_u8 channel; +} PACK_END tlvbuf_phyparamdsset; + +/** TLV buffer : Operational rates */ +typedef PACK_START struct _tlvbuf_rates { + /** Header */ + TLVHEADER; + /** Operational rates */ + t_u8 operational_rates[]; +} PACK_END tlvbuf_rates; + +/** TLV buffer : Tx power */ +typedef PACK_START struct _tlvbuf_tx_power { + /** Header */ + TLVHEADER; + /** Tx power in dBm */ + t_u8 tx_power_dbm; +} PACK_END tlvbuf_tx_power; + +/** TLV buffer : SSID broadcast control */ +typedef PACK_START struct _tlvbuf_bcast_ssid_ctl { + /** Header */ + TLVHEADER; + /** SSID broadcast control flag */ + t_u8 bcast_ssid_ctl; +} PACK_END tlvbuf_bcast_ssid_ctl; + +/** TLV buffer : RSN replay protection */ +typedef PACK_START struct _tlvbuf_rsn_replay_prot { + /** Header */ + TLVHEADER; + /** RSN replay protection control flag */ + t_u8 rsn_replay_prot; +} PACK_END tlvbuf_rsn_replay_prot; + +/** TLV buffer : Preamble control */ +typedef PACK_START struct _tlvbuf_preamble_ctl { + /** Header */ + TLVHEADER; + /** Preamble type */ + t_u8 preamble_type; +} PACK_END tlvbuf_preamble_ctl; + +/** ant_cfg structure */ +typedef PACK_START struct _ant_cfg_t { + /** Subcommand */ + int subcmd; + /** Action */ + int action; + /** TX mode configured */ + int tx_mode; + /** RX mode configured */ + int rx_mode; +} PACK_END ant_cfg_t; + +/** htstream_cfg structure */ +typedef struct _htstream_cfg_t { + /** Subcommand */ + int subcmd; + /** Action */ + int action; + /** HT stream configuration */ + t_u32 stream_cfg; +} htstream_cfg_t; + +/** TLV buffer : RTS threshold */ +typedef PACK_START struct _tlvbuf_rts_threshold { + /** Header */ + TLVHEADER; + /** RTS threshold */ + t_u16 rts_threshold; +} PACK_END tlvbuf_rts_threshold; + +/** TLV buffer : Tx data rate */ +typedef PACK_START struct _tlvbuf_tx_data_rate { + /** Header */ + TLVHEADER; + /** Tx data rate */ + t_u16 tx_data_rate; +} PACK_END tlvbuf_tx_data_rate; + +/** TLV buffer : MCBC Data Rate */ +typedef PACK_START struct _tlvbuf_mcbc_data_rate { + /** Header */ + TLVHEADER; + /** MCBC data rate */ + t_u16 mcbc_datarate; +} PACK_END tlvbuf_mcbc_data_rate; + +/** 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 +/** TLV buffer : Packet forward control */ +typedef PACK_START struct _tlvbuf_pkt_fwd_ctl { + /** Header */ + TLVHEADER; + /** Packet forwarding control flag */ + t_u8 pkt_fwd_ctl; +} PACK_END tlvbuf_pkt_fwd_ctl; + +#ifdef SDIO +/** 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; +#endif + +/** TLV buffer : STA MAC address filtering control */ +typedef PACK_START struct _tlvbuf_sta_mac_addr_filter { + /** Header */ + TLVHEADER; + /** Filter mode */ + t_u8 filter_mode; + /** Number of STA MACs */ + t_u8 count; + /** STA MAC addresses buffer */ + t_u8 mac_address[]; +} PACK_END tlvbuf_sta_mac_addr_filter; + +/** TLV buffer : STA ageout timer */ +typedef PACK_START struct _tlvbuf_sta_ageout_timer { + /** Header */ + TLVHEADER; + /** STA ageout timer in ms */ + t_u32 sta_ageout_timer_ms; +} PACK_END tlvbuf_sta_ageout_timer; + +/** TLV buffer : PS STA ageout timer */ +typedef PACK_START struct _tlvbuf_ps_sta_ageout_timer { + /** Header */ + TLVHEADER; + /** PS STA ageout timer in ms */ + t_u32 ps_sta_ageout_timer_ms; +} PACK_END tlvbuf_ps_sta_ageout_timer; + +/** TLV buffer : max station number */ +typedef PACK_START struct _tlvbuf_max_sta_num { + /** Header */ + TLVHEADER; + /** max station number configured*/ + t_u16 max_sta_num_configured; + /** max station number supported*/ + t_u16 max_sta_num_supported; +} PACK_END tlvbuf_max_sta_num; + +/** TLV buffer : retry limit */ +typedef PACK_START struct _tlvbuf_retry_limit { + /** Header */ + TLVHEADER; + /** Retry limit */ + t_u8 retry_limit; +} PACK_END tlvbuf_retry_limit; + +/** TLV buffer : sticky tim config */ +typedef PACK_START struct _tlvbuf_sticky_tim_config { + /** Header */ + TLVHEADER; + /** Enable */ + t_u16 enable; + /** Duration */ + t_u16 duration; + /** Sticky Bitmask */ + t_u16 sticky_bitmask; +} PACK_END tlvbuf_sticky_tim_config; + +/** TLV buffer : sticky tim sta mac address */ +typedef PACK_START struct _tlvbuf_sticky_tim_sta_mac_addr { + /** Header */ + TLVHEADER; + /** Control */ + t_u16 control; + /** Station MAC address */ + t_u8 sta_mac_address[ETH_ALEN]; +} PACK_END tlvbuf_sticky_tim_sta_mac_addr; + +/** TLV buffer : 2040 coex config */ +typedef PACK_START struct _tlvbuf_2040_coex { + /** Header */ + TLVHEADER; + /** Enable */ + t_u8 enable; +} PACK_END tlvbuf_2040_coex; + +/** TLV buffer : pairwise key handshake timeout */ +typedef PACK_START struct _tlvbuf_eapol_pwk_hsk_timeout { + /** Header */ + TLVHEADER; + /** pairwise update timeout in milliseconds */ + t_u32 pairwise_update_timeout; +} PACK_END tlvbuf_eapol_pwk_hsk_timeout; + +/** TLV buffer : pairwise key handshake number of retries */ +typedef PACK_START struct _tlvbuf_eapol_pwk_hsk_retries { + /** Header */ + TLVHEADER; + /** pairwise key retries */ + t_u32 pwk_retries; +} PACK_END tlvbuf_eapol_pwk_hsk_retries; + +/** TLV buffer : groupwise key handshake timeout */ +typedef PACK_START struct _tlvbuf_eapol_gwk_hsk_timeout { + /** Header */ + TLVHEADER; + /** groupwise update timeout in milliseconds */ + t_u32 groupwise_update_timeout; +} PACK_END tlvbuf_eapol_gwk_hsk_timeout; + +/** TLV buffer : groupwise key handshake number of retries */ +typedef PACK_START struct _tlvbuf_eapol_gwk_hsk_retries { + /** Header */ + TLVHEADER; + /** groupwise key retries */ + t_u32 gwk_retries; +} PACK_END tlvbuf_eapol_gwk_hsk_retries; + +/** custom IE */ +typedef 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[]; +} PACK_END custom_ie; + +/** TLV buffer : custom IE */ +typedef PACK_START struct _tlvbuf_custom_ie { + /** Header */ + TLVHEADER; + /** custom IE data */ + custom_ie ie_data[]; +} PACK_END tlvbuf_custom_ie; + +/** custom IE info */ +typedef PACK_START struct _custom_ie_info { + /** size of buffer */ + t_u16 buf_size; + /** no of buffers of buf_size */ + t_u16 buf_count; +} PACK_END custom_ie_info; + +/** TLV buffer : custom IE */ +typedef PACK_START struct _tlvbuf_max_mgmt_ie { + /** Header */ + TLVHEADER; + /** No of tuples */ + t_u16 count; + /** custom IE info tuples */ + custom_ie_info info[]; +} PACK_END tlvbuf_max_mgmt_ie; + +/* Bitmap for protocol to use */ +/** No security */ +#define PROTOCOL_NO_SECURITY 1 +/** Static WEP */ +#define PROTOCOL_STATIC_WEP 2 +/** WPA */ +#define PROTOCOL_WPA 8 +/** WPA2 */ +#define PROTOCOL_WPA2 32 +/** WP2 Mixed */ +#define PROTOCOL_WPA2_MIXED 40 +/** WPA3 SAE */ +#define PROTOCOL_WPA3_SAE 0x100 +/* Bitmap for unicast/bcast cipher type */ +/** None */ +#define CIPHER_NONE 0 +/** WEP 40 */ +#define CIPHER_WEP_40 1 +/** WEP 104 */ +#define CIPHER_WEP_104 2 +/** TKIP */ +#define CIPHER_TKIP 4 +/** AES CCMP */ +#define CIPHER_AES_CCMP 8 +/** Valid cipher bitmap */ +#define CIPHER_BITMAP 0x0c +/** Valid protocol bitmap */ +#define PROTOCOL_BITMAP 0x3E8 +/** AES CCMP + TKIP cipher */ +#define AES_CCMP_TKIP 12 + +/** TLV buffer : Authentication Mode */ +typedef PACK_START struct _tlvbuf_auth_mode { + /** Header */ + TLVHEADER; + /** Authentication Mode */ + t_u8 auth_mode; +} PACK_END tlvbuf_auth_mode; + +/** TLV buffer : Security Protocol */ +typedef PACK_START struct _tlvbuf_protocol { + /** Header */ + TLVHEADER; + /** Security protocol */ + t_u16 protocol; +} PACK_END tlvbuf_protocol; + +/** TLV buffer : cipher */ +typedef PACK_START struct _tlvbuf_cipher { + /** Header */ + TLVHEADER; + /** Pairwise cipher */ + t_u8 pairwise_cipher; + /** Group cipher */ + t_u8 group_cipher; +} PACK_END tlvbuf_cipher; + +/** TLV buffer : Pairwise cipher */ +typedef PACK_START struct _tlvbuf_pwk_cipher { + /** Header */ + TLVHEADER; + /** Protocol */ + t_u16 protocol; + /** Pairwise cipher */ + t_u8 pairwise_cipher; + /** Reserved */ + t_u8 reserved; +} PACK_END tlvbuf_pwk_cipher; + +/** TLV buffer : Group cipher */ +typedef PACK_START struct _tlvbuf_gwk_cipher { + /** Header */ + TLVHEADER; + /** Group cipher */ + t_u8 group_cipher; + /** Reserved*/ + t_u8 reserved; +} PACK_END tlvbuf_gwk_cipher; + +/** TLV buffer : Group re-key time */ +typedef PACK_START struct _tlvbuf_group_rekey_timer { + /** Header */ + TLVHEADER; + /** Group rekey time in seconds */ + t_u32 group_rekey_time_sec; +} PACK_END tlvbuf_group_rekey_timer; + +/** Key_mgmt_none */ +#define KEY_MGMT_NONE 0x04 +/** Key_mgmt_psk */ +#define KEY_MGMT_PSK 0x02 +/** Key_mgmt_sae */ +#define KEY_MGMT_SAE 0x400 +/** Key_mgmt_eap */ +#define KEY_MGMT_EAP 0x01 +/** Key_mgmt_psk_sha256 */ +#define KEY_MGMT_PSK_SHA256 0X100 + +/** Wmm Max AC queues */ +#define MAX_AC_QUEUES 4 + +/** TLV buffer : KeyMgmt */ +typedef PACK_START struct _tlvbuf_akmp { + /** Header */ + TLVHEADER; + /** KeyMgmt */ + t_u16 key_mgmt; + /** key management operation */ + t_u16 key_mgmt_operation; +} PACK_END tlvbuf_akmp; + +/** TLV buffer : Single WEP key */ +typedef PACK_START struct _tlvbuf_wep_key { + /** Header */ + TLVHEADER; + /** Key index */ + t_u8 key_index; + /** Default key flag */ + t_u8 is_default; + /** Key */ + t_u8 key[]; +} PACK_END tlvbuf_wep_key; + +/** TLV buffer : WPA passphrase */ +typedef PACK_START struct _tlvbuf_wpa_passphrase { + /** Header */ + TLVHEADER; + /** WPA passphrase */ + t_u8 passphrase[]; +} PACK_END tlvbuf_wpa_passphrase; + +/** TLV buffer : WPA3 SAE password */ +typedef PACK_START struct _tlvbuf_wpa3_sae_password { + /** Header */ + TLVHEADER; + /** WPA3 SAE password */ + t_u8 password[]; +} PACK_END tlvbuf_wpa3_sae_password; + +/** TLV buffer : Fragmentation threshold */ +typedef PACK_START struct _tlvbuf_frag_threshold { + /** Header */ + TLVHEADER; + /** Fragmentation threshold */ + t_u16 frag_threshold; +} PACK_END tlvbuf_frag_threshold; + +/** MRVL private CMD structure */ +typedef PACK_START struct _mrvl_priv_cmd { + /** Command buffer */ + t_u8 *buf; + /** Used length */ + t_u32 used_len; + /** Total length */ + t_u32 total_len; +} PACK_END mrvl_priv_cmd; + +/* APCMD definitions */ +/** APCMD buffer */ +typedef PACK_START struct _apcmdbuf { + /** Header */ + APCMDHEADER; +} PACK_END apcmdbuf; + +/** APCMD header length */ +#define APCMDHEADERLEN (sizeof(apcmdbuf)) + +/** APCMD buffer : sys_info request */ +typedef PACK_START struct _apcmdbuf_sys_info_request { + /** Header */ + APCMDHEADER; +} PACK_END apcmdbuf_sys_info_request; + +/** APCMD buffer : sys_info response */ +typedef PACK_START struct _apcmdbuf_sys_info_response { + /** Header */ + APCMDHEADER; + /** System information buffer */ + t_u8 sys_info[64]; +} PACK_END apcmdbuf_sys_info_response; + +/** APCMD buffer : sys_reset */ +typedef PACK_START struct _apcmdbuf_sys_reset { + /** Header */ + APCMDHEADER; +} PACK_END apcmdbuf_sys_reset; + +/** APCMD buffer : sys_configure */ +typedef PACK_START struct _apcmdbuf_sys_configure { + /** Header */ + APCMDHEADER; + /** Action : GET or SET */ + t_u16 action; +} PACK_END apcmdbuf_sys_configure; + +/* Max transmit power for indoor operation */ +#define MAX_TX_PWR_INDOOR 17 + +/** APCMD buffer : SNMP MIB */ +typedef PACK_START struct _apcmdbuf_snmp_mib { + /** Header */ + APCMDHEADER; + /** Action : GET or SET */ + t_u16 action; +} PACK_END apcmdbuf_snmp_mib; +/** APCMD buffer : bss_start */ +typedef PACK_START struct _apcmdbuf_bss_start { + /** Header */ + APCMDHEADER; +} PACK_END apcmdbuf_bss_start; + +/** APCMD buffer : bss_stop */ +typedef PACK_START struct _apcmdbuf_bss_stop { + /** Header */ + APCMDHEADER; +} PACK_END apcmdbuf_bss_stop; + +/** APCMD buffer : sta_deauth */ +typedef PACK_START struct _APCMDBUF_STA_DEAUTH { + /** Header */ + APCMDHEADER; + /** STA MAC address to deauthenticate */ + t_u8 sta_mac_address[ETH_ALEN]; +} PACK_END APCMDBUF_STA_DEAUTH; + +/** Reg TYPE*/ +enum reg_commands { + CMD_MAC = 1, + CMD_BBP, + CMD_RF +}; + +/** APCMD buffer: Regrdwr */ +typedef PACK_START struct _apcmdbuf_reg_rdwr { + /** Header */ + APCMDHEADER; + /** Read or Write */ + t_u16 action; + /** Register offset */ + t_u16 offset; + /** Value */ + t_u32 value; +} PACK_END apcmdbuf_reg_rdwr; + +/** DOMAIN_CODEs for DFS regions */ +enum { + DOMAIN_CODE_FCC = 0x01, + DOMAIN_CODE_ETSI, + DOMAIN_CODE_MKK, + DOMAIN_CODE_IN, + DOMAIN_CODE_MY, +}; + +/** Region Domain Code */ +typedef PACK_START struct _rgn_dom_code { + /** Header */ + TLVHEADER; + /** Domain Code */ + t_u8 domain_code; + /** Reserved field */ + t_u8 reserved; +} PACK_END rgn_dom_code_t; + +/** sub-band type */ +typedef PACK_START struct _ieeetypes_subband_set { + t_u8 first_chan; /**< First channel */ + t_u8 no_of_chan; /**< Number of channels */ + t_u8 max_tx_pwr; /**< Maximum Tx power */ +} PACK_END ieeetypes_subband_set_t; + +/** country code length used for 802.11D */ +#define COUNTRY_CODE_LEN 3 + +/** MAX domain SUB-BAND*/ +#define MAX_SUB_BANDS 40 + +/** Max Multi Domain Entries for G */ +#define MAX_MULTI_DOMAIN_CAPABILITY_ENTRY_G 1 + +/** Max Multi Domain Entries for A */ +#define MAX_MULTI_DOMAIN_CAPABILITY_ENTRY_A 31 + +/** Country code and Sub-band */ +typedef PACK_START struct domain_param { + /** Header */ + TLVHEADER; + t_u8 country_code[COUNTRY_CODE_LEN]; /**< Country code */ + ieeetypes_subband_set_t subband[]; /**< Set of subbands */ +} PACK_END domain_param_t; + +/** HostCmd_CFG_80211D */ +typedef PACK_START struct _apcmdbuf_cfg_80211d { + /** Header */ + APCMDHEADER; + /** Action */ + t_u16 action; /* 0 = ACT_GET; 1 = ACT_SET; */ + /** Domain parameters */ + domain_param_t domain; +} PACK_END apcmdbuf_cfg_80211d; + +/** HostCmd_MEM_ACCESS */ +typedef PACK_START struct _apcmdbuf_mem_access { + /** Header */ + APCMDHEADER; + /** Action */ + t_u16 action; /* 0 = ACT_GET; 1 = ACT_SET; */ + /** Reserved field */ + t_u16 reserved; + /** Address */ + t_u32 address; + /** Value */ + t_u32 value; +} PACK_END apcmdbuf_mem_access; + +/** HostCmd_EEPROM_ACCESS */ +typedef PACK_START struct _apcmdbuf_eeprom_access { + /** Header */ + APCMDHEADER; + /** Action */ + t_u16 action; /* 0 = ACT_GET; */ + /** Offset field */ + t_u16 offset; /* Multiples of 4 */ + /** Byte count */ + t_u16 byte_count; /* Multiples of 4 */ + /** Value */ + t_u8 value[1]; +} PACK_END apcmdbuf_eeprom_access; + +/** TLV : BT Coex common configuration */ +typedef PACK_START struct _tlvbuf_coex_common_cfg { + /** Header */ + TLVHEADER; + /** Configuration bitmap */ + t_u32 config_bitmap; + /** AP Bt Coex Enabled or not */ + t_u32 ap_bt_coex; + /** Reserved */ + t_u32 reserved[3]; +} PACK_END tlvbuf_coex_common_cfg; + +/** TLV : BT Coex SCO configuration */ +typedef PACK_START struct _tlvbuf_coex_sco_cfg { + /** Header */ + TLVHEADER; + /** Qtime protection */ + t_u16 protection_qtime[4]; + /** Rate protection */ + t_u16 protection_rate; + /** ACL frequency */ + t_u16 acl_frequency; + /** Reserved */ + t_u32 reserved[4]; +} PACK_END tlvbuf_coex_sco_cfg; + +/** TLV : BT Coex ACL configuration */ +typedef PACK_START struct _tlvbuf_coex_acl_cfg { + /** Header */ + TLVHEADER; + /** Enabled or not */ + t_u16 enabled; + /** BT time */ + t_u16 bt_time; + /** Wlan time */ + t_u16 wlan_time; + /** Rate protection */ + t_u16 protection_rate; + /** Reserved */ + t_u32 reserved[4]; +} PACK_END tlvbuf_coex_acl_cfg; + +/** TLV : BT Coex statistics */ +typedef PACK_START struct _tlvbuf_coex_stats { + /** Header */ + TLVHEADER; + /** Null not sent */ + t_u32 null_not_sent; + /** Null queued */ + t_u32 null_queued; + /** Null not queued */ + t_u32 null_not_queued; + /** CF end queued */ + t_u32 cf_end_queued; + /** CF end not queued */ + t_u32 cf_end_not_queued; + /** Null allocation failures */ + t_u32 null_alloc_fail; + /** CF end allocation failures */ + t_u32 cf_end_alloc_fail; + /** Reserved */ + t_u32 reserved[8]; +} PACK_END tlvbuf_coex_stats; + +/** APCMD buffer : BT Coex API extension */ +typedef PACK_START struct _apcmdbuf_coex_config { + /** Header */ + APCMDHEADER; + /** Action : GET or SET */ + t_u16 action; + /** Reserved for alignment */ + t_u16 coex_reserved; + /** TLV buffer */ + t_u8 tlv_buffer[]; +} PACK_END apcmdbuf_coex_config; + +/** BIT value */ +#define MBIT(x) (((t_u32)1) << (x)) +/** RadioType : Support for 40Mhz channel BW */ +#define IS_CHANNEL_WIDTH_40(Field2) (Field2 & MBIT(2)) +/** RadioType : Get secondary channel */ +#define GET_SECONDARY_CHAN(Field2) (Field2 & (MBIT(0) | MBIT(1))) +/** RadioType : Is RIFS allowed */ +#define IS_RIFS_ALLOWED(Field2) (Field2 & MBIT(3)) +/** RadioType : Get HT Protection */ +#define GET_HT_PROTECTION(Field3) (Field3 & (MBIT(0) | MBIT(1))) +/** RadioType : Are Non-GreenField STAs present */ +#define NONGF_STA_PRESENT(Field3) (Field3 & MBIT(2)) +/** RadioType : Are OBSS Non-HT STAs present */ +#define OBSS_NONHT_STA_PRESENT(Field3) (Field3 & MBIT(4)) + +/** HT Capabilities Data */ +typedef struct 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; +} PACK_END HTCap_t, *pHTCap_t; + +/** HT Information Data */ +typedef struct 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]; +} PACK_END HTInfo_t, *pHTInfo_t; + +/** MLAN 802.11 MAC Address */ +typedef t_u8 mlan_802_11_mac_addr[ETH_ALEN]; + +/** mlan_802_11_ssid data structure */ +typedef struct _mlan_802_11_ssid { + /** SSID Length */ + t_u32 ssid_len; + /** SSID information field */ + t_u8 ssid[MAX_SSID_LENGTH]; +} mlan_802_11_ssid; + +/** scan_chan_list data structure */ +typedef struct _scan_chan_list { + /** Channel number*/ + t_u8 chan_number; + /** Band config type */ + Band_Config_t bandcfg; +} 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_ONESHOT_FILTER]; +} mac_filter; + +/** Data structure of WMM Aci/Aifsn */ +typedef 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 */ +} PACK_END IEEEtypes_WmmAciAifsn_t, *pIEEEtypes_WmmAciAifsn_t; + +/** Data structure of WMM ECW */ +typedef 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 */ +} PACK_END IEEEtypes_WmmEcw_t, *pIEEEtypes_WmmEcw_t; + +/** Data structure of WMM AC parameters */ +typedef 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 */ +} PACK_END IEEEtypes_WmmAcParameters_t, *pIEEEtypes_WmmAcParameters_t; + +/** Data structure of WMM parameter IE */ +typedef 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 */ + IEEEtypes_WmmAcParameters_t ac_params[MAX_AC_QUEUES]; +} PACK_END WmmParameter_t, *pWmmParameter_t; + +/** 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 */ + 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; + +/** BSS config structure */ +typedef struct _bss_config_t { + /** 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; + /** Tx beacon rate */ + t_u16 tx_beacon_rate; + /** multicast/broadcast data rate */ + t_u16 mcbc_data_rate; + /** Tx power level */ + t_u8 tx_power_level; + /** Tx antenna */ + t_u8 tx_antenna; + /** Rx anteena */ + 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 the unit of 100ms */ + t_u32 sta_ageout_timer; + /** PS station ageout timer in the 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 */ + Band_Config_t bandcfg; + /** 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 + */ + /** 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 20/40 coex */ + t_u8 enable_2040coex; + /** key managment operation */ + t_u16 key_mgmt_operation; + /** BSS status */ + t_u16 bss_status; +#ifdef WIFI_DIRECT_SUPPORT + /* pre shared key */ + t_u8 psk[32]; +#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[MAX_CHANNELS]; + /** Wmm parameters */ + WmmParameter_t wmm_para; +} bss_config_t; + +/** Enumeration for band */ +enum _mlan_band_def { + BAND_B = 1, + BAND_G = 2, + BAND_A = 4, + BAND_GN = 8, + BAND_AN = 16, + BAND_GAC = 32, + BAND_AAC = 64, + BAND_GAX = 256, + BAND_AAX = 512, +}; + +/** station stats */ +typedef struct _sta_stats { + t_u64 last_rx_in_msec; +} sta_stats; + +/** station info */ +typedef struct _sta_info { + /** STA MAC address */ + t_u8 mac_address[ETH_ALEN]; + /** Power mgmt status */ + t_u8 power_mgmt_status; + /** RSSI */ + t_s8 rssi; + /** station bandmode */ + t_u16 bandmode; + /** station stats */ + sta_stats stats; + /** ie length */ + t_u16 ie_len; + /** ie buffer */ + t_u8 ie_buf[]; +} sta_info; + +/** sta_list structure */ +typedef struct _sta_list { + /** station count */ + t_u16 sta_count; + /** station list */ + sta_info info[MAX_NUM_CLIENTS]; +} sta_list; + +/** mlan_deauth_param */ +typedef struct _deauth_param { + /** STA mac addr */ + t_u8 mac_addr[ETH_ALEN]; + /** deauth reason */ + t_u16 reason_code; +} deauth_param; + +#define MAX_KEY_LENGTH 32 +/** encrypt key */ +typedef struct _encrypt_key { + /** Key index */ + t_u32 key_index; + /** Key length */ + t_u32 key_len; + /** Key */ + t_u8 key_material[MAX_KEY_LENGTH]; + /** mac address */ + t_u8 mac_addr[ETH_ALEN]; +} encrypt_key; + +/** injected pkt_header */ +typedef struct _pkt_header { + /** pkt_len */ + t_u32 pkt_len; + /** pkt_type */ + t_u32 tx_pkt_type; + /** tx control */ + t_u32 tx_control; +} pkt_header; + +/** APCMD buffer : bss_configure */ +typedef PACK_START struct _apcmdbuf_bss_configure { + /** Action : GET or SET */ + t_u32 action; +} PACK_END apcmdbuf_bss_configure; + +/** Max EEPROM length */ +#define MAX_EEPROM_LEN 20 + +/** Channel scan entry for each channel */ +typedef PACK_START struct _channel_scan_entry_t { + /** Channel Number */ + t_u8 chan_num; + /** Number of APs */ + t_u8 num_of_aps; + /** CCA count */ + t_u32 cca_count; + /** Duration */ + t_u32 duration; + /** Channel weight */ + t_u32 channel_weight; +} PACK_END channel_scan_entry_t; + +/** Channel scan entry */ +typedef PACK_START struct _channel_scan_entry { + /** Number of channels */ + t_u8 num_channels; + /** Channel scan entry */ + channel_scan_entry_t cst[]; +} PACK_END channel_scan_entry; + +/** HostCmd_CFG_DATA */ +typedef PACK_START struct _apcmdbuf_cfg_data { + /** Header */ + APCMDHEADER; + /** Action */ + t_u16 action; + /** Type */ + t_u16 type; + /** Data length */ + t_u16 data_len; + /** Data */ + t_u8 data[]; +} PACK_END apcmdbuf_cfg_data; + +/** Maximum size of set/get configurations */ +#define MAX_CFG_DATA_SIZE 3000 /* less than MRVDRV_SIZE_OF_CMD_BUFFER */ + +/** HostCmd_CMD_PMF_PARAMS */ +typedef PACK_START struct _apcmdbuf_pmf_params { + /** Header */ + APCMDHEADER; + /** Action */ + t_u16 action; /* 0 = ACT_GET; 1 = ACT_SET; */ + /** Params */ + PACK_START struct { + t_u8 mfpc:1; /* capable bit */ + t_u8 mfpr:1; /* required bit */ + t_u8 rsvd:6; + } PACK_END params; +} PACK_END apcmdbuf_pmf_params; + +/** Host Command ID bit mask (bit 11:0) */ +#define HostCmd_CMD_ID_MASK 0x0fff +/** APCMD response check */ +#define APCMD_RESP_CHECK 0x8000 + +/* AP CMD IDs */ +/** APCMD : sys_info */ +#define APCMD_SYS_INFO 0x00ae +/** APCMD : sys_reset */ +#define APCMD_SYS_RESET 0x00af +/** APCMD : sys_configure */ +#define APCMD_SYS_CONFIGURE 0x00b0 +/** APCMD : bss_start */ +#define APCMD_BSS_START 0x00b1 +/** APCMD : bss_stop */ +#define APCMD_BSS_STOP 0x00b2 +/** APCMD : sta_list */ +#define APCMD_STA_LIST 0x00b3 +/** APCMD : sta_deauth */ +#define APCMD_STA_DEAUTH 0x00b5 +/** SNMP MIB SET/GET */ +#define HostCmd_SNMP_MIB 0x0016 +/** Read/Write Mac register */ +#define HostCmd_CMD_MAC_REG_ACCESS 0x0019 +/** Read/Write BBP register */ +#define HostCmd_CMD_BBP_REG_ACCESS 0x001a +/** Read/Write RF register */ +#define HostCmd_CMD_RF_REG_ACCESS 0x001b +/** Host Command ID : EEPROM access */ +#define HostCmd_EEPROM_ACCESS 0x0059 +/** Host Command ID : Memory access */ +#define HostCmd_CMD_MEM_ACCESS 0x0086 +/** Host Command ID : 802.11D configuration */ +#define HostCmd_CMD_802_11D_DOMAIN_INFO 0x005b +/** Host Command ID : Configuration data */ +#define HostCmd_CMD_CFG_DATA 0x008f + +/** Oid for 802.11D enable/disable */ +#define OID_80211D_ENABLE 0x0009 +/** Oid for 802.11H enable/disable */ +#define OID_80211H_ENABLE 0x000a + +/** Host Command ID: ROBUST_COEX */ +#define HostCmd_ROBUST_COEX 0x00e0 + +/** Host Command ID: PMF_PARAMS */ +#define HostCmd_CMD_PMF_PARAMS 0x0131 + +/* TLV IDs */ +/** TLV : Base */ +#define PROPRIETARY_TLV_BASE_ID 0x0100 + +/** TLV : SSID */ +#define MRVL_SSID_TLV_ID 0x0000 +/** TLV : Operational rates */ +#define MRVL_RATES_TLV_ID 0x0001 +/** TLV : Channel */ +#define MRVL_PHYPARAMDSSET_TLV_ID 0x0003 +/**TLV: Domain type */ +#define TLV_TYPE_DOMAIN 0x0007 + +/** TLV type : Scan Channels list */ +#define MRVL_CHANNELLIST_TLV_ID (PROPRIETARY_TLV_BASE_ID + 0x01) //0x0101 +/** TLV type : Authentication type */ +#define MRVL_AUTH_TLV_ID (PROPRIETARY_TLV_BASE_ID + 0x1f) //0x011f +/** TLV Id : Channel Config */ +#define MRVL_CHANNELCONFIG_TLV_ID (PROPRIETARY_TLV_BASE_ID + 0x2a) //0x012a +/** TLV : AP MAC address */ +#define MRVL_AP_MAC_ADDRESS_TLV_ID (PROPRIETARY_TLV_BASE_ID + 0x2b) //0x012b +/** TLV : Beacon period */ +#define MRVL_BEACON_PERIOD_TLV_ID (PROPRIETARY_TLV_BASE_ID + 0x2c) //0x012c +/** TLV : DTIM period */ +#define MRVL_DTIM_PERIOD_TLV_ID (PROPRIETARY_TLV_BASE_ID + 0x2d) //0x012d +/** TLV : Tx power */ +#define MRVL_TX_POWER_TLV_ID (PROPRIETARY_TLV_BASE_ID + 0x2f) //0x012f +/** TLV : SSID broadcast control */ +#define MRVL_BCAST_SSID_CTL_TLV_ID (PROPRIETARY_TLV_BASE_ID + 0x30) //0x0130 +/** TLV : Preamble control */ +#define MRVL_PREAMBLE_CTL_TLV_ID (PROPRIETARY_TLV_BASE_ID + 0x31) //0x0131 +/** TLV : RTS threshold */ +#define MRVL_RTS_THRESHOLD_TLV_ID (PROPRIETARY_TLV_BASE_ID + 0x33) //0x0133 +/** TLV : Packet forwarding control */ +#define MRVL_PKT_FWD_CTL_TLV_ID (PROPRIETARY_TLV_BASE_ID + 0x36) //0x0136 +/** TLV : STA information */ +#define MRVL_STA_INFO_TLV_ID (PROPRIETARY_TLV_BASE_ID + 0x37) //0x0137 +/** TLV : STA MAC address filter */ +#define MRVL_STA_MAC_ADDR_FILTER_TLV_ID (PROPRIETARY_TLV_BASE_ID + 0x38) //0x0138 +/** TLV : STA ageout timer */ +#define MRVL_STA_AGEOUT_TIMER_TLV_ID (PROPRIETARY_TLV_BASE_ID + 0x39) //0x0139 +/** TLV : WEP keys */ +#define MRVL_WEP_KEY_TLV_ID (PROPRIETARY_TLV_BASE_ID + 0x3b) //0x013b +/** TLV : WPA passphrase */ +#define MRVL_WPA_PASSPHRASE_TLV_ID (PROPRIETARY_TLV_BASE_ID + 0x3c) //0x013c +/** TLV : WPA3 SAE password */ +#define MRVL_WPA3_SAE_PASSWORD_TLV_ID (PROPRIETARY_TLV_BASE_ID + 0x141) //0x0241 +/** TLV type : protocol TLV */ +#define MRVL_PROTOCOL_TLV_ID (PROPRIETARY_TLV_BASE_ID + 0x40) //0x0140 +/** TLV type : AKMP TLV */ +#define MRVL_AKMP_TLV_ID (PROPRIETARY_TLV_BASE_ID + 0x41) //0x0141 +/** TLV type : Cipher TLV */ +#define MRVL_CIPHER_TLV_ID (PROPRIETARY_TLV_BASE_ID + 0x42) //0x0142 +/** TLV : Fragment threshold */ +#define MRVL_FRAG_THRESHOLD_TLV_ID (PROPRIETARY_TLV_BASE_ID + 0x46) //0x0146 +/** TLV : Group rekey timer */ +#define MRVL_GRP_REKEY_TIME_TLV_ID (PROPRIETARY_TLV_BASE_ID + 0x47) //0x0147 +/**TLV: Max Station number */ +#define MRVL_MAX_STA_CNT_TLV_ID (PROPRIETARY_TLV_BASE_ID + 0x55) //0x0155 +/**TLV: Retry limit */ +#define MRVL_RETRY_LIMIT_TLV_ID (PROPRIETARY_TLV_BASE_ID + 0x5d) //0x015d +/**TLV: MCBC data rate */ +#define MRVL_MCBC_DATA_RATE_TLV_ID (PROPRIETARY_TLV_BASE_ID + 0x62) //0x0162 +/**TLV: RSN replay protection */ +#define MRVL_RSN_REPLAY_PROT_TLV_ID (PROPRIETARY_TLV_BASE_ID + 0x64) //0x0164 +/** TLV: Management IE list */ +#define MRVL_MGMT_IE_LIST_TLV_ID (PROPRIETARY_TLV_BASE_ID + 0x69) //0x0169 +/** TLV : Coex common configuration */ +#define MRVL_BT_COEX_COMMON_CFG_TLV_ID (PROPRIETARY_TLV_BASE_ID + 0x6c) //0x016c +/** TLV : Coex SCO configuration */ +#define MRVL_BT_COEX_SCO_CFG_TLV_ID (PROPRIETARY_TLV_BASE_ID + 0x6d) //0x016d +/** TLV : Coex ACL configuration */ +#define MRVL_BT_COEX_ACL_CFG_TLV_ID (PROPRIETARY_TLV_BASE_ID + 0x6e) //0x016e +/** TLV : Coex stats configuration */ +#define MRVL_BT_COEX_STATS_TLV_ID (PROPRIETARY_TLV_BASE_ID + 0x6f) //0x016f +/** TLV :Pairwise Handshake Timeout */ +#define MRVL_EAPOL_PWK_HSK_TIMEOUT_TLV_ID (PROPRIETARY_TLV_BASE_ID + 0x75) //0x0175 +/** TLV :Pairwise Handshake Retries */ +#define MRVL_EAPOL_PWK_HSK_RETRIES_TLV_ID (PROPRIETARY_TLV_BASE_ID + 0x76) //0x0176 +/** TLV :Groupwise Handshake Timeout */ +#define MRVL_EAPOL_GWK_HSK_TIMEOUT_TLV_ID (PROPRIETARY_TLV_BASE_ID + 0x77) //0x0177 +/** TLV :Groupwise Handshake Retries */ +#define MRVL_EAPOL_GWK_HSK_RETRIES_TLV_ID (PROPRIETARY_TLV_BASE_ID + 0x78) //0x0178 +/** TLV : PS STA ageout timer */ +#define MRVL_PS_STA_AGEOUT_TIMER_TLV_ID (PROPRIETARY_TLV_BASE_ID + 0x7b) //0x017b +/** TLV : Pairwise Cipher */ +#define MRVL_CIPHER_PWK_TLV_ID (PROPRIETARY_TLV_BASE_ID + 0x91) //0x0191 +/** TLV : Group Cipher */ +#define MRVL_CIPHER_GWK_TLV_ID (PROPRIETARY_TLV_BASE_ID + 0x92) //0x0192 +/** TLV : BSS Status */ +#define MRVL_BSS_STATUS_TLV_ID (PROPRIETARY_TLV_BASE_ID + 0x93) //0x0193 +/** TLV : Restricted Client Mode */ +#define MRVL_RESTRICT_CLIENT_MODE_TLV_ID (PROPRIETARY_TLV_BASE_ID + 0xC1) //0x01C1 +/** TLV : Sticky TIM config */ +#define MRVL_STICKY_TIM_CONFIG_TLV_ID (PROPRIETARY_TLV_BASE_ID + 0x96) //0x0196 +/** TLV : Sticky TIM MAC address */ +#define MRVL_STICKY_TIM_STA_MAC_ADDR_TLV_ID (PROPRIETARY_TLV_BASE_ID + 0x97) //0x0197 +/** TLV : 20/40 coex config */ +#define MRVL_2040_BSS_COEX_CONTROL_TLV_ID (PROPRIETARY_TLV_BASE_ID + 0x98) //0x0198 +/** TLV : Max Management IE */ +#define MRVL_MAX_MGMT_IE_TLV_ID (PROPRIETARY_TLV_BASE_ID + 0xAA) //0x01aa + +/** TLV : Region Domain Code */ +#define MRVL_REGION_DOMAIN_CODE_TLV_ID (PROPRIETARY_TLV_BASE_ID + 0xAB) //0x01ab + +#ifdef RX_PACKET_COALESCE +#define MRVL_RX_PKT_COAL_TLV_ID (PROPRIETARY_TLV_BASE_ID + 0xC9) +#endif + +/** TLV : Tx beacon rate */ +#define MRVL_TX_BEACON_RATE_TLV_ID (PROPRIETARY_TLV_BASE_ID + 288) //0x0220 + +#ifdef RX_PACKET_COALESCE +/** RX packet coalesce tlv */ +typedef PACK_START struct _tlvbuf_rx_pkt_coal_t { + /** Header */ + TLVHEADER; + /** threshold for rx packets */ + t_u32 rx_pkt_count; + /** timeout for rx coalescing timer */ + t_u16 delay; +} PACK_END tlvbuf_rx_pkt_coal_t; +#endif +#define MRVL_AP_WMM_PARAM_TLV_ID (PROPRIETARY_TLV_BASE_ID + 0xD0) + +/** TLV: HT_CAPABILITY */ +#define HT_CAPABILITY_TLV_ID 0x2d +/** TLV: HT_INFO */ +#define HT_INFO_TLV_ID 0x3d +/** config mask for HT_CAP */ +#define HT_CAP_CONFIG_MASK 0x10f3 +/** default htcap value */ +#define DEFAULT_HT_CAP_VALUE 0x117e +/** HT_CAP validity check */ +#define HT_CAP_CHECK_MASK 0x10c +/** config mask for ampdu parameter */ +#define AMPDU_CONFIG_MASK 0x1f + +/** Macro to check if 11n 40 Mhz is enabled */ +#define IS_11N_40MHZ_ENABLED(cap) ((cap) & 0x002) >> 1 +/** Macro to check if 11n 20MHz with short GI is enabled */ +#define IS_11N_20MHZ_SHORTGI_ENABLED(cap) ((cap) & 0x0020) >> 5 +/** Macro to check if 11n Green Field is enabled */ +#define IS_11N_GF_ENABLED(cap) ((cap) & 0x0010) >> 4 +/** MCS set length */ +#define MCS_SET_LEN 16 + +/** HT Capabilities tlv */ +typedef PACK_START struct _tlvbuf_htcap_t { + /** Header */ + TLVHEADER; + /** HTCap struct */ + HTCap_t ht_cap; +} PACK_END tlvbuf_htcap_t; + +/** HT Information tlv */ +typedef PACK_START struct _tlvbuf_htinfo_t { + /** Header */ + TLVHEADER; + /** HTCap struct */ + HTInfo_t ht_info; +} PACK_END tlvbuf_htinfo_t; + +/** Max bitmap rates size */ +#define MAX_BITMAP_RATES_SIZE 26 + +/** tx_rate_cfg structure */ +typedef PACK_START struct _tx_rate_cfg_t { + /** Action */ + int subcmd; + /** Action */ + int action; + /** Rate format */ + int rate_format; + /** Rate configured */ + int rate; + /** nss */ + int nss; + /** user_data_cnt */ + int user_data_cnt; + /** Rate bitmap */ + t_u16 bitmap_rates[MAX_BITMAP_RATES_SIZE]; + /** Rate Setting */ + t_u16 rate_setting; +} PACK_END tx_rate_cfg_t; + +/** Mask for 2X2 support*/ +#define STREAM_2X2_MASK 0x20 +/** MCS_SET_1 Mask */ +#define MCS_SET_1_MASK 0x0000ff00 +/** MCS0-7 supported */ +#define DEFAULT_MCS_SET_0 0xff +/** MCS8-15 support */ +#define DEFAULT_MCS_SET_1 0xff +/** MCS32 supported */ +#define DEFAULT_MCS_SET_4 0x01 +/** Rate bitmap for MCS 0 */ +#define UAP_RATE_BITMAP_MCS0 32 +/** Rate bitmap for MCS 127 */ +#define UAP_RATE_BITMAP_MCS127 159 +/** Rate index for MCS 0 */ +#define UAP_RATE_INDEX_MCS0 12 +/** Rate index for MCS 7 */ +#define UAP_RATE_INDEX_MCS7 19 +/** Rate index for MCS 32 */ +#define UAP_RATE_INDEX_MCS32 44 + +/* Mask to enable/disable restricted client mode */ +#define RESTRICT_CLIENT_MODE_ENABLE_MASK 0x01 +/* Mask for B Only mode */ +#define B_ONLY_MASK 0x0100 +/* Mask for A Only mode */ +#define A_ONLY_MASK 0x0200 +/* Mask for G Only mode */ +#define G_ONLY_MASK 0x0400 +/* Mask for N Only mode */ +#define N_ONLY_MASK 0x0800 +/* Mask for AC Only mode */ +#define AC_ONLY_MASK 0x1000 + +/** Type enumeration of WMM AC_QUEUES */ +typedef enum _wmm_ac { + AC_BE, + AC_BK, + AC_VI, + AC_VO, +} wmm_ac; + +/** Enumeration for band steering actions */ +typedef enum _bandSteerAct { + ACT_GET = 0, + ACT_SET_STATE = 1, + ACT_SET_BLOCK_2G_PRB_REQ = 2, + ACT_SET_MAX_BTM_REQ_ALLOWED = 4, +} bandSteerAct; + +/** Restricted Client Mode tlv */ +typedef PACK_START struct _tlvbuf_restrict_client_mode { + /** Header */ + TLVHEADER; + /** Mode Config + * Bit 0: 1 enable restricted client mode + * 0 disable restricted client mode + * Bits [1-7] : set to 0 + * Bits [8:12] + * Bit 8: B only Mode + * Bit 9: A only Mode + * Bit 10: G only Mode + * Bit 11: N only Mode + * Bit 12: AC only Mode + * Currently only one of the bits from [8-12] should be set + * Bits [13:15]: set to 0 + */ + t_u16 mode_config; +} PACK_END tlvbuf_restrict_client_mode; + +/** ID for VENDOR_SPECIFIC_IE */ +#define VENDOR_SPECIFIC_IE_TLV_ID 0xdd + +/** WMM_PS Mask */ +#define WMM_PS_MASK 0x7f +/** Enable WMM PS */ +#define ENABLE_WMM_PS 128 +/** Disable WMM PS */ +#define DISABLE_WMM_PS 0 +/** Maximum number of AC QOS queues available in the driver/firmware */ +#define MAX_AC_QUEUES 4 + +/** wmm parameter tlv */ +typedef PACK_START struct _tlvbuf_wmm_para_t { + /** Header */ + TLVHEADER; + /** Wmm parameter */ + WmmParameter_t wmm_para; +} PACK_END tlvbuf_wmm_para_t; + +/** data_structure for cmd vhtcfg */ +struct eth_priv_vhtcfg { + /** Band (1: 2.4G, 2: 5 G, 3: both 2.4G and 5G) */ + t_u32 band; + /** TxRx (1: Tx, 2: Rx, 3: both Tx and Rx) */ + t_u32 txrx; + /** BW CFG (0: 11N CFG, 1: vhtcap) */ + t_u32 bwcfg; + /** VHT capabilities. */ + t_u32 vht_cap_info; + /** VHT Tx mcs */ + t_u32 vht_tx_mcs; + /** VHT Rx mcs */ + t_u32 vht_rx_mcs; + /** VHT rx max rate */ + t_u16 vht_rx_max_rate; + /** VHT max tx rate */ + t_u16 vht_tx_max_rate; +}; + +typedef struct _vht_cfg_para { + /** Sub command */ + t_u32 subcmd; + /** Action: Set/Get + * Will be eliminatied on moal */ + t_u32 action; + /* VHT configuration */ + struct eth_priv_vhtcfg vht_cfg; +} vht_cfg_para; + +/** data_structure for cmd uap operation control */ +struct eth_priv_uap_oper_ctrl { + /**operation control*/ + t_u16 ctrl; + /**channel operation*/ + t_u16 chan_opt; + /**band configuration*/ + t_u8 bandcfg; + /**channel */ + t_u8 channel; +}; + +typedef struct _uap_operation_ctrl { + /** Sub command */ + t_u32 subcmd; + /** Action: Set/Get */ + t_u32 action; + /**uap operation control */ + struct eth_priv_uap_oper_ctrl uap_oper; +} uap_operation_ctrl; + +/** Function Prototype Declaration */ +int mac2raw(char *mac, t_u8 *raw); +void print_mac(t_u8 *raw); +int uap_ioctl(t_u8 *cmd, t_u16 *size, t_u16 buf_size); +void print_auth(tlvbuf_auth_mode *tlv); +void print_tlv(t_u8 *buf, t_u16 len); +void print_cipher(tlvbuf_cipher *tlv); +void print_pwk_cipher(tlvbuf_pwk_cipher *tlv); +void print_gwk_cipher(tlvbuf_gwk_cipher *tlv); +void print_rate(tlvbuf_rates *tlv); +int string2raw(char *str, unsigned char *raw); +void print_mac_filter(tlvbuf_sta_mac_addr_filter *tlv); +int ishexstring(void *hex); +unsigned int a2hex(char *s); +int fparse_for_hex(FILE * fp, t_u8 *dst); +int is_input_valid(valid_inputs cmd, int argc, char *argv[]); +int is_cipher_valid(int pairwisecipher, int groupcipher); +int is_cipher_valid_with_proto(int pairwisecipher, int groupcipher, + int protocol); +int get_sys_cfg_rates(t_u8 *rates); +int is_tx_rate_valid(t_u8 rate); +int is_mcbc_rate_valid(t_u8 rate); +void hexdump_data(char *prompt, void *p, int len, char delim); +unsigned char hexc2bin(char chr); +int check_sys_config(t_u8 *buf, t_u16 len); +int check_bss_config(t_u8 *buf); +int get_max_sta_num_supported(t_u16 *max_sta_num_supported); +int get_sys_cfg_protocol(t_u16 *proto); +int is_cipher_valid_with_11n(int pairwisecipher, int groupcipher, + int protocol, int enable_11n); +int get_sys_cfg_11n(HTCap_t *pHtCap); +int get_fw_info(fw_info *pfw_info); +t_u8 parse_domain_file(char *country, int band, + ieeetypes_subband_set_t *sub_bands, t_u8 *pdomain_code); +int sg_snmp_mib(t_u16 action, t_u16 oid, t_u16 size, t_u8 *oid_buf); +int check_channel_validity_11d(int channel, int band, int set_domain); +int check_tx_pwr_validity_11d(t_u8 tx_pwr); +int prepare_host_cmd_buffer(char *fname, char *cmd_name, t_u8 *buf); +char *mlan_config_get_line(FILE * fp, char *s, t_s32 size, int *line); +int uap_ioctl_dfs_repeater_mode(int *mode); +/** + * @brief isdigit for String. + * + * @param x Char string + * @return UAP_FAILURE for non-digit. + * UAP_SUCCESS for digit + */ +static inline int +ISDIGIT(char *x) +{ + unsigned int i; + for (i = 0; i < strlen(x); i++) + if (isdigit(x[i]) == 0) + return UAP_FAILURE; + return UAP_SUCCESS; +} + +/** + * @brief Detects if band is different across the list of scan channels + * + * @param argc Number of elements + * @param argv Array of strings + * @return UAP_FAILURE or UAP_SUCCESS + */ +static inline int +has_diff_band(int argc, char *argv[]) +{ + int i = 0; + int channel = 0; + int band[MAX_CHANNELS]; + /* Check for different bands */ + for (i = 0; i < argc; i++) { + band[i] = -1; + sscanf(argv[i], "%d.%d", &channel, &band[i]); + if (band[i] == -1) { + if (channel > MAX_CHANNELS_BG) { + band[i] = 1; + } else { + band[i] = 0; + } + } + } + for (i = 0; i <= (argc - 2); i++) { + if (band[i] != band[i + 1]) { + return UAP_FAILURE; + } + } + return UAP_SUCCESS; +} + +/** + * @brief Detects duplicates channel in array of strings + * + * @param argc Number of elements + * @param argv Array of strings + * @return UAP_FAILURE or UAP_SUCCESS + */ +static inline int +has_dup_channel(int argc, char *argv[]) +{ + int i, j; + /* Check for duplicate */ + for (i = 0; i < (argc - 1); i++) { + for (j = i + 1; j < argc; j++) { + if (atoi(argv[i]) == atoi(argv[j])) { + return UAP_FAILURE; + } + } + } + return UAP_SUCCESS; +} + +/** + * @brief Detects duplicates rate in array of strings + * Note that 0x82 and 0x2 are same for rate + * + * @param argc Number of elements + * @param argv Array of strings + * @return UAP_FAILURE or UAP_SUCCESS + */ +static inline int +has_dup_rate(int argc, char *argv[]) +{ + int i, j; + /* Check for duplicate */ + for (i = 0; i < (argc - 1); i++) { + for (j = i + 1; j < argc; j++) { + if ((A2HEXDECIMAL(argv[i]) & ~BASIC_RATE_SET_BIT) == + (A2HEXDECIMAL(argv[j]) & ~BASIC_RATE_SET_BIT)) { + return UAP_FAILURE; + } + } + } + return UAP_SUCCESS; +} +#endif /* _UAP_H */ diff --git a/mxm_wifiex/wlan_src/mapp/wifidirectutl/Makefile b/mxm_wifiex/wlan_src/mapp/wifidirectutl/Makefile new file mode 100644 index 0000000..e959672 --- /dev/null +++ b/mxm_wifiex/wlan_src/mapp/wifidirectutl/Makefile @@ -0,0 +1,57 @@ +# File : wifidirectutl/Makefile +# +# Copyright 2014-2020 NXP + +# Path to the top directory of the wlan distribution +PATH_TO_TOP = ../.. + +# Determine how we should copy things to the install directory +ABSPATH := $(filter /%, $(INSTALLDIR)) +RELPATH := $(filter-out /%, $(INSTALLDIR)) +INSTALLPATH := $(ABSPATH) +ifeq ($(strip $(INSTALLPATH)),) +INSTALLPATH := $(PATH_TO_TOP)/$(RELPATH) +endif + +# Override CFLAGS for application sources, remove __ kernel namespace defines +CFLAGS := $(filter-out -D__%, $(ccflags-y)) +# remove KERNEL include dir +CFLAGS := $(filter-out -I$(KERNELDIR)%, $(CFLAGS)) + + +CFLAGS += -Wall +LIBS = -lrt + + +.PHONY: default tags all + +OBJECTS = wifidirectutl.o +HEADERS = wifidirectutl.h + +ifneq (,$(findstring DWIFI_DISPLAY_SUPPORT, $(CFLAGS))) +OBJECTS += wifi_display.o +HEADERS += wifi_display.h +endif + +TARGET = wifidirectutl + +build default: $(TARGET) + @cp -f $(TARGET) $(INSTALLPATH) + @cp -rf config $(INSTALLPATH) + + +all : tags default + +$(TARGET): $(OBJECTS) $(HEADERS) + $(ECHO)$(CC) $(LIBS) -o $@ $(OBJECTS) + +%.o: %.c $(HEADERS) + $(ECHO)$(CC) $(CFLAGS) -c -o $@ $< + +tags: + ctags -R -f tags.txt + +distclean clean: + $(ECHO)$(RM) $(OBJECTS) $(TARGET) + $(ECHO)$(RM) tags.txt + diff --git a/mxm_wifiex/wlan_src/mapp/wifidirectutl/config/wifidirect.conf b/mxm_wifiex/wlan_src/mapp/wifidirectutl/config/wifidirect.conf new file mode 100644 index 0000000..00adc6b --- /dev/null +++ b/mxm_wifiex/wlan_src/mapp/wifidirectutl/config/wifidirect.conf @@ -0,0 +1,415 @@ +# File : wifidirect.conf + +######################### WIFIDIRECT Configuration command ################## + +wifidirect_config={ + # Arrange in order of subelement Ids + # + # WIFIDIRECT IE parameters. + # + + Capability={ + DeviceCapability=33 + GroupCapability=8 + } + GroupOwnerIntent={ + Intent=5 # 0-15. 15-> highest GO desire + } + Channel={ # Listen channel attribute. + CountryString="US" + RegulatoryClass=81 + ChannelNumber=6 + } + InfrastructureManageabilityInfo={ + Manageability=0 + } + ChannelList={ + CountryString="US" + # multiple attributes channel entry list + Regulatory_Class_1=81 # Regulatory class + NumofChannels_1=11 # No of channels + ChanList_1=1,2,3,4,5,6,7,8,9,10,11 # Scan channel list + Regulatory_Class_2=115 # Regulatory class + NumofChannels_2=4 # No of channels + ChanList_2=36,40,44,48 # Scan channel list + #Regulatory_Class_3=118 # Regulatory class + #NumofChannels_3=4 # No of channels + #ChanList_3=52,56,60,64 # Scan channel list + #Regulatory_Class_4=121 # Regulatory class + #NumofChannels_4=11 # No of channels + #ChanList_4=100,104,108,112,116,120,124,128,132,136,140 # Scan channel list + # Enable only one of the country blocks at a time + #CountryString="JP" + # multiple attributes channel entry list + #Regulatory_Class_1=81 # Regulatory class + #NumofChannels_1=13 # No of channels + #ChanList_1=1,2,3,4,5,6,7,8,9,10,11,12,13 # Scan channel list + #Regulatory_Class_2=115 # Regulatory class + #NumofChannels_2=4 # No of channels + #ChanList_2=36,40,44,48 # Scan channel list + #Regulatory_Class_3=118 # Regulatory class + #NumofChannels_3=4 # No of channels + #ChanList_3=52,56,60,64 # Scan channel list + #Regulatory_Class_4=121 # Regulatory class + #NumofChannels_4=11 # No of channels + #ChanList_4=100,104,108,112,116,120,124,128,132,136,140 # Scan channel list + } + NoticeOfAbsence={ + NoA_Index=0 # Instance of NoA timing + OppPS=1 # Opportunistic Power save + CTWindow=10 # Client Traffic Window + NoA_descriptor={ + CountType_1=255 # Count for GO mode OR Type for client mode + Duration_1=51200 # Max absence duration for GO mode OR + # min acceptable presence period for client mode + Interval_1=102400 + StartTime_1=0 + #CountType_2=1 # Count for GO mode OR Type for client mode + #Duration_2=0 # Max absence duration for GO mode OR + # min acceptable presence period for client mode + #Interval_2=0 + #StartTime_2=0 + } + } + DeviceInfo={ + DeviceAddress=00:50:43:00:00:00 + # categ: 2 bytes, OUI: 4 bytes, subcateg: 2 bytes + PrimaryDeviceTypeCategory=1 + PrimaryDeviceTypeOUI=0x00,0x50,0xF2,0x04 + PrimaryDeviceTypeSubCategory=1 + SecondaryDeviceCount=2 + SecondaryDeviceType={ + SecondaryDeviceTypeCategory_1=6 + SecondaryDeviceTypeOUI_1=0x00,0x50,0xF2,0x04 + SecondaryDeviceTypeSubCategory_1=1 + SecondaryDeviceTypeCategory_2=4 + SecondaryDeviceTypeOUI_2=0x00,0x50,0xF2,0x04 + SecondaryDeviceTypeSubCategory_2=1 + } + DeviceName="MRVL_DEFAULT_NAME" + # ConfigMethods USB= 0x01 + # ConfigMethods Ethernet= 0x02 + # ConfigMethods Label= 0x04 + # ConfigMethods Display= 0x08 + # ConfigMethods Ext_NFC_Token= 0x10 + # ConfigMethods Int_NFC_Token= 0x20 + # ConfigMethods NFC_Interface= 0x40 + # ConfigMethods PushButton= 0x80 + # ConfigMethods KeyPad= 0x100 + WPSConfigMethods=0x188 + } + GroupId={ + GroupAddr=00:50:43:00:00:00 + GroupSsId="DIRECT-" + } + GroupBSSId={ + # using LAA for interface address by default + GroupBssId=02:50:43:00:00:00 + } + DeviceId={ + WIFIDIRECT_MAC=00:50:43:00:00:00 # MAC address of wifidirect device in Hex + } + Interface={ + # using LAA for interface addresses by default + InterfaceAddress=02:50:43:00:00:00 + InterfaceAddressCount=2 + InterfaceAddressList=02:50:43:00:00:00,02:52:43:00:00:00 + } + ConfigurationTimeout={ + # units of 10 milliseconds + GroupConfigurationTimeout=250 + ClientConfigurationTimeout=100 + } + ExtendedListenTime={ + # units of milliseconds + AvailabilityPeriod=1000 + AvailabilityInterval=1500 + } + IntendedIntfAddress={ + # using LAA for interface address by default + GroupInterfaceAddress=02:50:43:00:00:00 + } + OperatingChannel={ # Operating channel attribute. + CountryString="US" + OpRegulatoryClass=81 + OpChannelNumber=6 + } + InvitationFlagBitmap={ + InvitationFlag=0 # bit0: Invitation type: + } # 0: request to reinvoke a persistent group + # 1: request to join an active WIFIDIRECT group + + + #Extra={ + #Buffer=0x00,0x50,0x43,0x07,0x20,0xa1 + #} + + # + # WPS IE parameters. + # + WPSIE={ + WPSVersion=0x10 + WPSSetupState=0x1 + WPSRequestType=0x0 + WPSResponseType=0x0 + WPSSpecConfigMethods=0x0188 + WPSUUID=0x12,0x34,0x56,0x78,0x12,0x34,0x56,0x78,0x12,0x34,0x56,0x78,0x12,0x34,0x56,0x78 + WPSPrimaryDeviceType=0x00,0x01,0x00,0x50,0xF2,0x04,0x00,0x01 + WPSRFBand=0x01 + WPSAssociationState=0x00 + WPSConfigurationError=0x00 + WPSDevicePassword=0x00 + WPSDeviceName="MRVL_DEFAULT_NAME" + WPSManufacturer=NXP + WPSModelName=SD-8787 + WPSModelNumber=0x00,0x00,0x00,0x01 + WPSSerialNumber=0x00,0x00,0x00,0x01 + WPSVendorExtension=0x00,0x37,0x2A,0x00,0x01,0x20 + } +} + + +######################### WIFIDIRECT Parameters configuration command ####### + +wifidirect_param_config={ + MinDiscoveryInterval=1 + MaxDiscoveryInterval=7 + EnableScan=1 + #ScanPeerDeviceId=00:50:43:77:43:47 + #ScanRequestDeviceType=0x01,0x00,0x50,0xF2,0x04,0x01,0x3C,0x10 + DeviceState=4 +} + +######################### WIFIDIRECT Action Frame command ################## + +wifidirect_action_frame={ + PeerAddr=00:50:43:00:00:00 + Category=4 # 4 : Public action frame, 0x7F : Vendor specific + Action=0 # 0xDD : Vendor specific, Others : Reserved. + OUI=0x50,0x6F,0x9A + OUIType=9 # WFA wifidirect. + # 15 : WPSE. + + # OUI SubType 0 : GO Negotiation Request + # OUI SubType 1 : GO Negotiation Response + # OUI SubType 2 : GO Negotiation Confirmation + # OUI SubType 3 : WIFIDIRECT Invitation Request + # OUI SubType 4 : WIFIDIRECT Invitation Response + # OUI SubType 5 : Device Discoverability Request + # OUI SubType 6 : Device Discoverability Response + # OUI SubType 7 : Provision Discovery Request + # OUI SubType 8 : Provision Discovery Response + + # + # UPDATE LINE BELOW for APPROPRIATE SUB TYPE + # + OUISubType=0 + + DialogToken=1 + + # Arrange in order of subelement Ids + # Other parameters which can be configured from WIFIDIRECT config command. + + #DeviceId={ + # WIFIDIRECT_MAC=00:50:43:77:46:41 # MAC address of wifidirect device in Hex + #} + #Interface={ + # InterfaceAddress=00:50:43:77:46:41 + # InterfaceAddressCount=2 + # InterfaceAddressList=00:50:43:77:46:41,00:50:43:78:47:42 + #} +} + +######################### WIFIDIRECT service discovery command ################## + +wifidirect_discovery_request={ + PeerAddr=00:50:43:00:00:00 + Category=4 + Action=10 + DialogToken=1 + AdvertizementProtocolIE=0x6c,0x02,0x00,0x00 + # octet 1: Element Id = 108 ( 0x6c) + # octer 2: Length of following fields + # octer 3: Bit7: PAME-BI ( Message Exchange BSSID independant) + # Bits0-6: Query response length limit. + # octer 4: Advertizement Protocol ID + QueryRequestLen={ + InfoId=0xDD,0xDD + RequestLen={ + OUI=0x50,0x6F,0x9A + OUISubType=9 + ServiceUpdateIndicator=0 + VendorLen={ + ServiceProtocol=0 # 0: All service protocol types + # 1: Bonjour, 2: uPnP, 3: WS-Discovery + # 255: Vendor specific + ServiceTransactionId=1 + QueryData={ + ## Use Data below, if ServiceProtocol=1 (Bonjour). + # + ## DNSName can be string or hexadecimal sequence of bytes. + #DNSName="_afpovertcp._tcp.local." + # DNSName=0x07,0x65,0x78,0x61,0x6D,0x70,0x6C,0x65,0x0B,0x5F,0x61,0x66,0x70,0x6F,0x76,0x65,0x72,0x74,0x63,0x70,0xC0,0x0C + #DNSType=12 + #BonjourVersion=1 + + ## Use Data below, if ServiceProtocol=2 (uPnP). + # + #uPnPVersion=0x10 + #uPnPQueryValue="ssdp:all" # Searches for all UPnP devices and services + # + # OR any one of following values in WIFIDIRECT spec. + #uPnPQueryValue="upnp:rootdevice" # Searches for all UPnP root devices + #uPnPQueryValue="uuid:device-uuid" # Searches for a particular device + #uPnPQueryValue="urn:schemas-upnp-org:device:deviceType:ver" + # Searches for devices of the given type + #uPnPQueryValue="urn:domain-name:device:deviceType:ver" + # Searches for devices with a vendor-specific type + #uPnPQueryValue="urn:schemas-upnp-org:service:serviceType:ver" + # Searches for devices containing a service of the given type + #uPnPQueryValue="urn:domain-name:service:serviceType:ver" + # Searches for devices containing a vendor-specific service + } + } + } + } +} + +wifidirect_discovery_response={ + PeerAddr=00:50:43:00:00:00 + Category=4 + Action=11 + DialogToken=1 + StatusCode=0 + GasComebackDelay=0x0000 + AdvertizementProtocolIE=0x6c,0x02,0x7F,0x00 + # octet 1: Element Id = 108 ( 0x6c) + # octer 2: Length of following fields + # octer 3: Bit7: PAME-BI ( Message Exchange BSSID independant) + # Bits0-6: Query response length limit. + # octer 4: Advertizement Protocol ID + QueryResponseLen={ + InfoId=0xDD,0xDD + ResponseLen={ + OUI=0x50,0x6F,0x9A + OUISubType=9 + ServiceUpdateIndicator=0 + VendorLen={ + ServiceProtocol=0 # 0: All service protocol types + # 1: Bonjour, 2: uPnP, 3: WS-Discovery + # 255: Vendor specific + ServiceTransactionId=1 + ServiceStatus=0 # 0: Success + # 1: Service protocol type not available + # 2: Query data not available + # 3: Bad request. + ResponseData={ + ## Use Data below, if ServiceProtocol=1 (Bonjour). + # + ## DNSName can be string or hexadecimal sequence of bytes. + + DNSName="_afpovertcp._tcp.local." + # DNSName=0x07,0x65,0x78,0x61,0x6D,0x70,0x6C,0x65,0x0B,0x5F,0x61,0x66,0x70,0x6F,0x76,0x65,0x72,0x74,0x63,0x70,0xC0,0x0C + DNSType=12 + BonjourVersion=1 + ## RecordData can be string or hexadecimal sequence of bytes. + # RecordData="" + RecordData=0x00 + + ## Use Data below, if ServiceProtocol=2 (uPnP). + # + #uPnPVersion=0x10 + #uPnPResponseValue="ssdp:all" # Searches for all UPnP devices and services + # + # OR any one of following values in WIFIDIRECT spec. + #uPnPResponseValue="upnp:rootdevice" # Searches for all UPnP root devices + #uPnPResponseValue="uuid:device-uuid" # Searches for a particular device + #uPnPResponseValue="urn:schemas-upnp-org:device:deviceType:ver" + # Searches for devices of the given type + #uPnPResponseValue="urn:domain-name:device:deviceType:ver" + # Searches for devices with a vendor-specific type + #uPnPResponseValue="urn:schemas-upnp-org:service:serviceType:ver" + # Searches for devices containing a service of the given type + #uPnPResponseValue="urn:domain-name:service:serviceType:ver" + # Searches for devices containing a vendor-specific service + } + } + } + } +} + +### GAS Comback request and response Frame ### + +wifidirect_gas_comeback_request={ + PeerAddr=00:50:43:00:00:00 + Category=4 + Action=12 + DialogToken=1 +} + +wifidirect_gas_comeback_response={ + PeerAddr=00:50:43:00:00:00 + Category=4 + Action=13 + DialogToken=1 + StatusCode=0 + GasResponseFragID=0x01 + # Bit 7: More GAS fragments bit + # Bits 0-6: GAS query response fragment ID. + # 0 for initial frame and increments subsequently. + GasComebackDelay=0x0000 + AdvertizementProtocolIE=0x6c,0x02,0x7F,0x00 + # octet 1: Element Id = 108 ( 0x6c) + # octer 2: Length of following fields + # octer 3: Bit7: PAME-BI ( Message Exchange BSSID independant) + # Bits0-6: Query response length limit. + # octer 4: Advertizement Protocol ID + QueryResponseLen={ + InfoId=0xDD,0xDD + ResponseLen={ + OUI=0x00,0x50,0xF2 + OUISubType=9 + ServiceUpdateIndicator=0 + VendorLen={ + ServiceProtocol=1 # 0: All service protocol types + # 1: Bonjour, 2: uPnP, 3: WS-Discovery + # 255: Vendor specific + ServiceTransactionId=1 + ServiceStatus=0 # 0: Success + # 1: Service protocol type not available + # 2: Query data not available + # 3: Bad request. + ResponseData={ + ## Use Data below, if ServiceProtocol=1 (Bonjour). + # + ## DNSName can be string or hexadecimal sequence of bytes. + + # DNSName="_afpovertcp._tcp.local." + DNSName=0x07,0x65,0x78,0x61,0x6D,0x70,0x6C,0x65,0x0B,0x5F,0x61,0x66,0x70,0x6F,0x76,0x65,0x72,0x74,0x63,0x70,0xC0,0x0C + DNSType=12 + BonjourVersion=1 + ## RecordData can be string or hexadecimal sequence of bytes. + # RecordData="" + RecordData=0x00 + + ## Use Data below, if ServiceProtocol=2 (uPnP). + # + #uPnPVersion=0x10 + #uPnPResponseValue="ssdp:all" # Searches for all UPnP devices and services + # + # OR any one of following values in WIFIDIRECT spec. + #uPnPResponseValue="upnp:rootdevice" # Searches for all UPnP root devices + #uPnPResponseValue="uuid:device-uuid" # Searches for a particular device + #uPnPResponseValue="urn:schemas-upnp-org:device:deviceType:ver" + # Searches for devices of the given type + #uPnPResponseValue="urn:domain-name:device:deviceType:ver" + # Searches for devices with a vendor-specific type + #uPnPResponseValue="urn:schemas-upnp-org:service:serviceType:ver" + # Searches for devices containing a service of the given type + #uPnPResponseValue="urn:domain-name:service:serviceType:ver" + # Searches for devices containing a vendor-specific service + } + } + } + } +} diff --git a/mxm_wifiex/wlan_src/mapp/wifidirectutl/wifidirectutl.c b/mxm_wifiex/wlan_src/mapp/wifidirectutl/wifidirectutl.c new file mode 100644 index 0000000..23ef0b2 --- /dev/null +++ b/mxm_wifiex/wlan_src/mapp/wifidirectutl/wifidirectutl.c @@ -0,0 +1,8338 @@ +/** @file wifidirectutl.c + * + * @brief Program to configure WifiDirect parameters. + * + * Usage: ./wifidirectutl + * + * + * Copyright 2014-2020 NXP + * + * NXP CONFIDENTIAL + * The source code contained or described herein and all documents related to + * the source code (Materials) are owned by NXP, its + * suppliers and/or its licensors. Title to the Materials remains with NXP, + * its suppliers and/or its licensors. The Materials contain + * trade secrets and proprietary and confidential information of NXP, its + * suppliers and/or its licensors. The Materials are protected by worldwide copyright + * and trade secret laws and treaty provisions. No part of the Materials may be + * used, copied, reproduced, modified, published, uploaded, posted, + * transmitted, distributed, or disclosed in any way without NXP's prior + * express written permission. + * + * No license under any patent, copyright, trade secret or other intellectual + * property right is granted to or conferred upon you by disclosure or delivery + * of the Materials, either expressly, by implication, inducement, estoppel or + * otherwise. Any license under such intellectual property rights must be + * express and approved by NXP in writing. + * + */ +/**************************************************************************** + Change log: + 07/10/09: Initial creation + ****************************************************************************/ + +/**************************************************************************** + Header files + ****************************************************************************/ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "wifidirectutl.h" +/**************************************************************************** + Definitions + ****************************************************************************/ + +/** Convert character to integer */ +#define CHAR2INT(x) (((x) >= 'A') ? ((x) - 'A' + 10) : ((x) - '0')) + +/** Uncomment this to enable DEBUG */ +/* #define DEBUG */ + +/**************************************************************************** + Global variables + ****************************************************************************/ +/** Device name */ +static +char dev_name[IFNAMSIZ + 1]; +/** Option for cmd */ +static +struct option cmd_options[] = { + {"help", 0, 0, 'h'}, + {0, 0, 0, 0} +}; + +/**************************************************************************** + Local functions + ***************************************************************************/ +/** + * @brief Dump hex data + * + * @param p A pointer to data buffer + * @param len The len of data buffer + * @param delim Deliminator character + * @return Hex integer + */ +#ifdef DEBUG +static void +hexdump(void *p, t_s32 len, char delim) +{ + t_s32 i; + t_u8 *s = p; + printf("HexDump: len=%d\n", (int)len); + for (i = 0; i < len; i++) { + if (i != len - 1) + printf("%02x%c", *s++, delim); + else + printf("%02x\n", *s); + if ((i + 1) % 16 == 0) + printf("\n"); + } +} +#endif + +static int +wifidir_use_fixed_ie_indices(void) +{ +#define WIFIDIR_USE_FIXED_IE_INDICES "WIFIDIR_USE_FIXED_IE_INDICES" + char *ret = getenv(WIFIDIR_USE_FIXED_IE_INDICES); + + if (ret != NULL && *ret == '1') { + printf("Using fixed ie indices 0 and 1 for P2P and WPS IEs"); + return 1; + } else { + return 0; + } +} + +/** + * @brief Converts a string to hex value + * + * @param str A pointer to the string + * @param raw A pointer to the raw data buffer + * @return Number of bytes read + */ +static int +string2raw(char *str, unsigned char *raw) +{ + int len = (strlen(str) + 1) / 2; + + do { + if (!isxdigit(*str)) { + return -1; + } + *str = toupper(*str); + *raw = CHAR2INT(*str) << 4; + ++str; + *str = toupper(*str); + if (*str == '\0') + break; + *raw |= CHAR2INT(*str); + ++raw; + } while (*++str != '\0'); + return len; +} + +/** + * @brief Convert string to hex integer + * + * @param s A pointer string buffer + * @return Hex integer + */ +static + unsigned int +a2hex(char *s) +{ + unsigned int val = 0; + if (!strncasecmp("0x", s, 2)) { + s += 2; + } + while (*s && isxdigit(*s)) { + val = (val << 4) + hexc2bin(*s++); + } + return val; +} + +/** + * @brief Hex to number + * + * @param c Hex value + * @return Integer value or -1 + */ +static int +hex2num(char c) +{ + if (c >= '0' && c <= '9') + return c - '0'; + if (c >= 'a' && c <= 'f') + return c - 'a' + 10; + if (c >= 'A' && c <= 'F') + return c - 'A' + 10; + + return -1; +} + +/** + * @brief Convert char to hex integer + * + * @param chr Char + * @return Hex integer + */ +unsigned char +hexc2bin(char chr) +{ + if (chr >= '0' && chr <= '9') + chr -= '0'; + else if (chr >= 'A' && chr <= 'F') + chr -= ('A' - 10); + else if (chr >= 'a' && chr <= 'f') + chr -= ('a' - 10); + + return chr; +} + +/** + * @brief Check hex string + * + * @param hex A pointer to hex string + * @return SUCCESS or FAILURE + */ +static int +ishexstring(void *hex) +{ + int i, a; + char *p = hex; + int len = strlen(p); + if (!strncasecmp("0x", p, 2)) { + p += 2; + len -= 2; + } + for (i = 0; i < len; i++) { + a = hex2num(*p); + if (a < 0) + return FAILURE; + p++; + } + return SUCCESS; +} + +/** + * @brief Prints a MAC address in colon separated form from hex data + * + * @param raw A pointer to the hex data buffer + * @return N/A + */ +static void +print_mac(t_u8 *raw) +{ + printf("%02x:%02x:%02x:%02x:%02x:%02x", (unsigned int)raw[0], + (unsigned int)raw[1], (unsigned int)raw[2], (unsigned int)raw[3], + (unsigned int)raw[4], (unsigned int)raw[5]); + return; +} + +/** + * @brief Converts colon separated MAC address to hex value + * + * @param mac A pointer to the colon separated MAC string + * @param raw A pointer to the hex data buffer + * @return SUCCESS or FAILURE + * WIFIDIRECT_RET_MAC_BROADCAST - if broadcast mac + * WIFIDIRECT_RET_MAC_MULTICAST - if multicast mac + */ +static + int +mac2raw(char *mac, t_u8 *raw) +{ + unsigned int temp_raw[ETH_ALEN]; + int num_tokens = 0; + int i; + if (strlen(mac) != ((2 * ETH_ALEN) + (ETH_ALEN - 1))) { + return FAILURE; + } + num_tokens = sscanf(mac, "%2x:%2x:%2x:%2x:%2x:%2x", + temp_raw + 0, temp_raw + 1, temp_raw + 2, + temp_raw + 3, temp_raw + 4, temp_raw + 5); + if (num_tokens != ETH_ALEN) { + return FAILURE; + } + for (i = 0; i < num_tokens; i++) + raw[i] = (t_u8)temp_raw[i]; + + if (memcmp(raw, "\xff\xff\xff\xff\xff\xff", ETH_ALEN) == 0) { + return WIFIDIRECT_RET_MAC_BROADCAST; + } else if (raw[0] & 0x01) { + return WIFIDIRECT_RET_MAC_MULTICAST; + } + return SUCCESS; +} + +/** + * @brief Prints usage information of wifidirectutl + * + * @return N/A + */ +static void +print_tool_usage(void) +{ + + printf("Usage:\n"); + printf("./wifidirectutl wifidirect_mode [mode]\n" + "./wifidirectutl wifidirect_config [*.conf]\n" + "./wifidirectutl wifidirect_params_config [*.conf]\n" + "./wifidirectutl wifidirect_action_frame <*.conf>|" + " \n" + "./wifidirectutl wifidirect_discovery_request <*.conf>\n" + "./wifidirectutl wifidirect_discovery_response <*.conf>\n" + "./wifidirectutl wifidirect_gas_comeback_request <*.conf>\n" + "./wifidirectutl wifidirect_gas_comeback_response <*.conf>\n"); + printf("\nPlease see example configuration file config/wifidirect.conf\n\n"); + printf("Configuration API:\n"); + printf("./wifidirectutl wifidirect_cfg_discovery_period [ ]\n" "./wifidirectutl wifidirect_cfg_intent [IntentValue]\n" "./wifidirectutl wifidirect_cfg_capability [ ]\n" "./wifidirectutl wifidirect_cfg_noa [ ]\n" "./wifidirectutl wifidirect_cfg_opp_ps [ ]\n" "./wifidirectutl wifidirect_cfg_invitation_list [mac_address]\n" "./wifidirectutl wifidirect_cfg_listen_channel [listenChannel]\n" "./wifidirectutl wifidirect_cfg_op_channel [operatingChannel]\n" "./wifidirecttul wifidirect_cfg_persistent_group_record [index] [role]\n" " [ ] [peermac1] [peermac2]\n" "./wifidirecttul wifidirect_cfg_persistent_group_invoke [index] | \n" "./wifidirectutl wifidirect_cfg_presence_req_params [ ]\n" "./wifidirectutl wifidirect_cfg_ext_listen_time [ ]\n"); + +} + +/** + * @brief Parses a command line + * + * @param line The line to parse + * @param args Pointer to the argument buffer to be filled in + * @param args_count Max number of elements which can be filled in buffer 'args' + * @return Number of arguments in the line or EOF + */ +static + int +parse_line(char *line, char *args[], t_u16 args_count) +{ + int arg_num = 0; + int is_start = 0; + int is_quote = 0; + int is_escape = 0; + int length = 0; + int i = 0; + int j = 0; + + arg_num = 0; + length = strlen(line); + /* Process line */ + + /* Find number of arguments */ + is_start = 0; + is_quote = 0; + for (i = 0; (i < length) && (arg_num < args_count); i++) { + /* Ignore leading spaces */ + if (is_start == 0) { + if (line[i] == ' ') { + continue; + } else if (line[i] == '\t') { + continue; + } else if (line[i] == '\n') { + break; + } else { + is_start = 1; + args[arg_num] = &line[i]; + arg_num++; + } + } + if (is_start == 1) { + if ((line[i] == '\\') && (i < (length - 1))) { + if (line[i + 1] == '"') { + is_escape = 1; + for (j = i; j < length - 1; j++) { + line[j] = line[j + 1]; + } + line[length - 1] = '\0'; + continue; + } + } + /* Ignore comments */ + if (line[i] == '#') { + if (is_quote == 0) { + line[i] = '\0'; + arg_num--; + } + break; + } + /* Separate by '=' */ + if (line[i] == '=') { + if (is_quote == 0) { + line[i] = '\0'; + is_start = 0; + continue; + } + } + /* Separate by ',' */ + if (line[i] == ',') { + if (is_quote == 0) { + line[i] = '\0'; + is_start = 0; + continue; + } + } + /* Change ',' to ' ', but not inside quotes */ + if ((line[i] == ',') && (is_quote == 0)) { + line[i] = ' '; + continue; + } + } + /* Remove newlines */ + if (line[i] == '\n') { + line[i] = '\0'; + } + /* Check for quotes */ + if (line[i] == '"') { + if (is_escape) { + is_escape = 0; + /* no change in is_quote */ + } else { + is_quote = (is_quote == 1) ? 0 : 1; + } + continue; + } + if (((line[i] == ' ') || (line[i] == '\t')) && (is_quote == 0)) { + line[i] = '\0'; + is_start = 0; + continue; + } + } + return arg_num; +} + +/** + * @brief Get one line from the File + * + * @param fp File handler + * @param str Storage location for data. + * @param size Maximum number of characters to read. + * @param lineno A pointer to return current line number + * @return returns string or NULL + */ +char * +mlan_config_get_line(FILE * fp, char *str, t_s32 size, int *lineno) +{ + char *start, *end; + int out, next_line; + + if (!fp || !str) + return NULL; + + do { +read_line: + if (!fgets(str, size, fp)) + break; + start = str; + start[size - 1] = '\0'; + end = start + strlen(str); + (*lineno)++; + + out = 1; + while (out && (start < end)) { + next_line = 0; + /* Remove empty lines and lines starting with # */ + switch (start[0]) { + case ' ': /* White space */ + case '\t': /* Tab */ + start++; + break; + case '#': + case '\n': + case '\0': + next_line = 1; + break; + case '\r': + if (start[1] == '\n') + next_line = 1; + else + start++; + break; + default: + out = 0; + break; + } + if (next_line) + goto read_line; + } + + /* Remove # comments unless they are within a double quoted + * string. Remove trailing white space. */ + end = strstr(start, "\""); + if (end) { + end = strstr(end + 1, "\""); + if (!end) + end = start; + } else + end = start; + + end = strstr(end + 1, "#"); + if (end) + *end-- = '\0'; + else + end = start + strlen(start) - 1; + + out = 1; + while (out && (start < end)) { + switch (*end) { + case ' ': /* White space */ + case '\t': /* Tab */ + case '\n': + case '\r': + *end = '\0'; + end--; + break; + default: + out = 0; + break; + } + } + + if (*start == '\0') + continue; + + return start; + } while (1); + + return NULL; +} + +/** + * @brief Parse function for a configuration line + * + * @param s Storage buffer for data + * @param size Maximum size of data + * @param stream File stream pointer + * @param line Pointer to current line within the file + * @param _pos Output string or NULL + * @return String or NULL + */ +static +char * +config_get_line(char *s, int size, FILE * stream, int *line, char **_pos) +{ + *_pos = mlan_config_get_line(stream, s, size, line); + return *_pos; +} + +/** + * @brief Detects duplicates channel in array of strings + * + * @param argc Number of elements + * @param argv Array of strings + * @return UAP_FAILURE or UAP_SUCCESS + */ +static inline int +has_dup_channel(int argc, char *argv[]) +{ + int i, j; + /* Check for duplicate */ + for (i = 0; i < (argc - 1); i++) { + for (j = i + 1; j < argc; j++) { + if (atoi(argv[i]) == atoi(argv[j])) { + return FAILURE; + } + } + } + return SUCCESS; +} + +/** + * @brief Performs the ioctl operation to send the command to + * the driver. + * + * @param cmd Pointer to the command buffer + * @param size Pointer to the command size. This value is + * overwritten by the function with the size of the + * received response. + * @param buf_size Size of the allocated command buffer + * @return SUCCESS or FAILURE + */ +static + int +wifidirect_ioctl(t_u8 *cmd, t_u16 *size, t_u16 buf_size) +{ + struct ifreq ifr; + mrvl_priv_cmd *mrvl_cmd = NULL; + t_u8 *buf = NULL, *temp = NULL; + wifidirectcmdbuf *header = NULL; + t_s32 sockfd; + t_u16 mrvl_header_len = 0; + int ret = SUCCESS; + + if (buf_size < *size) { + printf("buf_size should not less than cmd buffer size\n"); + return FAILURE; + } + + /* Open socket */ + if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) { + printf("ERR:Cannot open socket\n"); + return FAILURE; + } + *(t_u32 *)cmd = buf_size - BUF_HEADER_SIZE; + + mrvl_header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_HOSTCMD); + buf = (unsigned char *)malloc(buf_size + sizeof(mrvl_priv_cmd) + + mrvl_header_len); + if (buf == NULL) { + close(sockfd); + return FAILURE; + } + + memset(buf, 0, buf_size + sizeof(mrvl_priv_cmd) + mrvl_header_len); + /* Fill up buffer */ + mrvl_cmd = (mrvl_priv_cmd *)buf; + mrvl_cmd->buf = buf + sizeof(mrvl_priv_cmd); + mrvl_cmd->used_len = 0; + mrvl_cmd->total_len = buf_size + mrvl_header_len; + /* Copy NXP command string */ + temp = mrvl_cmd->buf; + strncpy((char *)temp, CMD_NXP, strlen(CMD_NXP)); + temp += (strlen(CMD_NXP)); + /* Insert command string */ + strncpy((char *)temp, PRIV_CMD_HOSTCMD, strlen(PRIV_CMD_HOSTCMD)); + temp += (strlen(PRIV_CMD_HOSTCMD)); + + memcpy(temp, (t_u8 *)cmd, *size); + + /* Initialize the ifr structure */ + memset(&ifr, 0, sizeof(ifr)); + strncpy(ifr.ifr_ifrn.ifrn_name, dev_name, IFNAMSIZ - 1); + ifr.ifr_ifru.ifru_data = (void *)mrvl_cmd; + header = (wifidirectcmdbuf *)(buf + sizeof(mrvl_priv_cmd) + + mrvl_header_len); + header->size = *size - BUF_HEADER_SIZE; +#ifdef DEBUG + /* Debug print */ + hexdump(mrvl_cmd, *size + sizeof(mrvl_priv_cmd) + mrvl_header_len, ' '); +#endif + endian_convert_request_header(header); + + /* Perform ioctl */ + errno = 0; + if (ioctl(sockfd, MRVLPRIVCMD, &ifr)) { + perror(""); + printf("ERR:MRVLPRIVCMD is not supported by %s\n", dev_name); + ret = FAILURE; + goto done; + } + endian_convert_response_header(header); + header->cmd_code &= HostCmd_CMD_ID_MASK; + header->cmd_code |= WIFIDIRECTCMD_RESP_CHECK; + *size = header->size; + memcpy(cmd, buf + sizeof(mrvl_priv_cmd) + mrvl_header_len, + *size + BUF_HEADER_SIZE); +#ifdef DEBUG + /* Debug print */ + hexdump(mrvl_cmd, + *size + BUF_HEADER_SIZE + sizeof(mrvl_priv_cmd) + + mrvl_header_len, ' '); +#endif + + /* Validate response size */ + if (*size > (buf_size - BUF_HEADER_SIZE)) { + printf("ERR:Response size (%d) greater than buffer size (%d)! Aborting!\n", *size, buf_size); + ret = FAILURE; + goto done; + } +done: + /* Close socket */ + close(sockfd); + if (buf) + free(buf); + return ret; +} + +/** + * @brief Show usage information for the wifidirect_gas_comeback_discovery commands + * + * $return N/A + */ +static void +print_wifidirect_gas_comeback_usage(void) +{ + printf("\nUsage : wifidirect_gas_comeback_request/response [CONFIG_FILE]\n"); + printf("CONFIG_FILE contains WIFIDIRECT GAS comeback request/response payload.\n"); + return; +} + +/** + * @brief Creates a wifidirect_gas_comeback_service_discovery request/response and + * sends to the driver + * + * Usage: "Usage : wifidirect_gas_comeback_request/response [CONFIG_FILE]" + * + * @param argc Number of arguments + * @param argv Pointer to the arguments + * @return SUCCESS or FAILURE + **/ +static void +wifidirectcmd_gas_comeback_discovery(int argc, char *argv[]) +{ + wifidirect_gas_comeback_request *req_buf = NULL; + wifidirect_gas_comeback_response *resp_buf = NULL; + char *line = NULL; + FILE *config_file = NULL; + int i, opt, li = 0, arg_num = 0, ret = 0, wifidirect_level = 0; + char *args[30], *pos = NULL, wifidirect_mac[20], wifidirect_cmd[40]; + t_u8 dev_address[ETH_ALEN], cmd_found = 0; + t_u8 *buffer = NULL, *tmp_buffer = NULL; + t_u8 req_resp = 0; /* req = 0, resp = 1 */ + t_u16 cmd_len = 0, query_len = 0, vendor_len = 0, service_len = 0; + t_u16 dns_len = 0, record_len = 0, upnp_len = 0; + + memset(wifidirect_mac, 0, sizeof(wifidirect_mac)); + + strncpy(wifidirect_cmd, argv[2], sizeof(wifidirect_cmd) - 1); + while ((opt = getopt_long(argc, argv, "+", cmd_options, NULL)) != -1) { + switch (opt) { + default: + print_wifidirect_gas_comeback_usage(); + return; + } + } + argc -= optind; + argv += optind; + + /* Check arguments */ + if (argc != 3) { + printf("ERR:Incorrect number of arguments.\n"); + print_wifidirect_gas_comeback_usage(); + return; + } + + /* Check if file exists */ + config_file = fopen(argv[2], "r"); + if (config_file == NULL) { + printf("\nERR:Config file can not open.\n"); + return; + } + line = (char *)malloc(MAX_CONFIG_LINE); + if (!line) { + printf("ERR:Cannot allocate memory for line\n"); + goto done; + } + memset(line, 0, MAX_CONFIG_LINE); + + /* Parse file and process */ + while (config_get_line(line, MAX_CONFIG_LINE, config_file, &li, &pos)) { + arg_num = parse_line(line, args, 30); + if (!cmd_found && + strncmp(args[0], wifidirect_cmd, strlen(args[0]))) + continue; + + if (strcmp(args[0], "wifidirect_gas_comeback_request") == 0) { + wifidirect_level = + WIFIDIRECT_DISCOVERY_REQUEST_RESPONSE; + /* For wifidirect_service_gas_comeback, basic initialization here */ + /* Subtract extra two bytes added as a part of query request structure */ + cmd_len = sizeof(wifidirect_gas_comeback_request) - 2; + buffer = (t_u8 *)malloc(cmd_len); + if (!buffer) { + printf("ERR:Cannot allocate memory!\n"); + goto done; + } + req_buf = (wifidirect_gas_comeback_request *)buffer; + req_buf->cmd_code = + HostCmd_CMD_WIFIDIRECT_SERVICE_DISCOVERY; + req_buf->size = cmd_len; + req_buf->seq_num = 0; + req_buf->result = 0; + cmd_found = 1; + + } else if (strcmp(args[0], "wifidirect_gas_comeback_response") + == 0) { + wifidirect_level = + WIFIDIRECT_DISCOVERY_REQUEST_RESPONSE; + req_resp = 1; + /* For wifidirect_service_discovery, basic initialization here */ + /* Subtract extra two bytes added as a part of query response structure */ + cmd_len = sizeof(wifidirect_gas_comeback_response) - 2; + buffer = (t_u8 *)malloc(cmd_len); + if (!buffer) { + printf("ERR:Cannot allocate memory!\n"); + goto done; + } + resp_buf = (wifidirect_gas_comeback_response *)buffer; + resp_buf->cmd_code = + HostCmd_CMD_WIFIDIRECT_SERVICE_DISCOVERY; + resp_buf->size = cmd_len; + resp_buf->seq_num = 0; + resp_buf->result = 0; + cmd_found = 1; + + } + if (!cmd_found) + break; + if (strcmp(args[0], "PeerAddr") == 0) { + strncpy(wifidirect_mac, args[1], + sizeof(wifidirect_mac) - 1); + if ((ret = + mac2raw(wifidirect_mac, dev_address)) != SUCCESS) { + printf("ERR: %s Address \n", + ret == FAILURE ? "Invalid MAC" : ret == + WIFIDIRECT_RET_MAC_BROADCAST ? + "Broadcast" : "Multicast"); + goto done; + } + (!req_resp) ? memcpy(req_buf->peer_mac_addr, + dev_address, + ETH_ALEN) : memcpy(resp_buf-> + peer_mac_addr, + dev_address, + ETH_ALEN); + + } else if (strcmp(args[0], "Category") == 0) { + if (is_input_valid + (WIFIDIRECT_CATEGORY, arg_num - 1, args + 1) + != SUCCESS) { + goto done; + + } + (!req_resp) ? (req_buf->category = + (t_u8)atoi(args[1])) : (resp_buf-> + category = + (t_u8) + atoi(args[1])); + } else if (strcmp(args[0], "Action") == 0) { + if (is_input_valid + (WIFIDIRECT_ACTION, arg_num - 1, args + 1) + != SUCCESS) { + goto done; + } + (!req_resp) ? (req_buf->action = + (t_u8)A2HEXDECIMAL(args[1])) + : (resp_buf->action = + (t_u8)A2HEXDECIMAL(args[1])); + } else if (strcmp(args[0], "DialogToken") == 0) { + if (is_input_valid + (WIFIDIRECT_DIALOGTOKEN, arg_num - 1, args + 1) + != SUCCESS) { + goto done; + } + (!req_resp) ? (req_buf->dialog_taken = + (t_u8)atoi(args[1])) : (resp_buf-> + dialog_taken = + (t_u8) + atoi(args[1])); + } else if (strcmp(args[0], "StatusCode") == 0) { + if (req_resp) { + resp_buf->status_code = + (t_u16)A2HEXDECIMAL(args[1]); + resp_buf->status_code = + cpu_to_le16(resp_buf->status_code); + } + } else if (strcmp(args[0], "GasComebackDelay") == 0) { + if (is_input_valid + (WIFIDIRECT_GAS_COMEBACK_DELAY, arg_num - 1, + args + 1) + != SUCCESS) { + goto done; + } + if (req_resp) { + resp_buf->gas_reply = + (t_u16)A2HEXDECIMAL(args[1]); + resp_buf->gas_reply = + cpu_to_le16(resp_buf->gas_reply); + } + } else if (strcmp(args[0], "GasResponseFragID") == 0) { + if (req_resp) + resp_buf->gas_fragment_id = + (t_u8)A2HEXDECIMAL(args[1]); + } else if (strcmp(args[0], "AdvertizementProtocolIE") == 0) { + if (is_input_valid + (WIFIDIRECT_DISC_ADPROTOIE, arg_num - 1, args + 1) + != SUCCESS) { + goto done; + } + for (i = 0; i < arg_num - 1; i++) { + if (req_resp) + resp_buf->advertize_protocol_ie[i] = + (t_u8)A2HEXDECIMAL(args[i + 1]); + } + } else if (strcmp(args[0], "InfoId") == 0) { + if (is_input_valid + (WIFIDIRECT_DISC_INFOID, arg_num - 1, args + 1) + != SUCCESS) { + goto done; + } + for (i = 0; i < arg_num - 1; i++) { + if (req_resp) + resp_buf->info_id[i] = + (t_u8)A2HEXDECIMAL(args[i + 1]); + } + query_len += arg_num - 1; + } else if (strcmp(args[0], "OUI") == 0) { + if (is_input_valid + (WIFIDIRECT_OUI, arg_num - 1, args + 1) + != SUCCESS) { + goto done; + } + for (i = 0; i < arg_num - 1; i++) { + if (req_resp) + resp_buf->oui[i] = + (t_u8)A2HEXDECIMAL(args[i + 1]); + } + service_len += arg_num - 1; + query_len += arg_num - 1; + } else if (strcmp(args[0], "OUISubType") == 0) { + if (is_input_valid + (WIFIDIRECT_OUISUBTYPE, arg_num - 1, args + 1) + != SUCCESS) { + goto done; + } + if (req_resp) + resp_buf->oui_sub_type = (t_u8)atoi(args[1]); + service_len++; + query_len++; + } else if (strcmp(args[0], "QueryRequestLen") == 0 || + strcmp(args[0], "QueryResponseLen") == 0) { + wifidirect_level = WIFIDIRECT_DISCOVERY_QUERY; + } else if (strcmp(args[0], "RequestLen") == 0 || + strcmp(args[0], "ResponseLen") == 0) { + wifidirect_level = WIFIDIRECT_DISCOVERY_SERVICE; + query_len += 2; + } else if (strcmp(args[0], "VendorLen") == 0) { + wifidirect_level = WIFIDIRECT_DISCOVERY_VENDOR; + service_len += 2; + query_len += 2; + } else if (strcmp(args[0], "QueryData") == 0 || + strcmp(args[0], "ResponseData") == 0) { + wifidirect_level = + WIFIDIRECT_DISCOVERY_QUERY_RESPONSE_PER_PROTOCOL; + } else if (strcmp(args[0], "ServiceProtocol") == 0) { + if (is_input_valid + (WIFIDIRECT_DISC_SERVICEPROTO, arg_num - 1, + args + 1) + != SUCCESS) { + goto done; + } + if (req_resp) + resp_buf->service_protocol = + (t_u8)atoi(args[1]); + vendor_len++; + service_len++; + query_len++; + /* + * For uPnP, due to union allocation, a extra byte is allocated + * reduce it here for uPnP + */ + cmd_len--; + } else if (strcmp(args[0], "ServiceUpdateIndicator") == 0) { + if (is_input_valid + (WIFIDIRECT_SERVICEUPDATE_INDICATOR, arg_num - 1, + args + 1) + != SUCCESS) { + goto done; + } + if (req_resp) + resp_buf->service_update_indicator = + cpu_to_le16((t_u16)atoi(args[1])); + service_len += 2; + query_len += 2; + } else if (strcmp(args[0], "ServiceTransactionId") == 0) { + if (is_input_valid + (WIFIDIRECT_DISC_SERVICETRANSACID, arg_num - 1, + args + 1) + != SUCCESS) { + goto done; + } + if (req_resp) + resp_buf->service_transaction_id = + (t_u8)atoi(args[1]); + vendor_len++; + service_len++; + query_len++; + } else if (strcmp(args[0], "ServiceStatus") == 0) { + if (is_input_valid + (WIFIDIRECT_DISC_SERVICE_STATUS, arg_num - 1, + args + 1) + != SUCCESS) { + goto done; + } + if (req_resp) + resp_buf->disc_status_code = + (t_u8)atoi(args[1]); + vendor_len++; + service_len++; + query_len++; + } else if (strcmp(args[0], "DNSName") == 0) { + if (args[1][0] == '"') { + args[1]++; + if (args[1][strlen(args[1]) - 1] == '"') + args[1][strlen(args[1]) - 1] = '\0'; + + dns_len = strlen(args[1]); + tmp_buffer = realloc(buffer, cmd_len + dns_len); + if (!tmp_buffer) { + printf("ERR:Cannot add DNS name to buffer!\n"); + goto done; + } else { + buffer = tmp_buffer; + tmp_buffer = NULL; + } + if (req_resp) + strncpy((char *)resp_buf->disc_resp.u. + bonjour.dns, args[1], + strlen(args[1])); + } else { + /* HEX input */ + dns_len = arg_num - 1; + tmp_buffer = realloc(buffer, cmd_len + dns_len); + if (!tmp_buffer) { + printf("ERR:Cannot add DNS name to buffer!\n"); + goto done; + } else { + buffer = tmp_buffer; + tmp_buffer = NULL; + } + for (i = 0; i < arg_num - 1; i++) { + if (req_resp) + resp_buf->disc_resp.u.bonjour. + dns[i] = + (t_u8) + A2HEXDECIMAL(args + [i + 1]); + } + } + cmd_len += dns_len; + vendor_len += dns_len; + service_len += dns_len; + query_len += dns_len; + } else if (strcmp(args[0], "DNSType") == 0) { + if (is_input_valid + (WIFIDIRECT_DISC_DNSTYPE, arg_num - 1, args + 1) + != SUCCESS) { + goto done; + } + if (req_resp) + *(&resp_buf->disc_resp.u.bonjour.dns_type + + dns_len) = (t_u8)A2HEXDECIMAL(args[1]); + vendor_len++; + service_len++; + query_len++; + } else if (strcmp(args[0], "BonjourVersion") == 0) { + if (is_input_valid + (WIFIDIRECT_DISC_BONJOUR_VERSION, arg_num - 1, + args + 1) + != SUCCESS) { + goto done; + } + if (req_resp) + *(&resp_buf->disc_resp.u.bonjour.version + + dns_len) = (t_u8)atoi(args[1]); + vendor_len++; + service_len++; + query_len++; + } else if (strcmp(args[0], "uPnPVersion") == 0) { + if (is_input_valid + (WIFIDIRECT_DISC_UPNP_VERSION, arg_num - 1, + args + 1) + != SUCCESS) { + goto done; + } + if (req_resp) + resp_buf->disc_resp.u.upnp.version = + (t_u8)A2HEXDECIMAL(args[1]); + vendor_len++; + service_len++; + query_len++; + } else if (strcmp(args[0], "uPnPQueryValue") == 0 || + strcmp(args[0], "uPnPResponseValue") == 0) { + if (args[1][0] == '"') { + args[1]++; + if (args[1][strlen(args[1]) - 1] == '"') + args[1][strlen(args[1]) - 1] = '\0'; + + upnp_len = strlen(args[1]); + tmp_buffer = + realloc(buffer, cmd_len + upnp_len); + if (!tmp_buffer) { + printf("ERR:Cannot add uPnP value to buffer!\n"); + goto done; + } else { + buffer = tmp_buffer; + tmp_buffer = NULL; + } + if (req_resp) + strncpy((char *)resp_buf->disc_resp.u. + upnp.value, args[1], upnp_len); + } else { + /* HEX input */ + upnp_len = arg_num - 1; + tmp_buffer = + realloc(buffer, cmd_len + upnp_len); + if (!tmp_buffer) { + printf("ERR:Cannot add uPnP value to buffer!\n"); + goto done; + } else { + buffer = tmp_buffer; + tmp_buffer = NULL; + } + for (i = 0; i < arg_num - 1; i++) { + if (req_resp) + resp_buf->disc_resp.u.upnp. + value[i] = + (t_u8) + A2HEXDECIMAL(args + [i + 1]); + } + } + cmd_len += upnp_len; + vendor_len += upnp_len; + service_len += upnp_len; + query_len += upnp_len; + } else if (strcmp(args[0], "RecordData") == 0) { + if (args[1][0] == '"') { + args[1]++; + if (args[1][strlen(args[1]) - 1] == '"') + args[1][strlen(args[1]) - 1] = '\0'; + + record_len = strlen(args[1]); + tmp_buffer = + realloc(buffer, cmd_len + record_len); + if (!tmp_buffer) { + printf("ERR:Cannot add Record name to buffer!\n"); + goto done; + } else { + buffer = tmp_buffer; + tmp_buffer = NULL; + } + if (!req_resp) { + printf("ERR:Cannot add Record name to buffer!\n"); + goto done; + } + strncpy((char *)resp_buf->disc_resp.u.bonjour. + record, args[1], strlen(args[1])); + } else { + /* HEX input */ + record_len = arg_num - 1; + tmp_buffer = + realloc(buffer, cmd_len + record_len); + if (!tmp_buffer) { + printf("ERR:Cannot add Record name to buffer!\n"); + goto done; + } else { + buffer = tmp_buffer; + tmp_buffer = NULL; + } + if (!req_resp) { + printf("ERR:Cannot add Record name to buffer!\n"); + goto done; + } + for (i = 0; i < arg_num - 1; i++) + resp_buf->disc_resp.u.bonjour. + record[i] = + (t_u8)A2HEXDECIMAL(args[i + 1]); + + } + cmd_len += record_len; + vendor_len += record_len; + service_len += record_len; + query_len += record_len; + } else if (strcmp(args[0], "}") == 0) { + switch (wifidirect_level) { + case WIFIDIRECT_DISCOVERY_QUERY: + if (req_resp) + resp_buf->query_len = + cpu_to_le16(query_len); + break; + case WIFIDIRECT_DISCOVERY_SERVICE: + if (req_resp) + resp_buf->response_len = + cpu_to_le16(service_len); + break; + case WIFIDIRECT_DISCOVERY_VENDOR: + if (req_resp) + resp_buf->vendor_len = + cpu_to_le16(vendor_len); + break; + default: + break; + } + if (wifidirect_level) { + if (wifidirect_level == + WIFIDIRECT_DISCOVERY_REQUEST_RESPONSE) + break; + wifidirect_level--; + } + } + } + /* Send collective command */ + if (buffer) + wifidirect_ioctl((t_u8 *)buffer, &cmd_len, cmd_len); +done: + fclose(config_file); + if (buffer) + free(buffer); + if (line) + free(line); +} + +/** + * @brief Show usage information for the wifidirect_discovery commands + * + * $return N/A + */ +static void +print_wifidirect_discovery_usage(void) +{ + printf("\nUsage : wifidirect_discovery_request/response [CONFIG_FILE]\n"); + printf("CONFIG_FILE contains WIFIDIRECT service discovery payload.\n"); + return; +} + +/** + * @brief Creates a wifidirect_service_discovery request/response and + * sends to the driver + * + * Usage: "Usage : wifidirect_discovery_request/response [CONFIG_FILE]" + * + * @param argc Number of arguments + * @param argv Pointer to the arguments + * @return SUCCESS or FAILURE + **/ +static void +wifidirectcmd_service_discovery(int argc, char *argv[]) +{ + wifidirect_discovery_request *req_buf = NULL; + wifidirect_discovery_response *resp_buf = NULL; + char *line = NULL; + FILE *config_file = NULL; + int i, opt, li = 0, arg_num = 0, ret = 0, wifidirect_level = 0; + char *args[30], *pos = NULL, wifidirect_mac[20], wifidirect_cmd[32]; + t_u8 dev_address[ETH_ALEN], cmd_found = 0; + t_u8 *buffer = NULL, *tmp_buffer = NULL; + t_u8 req_resp = 0; /* req = 0, resp = 1 */ + t_u16 cmd_len = 0, query_len = 0, vendor_len = 0, service_len = 0; + t_u16 dns_len = 0, record_len = 0, upnp_len = 0; + + memset(wifidirect_mac, 0, sizeof(wifidirect_mac)); + + strncpy(wifidirect_cmd, argv[2], sizeof(wifidirect_cmd) - 1); + while ((opt = getopt_long(argc, argv, "+", cmd_options, NULL)) != -1) { + switch (opt) { + default: + print_wifidirect_discovery_usage(); + return; + } + } + argc -= optind; + argv += optind; + + /* Check arguments */ + if (argc != 3) { + printf("ERR:Incorrect number of arguments.\n"); + print_wifidirect_discovery_usage(); + return; + } + + /* Check if file exists */ + config_file = fopen(argv[2], "r"); + if (config_file == NULL) { + printf("\nERR:Config file can not open.\n"); + return; + } + line = (char *)malloc(MAX_CONFIG_LINE); + if (!line) { + printf("ERR:Cannot allocate memory for line\n"); + goto done; + } + memset(line, 0, MAX_CONFIG_LINE); + + /* Parse file and process */ + while (config_get_line(line, MAX_CONFIG_LINE, config_file, &li, &pos)) { + arg_num = parse_line(line, args, 30); + if (!cmd_found && + strncmp(args[0], wifidirect_cmd, strlen(args[0]))) + continue; + + if (strcmp(args[0], "wifidirect_discovery_request") == 0) { + wifidirect_level = + WIFIDIRECT_DISCOVERY_REQUEST_RESPONSE; + /* For wifidirect_service_discovery, basic initialization here */ + cmd_len = sizeof(wifidirect_discovery_request); + buffer = (t_u8 *)malloc(cmd_len); + if (!buffer) { + printf("ERR:Cannot allocate memory!\n"); + goto done; + } + req_buf = (wifidirect_discovery_request *)buffer; + req_buf->cmd_code = + HostCmd_CMD_WIFIDIRECT_SERVICE_DISCOVERY; + req_buf->size = cmd_len; + req_buf->seq_num = 0; + req_buf->result = 0; + cmd_found = 1; + } else if (strcmp(args[0], "wifidirect_discovery_response") == + 0) { + wifidirect_level = + WIFIDIRECT_DISCOVERY_REQUEST_RESPONSE; + req_resp = 1; + /* For wifidirect_service_discovery, basic initialization here */ + cmd_len = sizeof(wifidirect_discovery_response); + buffer = (t_u8 *)malloc(cmd_len); + if (!buffer) { + printf("ERR:Cannot allocate memory!\n"); + goto done; + } + resp_buf = (wifidirect_discovery_response *)buffer; + resp_buf->cmd_code = + HostCmd_CMD_WIFIDIRECT_SERVICE_DISCOVERY; + resp_buf->size = cmd_len; + resp_buf->seq_num = 0; + resp_buf->result = 0; + cmd_found = 1; + + } + if (!cmd_found) + break; + if (strcmp(args[0], "PeerAddr") == 0) { + strncpy(wifidirect_mac, args[1], + sizeof(wifidirect_mac) - 1); + if ((ret = + mac2raw(wifidirect_mac, dev_address)) != SUCCESS) { + printf("ERR: %s Address \n", + ret == FAILURE ? "Invalid MAC" : ret == + WIFIDIRECT_RET_MAC_BROADCAST ? + "Broadcast" : "Multicast"); + goto done; + } + (!req_resp) ? memcpy(req_buf->peer_mac_addr, + dev_address, + ETH_ALEN) : memcpy(resp_buf-> + peer_mac_addr, + dev_address, + ETH_ALEN); + + } else if (strcmp(args[0], "Category") == 0) { + if (is_input_valid + (WIFIDIRECT_CATEGORY, arg_num - 1, args + 1) + != SUCCESS) { + goto done; + + } + (!req_resp) ? (req_buf->category = + (t_u8)atoi(args[1])) : (resp_buf-> + category = + (t_u8) + atoi(args[1])); + } else if (strcmp(args[0], "Action") == 0) { + if (is_input_valid + (WIFIDIRECT_ACTION, arg_num - 1, args + 1) + != SUCCESS) { + goto done; + } + (!req_resp) ? (req_buf->action = + (t_u8)A2HEXDECIMAL(args[1])) + : (resp_buf->action = + (t_u8)A2HEXDECIMAL(args[1])); + } else if (strcmp(args[0], "DialogToken") == 0) { + if (is_input_valid + (WIFIDIRECT_DIALOGTOKEN, arg_num - 1, args + 1) + != SUCCESS) { + goto done; + } + (!req_resp) ? (req_buf->dialog_taken = + (t_u8)atoi(args[1])) : (resp_buf-> + dialog_taken = + (t_u8) + atoi(args[1])); + } else if (strcmp(args[0], "StatusCode") == 0) { + if (req_resp) + resp_buf->status_code = (t_u8)atoi(args[1]); + } else if (strcmp(args[0], "GasComebackDelay") == 0) { + if (is_input_valid + (WIFIDIRECT_GAS_COMEBACK_DELAY, arg_num - 1, + args + 1) + != SUCCESS) { + goto done; + } + if (req_resp) { + resp_buf->gas_reply = + (t_u16)A2HEXDECIMAL(args[1]); + resp_buf->gas_reply = + cpu_to_le16(resp_buf->gas_reply); + } + } else if (strcmp(args[0], "AdvertizementProtocolIE") == 0) { + if (is_input_valid + (WIFIDIRECT_DISC_ADPROTOIE, arg_num - 1, args + 1) + != SUCCESS) { + goto done; + } + if (!req_resp) { + for (i = 0; + i < MIN(arg_num - 1, MAX_ADPROTOIE_LEN); + i++) + req_buf->advertize_protocol_ie[i] = + (t_u8)A2HEXDECIMAL(args[i + 1]); + } else { + for (i = 0; + i < MIN(arg_num - 1, MAX_ADPROTOIE_LEN); + i++) + resp_buf->advertize_protocol_ie[i] = + (t_u8)A2HEXDECIMAL(args[i + 1]); + } + } else if (strcmp(args[0], "InfoId") == 0) { + if (is_input_valid + (WIFIDIRECT_DISC_INFOID, arg_num - 1, args + 1) + != SUCCESS) { + goto done; + } + if (!req_resp) { + for (i = 0; + i < MIN(arg_num - 1, MAX_INFOID_LEN); i++) + req_buf->info_id[i] = + (t_u8)A2HEXDECIMAL(args[i + 1]); + } else { + for (i = 0; + i < MIN(arg_num - 1, MAX_INFOID_LEN); i++) + resp_buf->info_id[i] = + (t_u8)A2HEXDECIMAL(args[i + 1]); + } + query_len += arg_num - 1; + } else if (strcmp(args[0], "OUI") == 0) { + if (is_input_valid + (WIFIDIRECT_OUI, arg_num - 1, args + 1) + != SUCCESS) { + goto done; + } + if (!req_resp) { + for (i = 0; i < MIN(arg_num - 1, MAX_OUI_LEN); + i++) + req_buf->oui[i] = + (t_u8)A2HEXDECIMAL(args[i + 1]); + } else { + for (i = 0; i < MIN(arg_num - 1, MAX_OUI_LEN); + i++) + resp_buf->oui[i] = + (t_u8)A2HEXDECIMAL(args[i + 1]); + } + service_len += arg_num - 1; + query_len += arg_num - 1; + } else if (strcmp(args[0], "OUISubType") == 0) { + if (is_input_valid + (WIFIDIRECT_OUISUBTYPE, arg_num - 1, args + 1) + != SUCCESS) { + goto done; + } + (!req_resp) ? (req_buf->oui_sub_type = + (t_u8)atoi(args[1])) : (resp_buf-> + oui_sub_type = + (t_u8) + atoi(args[1])); + service_len++; + query_len++; + } else if (strcmp(args[0], "QueryRequestLen") == 0 || + strcmp(args[0], "QueryResponseLen") == 0) { + wifidirect_level = WIFIDIRECT_DISCOVERY_QUERY; + } else if (strcmp(args[0], "RequestLen") == 0 || + strcmp(args[0], "ResponseLen") == 0) { + wifidirect_level = WIFIDIRECT_DISCOVERY_SERVICE; + query_len += 2; + } else if (strcmp(args[0], "VendorLen") == 0) { + wifidirect_level = WIFIDIRECT_DISCOVERY_VENDOR; + service_len += 2; + query_len += 2; + } else if (strcmp(args[0], "QueryData") == 0 || + strcmp(args[0], "ResponseData") == 0) { + wifidirect_level = + WIFIDIRECT_DISCOVERY_QUERY_RESPONSE_PER_PROTOCOL; + } else if (strcmp(args[0], "ServiceProtocol") == 0) { + if (is_input_valid + (WIFIDIRECT_DISC_SERVICEPROTO, arg_num - 1, + args + 1) + != SUCCESS) { + goto done; + } + if (!req_resp) { + req_buf->service_protocol = (t_u8)atoi(args[1]); + /* + * For uPnP, due to union allocation, a extra byte + * is allocated reduce it here for uPnP + */ + if (req_buf->service_protocol == 2) + cmd_len--; + } else { + resp_buf->service_protocol = + (t_u8)atoi(args[1]); + if (resp_buf->service_protocol == 2) + cmd_len--; + } + vendor_len++; + service_len++; + query_len++; + } else if (strcmp(args[0], "ServiceUpdateIndicator") == 0) { + if (is_input_valid + (WIFIDIRECT_SERVICEUPDATE_INDICATOR, arg_num - 1, + args + 1) + != SUCCESS) { + goto done; + } + (!req_resp) ? (req_buf->service_update_indicator = + cpu_to_le16((t_u16)atoi(args[1]))) : + (resp_buf->service_update_indicator = + cpu_to_le16((t_u16)atoi(args[1]))); + service_len += 2; + query_len += 2; + } else if (strcmp(args[0], "ServiceTransactionId") == 0) { + if (is_input_valid + (WIFIDIRECT_DISC_SERVICETRANSACID, arg_num - 1, + args + 1) + != SUCCESS) { + goto done; + } + (!req_resp) ? (req_buf->service_transaction_id = + (t_u8)atoi(args[1])) : (resp_buf-> + service_transaction_id + = + (t_u8) + atoi(args[1])); + vendor_len++; + service_len++; + query_len++; + } else if (strcmp(args[0], "ServiceStatus") == 0) { + if (is_input_valid + (WIFIDIRECT_DISC_SERVICE_STATUS, arg_num - 1, + args + 1) + != SUCCESS) { + goto done; + } + if (req_resp) + resp_buf->disc_status_code = + (t_u8)atoi(args[1]); + vendor_len++; + service_len++; + query_len++; + } else if (strcmp(args[0], "DNSName") == 0) { + if (args[1][0] == '"') { + args[1]++; + if (args[1][strlen(args[1]) - 1] == '"') + args[1][strlen(args[1]) - 1] = '\0'; + + dns_len = strlen(args[1]); + tmp_buffer = realloc(buffer, cmd_len + dns_len); + if (!tmp_buffer) { + printf("ERR:Cannot add DNS name to buffer!\n"); + goto done; + } else { + buffer = tmp_buffer; + tmp_buffer = NULL; + } + (!req_resp) ? + (strncpy + ((char *)req_buf->disc_query.u.bonjour. + dns, args[1], + strlen(args[1]))) : (strncpy((char *) + resp_buf-> + disc_resp. + u. + bonjour. + dns, + args[1], + strlen + (args + [1]))); + } else { + /* HEX input */ + dns_len = arg_num - 1; + tmp_buffer = realloc(buffer, cmd_len + dns_len); + if (!tmp_buffer) { + printf("ERR:Cannot add DNS name to buffer!\n"); + goto done; + } else { + buffer = tmp_buffer; + tmp_buffer = NULL; + } + if (!req_resp) { + for (i = 0; i < arg_num - 1; i++) + req_buf->disc_query.u.bonjour. + dns[i] = + (t_u8) + A2HEXDECIMAL(args + [i + 1]); + } else { + for (i = 0; i < arg_num - 1; i++) + resp_buf->disc_resp.u.bonjour. + dns[i] = + (t_u8) + A2HEXDECIMAL(args + [i + 1]); + } + } + cmd_len += dns_len; + vendor_len += dns_len; + service_len += dns_len; + query_len += dns_len; + } else if (strcmp(args[0], "DNSType") == 0) { + if (is_input_valid + (WIFIDIRECT_DISC_DNSTYPE, arg_num - 1, args + 1) + != SUCCESS) { + goto done; + } + (!req_resp) ? + (* + (&req_buf->disc_query.u.bonjour.dns_type + + dns_len) = + (t_u8)A2HEXDECIMAL(args[1])) : (*(&resp_buf-> + disc_resp.u. + bonjour. + dns_type + + dns_len) = + (t_u8) + A2HEXDECIMAL + (args[1])); + vendor_len++; + service_len++; + query_len++; + } else if (strcmp(args[0], "BonjourVersion") == 0) { + if (is_input_valid + (WIFIDIRECT_DISC_BONJOUR_VERSION, arg_num - 1, + args + 1) + != SUCCESS) { + goto done; + } + (!req_resp) ? + (* + (&req_buf->disc_query.u.bonjour.version + + dns_len) = + (t_u8)atoi(args[1])) : (*(&resp_buf->disc_resp. + u.bonjour.version + + dns_len) = + (t_u8)atoi(args[1])); + vendor_len++; + service_len++; + query_len++; + } else if (strcmp(args[0], "uPnPVersion") == 0) { + if (is_input_valid + (WIFIDIRECT_DISC_UPNP_VERSION, arg_num - 1, + args + 1) + != SUCCESS) { + goto done; + } + (!req_resp) ? + (req_buf->disc_query.u.upnp.version = + (t_u8)A2HEXDECIMAL(args[1])) : (resp_buf-> + disc_resp.u. + upnp.version = + (t_u8) + A2HEXDECIMAL + (args[1])); + vendor_len++; + service_len++; + query_len++; + } else if (strcmp(args[0], "uPnPQueryValue") == 0 || + strcmp(args[0], "uPnPResponseValue") == 0) { + if (args[1][0] == '"') { + args[1]++; + if (args[1][strlen(args[1]) - 1] == '"') + args[1][strlen(args[1]) - 1] = '\0'; + + upnp_len = strlen(args[1]); + tmp_buffer = + realloc(buffer, cmd_len + upnp_len); + if (!tmp_buffer) { + printf("ERR:Cannot add uPnP value to buffer!\n"); + goto done; + } else { + buffer = tmp_buffer; + tmp_buffer = NULL; + } + (!req_resp) ? + (strncpy + ((char *)req_buf->disc_query.u.upnp. + value, args[1], + upnp_len)) : (strncpy((char *) + resp_buf-> + disc_resp.u. + upnp.value, + args[1], + upnp_len)); + } else { + /* HEX input */ + upnp_len = arg_num - 1; + tmp_buffer = + realloc(buffer, cmd_len + upnp_len); + if (!tmp_buffer) { + printf("ERR:Cannot add uPnP value to buffer!\n"); + goto done; + } else { + buffer = tmp_buffer; + tmp_buffer = NULL; + } + if (!req_resp) { + for (i = 0; i < arg_num - 1; i++) + req_buf->disc_query.u.upnp. + value[i] = + (t_u8) + A2HEXDECIMAL(args + [i + 1]); + } else { + for (i = 0; i < arg_num - 1; i++) + resp_buf->disc_resp.u.upnp. + value[i] = + (t_u8) + A2HEXDECIMAL(args + [i + 1]); + } + } + cmd_len += upnp_len; + vendor_len += upnp_len; + service_len += upnp_len; + query_len += upnp_len; + } else if (strcmp(args[0], "RecordData") == 0) { + if (args[1][0] == '"') { + args[1]++; + if (args[1][strlen(args[1]) - 1] == '"') + args[1][strlen(args[1]) - 1] = '\0'; + + record_len = strlen(args[1]); + tmp_buffer = + realloc(buffer, cmd_len + record_len); + if (!tmp_buffer) { + printf("ERR:Cannot add Record name to buffer!\n"); + goto done; + } else { + buffer = tmp_buffer; + tmp_buffer = NULL; + } + if (!req_resp) { + printf("ERR:Cannot add Record name to buffer!\n"); + goto done; + } + strncpy((char *)resp_buf->disc_resp.u.bonjour. + record + dns_len, args[1], + strlen(args[1])); + } else { + /* HEX input */ + record_len = arg_num - 1; + tmp_buffer = + realloc(buffer, cmd_len + record_len); + if (!tmp_buffer) { + printf("ERR:Cannot add Record name to buffer!\n"); + goto done; + } else { + buffer = tmp_buffer; + tmp_buffer = NULL; + } + if (!req_resp) { + printf("ERR:Cannot add Record name to buffer!\n"); + goto done; + } + for (i = 0; i < arg_num - 1; i++) + *(&resp_buf->disc_resp.u.bonjour. + record[i] + dns_len) = + (t_u8)A2HEXDECIMAL(args[i + 1]); + } + cmd_len += record_len; + vendor_len += record_len; + service_len += record_len; + query_len += record_len; + } else if (strcmp(args[0], "}") == 0) { + switch (wifidirect_level) { + case WIFIDIRECT_DISCOVERY_QUERY: + (!req_resp) ? (req_buf->query_len = + cpu_to_le16(query_len)) + : (resp_buf->query_len = + cpu_to_le16(query_len)); + break; + case WIFIDIRECT_DISCOVERY_SERVICE: + (!req_resp) ? (req_buf->request_len = + cpu_to_le16(service_len)) + : (resp_buf->response_len = + cpu_to_le16(service_len)); + break; + case WIFIDIRECT_DISCOVERY_VENDOR: + (!req_resp) ? (req_buf->vendor_len = + cpu_to_le16(vendor_len)) + : (resp_buf->vendor_len = + cpu_to_le16(vendor_len)); + break; + default: + break; + } + if (wifidirect_level) { + if (wifidirect_level == + WIFIDIRECT_DISCOVERY_REQUEST_RESPONSE) + break; + wifidirect_level--; + } + } + } + /* Send collective command */ + if (buffer) + wifidirect_ioctl((t_u8 *)buffer, &cmd_len, cmd_len); +done: + fclose(config_file); + if (buffer) + free(buffer); + if (line) + free(line); +} + +/** + * @brief Show usage information for the wifidirect_config command + * + * $return N/A + */ +static void +print_wifidirect_config_usage(void) +{ + printf("\nUsage : wifidirect_config [CONFIG_FILE]\n"); + printf("\nIf CONFIG_FILE is provided, a 'set' is performed, else a 'get' is performed.\n"); + printf("CONFIG_FILE contains all WIFIDIRECT parameters.\n"); + return; +} + +/** + * @brief Read the wifidirect parameters and sends to the driver + * + * @param file_name File to open for configuration parameters. + * @param cmd_name Command Name for which parameters are read. + * @param pbuf Pointer to output buffer + * @param ie_len_wifidirect Length of wifidirect parameters to return + * @param ie_len_wps Length of WPS parameters to return + * @return SUCCESS or FAILURE + */ +static const t_u8 wifidirect_oui[] = { 0x50, 0x6F, 0x9A, 0x09 }; +static const t_u8 wps_oui[] = { 0x00, 0x50, 0xF2, 0x04 }; + +static void +wifidirect_file_params_config(char *file_name, char *cmd_name, t_u8 *pbuf, + t_u16 *ie_len_wifidirect, t_u16 *ie_len_wps) +{ + FILE *config_file = NULL; + char *line = NULL; + int i = 0, li = 0, arg_num = 0, ret = 0, wifidirect_level = + 0, no_of_chan_entries = 0, no_of_noa = 0; + int secondary_index = -1, flag = 1, group_secondary_index = -1; + char **args = NULL; + char *pos = NULL; + char wifidirect_mac[20], country[4], wifidirect_ssid[33]; + char WPS_manufacturer[33], WPS_modelname[33], WPS_devicename[33], + wifi_group_direct_ssid[33]; + t_u8 dev_channels[MAX_CHANNELS]; + t_u8 iface_list[ETH_ALEN * MAX_INTERFACE_ADDR_COUNT]; + t_u8 dev_address[ETH_ALEN]; + t_u8 group_dev_address[ETH_ALEN]; + t_u8 *extra = NULL; + t_u8 *buffer = pbuf; + t_u16 cmd_len_wifidirect = 0, cmd_len_wps = 0, tlv_len = 0, extra_len = + 0, temp = 0; + t_u16 wps_model_len = 0, wps_serial_len = 0, wps_vendor_len = 0; + t_u16 pri_category = 0, pri_sub_category = 0, config_methods = 0; + t_u16 sec_category = 0, sec_sub_category = 0, group_sec_sub_category = + 0, group_sec_category = 0; + t_u16 avail_period = 0, avail_interval = 0; + t_u8 secondary_oui[4], group_secondary_oui[4]; + t_u16 WPS_specconfigmethods = 0, WPS_associationstate = 0, + WPS_configurationerror = 0, WPS_devicepassword = 0; + t_u8 dev_capability = 0, group_capability = 0, cmd_found = 0, + group_owner_intent = 0, primary_oui[4], iface_count = 0, + regulatory_class = 0, channel_number = 0, manageability = 0, + op_regulatory_class = 0, op_channel_number = + 0, invitation_flag = 0; + t_u8 WPS_version = 0, WPS_setupstate = 0, WPS_requesttype = + 0, WPS_responsetype = + 0, WPS_UUID[WPS_UUID_MAX_LEN], + WPS_primarydevicetype[WPS_DEVICE_TYPE_MAX_LEN], WPS_RFband = + 0, WPS_modelnumber[32], WPS_serialnumber[32], WPS_VendorExt[32]; + t_u8 go_config_timeout = 0, client_config_timeout = 0; + t_u8 secondary_dev_count = 0, group_secondary_dev_count = 0; + t_u16 temp16 = 0; + t_u8 secondary_dev_info[WPS_DEVICE_TYPE_LEN * + MAX_SECONDARY_DEVICE_COUNT]; + t_u8 group_secondary_dev_info[WPS_DEVICE_TYPE_LEN * + MAX_GROUP_SECONDARY_DEVICE_COUNT]; + t_u8 wifidirect_client_dev_count = 0, wifidirect_client_dev_index = + 0, temp8 = 0; + wifidirect_client_dev_info + wifidirect_client_dev_info_list[MAX_SECONDARY_DEVICE_COUNT]; + t_u8 wifidirect_total_secondary_dev_count = 0; + t_u8 wifidirect_group_total_ssid_len = 0, tlv_offset = + 0, temp_dev_size = 0; + t_u8 noa_index = 0, opp_ps = 0, ctwindow_opp_ps = 0, count_type = 0; + t_u32 duration = 0, interval = 0, start_time = 0; + t_u16 total_chan_len = 0; + t_u8 chan_entry_regulatory_class = 0, chan_entry_num_of_channels = 0; + t_u8 *chan_entry_list = NULL; + t_u8 *chan_buf = NULL; + noa_descriptor noa_descriptor_list[MAX_NOA_DESCRIPTORS]; + /* Check if file exists */ + config_file = fopen(file_name, "r"); + if (config_file == NULL) { + printf("\nERR:Config file can not open.\n"); + return; + } + + /* Memory allocations */ + line = (char *)malloc(MAX_CONFIG_LINE); + if (!line) { + printf("ERR:Cannot allocate memory for line\n"); + goto done; + } + memset(line, 0, MAX_CONFIG_LINE); + + extra = (t_u8 *)malloc(MAX_CONFIG_LINE); + if (!extra) { + printf("ERR:Cannot allocate memory for extra\n"); + goto done; + } + memset(extra, 0, MAX_CONFIG_LINE); + + args = (char **)malloc(sizeof(char *) * MAX_ARGS_NUM); + if (!args) { + printf("ERR:Cannot allocate memory for args\n"); + goto done; + } + memset(args, 0, (sizeof(char *) * MAX_ARGS_NUM)); + + if (!wifidir_use_fixed_ie_indices()) { + special_mask_custom_ie_buf *wifidirect_ie_buf; + wifidirect_ie_buf = (special_mask_custom_ie_buf *)buffer; + memcpy(&wifidirect_ie_buf->Oui[0], wifidirect_oui, + sizeof(wifidirect_oui)); + cmd_len_wifidirect += sizeof(wifidirect_oui); + } + /* Parse file and process */ + while (config_get_line(line, MAX_CONFIG_LINE, config_file, &li, &pos)) { + arg_num = parse_line(line, args, MAX_ARGS_NUM); + if (!cmd_found && strncmp(args[0], cmd_name, strlen(args[0]))) + continue; + cmd_found = 1; + if (strcmp(args[0], "wifidirect_config") == 0) { + wifidirect_level = WIFIDIRECT_PARAMS_CONFIG; + } else if (strcmp(args[0], "Capability") == 0) { + wifidirect_level = WIFIDIRECT_CAPABILITY_CONFIG; + } else if (strcmp(args[0], "GroupOwnerIntent") == 0) { + wifidirect_level = WIFIDIRECT_GROUP_OWNER_INTENT_CONFIG; + } else if (strcmp(args[0], "Channel") == 0) { + wifidirect_level = WIFIDIRECT_CHANNEL_CONFIG; + } else if (strcmp(args[0], "OperatingChannel") == 0) { + wifidirect_level = WIFIDIRECT_OPCHANNEL_CONFIG; + } else if (strcmp(args[0], "InfrastructureManageabilityInfo") == + 0) { + wifidirect_level = WIFIDIRECT_MANAGEABILITY_CONFIG; + } else if (strcmp(args[0], "InvitationFlagBitmap") == 0) { + wifidirect_level = WIFIDIRECT_INVITATION_FLAG_CONFIG; + } else if (strcmp(args[0], "ChannelList") == 0) { + wifidirect_level = WIFIDIRECT_CHANNEL_LIST_CONFIG; + } else if (strcmp(args[0], "NoticeOfAbsence") == 0) { + wifidirect_level = WIFIDIRECT_NOTICE_OF_ABSENCE; + } else if (strcmp(args[0], "NoA_descriptor") == 0) { + wifidirect_level = WIFIDIRECT_NOA_DESCRIPTOR; + } else if (strcmp(args[0], "DeviceInfo") == 0) { + wifidirect_level = WIFIDIRECT_DEVICE_INFO_CONFIG; + } else if (strcmp(args[0], "SecondaryDeviceType") == 0) { + wifidirect_level = WIFIDIRECT_DEVICE_SEC_INFO_CONFIG; + } else if (strcmp(args[0], "GroupInfo") == 0) { + wifidirect_level = WIFIDIRECT_GROUP_INFO_CONFIG; + } else if (strcmp(args[0], "GroupSecondaryDeviceTypes") == 0) { + wifidirect_level = WIFIDIRECT_GROUP_SEC_INFO_CONFIG; + } else if (strcmp(args[0], "GroupWifiDirectDeviceTypes") == 0) { + wifidirect_level = WIFIDIRECT_GROUP_CLIENT_INFO_CONFIG; + } else if (strcmp(args[0], "GroupId") == 0) { + wifidirect_level = WIFIDIRECT_GROUP_ID_CONFIG; + } else if (strcmp(args[0], "GroupBSSId") == 0) { + wifidirect_level = WIFIDIRECT_GROUP_BSS_ID_CONFIG; + } else if (strcmp(args[0], "DeviceId") == 0) { + wifidirect_level = WIFIDIRECT_DEVICE_ID_CONFIG; + } else if (strcmp(args[0], "Interface") == 0) { + wifidirect_level = WIFIDIRECT_INTERFACE_CONFIG; + } else if (strcmp(args[0], "ConfigurationTimeout") == 0) { + wifidirect_level = WIFIDIRECT_TIMEOUT_CONFIG; + } else if (strcmp(args[0], "ExtendedListenTime") == 0) { + wifidirect_level = WIFIDIRECT_EXTENDED_TIME_CONFIG; + } else if (strcmp(args[0], "IntendedIntfAddress") == 0) { + wifidirect_level = WIFIDIRECT_INTENDED_ADDR_CONFIG; + } else if (strcmp(args[0], "WPSIE") == 0) { + wifidirect_level = WIFIDIRECT_WPSIE; + } else if (strcmp(args[0], "Extra") == 0) { + wifidirect_level = WIFIDIRECT_EXTRA; + } else if (strcmp(args[0], "WIFIDIRECT_MAC") == 0 || + strcmp(args[0], "GroupAddr") == 0 || + strcmp(args[0], "GroupBssId") == 0 || + strcmp(args[0], "InterfaceAddress") == 0 || + strcmp(args[0], "GroupInterfaceAddress") == 0 || + strcmp(args[0], "DeviceAddress") == 0) { + strncpy(wifidirect_mac, args[1], 20 - 1); + if ((ret = + mac2raw(wifidirect_mac, dev_address)) != SUCCESS) { + printf("ERR: %s Address \n", + ret == FAILURE ? "Invalid MAC" : ret == + WIFIDIRECT_RET_MAC_BROADCAST ? + "Broadcast" : "Multicast"); + goto done; + } + } else if (strncmp(args[0], "GroupWifiDirectDeviceAddress", 21) + == 0) { + strncpy(wifidirect_mac, args[1], 20 - 1); + if ((ret = + mac2raw(wifidirect_mac, + group_dev_address)) != SUCCESS) { + printf("ERR: %s Address \n", + ret == FAILURE ? "Invalid MAC" : ret == + WIFIDIRECT_RET_MAC_BROADCAST ? + "Broadcast" : "Multicast"); + goto done; + } + wifidirect_client_dev_index++; + if (wifidirect_client_dev_index > + wifidirect_client_dev_count) { + printf("ERR: No of Client Dev count is less than no of client dev configs!!\n"); + goto done; + } + group_secondary_index = 0; + tlv_offset = + wifidirect_group_total_ssid_len + + wifidirect_total_secondary_dev_count * + WPS_DEVICE_TYPE_LEN; + memcpy(wifidirect_client_dev_info_list + [wifidirect_client_dev_index - + 1].wifidirect_dev_address + tlv_offset, + group_dev_address, ETH_ALEN); + } else if (strncmp(args[0], "GroupWifiDirectIntfAddress", 19) == + 0) { + strncpy(wifidirect_mac, args[1], 20 - 1); + if ((ret = + mac2raw(wifidirect_mac, + group_dev_address)) != SUCCESS) { + printf("ERR: %s Address \n", + ret == FAILURE ? "Invalid MAC" : ret == + WIFIDIRECT_RET_MAC_BROADCAST ? + "Broadcast" : "Multicast"); + goto done; + } + memcpy(wifidirect_client_dev_info_list + [wifidirect_client_dev_index - + 1].wifidirect_intf_address + tlv_offset, + group_dev_address, ETH_ALEN); + } else if (strncmp(args[0], "GroupWifiDirectDeviceCapab", 19) == + 0) { + if (is_input_valid + (WIFIDIRECT_DEVICECAPABILITY, arg_num - 1, + args + 1) != SUCCESS) { + goto done; + } + temp8 = (t_u8)atoi(args[1]); + memcpy(&wifidirect_client_dev_info_list + [wifidirect_client_dev_index - + 1].wifidirect_dev_capability + tlv_offset, + &temp8, sizeof(temp8)); + } else if (strncmp + (args[0], "GroupWifiDirectWPSConfigMethods", + 24) == 0) { + if (is_input_valid + (WIFIDIRECT_WPSCONFMETHODS, arg_num - 1, + args + 1) != SUCCESS) { + goto done; + } + temp16 = (t_u16)A2HEXDECIMAL(args[1]); + memcpy(&wifidirect_client_dev_info_list + [wifidirect_client_dev_index - + 1].config_methods + tlv_offset, &temp16, + sizeof(temp16)); + (t_u16)A2HEXDECIMAL(args[1]); + } else if (strncmp + (args[0], "GroupPrimaryDeviceTypeCategory", + 30) == 0) { + if (is_input_valid + (WIFIDIRECT_PRIDEVTYPECATEGORY, arg_num - 1, + args + 1) != SUCCESS) { + goto done; + } + pri_category = (t_u16)atoi(args[1]); + temp16 = htons(pri_category); + memcpy(&wifidirect_client_dev_info_list + [wifidirect_client_dev_index - + 1].primary_category + tlv_offset, &temp16, + sizeof(temp16)); + } else if (strncmp(args[0], "GroupPrimaryDeviceTypeOUI", 25) == + 0) { + if (is_input_valid + (WIFIDIRECT_PRIDEVTYPEOUI, arg_num - 1, + args + 1) != SUCCESS) { + goto done; + } + for (i = 0; i < 4; i++) { + temp8 = (t_u8)A2HEXDECIMAL(args[i + 1]); + memcpy(&wifidirect_client_dev_info_list + [wifidirect_client_dev_index - + 1].primary_oui[i] + + tlv_offset, &temp8, sizeof(temp8)); + } + } else if (strncmp + (args[0], "GroupPrimaryDeviceTypeSubCategory", + 33) == 0) { + if (is_input_valid + (WIFIDIRECT_PRIDEVTYPESUBCATEGORY, arg_num - 1, + args + 1) != SUCCESS) { + goto done; + } + pri_sub_category = (t_u16)atoi(args[1]); + temp16 = htons(pri_sub_category); + memcpy(&wifidirect_client_dev_info_list + [wifidirect_client_dev_index - + 1].primary_subcategory + tlv_offset, &temp16, + sizeof(temp16)); + } else if (strncmp(args[0], "GroupSecondaryDeviceCount", 25) == + 0) { + if (is_input_valid + (WIFIDIRECT_GROUP_SECONDARYDEVCOUNT, arg_num - 1, + args + 1) != SUCCESS) { + goto done; + } + group_secondary_dev_count = (t_u8)atoi(args[1]); + memcpy(&wifidirect_client_dev_info_list + [wifidirect_client_dev_index - + 1].wifidirect_secondary_dev_count + tlv_offset, + &group_secondary_dev_count, + sizeof(group_secondary_dev_count)); + wifidirect_total_secondary_dev_count += + group_secondary_dev_count; + if (group_secondary_dev_count) + memset(group_secondary_dev_info, 0, + sizeof(group_secondary_dev_info)); + } else if (strncmp + (args[0], "GroupSecondaryDeviceTypeCategory", + 30) == 0) { + if (is_input_valid + (WIFIDIRECT_PRIDEVTYPECATEGORY, arg_num - 1, + args + 1) != SUCCESS) { + goto done; + } + sec_category = (t_u16)atoi(args[1]); + group_sec_category = cpu_to_le16(sec_category); + group_secondary_index++; + } else if (strncmp(args[0], "GroupSecondaryDeviceTypeOUI", 27) + == 0) { + if (is_input_valid + (WIFIDIRECT_PRIDEVTYPEOUI, arg_num - 1, + args + 1) != SUCCESS) { + goto done; + } + for (i = 0; i < 4; i++) + group_secondary_oui[i] = + (t_u8)A2HEXDECIMAL(args[i + 1]); + } else if (strncmp + (args[0], "GroupSecondaryDeviceTypeSubCategory", + 35) == 0) { + if (is_input_valid + (WIFIDIRECT_PRIDEVTYPESUBCATEGORY, arg_num - 1, + args + 1) != SUCCESS) { + goto done; + } + if (group_secondary_index < 0 || + group_secondary_index >= + MAX_SECONDARY_DEVICE_COUNT) { + printf("Error in configuration file %s:%d", + file_name, li); + goto done; + } + sec_sub_category = (t_u16)atoi(args[1]); + group_sec_sub_category = + cpu_to_le16(group_sec_sub_category); + if (group_secondary_dev_count) { + memcpy(&group_secondary_dev_info + [(group_secondary_index - + 1) * WPS_DEVICE_TYPE_LEN], + &group_sec_category, sizeof(t_u16)); + memcpy(&group_secondary_dev_info + [((group_secondary_index - + 1) * WPS_DEVICE_TYPE_LEN) + 2], + group_secondary_oui, + sizeof(secondary_oui)); + memcpy(&group_secondary_dev_info + [((group_secondary_index - + 1) * WPS_DEVICE_TYPE_LEN) + 6], + &group_sec_sub_category, sizeof(t_u16)); + } + + } else if (strncmp(args[0], "GroupWifiDirectDeviceCount", 19) == + 0) { + if (is_input_valid + (WIFIDIRECT_SECONDARYDEVCOUNT, arg_num - 1, + args + 1) != SUCCESS) { + goto done; + } + wifidirect_client_dev_count = (t_u8)atoi(args[1]); + } else if (strncmp(args[0], "GroupWifiDirectDeviceName", 18) == + 0) { + + if (is_input_valid + (WIFIDIRECT_GROUP_WIFIDIRECT_DEVICE_NAME, + arg_num - 1, args + 1) != SUCCESS) { + goto done; + } + + strncpy(wifi_group_direct_ssid, args[1] + 1, + strlen(args[1]) - 2); + wifi_group_direct_ssid[strlen(args[1]) - 2] = '\0'; + temp = htons(SC_Device_Name); + memcpy(((t_u8 *) + &wifidirect_client_dev_info_list + [wifidirect_client_dev_index - + 1].wifidirect_device_name_type + tlv_offset), + &temp, sizeof(temp)); + temp = htons(strlen(wifi_group_direct_ssid)); + memcpy(((t_u8 *) + &wifidirect_client_dev_info_list + [wifidirect_client_dev_index - + 1].wifidirect_device_name_len + tlv_offset), + &temp, sizeof(temp)); + memset(((t_u8 *) + &wifidirect_client_dev_info_list + [wifidirect_client_dev_index - + 1].wifidirect_device_name + tlv_offset), 0, + strlen(wifi_group_direct_ssid)); + memcpy(((t_u8 *) + &wifidirect_client_dev_info_list + [wifidirect_client_dev_index - + 1].wifidirect_device_name + tlv_offset), + &wifi_group_direct_ssid, + strlen(wifi_group_direct_ssid)); + wifidirect_group_total_ssid_len += + strlen(wifi_group_direct_ssid); + + if (wifidirect_client_dev_index - 1) { + temp_dev_size = + sizeof(wifidirect_client_dev_info) + + strlen(wifi_group_direct_ssid) + + group_secondary_dev_count * + WPS_DEVICE_TYPE_LEN; + memcpy(&wifidirect_client_dev_info_list + [wifidirect_client_dev_index - + 1].dev_length + (tlv_offset - + (group_secondary_dev_count + * + WPS_DEVICE_TYPE_LEN)), + &temp_dev_size, sizeof(temp_dev_size)); + } else { + + temp_dev_size = + sizeof(wifidirect_client_dev_info) + + strlen(wifi_group_direct_ssid) + + group_secondary_dev_count * + WPS_DEVICE_TYPE_LEN; + wifidirect_client_dev_info_list + [wifidirect_client_dev_index - + 1].dev_length = + sizeof(wifidirect_client_dev_info) + + strlen(wifi_group_direct_ssid) + + group_secondary_dev_count * + WPS_DEVICE_TYPE_LEN; + } + } else if (strcmp(args[0], "DeviceCapability") == 0) { + if (is_input_valid + (WIFIDIRECT_DEVICECAPABILITY, arg_num - 1, + args + 1) != SUCCESS) { + goto done; + } + dev_capability = (t_u8)atoi(args[1]); + } else if (strcmp(args[0], "GroupCapability") == 0) { + if (is_input_valid + (WIFIDIRECT_GROUPCAPABILITY, arg_num - 1, + args + 1) != SUCCESS) { + goto done; + } + group_capability = (t_u8)atoi(args[1]); + } else if (strcmp(args[0], "Intent") == 0) { + /* Intent -> 0 - 15 */ + if (is_input_valid + (WIFIDIRECT_INTENT, arg_num - 1, + args + 1) != SUCCESS) { + goto done; + } + group_owner_intent = (t_u8)atoi(args[1]); + } else if (strcmp(args[0], "RegulatoryClass") == 0) { + if (is_input_valid + (WIFIDIRECT_REGULATORYCLASS, arg_num - 1, + args + 1) != SUCCESS) { + goto done; + } + regulatory_class = (t_u8)atoi(args[1]); + } else if (strcmp(args[0], "ChannelNumber") == 0) { + if (is_input_valid(CHANNEL, arg_num - 1, args + 1) != + SUCCESS) { + goto done; + } + channel_number = (t_u8)atoi(args[1]); + } else if (strcmp(args[0], "OpRegulatoryClass") == 0) { + if (is_input_valid + (WIFIDIRECT_REGULATORYCLASS, arg_num - 1, + args + 1) != SUCCESS) { + goto done; + } + op_regulatory_class = (t_u8)atoi(args[1]); + } else if (strcmp(args[0], "OpChannelNumber") == 0) { + if (is_input_valid(CHANNEL, arg_num - 1, args + 1) != + SUCCESS) { + goto done; + } + op_channel_number = (t_u8)atoi(args[1]); + } else if (strcmp(args[0], "Manageability") == 0) { + if (is_input_valid + (WIFIDIRECT_MANAGEABILITY, arg_num - 1, args + 1) + != SUCCESS) { + goto done; + } + manageability = (t_u8)atoi(args[1]); + } else if (strcmp(args[0], "InvitationFlag") == 0) { + if (is_input_valid + (WIFIDIRECT_INVITATIONFLAG, arg_num - 1, args + 1) + != SUCCESS) { + goto done; + } + invitation_flag = (t_u8)atoi(args[1]); + } else if (strcmp(args[0], "CountryString") == 0) { + if (is_input_valid + (WIFIDIRECT_COUNTRY, arg_num - 1, + args + 1) != SUCCESS) { + goto done; + } + strncpy(country, args[1] + 1, 3); + country[strlen(args[1]) - 2] = '\0'; + } else if (strncmp(args[0], "Regulatory_Class_", 17) == 0) { + if (is_input_valid + (WIFIDIRECT_REGULATORYCLASS, arg_num - 1, + args + 1) != SUCCESS) { + goto done; + } + if (!no_of_chan_entries) { + chan_entry_list = + (t_u8 *)malloc(MAX_BUFFER_SIZE); + if (!chan_entry_list) { + printf("ERR:cannot allocate memory for chan_entry_list!\n"); + goto done; + } + memset(chan_entry_list, 0, MAX_BUFFER_SIZE); + chan_buf = chan_entry_list; + } + no_of_chan_entries++; + chan_entry_regulatory_class = (t_u8)atoi(args[1]); + } else if (strncmp(args[0], "NumofChannels", 13) == 0) { + if (is_input_valid + (WIFIDIRECT_NO_OF_CHANNELS, arg_num - 1, + args + 1) != SUCCESS) { + goto done; + } + chan_entry_num_of_channels = (t_u8)atoi(args[1]); + } else if (strncmp(args[0], "ChanList", 8) == 0) { + if (chan_entry_num_of_channels != (arg_num - 1)) { + printf("ERR:no of channels in ChanList and NumofChannels do not match!\n"); + goto done; + } + if (is_input_valid(SCANCHANNELS, arg_num - 1, args + 1) + != SUCCESS) { + goto done; + } + for (i = 0; i < chan_entry_num_of_channels; i++) + dev_channels[i] = (t_u8)atoi(args[i + 1]); + total_chan_len += chan_entry_num_of_channels; + memcpy(chan_buf, &chan_entry_regulatory_class, + sizeof(t_u8)); + memcpy(chan_buf + 1, &chan_entry_num_of_channels, + sizeof(t_u8)); + memcpy(chan_buf + 2, dev_channels, + chan_entry_num_of_channels); + chan_buf += + sizeof(t_u8) + sizeof(t_u8) + + chan_entry_num_of_channels; + } else if (strcmp(args[0], "NoA_Index") == 0) { + if (is_input_valid + (WIFIDIRECT_NOA_INDEX, arg_num - 1, + args + 1) != SUCCESS) { + goto done; + } + noa_index = (t_u8)atoi(args[1]); + } else if (strcmp(args[0], "OppPS") == 0) { + if (is_input_valid + (WIFIDIRECT_OPP_PS, arg_num - 1, + args + 1) != SUCCESS) { + goto done; + } + opp_ps = (t_u8)atoi(args[1]); + } else if (strcmp(args[0], "CTWindow") == 0) { + if (is_input_valid + (WIFIDIRECT_CTWINDOW, arg_num - 1, + args + 1) != SUCCESS) { + goto done; + } + if ((opp_ps != 0) && (atoi(args[1]) < 10)) { + printf("ERR: CTwindow should be greater than or equal to 10 if opp_ps is set!\n"); + goto done; + } + ctwindow_opp_ps = + (t_u8)atoi(args[1]) | SET_OPP_PS(opp_ps); + } else if (strncmp(args[0], "CountType", 9) == 0) { + if (is_input_valid + (WIFIDIRECT_COUNT_TYPE, arg_num - 1, + args + 1) != SUCCESS) { + goto done; + } + no_of_noa++; + if (no_of_noa > MAX_NOA_DESCRIPTORS) { + printf("Number of descriptors should not be greater than %d\n", MAX_NOA_DESCRIPTORS); + goto done; + } + count_type = (t_u8)atoi(args[1]); + noa_descriptor_list[no_of_noa - 1].count_type = + count_type; + } else if (strncmp(args[0], "Duration", 8) == 0) { + if (is_input_valid + (WIFIDIRECT_DURATION, arg_num - 1, + args + 1) != SUCCESS) { + goto done; + } + duration = (t_u32)atoi(args[1]); + duration = cpu_to_le32(duration); + noa_descriptor_list[no_of_noa - 1].duration = duration; + } else if (strncmp(args[0], "Interval", 8) == 0) { + if (is_input_valid + (WIFIDIRECT_INTERVAL, arg_num - 1, + args + 1) != SUCCESS) { + goto done; + } + interval = (t_u32)atoi(args[1]); + interval = cpu_to_le32(interval); + noa_descriptor_list[no_of_noa - 1].interval = interval; + } else if (strncmp(args[0], "StartTime", 9) == 0) { + if (is_input_valid + (WIFIDIRECT_START_TIME, arg_num - 1, + args + 1) != SUCCESS) { + goto done; + } + start_time = (t_u32)atoi(args[1]); + start_time = cpu_to_le32(start_time); + noa_descriptor_list[no_of_noa - 1].start_time = + start_time; + } else if (strcmp(args[0], "PrimaryDeviceTypeCategory") == 0) { + if (is_input_valid + (WIFIDIRECT_PRIDEVTYPECATEGORY, arg_num - 1, + args + 1) != SUCCESS) { + goto done; + } + pri_category = (t_u16)atoi(args[1]); + } else if (strcmp(args[0], "PrimaryDeviceTypeOUI") == 0) { + if (is_input_valid + (WIFIDIRECT_PRIDEVTYPEOUI, arg_num - 1, + args + 1) != SUCCESS) { + goto done; + } + for (i = 0; i < 4; i++) + primary_oui[i] = + (t_u8)A2HEXDECIMAL(args[i + 1]); + } else if (strcmp(args[0], "PrimaryDeviceTypeSubCategory") == 0) { + if (is_input_valid + (WIFIDIRECT_PRIDEVTYPESUBCATEGORY, arg_num - 1, + args + 1) != SUCCESS) { + goto done; + } + pri_sub_category = (t_u16)atoi(args[1]); + } else if (strcmp(args[0], "SecondaryDeviceCount") == 0) { + if (is_input_valid + (WIFIDIRECT_SECONDARYDEVCOUNT, arg_num - 1, + args + 1) != SUCCESS) { + goto done; + } + secondary_dev_count = (t_u8)atoi(args[1]); + if (secondary_dev_count) + memset(secondary_dev_info, 0, + sizeof(secondary_dev_info)); + } else if (strncmp(args[0], "SecondaryDeviceTypeCategory", 27) + == 0) { + if (is_input_valid + (WIFIDIRECT_PRIDEVTYPECATEGORY, arg_num - 1, + args + 1) != SUCCESS) { + goto done; + } + sec_category = (t_u16)atoi(args[1]); + sec_category = htons(sec_category); + secondary_index++; + } else if (strncmp(args[0], "SecondaryDeviceTypeOUI", 22) == 0) { + if (is_input_valid + (WIFIDIRECT_PRIDEVTYPEOUI, arg_num - 1, + args + 1) != SUCCESS) { + goto done; + } + for (i = 0; i < 4; i++) + secondary_oui[i] = + (t_u8)A2HEXDECIMAL(args[i + 1]); + } else if (strncmp + (args[0], "SecondaryDeviceTypeSubCategory", + 30) == 0) { + if (is_input_valid + (WIFIDIRECT_PRIDEVTYPESUBCATEGORY, arg_num - 1, + args + 1) != SUCCESS) { + goto done; + } + if (secondary_index < 0 || + secondary_index >= MAX_SECONDARY_DEVICE_COUNT) { + printf("Error in configuration file %s:%d", + file_name, li); + goto done; + } + sec_sub_category = (t_u16)atoi(args[1]); + sec_sub_category = htons(sec_sub_category); + if (secondary_dev_count) { + memcpy(&secondary_dev_info + [secondary_index * WPS_DEVICE_TYPE_LEN], + &sec_category, sizeof(t_u16)); + memcpy(&secondary_dev_info + [(secondary_index * + WPS_DEVICE_TYPE_LEN) + 2], + secondary_oui, sizeof(secondary_oui)); + memcpy(&secondary_dev_info + [(secondary_index * + WPS_DEVICE_TYPE_LEN) + 6], + &sec_sub_category, sizeof(t_u16)); + } + } else if (strcmp(args[0], "InterfaceAddressCount") == 0) { + if (is_input_valid + (WIFIDIRECT_INTERFACECOUNT, arg_num - 1, + args + 1) != SUCCESS) { + goto done; + } + iface_count = (t_u8)atoi(args[1]); + } else if (strcmp(args[0], "InterfaceAddressList") == 0) { + if (iface_count != (arg_num - 1)) { + printf("Incorrect address list for %d entries.\n", iface_count); + goto done; + } + for (i = 0; + i < iface_count && i < MAX_INTERFACE_ADDR_COUNT; + i++) { + if ((ret = + mac2raw(args[i + 1], + &iface_list[i * ETH_ALEN])) != + SUCCESS) { + printf("ERR: %s Address \n", + ret == + FAILURE ? "Invalid MAC" : ret == + WIFIDIRECT_RET_MAC_BROADCAST ? + "Broadcast" : "Multicast"); + goto done; + } + } + } else if (strcmp(args[0], "GroupConfigurationTimeout") == 0) { + if (is_input_valid + (WIFIDIRECT_ATTR_CONFIG_TIMEOUT, arg_num - 1, + args + 1) != SUCCESS) { + goto done; + } + go_config_timeout = (t_u8)atoi(args[1]); + } else if (strcmp(args[0], "ClientConfigurationTimeout") == 0) { + if (is_input_valid + (WIFIDIRECT_ATTR_CONFIG_TIMEOUT, arg_num - 1, + args + 1) != SUCCESS) { + goto done; + } + client_config_timeout = (t_u8)atoi(args[1]); + } else if (strcmp(args[0], "AvailabilityPeriod") == 0) { + if (is_input_valid + (WIFIDIRECT_ATTR_EXTENDED_TIME, arg_num - 1, + args + 1) != SUCCESS) { + goto done; + } + avail_period = (t_u16)atoi(args[1]); + } else if (strcmp(args[0], "AvailabilityInterval") == 0) { + if (is_input_valid + (WIFIDIRECT_ATTR_EXTENDED_TIME, arg_num - 1, + args + 1) != SUCCESS) { + goto done; + } + avail_interval = (t_u16)atoi(args[1]); + } else if (strcmp(args[0], "WPSConfigMethods") == 0) { + if (is_input_valid + (WIFIDIRECT_WPSCONFMETHODS, arg_num - 1, + args + 1) != SUCCESS) { + goto done; + } + config_methods = (t_u16)A2HEXDECIMAL(args[1]); + } else if (strcmp(args[0], "DeviceName") == 0 || + strcmp(args[0], "GroupSsId") == 0) { + if (is_input_valid + (WIFIDIRECT_WPSDEVICENAME, arg_num - 1, + args + 1) != SUCCESS) { + goto done; + } + memset(wifidirect_ssid, 0, sizeof(wifidirect_ssid)); + strncpy(wifidirect_ssid, args[1], + sizeof(wifidirect_ssid) - 1); + } else if (strcmp(args[0], "WPSVersion") == 0) { + if (is_input_valid + (WIFIDIRECT_WPSVERSION, arg_num - 1, + args + 1) != SUCCESS) { + goto done; + } + WPS_version = (t_u8)A2HEXDECIMAL(args[1]); + } else if (strcmp(args[0], "WPSSetupState") == 0) { + if (is_input_valid + (WIFIDIRECT_WPSSETUPSTATE, arg_num - 1, + args + 1) != SUCCESS) { + goto done; + } + WPS_setupstate = (t_u8)A2HEXDECIMAL(args[1]); + } else if (strcmp(args[0], "WPSDeviceName") == 0) { + if (is_input_valid + (WIFIDIRECT_WPSDEVICENAME, arg_num - 1, + args + 1) != SUCCESS) { + goto done; + } + memset(WPS_devicename, 0, sizeof(WPS_devicename)); + strncpy(WPS_devicename, args[1], + sizeof(WPS_devicename) - 1); + } else if (strcmp(args[0], "WPSRequestType") == 0) { + if (is_input_valid + (WIFIDIRECT_WPSREQRESPTYPE, arg_num - 1, + args + 1) != SUCCESS) { + goto done; + } + WPS_requesttype = (t_u8)A2HEXDECIMAL(args[1]); + } else if (strcmp(args[0], "WPSResponseType") == 0) { + if (is_input_valid + (WIFIDIRECT_WPSREQRESPTYPE, arg_num - 1, + args + 1) != SUCCESS) { + goto done; + } + WPS_responsetype = (t_u8)A2HEXDECIMAL(args[1]); + } else if (strcmp(args[0], "WPSSpecConfigMethods") == 0) { + if (is_input_valid + (WIFIDIRECT_WPSSPECCONFMETHODS, arg_num - 1, + args + 1) != SUCCESS) { + goto done; + } + WPS_specconfigmethods = (t_u16)A2HEXDECIMAL(args[1]); + } else if (strcmp(args[0], "WPSUUID") == 0) { + if (is_input_valid + (WIFIDIRECT_WPSUUID, arg_num - 1, + args + 1) != SUCCESS) { + goto done; + } + for (i = 0; i < WPS_UUID_MAX_LEN; i++) + WPS_UUID[i] = (t_u8)A2HEXDECIMAL(args[i + 1]); + } else if (strcmp(args[0], "WPSPrimaryDeviceType") == 0) { + if (is_input_valid + (WIFIDIRECT_WPSPRIMARYDEVICETYPE, arg_num - 1, + args + 1) != SUCCESS) { + goto done; + } + for (i = 0; i < WPS_DEVICE_TYPE_MAX_LEN; i++) + WPS_primarydevicetype[i] = + (t_u8)A2HEXDECIMAL(args[i + 1]); + } else if (strcmp(args[0], "WPSRFBand") == 0) { + if (is_input_valid + (WIFIDIRECT_WPSRFBAND, arg_num - 1, + args + 1) != SUCCESS) { + goto done; + } + WPS_RFband = (t_u8)A2HEXDECIMAL(args[1]); + } else if (strcmp(args[0], "WPSAssociationState") == 0) { + if (is_input_valid + (WIFIDIRECT_WPSASSOCIATIONSTATE, arg_num - 1, + args + 1) != SUCCESS) { + goto done; + } + WPS_associationstate = (t_u16)A2HEXDECIMAL(args[1]); + } else if (strcmp(args[0], "WPSConfigurationError") == 0) { + if (is_input_valid + (WIFIDIRECT_WPSCONFIGURATIONERROR, arg_num - 1, + args + 1) != SUCCESS) { + goto done; + } + WPS_configurationerror = (t_u16)A2HEXDECIMAL(args[1]); + } else if (strcmp(args[0], "WPSDevicePassword") == 0) { + if (is_input_valid + (WIFIDIRECT_WPSDEVICEPASSWORD, arg_num - 1, + args + 1) != SUCCESS) { + goto done; + } + WPS_devicepassword = (t_u16)A2HEXDECIMAL(args[1]); + } else if (strcmp(args[0], "WPSManufacturer") == 0) { + if (is_input_valid + (WIFIDIRECT_WPSMANUFACTURER, arg_num - 1, + args + 1) != SUCCESS) { + goto done; + } + memset(WPS_manufacturer, 0, sizeof(WPS_manufacturer)); + strncpy(WPS_manufacturer, args[1], + sizeof(WPS_manufacturer)); + } else if (strcmp(args[0], "WPSModelName") == 0) { + if (is_input_valid + (WIFIDIRECT_WPSMODELNAME, arg_num - 1, + args + 1) != SUCCESS) { + goto done; + } + memset(WPS_modelname, 0, sizeof(WPS_modelname)); + strncpy(WPS_modelname, args[1], sizeof(WPS_modelname)); + } else if (strcmp(args[0], "WPSModelNumber") == 0) { + if (is_input_valid + (WIFIDIRECT_WPSMODELNUMBER, arg_num - 1, + args + 1) != SUCCESS) { + goto done; + } + for (i = 0; i < arg_num - 1; i++) + WPS_modelnumber[i] = + (t_u8)A2HEXDECIMAL(args[i + 1]); + wps_model_len = arg_num - 1; + } else if (strcmp(args[0], "WPSSerialNumber") == 0) { + if (is_input_valid + (WIFIDIRECT_WPSSERIALNUMBER, arg_num - 1, + args + 1) != SUCCESS) { + goto done; + } + for (i = 0; i < arg_num - 1; i++) + WPS_serialnumber[i] = + (t_u8)A2HEXDECIMAL(args[i + 1]); + wps_serial_len = arg_num - 1; + } else if (strcmp(args[0], "WPSVendorExtension") == 0) { + for (i = 0; i < arg_num - 1; i++) + WPS_VendorExt[i] = + (t_u8)A2HEXDECIMAL(args[i + 1]); + wps_vendor_len = arg_num - 1; + } else if (strcmp(args[0], "Buffer") == 0) { + for (i = 0; i < arg_num - 1; i++) + extra[i] = (t_u8)A2HEXDECIMAL(args[i + 1]); + extra_len = arg_num - 1; + } else if (strcmp(args[0], "}") == 0) { + /* Based on level, populate appropriate struct */ + switch (wifidirect_level) { + case WIFIDIRECT_DEVICE_ID_CONFIG: + { + tlvbuf_wifidirect_device_id *tlv = NULL; + /* Append a new TLV */ + tlv_len = + sizeof + (tlvbuf_wifidirect_device_id); + tlv = (tlvbuf_wifidirect_device_id + *)(buffer + cmd_len_wifidirect); + cmd_len_wifidirect += tlv_len; + /* Set TLV fields */ + tlv->tag = + TLV_TYPE_WIFIDIRECT_DEVICE_ID; + tlv->length = + tlv_len - (sizeof(t_u8) + + sizeof(t_u16)); + memcpy(tlv->dev_mac_address, + dev_address, ETH_ALEN); + endian_convert_tlv_wifidirect_header_out + (tlv); + break; + } + case WIFIDIRECT_CAPABILITY_CONFIG: + { + tlvbuf_wifidirect_capability *tlv = + NULL; + /* Append a new TLV */ + tlv_len = + sizeof + (tlvbuf_wifidirect_capability); + tlv = (tlvbuf_wifidirect_capability + *)(buffer + cmd_len_wifidirect); + cmd_len_wifidirect += tlv_len; + /* Set TLV fields */ + tlv->tag = + TLV_TYPE_WIFIDIRECT_CAPABILITY; + tlv->length = + tlv_len - (sizeof(t_u8) + + sizeof(t_u16)); + tlv->dev_capability = dev_capability; + tlv->group_capability = + group_capability; + endian_convert_tlv_wifidirect_header_out + (tlv); + break; + } + case WIFIDIRECT_GROUP_OWNER_INTENT_CONFIG: + { + tlvbuf_wifidirect_group_owner_intent + *tlv = NULL; + /* Append a new TLV */ + tlv_len = + sizeof + (tlvbuf_wifidirect_group_owner_intent); + tlv = (tlvbuf_wifidirect_group_owner_intent *)(buffer + cmd_len_wifidirect); + cmd_len_wifidirect += tlv_len; + /* Set TLV fields */ + tlv->tag = + TLV_TYPE_WIFIDIRECT_GROUPOWNER_INTENT; + tlv->length = + tlv_len - (sizeof(t_u8) + + sizeof(t_u16)); + tlv->dev_intent = group_owner_intent; + endian_convert_tlv_wifidirect_header_out + (tlv); + break; + } + case WIFIDIRECT_MANAGEABILITY_CONFIG: + { + tlvbuf_wifidirect_manageability *tlv = + NULL; + /* Append a new TLV */ + tlv_len = + sizeof + (tlvbuf_wifidirect_manageability); + tlv = (tlvbuf_wifidirect_manageability + *)(buffer + cmd_len_wifidirect); + cmd_len_wifidirect += tlv_len; + /* Set TLV fields */ + tlv->tag = + TLV_TYPE_WIFIDIRECT_MANAGEABILITY; + tlv->length = + tlv_len - (sizeof(t_u8) + + sizeof(t_u16)); + tlv->manageability = manageability; + endian_convert_tlv_wifidirect_header_out + (tlv); + break; + } + case WIFIDIRECT_INVITATION_FLAG_CONFIG: + { + tlvbuf_wifidirect_invitation_flag *tlv = + NULL; + /* Append a new TLV */ + tlv_len = + sizeof + (tlvbuf_wifidirect_invitation_flag); + tlv = (tlvbuf_wifidirect_invitation_flag + *)(buffer + cmd_len_wifidirect); + cmd_len_wifidirect += tlv_len; + /* Set TLV fields */ + tlv->tag = + TLV_TYPE_WIFIDIRECT_INVITATION_FLAG; + tlv->length = + tlv_len - (sizeof(t_u8) + + sizeof(t_u16)); + tlv->invitation_flag |= invitation_flag; + endian_convert_tlv_wifidirect_header_out + (tlv); + break; + } + case WIFIDIRECT_CHANNEL_LIST_CONFIG: + { + tlvbuf_wifidirect_channel_list *tlv = + NULL; + /* Append a new TLV */ + tlv_len = + sizeof + (tlvbuf_wifidirect_channel_list) + + + no_of_chan_entries * + sizeof(chan_entry) + + total_chan_len; + tlv = (tlvbuf_wifidirect_channel_list + *)(buffer + cmd_len_wifidirect); + cmd_len_wifidirect += tlv_len; + /* Set TLV fields */ + tlv->tag = + TLV_TYPE_WIFIDIRECT_CHANNEL_LIST; + tlv->length = + tlv_len - (sizeof(t_u8) + + sizeof(t_u16)); + memcpy(tlv->country_string, country, 3); + if (tlv->country_string[2] == 0) + tlv->country_string[2] = + WIFIDIRECT_COUNTRY_LAST_BYTE; + memcpy(tlv->wifidirect_chan_entry_list, + chan_entry_list, + (tlv->length - 3)); + endian_convert_tlv_wifidirect_header_out + (tlv); + break; + } + case WIFIDIRECT_NOTICE_OF_ABSENCE: + { + tlvbuf_wifidirect_notice_of_absence *tlv + = NULL; + /* Append a new TLV */ + tlv_len = + sizeof + (tlvbuf_wifidirect_notice_of_absence) + + + no_of_noa * + sizeof(noa_descriptor); + tlv = (tlvbuf_wifidirect_notice_of_absence *)(buffer + cmd_len_wifidirect); + cmd_len_wifidirect += tlv_len; + /* Set TLV fields */ + tlv->tag = + TLV_TYPE_WIFIDIRECT_NOTICE_OF_ABSENCE; + tlv->length = + tlv_len - (sizeof(t_u8) + + sizeof(t_u16)); + tlv->noa_index = noa_index; + tlv->ctwindow_opp_ps = ctwindow_opp_ps; + memcpy(tlv-> + wifidirect_noa_descriptor_list, + noa_descriptor_list, + no_of_noa * + sizeof(noa_descriptor)); + endian_convert_tlv_wifidirect_header_out + (tlv); + flag = 1; + break; + } + case WIFIDIRECT_NOA_DESCRIPTOR: + { + wifidirect_level = + WIFIDIRECT_NOTICE_OF_ABSENCE; + flag = 0; + break; + } + case WIFIDIRECT_CHANNEL_CONFIG: + { + tlvbuf_wifidirect_channel *tlv = NULL; + /* Append a new TLV */ + tlv_len = + sizeof + (tlvbuf_wifidirect_channel); + tlv = (tlvbuf_wifidirect_channel + *)(buffer + cmd_len_wifidirect); + cmd_len_wifidirect += tlv_len; + /* Set TLV fields */ + tlv->tag = TLV_TYPE_WIFIDIRECT_CHANNEL; + tlv->length = + tlv_len - (sizeof(t_u8) + + sizeof(t_u16)); + memcpy(tlv->country_string, country, 3); + if (tlv->country_string[2] == 0) + tlv->country_string[2] = + WIFIDIRECT_COUNTRY_LAST_BYTE; + tlv->regulatory_class = + regulatory_class; + tlv->channel_number = channel_number; + endian_convert_tlv_wifidirect_header_out + (tlv); + break; + } + case WIFIDIRECT_OPCHANNEL_CONFIG: + { + tlvbuf_wifidirect_channel *tlv = NULL; + /* Append a new TLV */ + tlv_len = + sizeof + (tlvbuf_wifidirect_channel); + tlv = (tlvbuf_wifidirect_channel + *)(buffer + cmd_len_wifidirect); + cmd_len_wifidirect += tlv_len; + /* Set TLV fields */ + tlv->tag = + TLV_TYPE_WIFIDIRECT_OPCHANNEL; + tlv->length = + tlv_len - (sizeof(t_u8) + + sizeof(t_u16)); + memcpy(tlv->country_string, country, 3); + if (tlv->country_string[2] == 0) + tlv->country_string[2] = + WIFIDIRECT_COUNTRY_LAST_BYTE; + tlv->regulatory_class = + op_regulatory_class; + tlv->channel_number = op_channel_number; + endian_convert_tlv_wifidirect_header_out + (tlv); + break; + } + + case WIFIDIRECT_DEVICE_INFO_CONFIG: + { + tlvbuf_wifidirect_device_info *tlv = + NULL; + /* Append a new TLV */ + tlv_len = + sizeof + (tlvbuf_wifidirect_device_info) + + + secondary_dev_count * + WPS_DEVICE_TYPE_LEN + + strlen(wifidirect_ssid); + tlv = (tlvbuf_wifidirect_device_info + *)(buffer + cmd_len_wifidirect); + cmd_len_wifidirect += tlv_len; + /* Set TLV fields */ + tlv->tag = + TLV_TYPE_WIFIDIRECT_DEVICE_INFO; + tlv->length = + tlv_len - (sizeof(t_u8) + + sizeof(t_u16)); + memcpy(tlv->dev_address, dev_address, + ETH_ALEN); + tlv->config_methods = + htons(config_methods); + tlv->primary_category = + htons(pri_category); + memcpy(tlv->primary_oui, primary_oui, + 4); + tlv->primary_subcategory = + htons(pri_sub_category); + tlv->secondary_dev_count = + secondary_dev_count; + endian_convert_tlv_wifidirect_header_out + (tlv); + /* Parameters within secondary_dev_info are already htons'ed */ + memcpy(tlv->secondary_dev_info, + secondary_dev_info, + secondary_dev_count * + WPS_DEVICE_TYPE_LEN); + temp = htons(SC_Device_Name); + memcpy(((t_u8 *)(&tlv-> + device_name_type)) + + secondary_dev_count * + WPS_DEVICE_TYPE_LEN, &temp, + sizeof(temp)); + temp = htons(strlen(wifidirect_ssid)); + memcpy(((t_u8 *)(&tlv-> + device_name_len)) + + secondary_dev_count * + WPS_DEVICE_TYPE_LEN, &temp, + sizeof(temp)); + memcpy(((t_u8 *)(&tlv->device_name)) + + secondary_dev_count * + WPS_DEVICE_TYPE_LEN, + wifidirect_ssid, + strlen(wifidirect_ssid)); + flag = 1; + break; + } + case WIFIDIRECT_GROUP_INFO_CONFIG: + { + tlvbuf_wifidirect_group_info *tlv = + NULL; + /* Append a new TLV */ + tlv_offset = + wifidirect_group_total_ssid_len + + + wifidirect_total_secondary_dev_count + * WPS_DEVICE_TYPE_LEN; + tlv_len = + sizeof + (tlvbuf_wifidirect_group_info) + + + wifidirect_client_dev_count * + sizeof + (wifidirect_client_dev_info) + + tlv_offset; + tlv = (tlvbuf_wifidirect_group_info + *)(buffer + cmd_len_wifidirect); + cmd_len_wifidirect += tlv_len; + /* Set TLV fields */ + tlv->tag = + TLV_TYPE_WIFIDIRECT_GROUP_INFO; + tlv->length = tlv_len; + memcpy(tlv->wifidirect_client_dev_list, + wifidirect_client_dev_info_list, + wifidirect_client_dev_count * + sizeof + (wifidirect_client_dev_info) + + tlv_offset); + /* Parameters within secondary_dev_info are already htons'ed */ + //wps_hexdump(DEBUG_WLAN,"Group Info Hexdump:", (t_u8*)tlv, tlv_len); + endian_convert_tlv_wifidirect_header_out + (tlv); + flag = 1; + break; + } + case WIFIDIRECT_GROUP_SEC_INFO_CONFIG: + { + wifidirect_level = + WIFIDIRECT_GROUP_CLIENT_INFO_CONFIG; + + if (wifidirect_client_dev_index && + group_secondary_index) { + memset(((t_u8 *) + &wifidirect_client_dev_info_list + [wifidirect_client_dev_index + - + 1]. + wifidirect_secondary_dev_info + + tlv_offset), 0, + group_secondary_index * + WPS_DEVICE_TYPE_LEN); + memcpy(((t_u8 *) + &wifidirect_client_dev_info_list + [wifidirect_client_dev_index + - + 1]. + wifidirect_secondary_dev_info + + tlv_offset), + &group_secondary_dev_info, + group_secondary_index * + WPS_DEVICE_TYPE_LEN); + } + tlv_offset = + wifidirect_group_total_ssid_len + + + wifidirect_total_secondary_dev_count + * WPS_DEVICE_TYPE_LEN; + flag = 0; + break; + } + case WIFIDIRECT_GROUP_CLIENT_INFO_CONFIG: + { + wifidirect_level = + WIFIDIRECT_GROUP_INFO_CONFIG; + flag = 0; + break; + } + case WIFIDIRECT_DEVICE_SEC_INFO_CONFIG: + { + wifidirect_level = + WIFIDIRECT_DEVICE_INFO_CONFIG; + flag = 0; + break; + } + case WIFIDIRECT_GROUP_ID_CONFIG: + { + tlvbuf_wifidirect_group_id *tlv = NULL; + /* Append a new TLV */ + tlv_len = + sizeof + (tlvbuf_wifidirect_group_id) + + strlen(wifidirect_ssid); + tlv = (tlvbuf_wifidirect_group_id + *)(buffer + cmd_len_wifidirect); + cmd_len_wifidirect += tlv_len; + /* Set TLV fields */ + tlv->tag = TLV_TYPE_WIFIDIRECT_GROUP_ID; + tlv->length = + tlv_len - (sizeof(t_u8) + + sizeof(t_u16)); + memcpy(tlv->group_address, dev_address, + ETH_ALEN); + memcpy(tlv->group_ssid, wifidirect_ssid, + strlen(wifidirect_ssid)); + endian_convert_tlv_wifidirect_header_out + (tlv); + break; + } + case WIFIDIRECT_GROUP_BSS_ID_CONFIG: + { + tlvbuf_wifidirect_group_bss_id *tlv = + NULL; + /* Append a new TLV */ + tlv_len = + sizeof + (tlvbuf_wifidirect_group_bss_id); + tlv = (tlvbuf_wifidirect_group_bss_id + *)(buffer + cmd_len_wifidirect); + cmd_len_wifidirect += tlv_len; + /* Set TLV fields */ + tlv->tag = + TLV_TYPE_WIFIDIRECT_GROUP_BSS_ID; + tlv->length = + tlv_len - (sizeof(t_u8) + + sizeof(t_u16)); + memcpy(tlv->group_bssid, dev_address, + ETH_ALEN); + endian_convert_tlv_wifidirect_header_out + (tlv); + break; + } + case WIFIDIRECT_INTERFACE_CONFIG: + { + tlvbuf_wifidirect_interface *tlv = NULL; + /* Append a new TLV */ + tlv_len = + sizeof + (tlvbuf_wifidirect_interface) + + iface_count * ETH_ALEN; + tlv = (tlvbuf_wifidirect_interface + *)(buffer + cmd_len_wifidirect); + cmd_len_wifidirect += tlv_len; + /* Set TLV fields */ + tlv->tag = + TLV_TYPE_WIFIDIRECT_INTERFACE; + tlv->length = + tlv_len - (sizeof(t_u8) + + sizeof(t_u16)); + memcpy(tlv->interface_id, dev_address, + ETH_ALEN); + tlv->interface_count = iface_count; + memcpy(tlv->interface_idlist, + iface_list, + iface_count * ETH_ALEN); + endian_convert_tlv_wifidirect_header_out + (tlv); + break; + } + + case WIFIDIRECT_TIMEOUT_CONFIG: + { + tlvbuf_wifidirect_config_timeout *tlv = + NULL; + /* Append a new TLV */ + tlv_len = + sizeof + (tlvbuf_wifidirect_config_timeout); + tlv = (tlvbuf_wifidirect_config_timeout + *)(buffer + cmd_len_wifidirect); + cmd_len_wifidirect += tlv_len; + /* Set TLV fields */ + tlv->tag = + TLV_TYPE_WIFIDIRECT_CONFIG_TIMEOUT; + tlv->length = + tlv_len - (sizeof(t_u8) + + sizeof(t_u16)); + tlv->group_config_timeout = + go_config_timeout; + tlv->device_config_timeout = + client_config_timeout; + endian_convert_tlv_wifidirect_header_out + (tlv); + break; + } + case WIFIDIRECT_EXTENDED_TIME_CONFIG: + { + tlvbuf_wifidirect_ext_listen_time *tlv = + NULL; + /* Append a new TLV */ + tlv_len = + sizeof + (tlvbuf_wifidirect_ext_listen_time); + tlv = (tlvbuf_wifidirect_ext_listen_time + *)(buffer + cmd_len_wifidirect); + cmd_len_wifidirect += tlv_len; + /* Set TLV fields */ + tlv->tag = + TLV_TYPE_WIFIDIRECT_EXTENDED_LISTEN_TIME; + tlv->length = + tlv_len - (sizeof(t_u8) + + sizeof(t_u16)); + tlv->availability_period = + le16_to_cpu(avail_period); + tlv->availability_interval = + le16_to_cpu(avail_interval); + endian_convert_tlv_wifidirect_header_out + (tlv); + break; + } + case WIFIDIRECT_INTENDED_ADDR_CONFIG: + { + tlvbuf_wifidirect_intended_addr *tlv = + NULL; + /* Append a new TLV */ + tlv_len = + sizeof + (tlvbuf_wifidirect_intended_addr); + tlv = (tlvbuf_wifidirect_intended_addr + *)(buffer + cmd_len_wifidirect); + cmd_len_wifidirect += tlv_len; + /* Set TLV fields */ + tlv->tag = + TLV_TYPE_WIFIDIRECT_INTENDED_ADDRESS; + tlv->length = + tlv_len - (sizeof(t_u8) + + sizeof(t_u16)); + memcpy(tlv->group_address, dev_address, + ETH_ALEN); + endian_convert_tlv_wifidirect_header_out + (tlv); + break; + } + + case WIFIDIRECT_WPSIE: + { +#ifdef DEBUG + /* Debug print */ + hexdump(buffer, cmd_len_wifidirect, + ' '); +#endif + /* Append TLV for WPSVersion */ + tlvbuf_wps_ie *tlv = NULL; + tlv_len = + sizeof(tlvbuf_wps_ie) + + sizeof(WPS_version); + tlv = (tlvbuf_wps_ie *)(buffer + + cmd_len_wifidirect + + + sizeof + (custom_ie) + + cmd_len_wps); + + if (!wifidir_use_fixed_ie_indices()) { + special_mask_custom_ie_buf + *wps_ie_buf; + wps_ie_buf = + (special_mask_custom_ie_buf + *)tlv; + memcpy(&wps_ie_buf->Oui[0], + wps_oui, + sizeof(wps_oui)); + cmd_len_wps += sizeof(wps_oui); + } + tlv = (tlvbuf_wps_ie *)(buffer + + cmd_len_wifidirect + + + sizeof + (custom_ie) + + cmd_len_wps); + tlv->tag = SC_Version; + tlv->length = + tlv_len - 2 * sizeof(t_u16); + *(tlv->data) = WPS_version; + endian_convert_tlv_wps_header_out(tlv); + cmd_len_wps += tlv_len; + + /* Append TLV for WPSSetupState */ + tlv_len = + sizeof(tlvbuf_wps_ie) + + sizeof(WPS_setupstate); + tlv = (tlvbuf_wps_ie *)(buffer + + cmd_len_wifidirect + + + sizeof + (custom_ie) + + cmd_len_wps); + tlv->tag = SC_Simple_Config_State; + tlv->length = + tlv_len - 2 * sizeof(t_u16); + *(tlv->data) = WPS_setupstate; + endian_convert_tlv_wps_header_out(tlv); + cmd_len_wps += tlv_len; + + /* Append TLV for WPSRequestType */ + tlv_len = + sizeof(tlvbuf_wps_ie) + + sizeof(WPS_requesttype); + tlv = (tlvbuf_wps_ie *)(buffer + + cmd_len_wifidirect + + + sizeof + (custom_ie) + + cmd_len_wps); + tlv->tag = SC_Request_Type; + tlv->length = + tlv_len - 2 * sizeof(t_u16); + *(tlv->data) = WPS_requesttype; + endian_convert_tlv_wps_header_out(tlv); + cmd_len_wps += tlv_len; + + /* Append TLV for WPSResponseType */ + tlv_len = + sizeof(tlvbuf_wps_ie) + + sizeof(WPS_responsetype); + tlv = (tlvbuf_wps_ie *)(buffer + + cmd_len_wifidirect + + + sizeof + (custom_ie) + + cmd_len_wps); + tlv->tag = SC_Response_Type; + tlv->length = + tlv_len - 2 * sizeof(t_u16); + *(tlv->data) = WPS_responsetype; + endian_convert_tlv_wps_header_out(tlv); + cmd_len_wps += tlv_len; + + /* Append TLV for WPSSpecConfigMethods */ + tlv_len = + sizeof(tlvbuf_wps_ie) + + sizeof(WPS_specconfigmethods); + tlv = (tlvbuf_wps_ie *)(buffer + + cmd_len_wifidirect + + + sizeof + (custom_ie) + + cmd_len_wps); + tlv->tag = SC_Config_Methods; + tlv->length = + tlv_len - 2 * sizeof(t_u16); + temp = htons(WPS_specconfigmethods); + memcpy((t_u16 *)tlv->data, &temp, + sizeof(temp)); + endian_convert_tlv_wps_header_out(tlv); + cmd_len_wps += tlv_len; + + /* Append TLV for WPSUUID */ + tlv_len = + sizeof(tlvbuf_wps_ie) + + sizeof(WPS_UUID); + tlv = (tlvbuf_wps_ie *)(buffer + + cmd_len_wifidirect + + + sizeof + (custom_ie) + + cmd_len_wps); + tlv->tag = SC_UUID_E; + tlv->length = + tlv_len - 2 * sizeof(t_u16); + memcpy(tlv->data, WPS_UUID, + WPS_UUID_MAX_LEN); + endian_convert_tlv_wps_header_out(tlv); + cmd_len_wps += tlv_len; + + /* Append TLV for WPSPrimaryDeviceType */ + tlv_len = + sizeof(tlvbuf_wps_ie) + + sizeof(WPS_primarydevicetype); + tlv = (tlvbuf_wps_ie *)(buffer + + cmd_len_wifidirect + + + sizeof + (custom_ie) + + cmd_len_wps); + tlv->tag = SC_Primary_Device_Type; + tlv->length = + tlv_len - 2 * sizeof(t_u16); + memcpy(tlv->data, WPS_primarydevicetype, + WPS_DEVICE_TYPE_MAX_LEN); + endian_convert_tlv_wps_header_out(tlv); + cmd_len_wps += tlv_len; + + /* Append TLV for WPSRFBand */ + tlv_len = + sizeof(tlvbuf_wps_ie) + + sizeof(WPS_RFband); + tlv = (tlvbuf_wps_ie *)(buffer + + cmd_len_wifidirect + + + sizeof + (custom_ie) + + cmd_len_wps); + tlv->tag = SC_RF_Band; + tlv->length = + tlv_len - 2 * sizeof(t_u16); + *(tlv->data) = WPS_RFband; + endian_convert_tlv_wps_header_out(tlv); + cmd_len_wps += tlv_len; + + /* Append TLV for WPSAssociationState */ + tlv_len = + sizeof(tlvbuf_wps_ie) + + sizeof(WPS_associationstate); + tlv = (tlvbuf_wps_ie *)(buffer + + cmd_len_wifidirect + + + sizeof + (custom_ie) + + cmd_len_wps); + tlv->tag = SC_Association_State; + tlv->length = + tlv_len - 2 * sizeof(t_u16); + temp = htons(WPS_associationstate); + memcpy((t_u16 *)tlv->data, &temp, + sizeof(temp)); + endian_convert_tlv_wps_header_out(tlv); + cmd_len_wps += tlv_len; + + /* Append TLV for WPSConfigurationError */ + tlv_len = + sizeof(tlvbuf_wps_ie) + + sizeof(WPS_configurationerror); + tlv = (tlvbuf_wps_ie *)(buffer + + cmd_len_wifidirect + + + sizeof + (custom_ie) + + cmd_len_wps); + tlv->tag = SC_Configuration_Error; + tlv->length = + tlv_len - 2 * sizeof(t_u16); + temp = htons(WPS_configurationerror); + memcpy((t_u16 *)tlv->data, &temp, + sizeof(temp)); + endian_convert_tlv_wps_header_out(tlv); + cmd_len_wps += tlv_len; + + /* Append TLV for WPSDevicePassword */ + tlv_len = + sizeof(tlvbuf_wps_ie) + + sizeof(WPS_devicepassword); + tlv = (tlvbuf_wps_ie *)(buffer + + cmd_len_wifidirect + + + sizeof + (custom_ie) + + cmd_len_wps); + tlv->tag = SC_Device_Password_ID; + tlv->length = + tlv_len - 2 * sizeof(t_u16); + temp = htons(WPS_devicepassword); + memcpy((t_u16 *)tlv->data, &temp, + sizeof(temp)); + endian_convert_tlv_wps_header_out(tlv); + cmd_len_wps += tlv_len; + + /* Append TLV for WPSDeviceName */ + tlv_len = + sizeof(tlvbuf_wps_ie) + + strlen(WPS_devicename); + tlv = (tlvbuf_wps_ie *)(buffer + + cmd_len_wifidirect + + + sizeof + (custom_ie) + + cmd_len_wps); + tlv->tag = SC_Device_Name; + tlv->length = + tlv_len - 2 * sizeof(t_u16); + memcpy(tlv->data, WPS_devicename, + strlen(WPS_devicename)); + endian_convert_tlv_wps_header_out(tlv); + cmd_len_wps += tlv_len; + + /* Append TLV for WPSManufacturer */ + tlv_len = + sizeof(tlvbuf_wps_ie) + + strlen(WPS_manufacturer); + tlv = (tlvbuf_wps_ie *)(buffer + + cmd_len_wifidirect + + + sizeof + (custom_ie) + + cmd_len_wps); + tlv->tag = SC_Manufacturer; + tlv->length = + tlv_len - 2 * sizeof(t_u16); + memcpy(tlv->data, WPS_manufacturer, + strlen(WPS_manufacturer)); + endian_convert_tlv_wps_header_out(tlv); + cmd_len_wps += tlv_len; + + /* Append TLV for WPSModelName */ + tlv_len = + sizeof(tlvbuf_wps_ie) + + strlen(WPS_modelname); + tlv = (tlvbuf_wps_ie *)(buffer + + cmd_len_wifidirect + + + sizeof + (custom_ie) + + cmd_len_wps); + tlv->tag = SC_Model_Name; + tlv->length = + tlv_len - 2 * sizeof(t_u16); + memcpy(tlv->data, WPS_modelname, + strlen(WPS_modelname)); + endian_convert_tlv_wps_header_out(tlv); + cmd_len_wps += tlv_len; + + /* Append TLV for WPSModelNumber */ + tlv_len = + sizeof(tlvbuf_wps_ie) + + wps_model_len; + tlv = (tlvbuf_wps_ie *)(buffer + + cmd_len_wifidirect + + + sizeof + (custom_ie) + + cmd_len_wps); + tlv->tag = SC_Model_Number; + tlv->length = + tlv_len - 2 * sizeof(t_u16); + memcpy(tlv->data, WPS_modelnumber, + wps_model_len); + endian_convert_tlv_wps_header_out(tlv); + cmd_len_wps += tlv_len; + + /* Append TLV for WPSSerialNumber */ + tlv_len = + sizeof(tlvbuf_wps_ie) + + wps_serial_len; + tlv = (tlvbuf_wps_ie *)(buffer + + cmd_len_wifidirect + + + sizeof + (custom_ie) + + cmd_len_wps); + tlv->tag = SC_Serial_Number; + tlv->length = + tlv_len - 2 * sizeof(t_u16); + memcpy(tlv->data, WPS_serialnumber, + wps_serial_len); + endian_convert_tlv_wps_header_out(tlv); + cmd_len_wps += tlv_len; + + /* Append TLV for WPSVendorExtension */ + tlv_len = + sizeof(tlvbuf_wps_ie) + + wps_vendor_len; + tlv = (tlvbuf_wps_ie *)(buffer + + cmd_len_wifidirect + + + sizeof + (custom_ie) + + cmd_len_wps); + tlv->tag = SC_Vendor_Extension; + tlv->length = + tlv_len - 2 * sizeof(t_u16); + memcpy(tlv->data, WPS_VendorExt, + wps_vendor_len); + endian_convert_tlv_wps_header_out(tlv); + cmd_len_wps += tlv_len; +#ifdef DEBUG + /* Debug print */ + hexdump(buffer + sizeof(custom_ie) + + cmd_len_wifidirect, cmd_len_wps, + ' '); +#endif + break; + } + case WIFIDIRECT_EXTRA: + { + memcpy(buffer + cmd_len_wifidirect, + extra, extra_len); + cmd_len_wifidirect += extra_len; + break; + } + default: + *ie_len_wifidirect = cmd_len_wifidirect; + if (ie_len_wps) + *ie_len_wps = cmd_len_wps; + break; + } + memset(country, 0, sizeof(country)); + if (wifidirect_level == 0) + cmd_found = 0; + if (flag) + wifidirect_level = 0; + } + } + +done: + fclose(config_file); + if (chan_entry_list) + free(chan_entry_list); + if (line) + free(line); + if (extra) + free(extra); + if (args) + free(args); + return; +} + +/** + * @brief Process and send ie config command + * @param ie_index A pointer to the IE buffer index + * @param data_len_wifidirect Length of WIFIDIRECT data, 0 to get, else set. + * @param data_len_wps Length of WPS data, 0 to get, else set. + * @param buf Pointer to buffer to set. + * @return SUCCESS--success, FAILURE--fail + */ +static int +wifidirect_ie_config(t_u16 *ie_index, t_u16 data_len_wifidirect, + t_u16 data_len_wps, t_u8 *buf) +{ + struct iwreq iwr; + t_s32 sockfd; + int i, ret = SUCCESS; + tlvbuf_custom_ie *tlv = NULL; + custom_ie *ie_ptr = NULL; + + tlv = (tlvbuf_custom_ie *)buf; + tlv->tag = MRVL_MGMT_IE_LIST_TLV_ID; + /* Locate headers */ + ie_ptr = (custom_ie *)(tlv->ie_data); + + /* Set TLV fields : WIFIDIRECT IE parameters */ + if (data_len_wifidirect) { + /* Set IE */ +#define MGMT_MASK_AUTO 0xffff + ie_ptr->mgmt_subtype_mask = MGMT_MASK_AUTO; + tlv->length = sizeof(custom_ie) + data_len_wifidirect; + ie_ptr->ie_length = data_len_wifidirect; + ie_ptr->ie_index = *ie_index; + } else { + /* Get WPS IE */ + tlv->length = 0; + } + + if (!wifidir_use_fixed_ie_indices()) { + if (*ie_index != 0xFFFF) { + (*ie_index)++; + } + } else { + (*ie_index)++; + } + /* Locate headers */ + ie_ptr = (custom_ie *)((t_u8 *)(tlv->ie_data) + sizeof(custom_ie) + + data_len_wifidirect); + + /* Set WPS IE parameters */ + if (data_len_wps) { + /* Set IE */ + /* Firmware Handled IE - mask should be set to -1 */ + ie_ptr->mgmt_subtype_mask = MGMT_MASK_AUTO; + tlv->length += sizeof(custom_ie) + data_len_wps; + ie_ptr->ie_length = data_len_wps; + ie_ptr->ie_index = *ie_index; + } + + memset(&iwr, 0, sizeof(iwr)); + strncpy(iwr.ifr_name, (char *)dev_name, IFNAMSIZ - 1); + + iwr.u.data.pointer = (void *)buf; + iwr.u.data.length = + ((2 * sizeof(custom_ie)) + sizeof(tlvbuf_custom_ie) + + data_len_wifidirect + data_len_wps); + iwr.u.data.flags = 0; + + /* + * create a socket + */ + if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) { + printf("Cannot open socket.\n"); + ret = FAILURE; + goto _exit_; + } + + if (ioctl(sockfd, CUSTOM_IE, &iwr)) { + perror("ioctl[CUSTOM_IE]"); + printf("Failed to set/get/clear the IE buffer\n"); + ret = FAILURE; + close(sockfd); + goto _exit_; + } + close(sockfd); + +/** Max IE index */ +#define MAX_MGMT_IE_INDEX 12 + + if (!data_len_wifidirect) { + /* Get the IE buffer index number for MGMT_IE_LIST_TLV */ + tlv = (tlvbuf_custom_ie *)buf; + *ie_index = 0xFFFF; + if (tlv->tag == MRVL_MGMT_IE_LIST_TLV_ID) { + ie_ptr = (custom_ie *)(tlv->ie_data); + for (i = 0; i < MAX_MGMT_IE_INDEX; i++) { + /* zero mask indicates a wps IE, return previous index */ + if (ie_ptr->mgmt_subtype_mask == MGMT_MASK_AUTO + && ie_ptr->ie_length) { + *ie_index = ie_ptr->ie_index; + break; + } + if (i < (MAX_MGMT_IE_INDEX - 1)) + ie_ptr = (custom_ie *)((t_u8 *)ie_ptr + + sizeof(custom_ie) + + + ie_ptr-> + ie_length); + } + } + if (*ie_index == 0xFFFF) { + ret = FAILURE; + } + } +_exit_: + + return ret; +} + +/** + * @brief Creates a wifidirect_config request and sends to the driver + * + * Usage: "Usage : wifidirect_config [CONFIG_FILE]" + * + * @param argc Number of arguments + * @param argv Pointer to the arguments + * @return None + */ +static void +wifidirectcmd_config(int argc, char *argv[]) +{ + t_u8 *buf = NULL, *ptr, *dev_ptr, *array_ptr; + t_u16 ie_len_wifidirect = 0, ie_len_wps = 0, ie_len; + t_u16 ie_index, temp; + int i, opt, ret = SUCCESS; + tlvbuf_custom_ie *tlv = NULL; + custom_ie *ie_ptr = NULL; + t_u16 len = 0, len_wifidirect = 0; + t_u8 type = 0; + t_u16 wps_len = 0, wps_type = 0; + + if (!wifidir_use_fixed_ie_indices()) { + ie_index = 0xFFFF; + } else { + ie_index = 0; + } + while ((opt = getopt_long(argc, argv, "+", cmd_options, NULL)) != -1) { + switch (opt) { + default: + print_wifidirect_config_usage(); + return; + } + } + argc -= optind; + argv += optind; + + /* Check arguments */ + if (argc < 2) { + printf("ERR:wrong number of arguments.\n"); + print_wifidirect_config_usage(); + return; + } + buf = (t_u8 *)malloc(MRVDRV_SIZE_OF_CMD_BUFFER); + if (!buf) { + printf("ERR:Cannot allocate memory!\n"); + return; + } + memset(buf, 0, MRVDRV_SIZE_OF_CMD_BUFFER); + + if (argc >= 3) { + /* Read parameters and send command to firmware */ + wifidirect_file_params_config(argv[2], argv[1], buf + + sizeof(tlvbuf_custom_ie) + + sizeof(custom_ie), + &ie_len_wifidirect, &ie_len_wps); + if (argc == 4) { + ie_index = atoi(argv[3]); + if (ie_index >= 4) { + printf("ERR:wrong argument %s.\n", argv[3]); + return; + } + } + if (ie_len_wifidirect > MAX_SIZE_IE_BUFFER || + ie_len_wps > MAX_SIZE_IE_BUFFER) { + printf("ERR:IE parameter size exceeds limit in %s.\n", + argv[2]); + free(buf); + return; + } + ie_len = ie_len_wifidirect + ie_len_wps + + sizeof(tlvbuf_custom_ie) + (2 * sizeof(custom_ie)); + if (ie_len >= MRVDRV_SIZE_OF_CMD_BUFFER) { + printf("ERR:Too much data in configuration file %s.\n", + argv[2]); + free(buf); + return; + } +#ifdef DEBUG + hexdump(buf, ie_len, ' '); +#endif + ret = wifidirect_ie_config(&ie_index, ie_len_wifidirect, + ie_len_wps, buf); + if (ret != SUCCESS) { + printf("ERR:Could not set wifidirect parameters\n"); + } + } else { + ret = wifidirect_ie_config(&ie_index, 0, 0, buf); + /* Print response */ + if (ret == SUCCESS && ie_index < 3) { + tlv = (tlvbuf_custom_ie *)buf; + if (tlv->tag == MRVL_MGMT_IE_LIST_TLV_ID) { + ie_ptr = (custom_ie *)(tlv->ie_data); + /* Goto appropriate Ie Index */ + for (i = 0; i < ie_index; i++) { + ie_ptr = (custom_ie *)((t_u8 *)ie_ptr + + sizeof(custom_ie) + + + ie_ptr-> + ie_length); + } + ie_len_wifidirect = ie_ptr->ie_length; + ptr = ie_ptr->ie_buffer; + /* Locate headers */ + printf("WIFIDIRECT settings:\n"); + if (!wifidir_use_fixed_ie_indices()) { + while (memcmp + (ptr, wifidirect_oui, + sizeof(wifidirect_oui))) { + ie_ptr = (custom_ie *)((t_u8 *) + ie_ptr + + sizeof + (custom_ie) + + + ie_ptr-> + ie_length); + ie_len_wifidirect = + ie_ptr->ie_length; + ptr = ie_ptr->ie_buffer; + } + ptr += sizeof(wifidirect_oui); + ie_len_wifidirect -= + sizeof(wifidirect_oui); + } + while (ie_len_wifidirect > + WIFIDIRECT_IE_HEADER_LEN) { + type = *ptr; + memcpy(&len, ptr + 1, sizeof(t_u16)); + len = le16_to_cpu(len); + switch (type) { + case TLV_TYPE_WIFIDIRECT_DEVICE_ID: + { + tlvbuf_wifidirect_device_id + *wifidirect_tlv + = + (tlvbuf_wifidirect_device_id + *)ptr; + printf("\t Device ID - "); + print_mac + (wifidirect_tlv-> + dev_mac_address); + printf("\n"); + } + break; + + case TLV_TYPE_WIFIDIRECT_CAPABILITY: + { + tlvbuf_wifidirect_capability + *wifidirect_tlv + = + (tlvbuf_wifidirect_capability + *)ptr; + printf("\t Device capability = %d\n", (int)wifidirect_tlv->dev_capability); + printf("\t Group capability = %d\n", (int)wifidirect_tlv->group_capability); + } + break; + case TLV_TYPE_WIFIDIRECT_GROUPOWNER_INTENT: + { + tlvbuf_wifidirect_group_owner_intent + *wifidirect_tlv + = + (tlvbuf_wifidirect_group_owner_intent + *)ptr; + printf("\t Group owner intent = %d\n", (int)wifidirect_tlv->dev_intent); + } + break; + case TLV_TYPE_WIFIDIRECT_MANAGEABILITY: + { + tlvbuf_wifidirect_manageability + *wifidirect_tlv + = + (tlvbuf_wifidirect_manageability + *)ptr; + printf("\t Manageability = %d\n", (int)wifidirect_tlv->manageability); + } + break; + case TLV_TYPE_WIFIDIRECT_CHANNEL_LIST: + { + tlvbuf_wifidirect_channel_list + *wifidirect_tlv + = + (tlvbuf_wifidirect_channel_list + *)ptr; + chan_entry *temp_ptr; + printf("\t Country String \"%c%c\"", wifidirect_tlv->country_string[0], wifidirect_tlv->country_string[1]); + if (isalpha + (wifidirect_tlv-> + country_string[2])) + printf("\"%c\"", + wifidirect_tlv-> + country_string + [2]); + printf("\n"); + temp_ptr = + (chan_entry *) + wifidirect_tlv-> + wifidirect_chan_entry_list; + len_wifidirect = + le16_to_cpu + (wifidirect_tlv-> + length) - + (sizeof + (tlvbuf_wifidirect_channel_list) + - + WIFIDIRECT_IE_HEADER_LEN); + if (len_wifidirect) + printf("\t Channel List :- \n"); + while (len_wifidirect) { + printf("\t\t Regulatory_class = %d\n", (int)(temp_ptr->regulatory_class)); + printf("\t\t No of channels = %d\n", (int)temp_ptr->num_of_channels); + printf("\t\t Channel list = "); + for (i = 0; + i < + temp_ptr-> + num_of_channels; + i++) { + printf("%d ", *(temp_ptr->chan_list + i)); + } + len_wifidirect + -= + sizeof + (chan_entry) + + + temp_ptr-> + num_of_channels; + temp_ptr = + (chan_entry + *)((t_u8 *)temp_ptr + sizeof(chan_entry) + temp_ptr->num_of_channels); + printf("\n"); + } + } + break; + case TLV_TYPE_WIFIDIRECT_NOTICE_OF_ABSENCE: + { + tlvbuf_wifidirect_notice_of_absence + *wifidirect_tlv + = + (tlvbuf_wifidirect_notice_of_absence + *)ptr; + noa_descriptor + *temp_ptr; + printf("\t Notice of Absence index = %d\n", (int)wifidirect_tlv->noa_index); + printf("\t CTWindow and opportunistic PS parameters = %d\n", (int)wifidirect_tlv->ctwindow_opp_ps); + temp_ptr = + (noa_descriptor + *) + wifidirect_tlv-> + wifidirect_noa_descriptor_list; + len_wifidirect = + le16_to_cpu + (wifidirect_tlv-> + length) - + (sizeof + (tlvbuf_wifidirect_notice_of_absence) + - + WIFIDIRECT_IE_HEADER_LEN); + while (len_wifidirect) { + printf("\t Count or Type = %d\n", (int)temp_ptr->count_type); + printf("\t Duration = %dms\n", le32_to_cpu(temp_ptr->duration)); + printf("\t Interval = %dms\n", le32_to_cpu(temp_ptr->interval)); + printf("\t Start Time = %d\n", le32_to_cpu(temp_ptr->start_time)); + printf("\n"); + temp_ptr += + sizeof + (noa_descriptor); + len_wifidirect + -= + sizeof + (noa_descriptor); + } + } + break; + case TLV_TYPE_WIFIDIRECT_DEVICE_INFO: + { + tlvbuf_wifidirect_device_info + *wifidirect_tlv + = + (tlvbuf_wifidirect_device_info + *)ptr; + printf("\t Device address - "); + print_mac + (wifidirect_tlv-> + dev_address); + printf("\n"); + /* display config_methods */ + printf("\t Config methods - 0x%02X\n", ntohs(wifidirect_tlv->config_methods)); + printf("\t Primary device type = %02d-%02X%02X%02X%02X-%02d\n", (int)ntohs(wifidirect_tlv->primary_category), (int)wifidirect_tlv->primary_oui[0], (int)wifidirect_tlv->primary_oui[1], (int)wifidirect_tlv->primary_oui[2], (int)wifidirect_tlv->primary_oui[3], (int)ntohs(wifidirect_tlv->primary_subcategory)); + printf("\t Secondary Device Count = %d\n", (int)wifidirect_tlv->secondary_dev_count); + array_ptr = + wifidirect_tlv-> + secondary_dev_info; + for (i = 0; + i < + wifidirect_tlv-> + secondary_dev_count; + i++) { + memcpy(&temp, + array_ptr, + sizeof + (t_u16)); + printf("\t\t Secondary device type = %02d-", ntohs(temp)); + array_ptr += + sizeof + (temp); + printf("%02X%02X%02X%02X", array_ptr[0], array_ptr[1], array_ptr[2], array_ptr[3]); + array_ptr += 4; + memcpy(&temp, + array_ptr, + sizeof + (t_u16)); + printf("-%02d\n", ntohs(temp)); + array_ptr += + sizeof + (temp); + } + array_ptr = + wifidirect_tlv-> + device_name + + wifidirect_tlv-> + secondary_dev_count + * + WPS_DEVICE_TYPE_LEN; + dev_ptr = + (((t_u8 + *) + (&wifidirect_tlv-> + device_name_len)) + + + wifidirect_tlv-> + secondary_dev_count + * + WPS_DEVICE_TYPE_LEN); + if (*(t_u16 *)dev_ptr) + printf("\t Device Name = "); + memcpy(&temp, dev_ptr, + sizeof(t_u16)); + for (i = 0; + i < ntohs(temp); + i++) + printf("%c", + *array_ptr++); + printf("\n"); + } + break; + case TLV_TYPE_WIFIDIRECT_GROUP_INFO: + { + tlvbuf_wifidirect_group_info + *wifidirect_tlv + = + (tlvbuf_wifidirect_group_info + *)ptr; + t_u8 no_of_wifidirect_clients = 0, wifidirect_client_dev_length = 0; + wifidirect_client_dev_info + *temp_ptr; + temp_ptr = + (wifidirect_client_dev_info + *) + wifidirect_tlv-> + wifidirect_client_dev_list; + if (temp_ptr == NULL) + break; + wifidirect_client_dev_length + = + temp_ptr-> + dev_length; + temp = le16_to_cpu + (wifidirect_tlv-> + length) - + wifidirect_client_dev_length; + while (temp && temp_ptr) { + + printf("\t Group WifiDirect Client Device address - "); + print_mac + (temp_ptr-> + wifidirect_dev_address); + printf("\n"); + printf("\t Group WifiDirect Client Interface address - "); + print_mac + (temp_ptr-> + wifidirect_intf_address); + printf("\n"); + printf("\t Group WifiDirect Client Device capability = %d\n", (int)temp_ptr->wifidirect_dev_capability); + printf("\t Group WifiDirect Client Config methods - 0x%02X\n", ntohs(temp_ptr->config_methods)); + printf("\t Group WifiDirect Client Primay device type = %02d-%02X%02X%02X%02X-%02d\n", (int)ntohs(temp_ptr->primary_category), (int)temp_ptr->primary_oui[0], (int)temp_ptr->primary_oui[1], (int)temp_ptr->primary_oui[2], (int)temp_ptr->primary_oui[3], (int)ntohs(temp_ptr->primary_subcategory)); + printf("\t Group WifiDirect Client Secondary Device Count = %d\n", (int)temp_ptr->wifidirect_secondary_dev_count); + array_ptr = + temp_ptr-> + wifidirect_secondary_dev_info; + for (i = 0; + i < + temp_ptr-> + wifidirect_secondary_dev_count; + i++) { + memcpy(&temp, array_ptr, sizeof(t_u16)); + printf("\t Group WifiDirect Client Secondary device type = %02d-", ntohs(temp)); + array_ptr + += + sizeof + (temp); + printf("%02X%02X%02X%02X", array_ptr[0], array_ptr[1], array_ptr[2], array_ptr[3]); + array_ptr + += + 4; + memcpy(&temp, array_ptr, sizeof(t_u16)); + printf("-%02d\n", ntohs(temp)); + array_ptr + += + sizeof + (temp); + } + /* display device name */ + array_ptr = + temp_ptr-> + wifidirect_device_name + + + temp_ptr-> + wifidirect_secondary_dev_count + * + WPS_DEVICE_TYPE_LEN; + printf("\t Group WifiDirect Device Name = "); + memcpy(&temp, + (((t_u8 + *) + (&temp_ptr-> + wifidirect_device_name_len)) + + + temp_ptr-> + wifidirect_secondary_dev_count + * + WPS_DEVICE_TYPE_LEN), + sizeof + (t_u16)); + temp = ntohs + (temp); + for (i = 0; + i < temp; + i++) + printf("%c", *array_ptr++); + printf("\n"); + temp_ptr += + wifidirect_client_dev_length; + temp -= wifidirect_client_dev_length; + no_of_wifidirect_clients++; + if (temp_ptr) + wifidirect_client_dev_length + = + temp_ptr-> + dev_length; + } + printf("\n"); + printf("\t Group WifiDirect Client Devices count = %d\n", no_of_wifidirect_clients); + } + break; + case TLV_TYPE_WIFIDIRECT_GROUP_ID: + { + tlvbuf_wifidirect_group_id + *wifidirect_tlv + = + (tlvbuf_wifidirect_group_id + *)ptr; + printf("\t Group address - "); + print_mac + (wifidirect_tlv-> + group_address); + printf("\n"); + array_ptr = + wifidirect_tlv-> + group_ssid; + printf("\t Group ssid = "); + for (i = 0; + (unsigned int)i < + le16_to_cpu + (wifidirect_tlv-> + length) + - + (sizeof + (tlvbuf_wifidirect_group_id) + - + WIFIDIRECT_IE_HEADER_LEN); + i++) + printf("%c", + *array_ptr++); + printf("\n"); + } + break; + case TLV_TYPE_WIFIDIRECT_GROUP_BSS_ID: + { + tlvbuf_wifidirect_group_bss_id + *wifidirect_tlv + = + (tlvbuf_wifidirect_group_bss_id + *)ptr; + printf("\t Group BSS Id - "); + print_mac + (wifidirect_tlv-> + group_bssid); + printf("\n"); + } + break; + case TLV_TYPE_WIFIDIRECT_INTERFACE: + { + tlvbuf_wifidirect_interface + *wifidirect_tlv + = + (tlvbuf_wifidirect_interface + *)ptr; + printf("\t Interface Id - "); + print_mac + (wifidirect_tlv-> + interface_id); + printf("\t Interface count = %d", (int)wifidirect_tlv->interface_count); + for (i = 0; + i < + wifidirect_tlv-> + interface_count; + i++) { + printf("\n\t Interface address [%d]", i + 1); + print_mac + (&wifidirect_tlv-> + interface_idlist + [i * + ETH_ALEN]); + } + printf("\n"); + } + break; + case TLV_TYPE_WIFIDIRECT_CHANNEL: + { + tlvbuf_wifidirect_channel + *wifidirect_tlv + = + (tlvbuf_wifidirect_channel + *)ptr; + printf("\t Listen Channel Country String \"%c%c\"", wifidirect_tlv->country_string[0], wifidirect_tlv->country_string[1]); + if (isalpha + (wifidirect_tlv-> + country_string[2])) + printf("\"%c\"", + wifidirect_tlv-> + country_string + [2]); + printf("\n"); + printf("\t Listern Channel regulatory class = %d\n", (int)wifidirect_tlv->regulatory_class); + printf("\t Listen Channel number = %d\n", (int)wifidirect_tlv->channel_number); + } + break; + + case TLV_TYPE_WIFIDIRECT_OPCHANNEL: + { + tlvbuf_wifidirect_channel + *wifidirect_tlv + = + (tlvbuf_wifidirect_channel + *)ptr; + printf("\t Operating Channel Country String %c%c", wifidirect_tlv->country_string[0], wifidirect_tlv->country_string[1]); + if (isalpha + (wifidirect_tlv-> + country_string[2])) + printf("%c", + wifidirect_tlv-> + country_string + [2]); + printf("\n"); + printf("\t Operating Channel regulatory class = %d\n", (int)wifidirect_tlv->regulatory_class); + printf("\t Operating Channel number = %d\n", (int)wifidirect_tlv->channel_number); + } + break; + case TLV_TYPE_WIFIDIRECT_INVITATION_FLAG: + { + tlvbuf_wifidirect_invitation_flag + *wifidirect_tlv + = + (tlvbuf_wifidirect_invitation_flag + *)ptr; + printf("\t Invitation flag = %d\n", (int)wifidirect_tlv->invitation_flag & INVITATION_FLAG_MASK); + } + break; + case TLV_TYPE_WIFIDIRECT_CONFIG_TIMEOUT: + { + tlvbuf_wifidirect_config_timeout + *wifidirect_tlv + = + (tlvbuf_wifidirect_config_timeout + *)ptr; + printf("\t GO configuration timeout = %d msec\n", (int)wifidirect_tlv->group_config_timeout * 10); + printf("\t Client configuration timeout = %d msec\n", (int)wifidirect_tlv->device_config_timeout * 10); + } + break; + case TLV_TYPE_WIFIDIRECT_EXTENDED_LISTEN_TIME: + { + tlvbuf_wifidirect_ext_listen_time + *wifidirect_tlv + = + (tlvbuf_wifidirect_ext_listen_time + *)ptr; + printf("\t Availability Period = %d msec\n", (int)wifidirect_tlv->availability_period); + printf("\t Availability Interval = %d msec\n", (int)wifidirect_tlv->availability_interval); + } + break; + case TLV_TYPE_WIFIDIRECT_INTENDED_ADDRESS: + { + tlvbuf_wifidirect_intended_addr + *wifidirect_tlv + = + (tlvbuf_wifidirect_intended_addr + *)ptr; + printf("\t Intended Interface Address - "); + print_mac + (wifidirect_tlv-> + group_address); + printf("\n"); + } + break; + default: + printf("unknown ie=0x%x, len=%d\n", type, len); + break; + } + ptr += len + WIFIDIRECT_IE_HEADER_LEN; + ie_len_wifidirect -= + len + WIFIDIRECT_IE_HEADER_LEN; + } + + /* Goto next index, Locate headers */ + printf("WPS settings:\n"); + ie_ptr = (custom_ie *)((t_u8 *)ie_ptr + + sizeof(custom_ie) + + ie_ptr->ie_length); + ptr = ie_ptr->ie_buffer; + ie_len_wps = ie_ptr->ie_length; + if (!wifidir_use_fixed_ie_indices()) { + while (memcmp + (ptr, wps_oui, + sizeof(wps_oui))) { + ie_ptr = (custom_ie *)((t_u8 *) + ie_ptr + + sizeof + (custom_ie) + + + ie_ptr-> + ie_length); + ie_len_wps = ie_ptr->ie_length; + ptr = ie_ptr->ie_buffer; + } + ptr += sizeof(wps_oui); + ie_len_wifidirect -= sizeof(wps_oui); + } + while (ie_len_wps > sizeof(tlvbuf_wps_ie)) { + memcpy(&wps_type, ptr, sizeof(t_u16)); + memcpy(&wps_len, ptr + 2, + sizeof(t_u16)); + endian_convert_tlv_wps_header_in + (wps_type, wps_len); + switch (wps_type) { + case SC_Version: + { + tlvbuf_wps_ie *wps_tlv = + (tlvbuf_wps_ie + *)ptr; + printf("\t WPS Version = 0x%2x\n", *(wps_tlv->data)); + } + break; + case SC_Simple_Config_State: + { + tlvbuf_wps_ie *wps_tlv = + (tlvbuf_wps_ie + *)ptr; + printf("\t WPS setupstate = 0x%x\n", *(wps_tlv->data)); + } + break; + case SC_Request_Type: + { + tlvbuf_wps_ie *wps_tlv = + (tlvbuf_wps_ie + *)ptr; + printf("\t WPS RequestType = 0x%x\n", *(wps_tlv->data)); + } + break; + case SC_Response_Type: + { + tlvbuf_wps_ie *wps_tlv = + (tlvbuf_wps_ie + *)ptr; + printf("\t WPS ResponseType = 0x%x\n", *(wps_tlv->data)); + } + break; + case SC_Config_Methods: + { + t_u16 wps_config_methods + = 0; + tlvbuf_wps_ie *wps_tlv = + (tlvbuf_wps_ie + *)ptr; + memcpy(&wps_config_methods, wps_tlv->data, sizeof(t_u16)); + wps_config_methods = + ntohs + (wps_config_methods); + printf("\t WPS SpecConfigMethods = 0x%x\n", wps_config_methods); + } + break; + case SC_UUID_E: + { + tlvbuf_wps_ie *wps_tlv = + (tlvbuf_wps_ie + *)ptr; + array_ptr = + wps_tlv->data; + printf("\t WPS UUID = "); + for (i = 0; i < wps_len; + i++) + printf("%2X ", + *array_ptr++); + printf("\n"); + } + break; + case SC_Primary_Device_Type: + { + tlvbuf_wps_ie *wps_tlv = + (tlvbuf_wps_ie + *)ptr; + array_ptr = + wps_tlv->data; + printf("\t WPS Primary Device Type = "); + for (i = 0; i < wps_len; + i++) + printf("%02X ", + *array_ptr++); + printf("\n"); + } + break; + case SC_RF_Band: + { + tlvbuf_wps_ie *wps_tlv = + (tlvbuf_wps_ie + *)ptr; + printf("\t WPS RF Band = 0x%x\n", *(wps_tlv->data)); + } + break; + case SC_Association_State: + { + t_u16 wps_association_state = 0; + tlvbuf_wps_ie *wps_tlv = + (tlvbuf_wps_ie + *)ptr; + memcpy(&wps_association_state, wps_tlv->data, sizeof(t_u16)); + printf("\t WPS Association State = 0x%x\n", wps_association_state); + } + break; + case SC_Configuration_Error: + { + t_u16 wps_configuration_error = 0; + tlvbuf_wps_ie *wps_tlv = + (tlvbuf_wps_ie + *)ptr; + memcpy(&wps_configuration_error, wps_tlv->data, sizeof(t_u16)); + wps_configuration_error + = + ntohs + (wps_configuration_error); + printf("\t WPS Configuration Error = 0x%x\n", wps_configuration_error); + } + break; + case SC_Device_Password_ID: + { + t_u16 wps_device_password_id = 0; + tlvbuf_wps_ie *wps_tlv = + (tlvbuf_wps_ie + *)ptr; + memcpy(&wps_device_password_id, wps_tlv->data, sizeof(t_u16)); + wps_device_password_id = + ntohs + (wps_device_password_id); + printf("\t WPS Device Password ID = 0x%x\n", wps_device_password_id); + } + break; + case SC_Device_Name: + { + tlvbuf_wps_ie *wps_tlv = + (tlvbuf_wps_ie + *)ptr; + array_ptr = + wps_tlv->data; + printf("\t WPS Device Name = "); + for (i = 0; i < wps_len; + i++) + printf("%c", + *array_ptr++); + printf("\n"); + } + break; + case SC_Manufacturer: + { + tlvbuf_wps_ie *wps_tlv = + (tlvbuf_wps_ie + *)ptr; + array_ptr = + wps_tlv->data; + printf("\t WPS Manufacturer = "); + for (i = 0; i < wps_len; + i++) + printf("%c", + *array_ptr++); + printf("\n"); + } + break; + case SC_Model_Name: + { + tlvbuf_wps_ie *wps_tlv = + (tlvbuf_wps_ie + *)ptr; + array_ptr = + wps_tlv->data; + printf("\t WPS Model Name = "); + for (i = 0; i < wps_len; + i++) + printf("%c", + *array_ptr++); + printf("\n"); + } + break; + case SC_Model_Number: + { + tlvbuf_wps_ie *wps_tlv = + (tlvbuf_wps_ie + *)ptr; + array_ptr = + wps_tlv->data; + printf("\t WPS Model Number = "); + for (i = 0; i < wps_len; + i++) + printf("%c", + *array_ptr++); + printf("\n"); + } + break; + case SC_Serial_Number: + { + tlvbuf_wps_ie *wps_tlv = + (tlvbuf_wps_ie + *)ptr; + array_ptr = + wps_tlv->data; + printf("\t WPS Serial Number = "); + for (i = 0; i < wps_len; + i++) + printf("%c", + *array_ptr++); + printf("\n"); + } + break; + case SC_Vendor_Extension: + { + tlvbuf_wps_ie *wps_tlv = + (tlvbuf_wps_ie + *)ptr; + array_ptr = + wps_tlv->data; + printf("\t WPS Vendor Extension = "); + for (i = 0; i < wps_len; + i++) + printf("0x%02x ", *array_ptr++); + printf("\n"); + } + break; + default: + printf("unknown ie=0x%x, len=%d\n", wps_type, wps_len); + break; + } + ptr += wps_len + sizeof(tlvbuf_wps_ie); + ie_len_wps -= + wps_len + sizeof(tlvbuf_wps_ie); + } + } + } else { + printf("ERR:Could not retrieve wifidirect parameters\n"); + } + } + + free(buf); + return; +} + +/** + * @brief Show usage information for the wifidirect_params_config command + * + * $return N/A + */ +static void +print_wifidirect_params_config_usage(void) +{ + printf("\nUsage : wifidirect_params_config \n"); + printf("\nIssue set or get request using parameters in the CONFIG_FILE.\n"); + return; +} + +/** + * @brief Creates a wifidirect_params_config request and sends to the driver + * + * Usage: "Usage : wifidirect_params_config " + * + * @param argc Number of arguments + * @param argv Pointer to the arguments + * @return None + */ +static void +wifidirectcmd_params_config(int argc, char *argv[]) +{ + wifidirect_params_config *param_buf = NULL; + tlvbuf_wps_ie *new_tlv = NULL; + char *line = NULL, wifidirect_mac[20]; + FILE *config_file = NULL; + int i, opt, li = 0, arg_num = 0, ret = 0; + char *args[30], *pos = NULL; + t_u8 dev_address[ETH_ALEN], enable_scan; + t_u8 *buffer = NULL, WPS_primarydevicetype[WPS_DEVICE_TYPE_MAX_LEN]; + t_u16 device_state = 0, tlv_len = 0, max_disc_int = 0, min_disc_int = + 0, cmd_len = 0; + + memset(wifidirect_mac, 0, sizeof(wifidirect_mac)); + + while ((opt = getopt_long(argc, argv, "+", cmd_options, NULL)) != -1) { + switch (opt) { + default: + print_wifidirect_params_config_usage(); + return; + } + } + argc -= optind; + argv += optind; + + /* Check arguments */ + if (argc < 2) { + printf("ERR:wrong number of arguments.\n"); + print_wifidirect_params_config_usage(); + return; + } + + cmd_len = sizeof(wifidirect_params_config); + buffer = (t_u8 *)malloc(MRVDRV_SIZE_OF_CMD_BUFFER); + if (!buffer) { + printf("ERR:Cannot allocate memory!\n"); + goto done; + } + memset(buffer, 0, MRVDRV_SIZE_OF_CMD_BUFFER); + param_buf = (wifidirect_params_config *)buffer; + param_buf->cmd_code = HostCmd_CMD_WIFIDIRECT_PARAMS_CONFIG; + param_buf->seq_num = 0; + param_buf->result = 0; + + if (argc >= 3) { + /* Check if file exists */ + config_file = fopen(argv[2], "r"); + if (config_file == NULL) { + printf("\nERR:Config file can not open.\n"); + goto done; + } + line = (char *)malloc(MAX_CONFIG_LINE); + if (!line) { + printf("ERR:Cannot allocate memory for line\n"); + goto done; + } + memset(line, 0, MAX_CONFIG_LINE); + param_buf->action = cpu_to_le16(ACTION_SET); + + /* Parse file and process */ + while (config_get_line + (line, MAX_CONFIG_LINE, config_file, &li, &pos)) { + arg_num = parse_line(line, args, 30); + + if (strcmp(args[0], "EnableScan") == 0) { + if (is_input_valid + (WIFIDIRECT_ENABLE_SCAN, arg_num - 1, + args + 1) + != SUCCESS) { + goto done; + + } + enable_scan = (t_u8)atoi(args[1]); + /* Append a new TLV */ + tlv_len = sizeof(tlvbuf_wps_ie) + sizeof(t_u8); + new_tlv = (tlvbuf_wps_ie *)(buffer + cmd_len); + cmd_len += tlv_len; + /* Set TLV fields */ + new_tlv->tag = + MRVL_WIFIDIRECT_SCAN_ENABLE_TLV_ID; + new_tlv->length = tlv_len - 2 * sizeof(t_u16); + memcpy(new_tlv->data, &enable_scan, + sizeof(t_u8)); + endian_convert_tlv_header_out(new_tlv); + + } else if (strcmp(args[0], "ScanPeerDeviceId") == 0) { + strncpy(wifidirect_mac, args[1], + sizeof(wifidirect_mac) - 1); + if ((ret = + mac2raw(wifidirect_mac, + dev_address)) != SUCCESS) { + printf("ERR: %s Address \n", + ret == + FAILURE ? "Invalid MAC" : ret == + WIFIDIRECT_RET_MAC_BROADCAST ? + "Broadcast" : "Multicast"); + goto done; + } + /* Append a new TLV */ + tlv_len = sizeof(tlvbuf_wps_ie) + ETH_ALEN; + new_tlv = (tlvbuf_wps_ie *)(buffer + cmd_len); + cmd_len += tlv_len; + /* Set TLV fields */ + new_tlv->tag = + MRVL_WIFIDIRECT_PEER_DEVICE_TLV_ID; + new_tlv->length = tlv_len - 2 * sizeof(t_u16); + memcpy(new_tlv->data, dev_address, ETH_ALEN); + endian_convert_tlv_header_out(new_tlv); + + } else if (strcmp(args[0], "MinDiscoveryInterval") == 0) { + if (is_input_valid + (WIFIDIRECT_MINDISCOVERYINT, arg_num - 1, + args + 1) != SUCCESS) { + goto done; + } + min_disc_int = cpu_to_le16(atoi(args[1])); + } else if (strcmp(args[0], "MaxDiscoveryInterval") == 0) { + if (is_input_valid + (WIFIDIRECT_MAXDISCOVERYINT, arg_num - 1, + args + 1) != SUCCESS) { + goto done; + } + max_disc_int = cpu_to_le16(atoi(args[1])); + + /* Append a new TLV */ + tlv_len = + sizeof(tlvbuf_wps_ie) + + 2 * sizeof(t_u16); + new_tlv = (tlvbuf_wps_ie *)(buffer + cmd_len); + cmd_len += tlv_len; + /* Set TLV fields */ + new_tlv->tag = + MRVL_WIFIDIRECT_DISC_PERIOD_TLV_ID; + new_tlv->length = tlv_len - 2 * sizeof(t_u16); + memcpy(&new_tlv->data, &min_disc_int, + sizeof(t_u16)); + memcpy((((t_u8 *)&new_tlv->data) + + sizeof(t_u16)), &max_disc_int, + sizeof(t_u16)); + endian_convert_tlv_header_out(new_tlv); + + } else if (strcmp(args[0], "ScanRequestDeviceType") == + 0) { + if (is_input_valid + (WIFIDIRECT_WPSPRIMARYDEVICETYPE, + arg_num - 1, args + 1) + != SUCCESS) { + goto done; + } + for (i = 0; i < WPS_DEVICE_TYPE_MAX_LEN; i++) + WPS_primarydevicetype[i] = + (t_u8)A2HEXDECIMAL(args[i + 1]); + + /* Append a new TLV */ + tlv_len = + sizeof(tlvbuf_wps_ie) + + WPS_DEVICE_TYPE_MAX_LEN; + new_tlv = (tlvbuf_wps_ie *)(buffer + cmd_len); + cmd_len += tlv_len; + /* Set TLV fields */ + new_tlv->tag = + MRVL_WIFIDIRECT_SCAN_REQ_DEVICE_TLV_ID; + new_tlv->length = tlv_len - 2 * sizeof(t_u16); + memcpy(&new_tlv->data, WPS_primarydevicetype, + WPS_DEVICE_TYPE_MAX_LEN); + endian_convert_tlv_header_out(new_tlv); + + } else if (strcmp(args[0], "DeviceState") == 0) { + if (is_input_valid + (WIFIDIRECT_DEVICE_STATE, arg_num - 1, + args + 1) + != SUCCESS) { + goto done; + } + device_state = + cpu_to_le16((t_u16)atoi(args[1])); + + /* Append a new TLV */ + tlv_len = sizeof(tlvbuf_wps_ie) + sizeof(t_u16); + new_tlv = (tlvbuf_wps_ie *)(buffer + cmd_len); + cmd_len += tlv_len; + /* Set TLV fields */ + new_tlv->tag = + MRVL_WIFIDIRECT_DEVICE_STATE_TLV_ID; + new_tlv->length = tlv_len - 2 * sizeof(t_u16); + memcpy(new_tlv->data, &device_state, + sizeof(t_u16)); + endian_convert_tlv_header_out(new_tlv); + } + } + } + + param_buf->size = cmd_len; + /* Send collective command */ + wifidirect_ioctl((t_u8 *)buffer, &cmd_len, MRVDRV_SIZE_OF_CMD_BUFFER); + + /* Process response */ + if (argc < 3) { + /* Verify response */ + if (param_buf->cmd_code != + (HostCmd_CMD_WIFIDIRECT_PARAMS_CONFIG | + WIFIDIRECTCMD_RESP_CHECK)) { + printf("ERR:Corrupted response!\n"); + goto done; + } + /* Print response */ + if (param_buf->result == CMD_SUCCESS) { + param_buf = (wifidirect_params_config *)buffer; + new_tlv = (tlvbuf_wps_ie *)param_buf->wifidirect_tlv; + tlv_len = + param_buf->size - + (sizeof(wifidirect_params_config) - + BUF_HEADER_SIZE); + if (tlv_len > sizeof(tlvbuf_wps_ie)) + printf("WifiDirect Parameter settings: \n"); + else + printf("WifiDirect Parameter settings are not received.\n"); + while (tlv_len > sizeof(tlvbuf_wps_ie)) { + endian_convert_tlv_header_in(new_tlv); + switch (new_tlv->tag) { + case MRVL_WIFIDIRECT_SCAN_ENABLE_TLV_ID: + { + enable_scan = + *((t_u8 *)&new_tlv-> + data); + printf("\t Scan %s\n", + (enable_scan == + 1) ? "enabled." : + "disabled."); + } + break; + case MRVL_WIFIDIRECT_PEER_DEVICE_TLV_ID: + { + memcpy(dev_address, + new_tlv->data, ETH_ALEN); + printf("\t Peer Device ID : "); + print_mac(dev_address); + printf("\n"); + } + break; + case MRVL_WIFIDIRECT_DISC_PERIOD_TLV_ID: + { + t_u16 temp; + memcpy(&temp, &new_tlv->data, + sizeof(t_u16)); + printf("\t Minimum Discovery Interval : %d\n", le16_to_cpu(temp)); + memcpy(&temp, + ((t_u8 *)&new_tlv-> + data) + sizeof(t_u16), + sizeof(t_u16)); + printf("\t Maximum Discovery Interval : %d\n", le16_to_cpu(temp)); + } + break; + case MRVL_WIFIDIRECT_SCAN_REQ_DEVICE_TLV_ID: + { + memcpy(WPS_primarydevicetype, + &new_tlv->data, + WPS_DEVICE_TYPE_MAX_LEN); + printf("\tType: %02x:%02x\n", + (unsigned int) + WPS_primarydevicetype[0], + (unsigned int) + WPS_primarydevicetype + [1]); + printf("\tOUI: %02x:%02x:%02x:%02x\n", (unsigned int)WPS_primarydevicetype[2], (unsigned int)WPS_primarydevicetype[3], (unsigned int)WPS_primarydevicetype[4], (unsigned int)WPS_primarydevicetype[5]); + printf("\tSubType: %02x:%02x\n", + (unsigned int) + WPS_primarydevicetype[6], + (unsigned int) + WPS_primarydevicetype + [7]); + } + break; + case MRVL_WIFIDIRECT_DEVICE_STATE_TLV_ID: + { + memcpy(&device_state, + &new_tlv->data, + sizeof(t_u16)); + printf("\t Device State %d\n", + le16_to_cpu + (device_state)); + } + break; + default: + printf("Unknown ie=0x%x, len=%d\n", + new_tlv->tag, new_tlv->length); + break; + } + tlv_len -= + new_tlv->length + sizeof(tlvbuf_wps_ie); + new_tlv = + (tlvbuf_wps_ie *)(((t_u8 *)new_tlv) + + new_tlv->length + + sizeof + (tlvbuf_wps_ie)); + } + } else { + printf("ERR:Could not retrieve wifidirect parameters.\n"); + } + } + +done: + if (config_file) + fclose(config_file); + if (line) + free(line); + if (buffer) + free(buffer); + return; +} + +/** + * @brief Show usage information for the wifidirect_action_frame command + * + * $return N/A + */ +static void +print_wifidirect_action_frame_usage(void) +{ + printf("\nUsage : wifidirect_action_frame |" + " [ ]\n"); + printf("\nAction frame is sent using parameters in the CONFIG_FILE " + "or parameters specified on command line.\n"); + return; +} + +/** + * @brief Creates a wifidirect_action_frame request and sends to the driver + * + * Usage: "Usage : wifidirect_action_frame | + * [ ]" + * + * @param argc Number of arguments + * @param argv Pointer to the arguments + * @return None + */ +static void +wifidirectcmd_action_frame(int argc, char *argv[]) +{ + wifidirect_action_frame *action_buf = NULL; + char *line = NULL, wifidirect_mac[20]; + FILE *config_file = NULL; + int i, opt, li = 0, arg_num = 0, ret = 0, cmd_found = 0; + char *args[30], *pos = NULL; + t_u8 dev_address[ETH_ALEN]; + t_u8 *buffer = NULL; + t_u16 ie_len = 0, cmd_len = 0; + + memset(wifidirect_mac, 0, sizeof(wifidirect_mac)); + + while ((opt = getopt_long(argc, argv, "+", cmd_options, NULL)) != -1) { + switch (opt) { + default: + print_wifidirect_action_frame_usage(); + return; + } + } + argc -= optind; + argv += optind; + + /* Check arguments */ + if ((argc != 3) && (argc != 6)) { + printf("ERR:wrong number of arguments.\n"); + print_wifidirect_action_frame_usage(); + return; + } + + cmd_len = sizeof(wifidirect_action_frame); + buffer = (t_u8 *)malloc(MRVDRV_SIZE_OF_CMD_BUFFER); + if (!buffer) { + printf("ERR:Cannot allocate memory!\n"); + goto done; + } + memset(buffer, 0, MRVDRV_SIZE_OF_CMD_BUFFER); + action_buf = (wifidirect_action_frame *)buffer; + action_buf->cmd_code = HostCmd_CMD_802_11_ACTION_FRAME; + action_buf->seq_num = 0; + action_buf->result = 0; + + /* Check if file exists */ + config_file = fopen(argv[2], "r"); + if (config_file && argc == 3) { + line = (char *)malloc(MAX_CONFIG_LINE); + if (!line) { + printf("ERR:Cannot allocate memory for line\n"); + goto done; + } + + /* Parse file and process */ + while (config_get_line + (line, MAX_CONFIG_LINE, config_file, &li, &pos)) { + arg_num = parse_line(line, args, 30); + + if (strcmp(args[0], argv[1]) == 0) { + cmd_found = 1; + } + if (cmd_found == 0) + continue; + + if (strcmp(args[0], "}") == 0) { + cmd_found = 0; + } else if (strcmp(args[0], "Category") == 0) { + if (is_input_valid + (WIFIDIRECT_CATEGORY, arg_num - 1, args + 1) + != SUCCESS) { + goto done; + + } + action_buf->category = (t_u8)atoi(args[1]); + + } else if (strcmp(args[0], "PeerAddr") == 0) { + strncpy(wifidirect_mac, args[1], + sizeof(wifidirect_mac) - 1); + if ((ret = + mac2raw(wifidirect_mac, + dev_address)) != SUCCESS) { + printf("ERR: %s Address \n", + ret == + FAILURE ? "Invalid MAC" : ret == + WIFIDIRECT_RET_MAC_BROADCAST ? + "Broadcast" : "Multicast"); + goto done; + } + memcpy(action_buf->peer_mac_addr, dev_address, + ETH_ALEN); + } else if (strcmp(args[0], "Action") == 0) { + if (is_input_valid + (WIFIDIRECT_ACTION, arg_num - 1, args + 1) + != SUCCESS) { + goto done; + } + action_buf->action = + (t_u8)A2HEXDECIMAL(args[1]); + + } else if (strcmp(args[0], "DialogToken") == 0) { + if (is_input_valid + (WIFIDIRECT_DIALOGTOKEN, arg_num - 1, + args + 1) + != SUCCESS) { + goto done; + } + action_buf->dialog_taken = (t_u8)atoi(args[1]); + + } else if (strcmp(args[0], "OUI") == 0) { + if (is_input_valid + (WIFIDIRECT_OUI, arg_num - 1, args + 1) + != SUCCESS) { + goto done; + } + for (i = 0; i < MIN(arg_num - 1, MAX_OUI_LEN); + i++) + action_buf->oui[i] = + A2HEXDECIMAL(args[i + 1]); + } else if (strcmp(args[0], "OUIType") == 0) { + if (is_input_valid + (WIFIDIRECT_OUITYPE, arg_num - 1, args + 1) + != SUCCESS) { + goto done; + } + action_buf->oui_type = (t_u8)atoi(args[1]); + } else if (strcmp(args[0], "OUISubType") == 0) { + if (is_input_valid + (WIFIDIRECT_OUISUBTYPE, arg_num - 1, + args + 1) + != SUCCESS) { + goto done; + } + action_buf->oui_sub_type = (t_u8)atoi(args[1]); + } + } + fclose(config_file); + config_file = NULL; + + /* Now, read IE parameters from file */ + wifidirect_file_params_config(argv[2], argv[1], + action_buf->ie_list, &ie_len, + NULL); + if ((cmd_len + ie_len) >= MRVDRV_SIZE_OF_CMD_BUFFER) { + printf("ERR:Too much data in configuration file %s.\n", + argv[2]); + free(buffer); + return; + } + cmd_len += ie_len; + } else { + if (argc == 3) { + printf("ERR:Can not open config file.\n"); + goto done; + } + strncpy(wifidirect_mac, argv[2], sizeof(wifidirect_mac) - 1); + if ((ret = mac2raw(wifidirect_mac, dev_address)) != SUCCESS) { + printf("ERR: %s Address \n", + ret == FAILURE ? "Invalid MAC" : ret == + WIFIDIRECT_RET_MAC_BROADCAST ? "Broadcast" : + "Multicast"); + goto done; + } + memcpy(action_buf->peer_mac_addr, dev_address, ETH_ALEN); + + if (is_input_valid(WIFIDIRECT_CATEGORY, 1, &argv[3]) + != SUCCESS) { + goto done; + } + action_buf->category = (t_u8)atoi(argv[3]); + + if (is_input_valid(WIFIDIRECT_OUISUBTYPE, 1, &argv[4]) + != SUCCESS) { + goto done; + } + action_buf->oui_sub_type = (t_u8)atoi(argv[4]); + + if (is_input_valid(WIFIDIRECT_DIALOGTOKEN, 1, &argv[5]) + != SUCCESS) { + goto done; + } + action_buf->dialog_taken = (t_u8)atoi(argv[5]); + + action_buf->action = 0; + action_buf->oui[0] = 0x50; + action_buf->oui[1] = 0x6F; + action_buf->oui[2] = 0x9A; + action_buf->oui_type = OUI_TYPE_WFA_WIFIDIRECT; + } + action_buf->size = cmd_len; +#ifdef DEBUG + /* Debug print */ + hexdump(buffer, cmd_len, ' '); +#endif + /* Send collective command */ + wifidirect_ioctl((t_u8 *)buffer, &cmd_len, MRVDRV_SIZE_OF_CMD_BUFFER); + +done: + if (config_file) + fclose(config_file); + if (line) + free(line); + if (buffer) + free(buffer); + return; +} + +/** + * @brief Show usage information for the wifidirect status command + * + * $return N/A + */ +static void +print_wifidirect_status_usage(void) +{ + printf("\nUsage : wifidirect_mode [STATUS]"); + printf("\nOptions: STATUS : 0 - stop wifidirect status"); + printf("\n 1 - start wifidirect status"); + printf("\n 2 - start wifidirect group owner mode"); + printf("\n 3 - start wifidirect client mode"); + printf("\n 4 - start wifidirect find phase"); + printf("\n 5 - stop wifidirect find phase"); + printf("\n empty - get current wifidirect status\n"); + return; +} + +/** + * @brief Creates wifidirect mode start or stop request and send to driver + * + * Usage: "Usage : wifidirect_mode [STATUS]" + * + * Options: STATUS : 0 - start wifidirect status + * 1 - stop wifidirect status + * + * @param argc Number of arguments + * @param argv Pointer to the arguments + * @return N/A + */ +static void +wifidirectcmd_status(int argc, char *argv[]) +{ + int opt, ret; + t_u16 data = 0; + t_u16 cmd_len = 0; + t_u8 *buffer = NULL; + wifidirect_mode_config *cmd_buf = NULL; + while ((opt = getopt_long(argc, argv, "+", cmd_options, NULL)) != -1) { + switch (opt) { + default: + print_wifidirect_status_usage(); + return; + } + } + argc -= optind; + argv += optind; + /* Check arguments */ + if (argc < 2) { + printf("ERR:wrong arguments.\n"); + print_wifidirect_status_usage(); + return; + } + if (argc == 3) { + if ((ISDIGIT(argv[2]) == 0) || (atoi(argv[2]) < 0) || + (atoi(argv[2]) >= 0xFF)) { + printf("ERR:Illegal wifidirect mode %s. Must be in range from '0' to '5'.\n", argv[2]); + print_wifidirect_status_usage(); + return; + } + data = (t_u16)atoi(argv[2]); + } + + /* send hostcmd now */ + cmd_len = sizeof(wifidirect_mode_config); + buffer = (t_u8 *)malloc(MRVDRV_SIZE_OF_CMD_BUFFER); + if (!buffer) { + printf("ERR:Cannot allocate memory!\n"); + return; + } + + cmd_buf = (wifidirect_mode_config *)buffer; + cmd_buf->cmd_code = HostCmd_CMD_WIFIDIRECT_MODE_CONFIG; + cmd_buf->size = cmd_len - BUF_HEADER_SIZE; + cmd_buf->seq_num = 0; + cmd_buf->result = 0; + + if (argc == 2) { + cmd_buf->action = ACTION_GET; + } else { + cmd_buf->action = cpu_to_le16(ACTION_SET); + cmd_buf->mode = cpu_to_le16(data); + } + ret = wifidirect_ioctl((t_u8 *)buffer, &cmd_len, + MRVDRV_SIZE_OF_CMD_BUFFER); + if (ret != SUCCESS) { + printf("Error executing wifidirect mode command\n"); + free(buffer); + return; + } + + data = le16_to_cpu(cmd_buf->mode); + switch (data) { + case 0: + printf("Wifidirect Device Mode = Not Configured\n"); + break; + case 1: + printf("Wifidirect Device Mode = Device\n"); + break; + case 2: + printf("Wifidirect Device Mode = Wifidirect Group Owner (GO)\n"); + break; + case 3: + printf("Wifidirect Device Mode = Wifidirect Group Client (GC)\n"); + break; + default: + printf("Wifidirect Device Mode = Not specified\n"); + break; + } + free(buffer); + return; +} + +/** + * @brief Show usage information for the wifidirect discovery period command + * + * @return N/A + */ +static void +print_wifidirect_cfg_discovery_period_usage(void) +{ + printf("Usage : wifidirect_cfg_discovery_period [ ]\n"); + printf("For 'Set' both MinDiscPeriod and MaxDiscPeriod should be specified.\n"); + printf("If no parameter is given, 'get' is performed.\n"); + return; +} + +/** + * @brief Set/get wifidirect discovery period + * + * Usage: "Usage : wifidirect_cfg_discovery_period [ ]" + * + * @param argc Number of arguments + * @param argv Pointer to the arguments + * @return None + */ +static void +wifidirect_cfg_cmd_discovery_period(int argc, char *argv[]) +{ + wifidirect_params_config *cmd_buf = NULL; + tlvbuf_wifidirect_discovery_period *tlv = NULL; + t_u8 *buffer = NULL; + t_u16 cmd_len = 0; + int opt, ret = 0; + + while ((opt = getopt_long(argc, argv, "+", cmd_options, NULL)) != -1) { + switch (opt) { + default: + print_wifidirect_cfg_discovery_period_usage(); + return; + } + } + argc -= optind; + argv += optind; + + /* Check arguments */ + if ((argc != 2) && (argc != 4)) { + printf("ERR:wrong number of arguments.\n"); + print_wifidirect_cfg_discovery_period_usage(); + return; + } else if ((argc > 2) && + ((is_input_valid(WIFIDIRECT_MINDISCOVERYINT, 1, &argv[2]) != + SUCCESS) || + (is_input_valid(WIFIDIRECT_MAXDISCOVERYINT, 1, &argv[3]) != + SUCCESS))) { + print_wifidirect_cfg_discovery_period_usage(); + return; + } + + cmd_len = + sizeof(wifidirect_params_config) + + sizeof(tlvbuf_wifidirect_discovery_period); + + buffer = (t_u8 *)malloc(MRVDRV_SIZE_OF_CMD_BUFFER); + + if (!buffer) { + printf("ERR:Cannot allocate memory!\n"); + goto done; + } + + memset(buffer, 0, MRVDRV_SIZE_OF_CMD_BUFFER); + + cmd_buf = (wifidirect_params_config *)buffer; + tlv = (tlvbuf_wifidirect_discovery_period *)(buffer + + sizeof + (wifidirect_params_config)); + + cmd_buf->cmd_code = HostCmd_CMD_WIFIDIRECT_PARAMS_CONFIG; + cmd_buf->size = cmd_len - BUF_HEADER_SIZE; + cmd_buf->seq_num = 0; + cmd_buf->result = 0; + + tlv->tag = MRVL_WIFIDIRECT_DISC_PERIOD_TLV_ID; + tlv->length = + sizeof(tlvbuf_wifidirect_discovery_period) - + MRVL_TLV_HEADER_SIZE; + + if (argc == 2) { + cmd_buf->action = ACTION_GET; + } else { + cmd_buf->action = cpu_to_le16(ACTION_SET); + tlv->min_disc_interval = cpu_to_le16((t_u16)atoi(argv[2])); + tlv->max_disc_interval = cpu_to_le16((t_u16)atoi(argv[3])); + } + endian_convert_tlv_header_out(tlv); + +#ifdef DEBUG + hexdump(buffer, cmd_len, ' '); +#endif + + ret = wifidirect_ioctl((t_u8 *)buffer, &cmd_len, + MRVDRV_SIZE_OF_CMD_BUFFER); + endian_convert_tlv_header_in(tlv); + +#ifdef DEBUG + hexdump(buffer, cmd_len + BUF_HEADER_SIZE, ' '); +#endif + + /* Process Response */ + if (ret == SUCCESS) { + /* Verify response */ + if (cmd_buf->cmd_code != + (HostCmd_CMD_WIFIDIRECT_PARAMS_CONFIG | + WIFIDIRECTCMD_RESP_CHECK)) { + printf("ERR:Corrupted response!\n"); + goto done; + } + /* Print response */ + if (cmd_buf->result == CMD_SUCCESS) { + if (argc == 2) { + printf("Min Discovery period = %d\n", + le16_to_cpu(tlv->min_disc_interval)); + printf("Max discovery period = %d\n", + le16_to_cpu(tlv->max_disc_interval)); + } else { + printf("Discovery period setting successful!\n"); + } + } else { + if (argc == 2) { + printf("ERR:Couldn't get min and max discovery period!\n"); + } else { + printf("ERR:Couldn't set min and max discovery period!\n"); + } + } + } else { + printf("ERR:Command sending failed!\n"); + } +done: + if (buffer) + free(buffer); + return; +} + +/** + * @brief Show usage information for the wifidirect Intent command + * + * @return N/A + */ +static void +print_wifidirect_cfg_intent_usage(void) +{ + printf("Usage : wifidirect_cfg_intent [IntentValue]\n"); + printf("If IntentValue parameter is provided, 'set' is performed otherwise 'get' is performed.\n"); + return; +} + +/** + * @brief Set/get wifidirect Intent + * + * Usage: "Usage : wifidirect_cfg_intent [IntentValue]" + * + * @param argc Number of arguments + * @param argv Pointer to the arguments + * @return None + */ +static void +wifidirect_cfg_cmd_intent(int argc, char *argv[]) +{ + wifidirect_params_config *cmd_buf = NULL; + tlvbuf_wifidirect_intent *tlv = NULL; + t_u8 *buffer = NULL; + t_u16 cmd_len = 0; + int opt, ret = 0; + + while ((opt = getopt_long(argc, argv, "+", cmd_options, NULL)) != -1) { + switch (opt) { + default: + print_wifidirect_cfg_intent_usage(); + return; + } + } + argc -= optind; + argv += optind; + + /* Check arguments */ + if (argc < 2) { + printf("ERR: Wrong number of arguments!\n"); + print_wifidirect_cfg_intent_usage(); + return; + } else if ((argc > 2) && + (is_input_valid(WIFIDIRECT_INTENT, argc - 2, argv + 2) != + SUCCESS)) { + print_wifidirect_cfg_intent_usage(); + return; + } + cmd_len = + sizeof(wifidirect_params_config) + + sizeof(tlvbuf_wifidirect_intent); + + buffer = (t_u8 *)malloc(MRVDRV_SIZE_OF_CMD_BUFFER); + + if (!buffer) { + printf("ERR:Cannot allocate memory!\n"); + goto done; + } + + memset(buffer, 0, MRVDRV_SIZE_OF_CMD_BUFFER); + + cmd_buf = (wifidirect_params_config *)buffer; + tlv = (tlvbuf_wifidirect_intent *)(buffer + + sizeof(wifidirect_params_config)); + + cmd_buf->cmd_code = HostCmd_CMD_WIFIDIRECT_PARAMS_CONFIG; + cmd_buf->size = cmd_len - BUF_HEADER_SIZE; + cmd_buf->seq_num = 0; + cmd_buf->result = 0; + + tlv->tag = MRVL_WIFIDIRECT_INTENT_TLV_ID; + tlv->length = sizeof(tlvbuf_wifidirect_intent) - MRVL_TLV_HEADER_SIZE; + + if (argc == 2) { + cmd_buf->action = ACTION_GET; + } else { + cmd_buf->action = cpu_to_le16(ACTION_SET); + tlv->intent = (t_u8)atoi(argv[2]); + } + endian_convert_tlv_header_out(tlv); +#ifdef DEBUG + hexdump(buffer, cmd_len, ' '); +#endif + ret = wifidirect_ioctl((t_u8 *)buffer, &cmd_len, + MRVDRV_SIZE_OF_CMD_BUFFER); + endian_convert_tlv_header_in(tlv); +#ifdef DEBUG + hexdump(buffer, cmd_len + BUF_HEADER_SIZE, ' '); +#endif + /* Process Response */ + if (ret == SUCCESS) { + /* Verify response */ + if (cmd_buf->cmd_code != + (HostCmd_CMD_WIFIDIRECT_PARAMS_CONFIG | + WIFIDIRECTCMD_RESP_CHECK)) { + printf("ERR:Corrupted response!\n"); + goto done; + } + /* Print response */ + if (cmd_buf->result == CMD_SUCCESS) { + if (argc == 2) { + printf("Intent Value = %d\n", (int)tlv->intent); + } else { + printf("Intent value setting successful!\n"); + } + } else { + if (argc == 2) { + printf("ERR:Couldn't get Intent value!\n"); + } else { + printf("ERR:Couldn't set Intent value!\n"); + } + } + } else { + printf("ERR:Command sending failed!\n"); + } +done: + if (buffer) + free(buffer); + return; +} + +/** + * @brief Show usage information for the wifidirect Listen Channel command + * + * @return N/A + */ +static void +print_wifidirect_cfg_listen_channel_usage(void) +{ + printf("Usage : wifidirect_cfg_listen_channel [ListenChannel]\n"); + printf("If ListenChannel parameter is provided, 'set' is performed otherwise 'get' is performed.\n"); + return; +} + +/** + * @brief Set/get wifidirect ListenChannel + * + * Usage: "Usage : wifidirect_cfg_listen_channel [ListenChannel]" + * + * @param argc Number of arguments + * @param argv Pointer to the arguments + * @return None + */ +static void +wifidirect_cfg_cmd_listen_channel(int argc, char *argv[]) +{ + wifidirect_params_config *cmd_buf = NULL; + tlvbuf_wifidirect_listen_channel *tlv = NULL; + t_u8 *buffer = NULL; + t_u16 cmd_len = 0; + int opt, ret = 0; + + while ((opt = getopt_long(argc, argv, "+", cmd_options, NULL)) != -1) { + switch (opt) { + default: + print_wifidirect_cfg_listen_channel_usage(); + return; + } + } + argc -= optind; + argv += optind; + + /* Check arguments */ + if (argc < 2) { + printf("ERR: Wrong number of arguments!\n"); + print_wifidirect_cfg_listen_channel_usage(); + return; + } else if ((argc > 2) && + (is_input_valid(CHANNEL, argc - 2, argv + 2) != SUCCESS)) { + print_wifidirect_cfg_listen_channel_usage(); + return; + } + cmd_len = + sizeof(wifidirect_params_config) + + sizeof(tlvbuf_wifidirect_listen_channel); + + buffer = (t_u8 *)malloc(MRVDRV_SIZE_OF_CMD_BUFFER); + + if (!buffer) { + printf("ERR:Cannot allocate memory!\n"); + goto done; + } + + memset(buffer, 0, MRVDRV_SIZE_OF_CMD_BUFFER); + + cmd_buf = (wifidirect_params_config *)buffer; + tlv = (tlvbuf_wifidirect_listen_channel *)(buffer + + sizeof + (wifidirect_params_config)); + + cmd_buf->cmd_code = HostCmd_CMD_WIFIDIRECT_PARAMS_CONFIG; + cmd_buf->size = cmd_len - BUF_HEADER_SIZE; + cmd_buf->seq_num = 0; + cmd_buf->result = 0; + + tlv->tag = MRVL_WIFIDIRECT_LISTEN_CHANNEL_TLV_ID; + tlv->length = + sizeof(tlvbuf_wifidirect_listen_channel) - MRVL_TLV_HEADER_SIZE; + + if (argc == 2) { + cmd_buf->action = ACTION_GET; + } else { + cmd_buf->action = cpu_to_le16(ACTION_SET); + tlv->listen_channel = (t_u8)atoi(argv[2]); + } + endian_convert_tlv_header_out(tlv); +#ifdef DEBUG + hexdump(buffer, cmd_len, ' '); +#endif + ret = wifidirect_ioctl((t_u8 *)buffer, &cmd_len, + MRVDRV_SIZE_OF_CMD_BUFFER); + endian_convert_tlv_header_in(tlv); +#ifdef DEBUG + hexdump(buffer, cmd_len + BUF_HEADER_SIZE, ' '); +#endif + /* Process Response */ + if (ret == SUCCESS) { + /* Verify response */ + if (cmd_buf->cmd_code != + (HostCmd_CMD_WIFIDIRECT_PARAMS_CONFIG | + WIFIDIRECTCMD_RESP_CHECK)) { + printf("ERR:Corrupted response!\n"); + goto done; + } + /* Print response */ + if (cmd_buf->result == CMD_SUCCESS) { + if (argc == 2) { + printf("Listen Channel = %d\n", + (int)tlv->listen_channel); + } else { + printf("Listen Channel setting successful!\n"); + } + } else { + if (argc == 2) { + printf("ERR:Couldn't get Listen Channel!\n"); + } else { + printf("ERR:Couldn't set Listen Channel!\n"); + } + } + } else { + printf("ERR:Command sending failed!\n"); + } +done: + if (buffer) + free(buffer); + return; +} + +/** + * @brief Show usage information for the wifidirect Operating Channel command + * + * @return N/A + */ +static void +print_wifidirect_cfg_op_channel_usage(void) +{ + printf("Usage : wifidirect_cfg_op_channel [OperatingChannel]\n"); + printf("If OperatingChannel parameter is provided, 'set' is performed otherwise 'get' is performed.\n"); + return; +} + +/** + * @brief Set/get wifidirect OperatingChannel + * + * Usage: "Usage : wifidirect_cfg_op_channel [OperatingChannel]" + * + * @param argc Number of arguments + * @param argv Pointer to the arguments + * @return None + */ +static void +wifidirect_cfg_cmd_op_channel(int argc, char *argv[]) +{ + wifidirect_params_config *cmd_buf = NULL; + tlvbuf_wifidirect_operating_channel *tlv = NULL; + t_u8 *buffer = NULL; + t_u16 cmd_len = 0; + int opt, ret = 0; + + while ((opt = getopt_long(argc, argv, "+", cmd_options, NULL)) != -1) { + switch (opt) { + default: + print_wifidirect_cfg_op_channel_usage(); + return; + } + } + argc -= optind; + argv += optind; + + /* Check arguments */ + if (argc < 2) { + printf("ERR: Wrong number of arguments!\n"); + print_wifidirect_cfg_op_channel_usage(); + return; + } else if ((argc > 2) && + (is_input_valid(CHANNEL, argc - 2, argv + 2) != SUCCESS)) { + print_wifidirect_cfg_op_channel_usage(); + return; + } + cmd_len = + sizeof(wifidirect_params_config) + + sizeof(tlvbuf_wifidirect_operating_channel); + + buffer = (t_u8 *)malloc(MRVDRV_SIZE_OF_CMD_BUFFER); + + if (!buffer) { + printf("ERR:Cannot allocate memory!\n"); + goto done; + } + + memset(buffer, 0, MRVDRV_SIZE_OF_CMD_BUFFER); + + cmd_buf = (wifidirect_params_config *)buffer; + tlv = (tlvbuf_wifidirect_operating_channel *)(buffer + + sizeof + (wifidirect_params_config)); + + cmd_buf->cmd_code = HostCmd_CMD_WIFIDIRECT_PARAMS_CONFIG; + cmd_buf->size = cmd_len - BUF_HEADER_SIZE; + cmd_buf->seq_num = 0; + cmd_buf->result = 0; + + tlv->tag = MRVL_WIFIDIRECT_OPERATING_CHANNEL_TLV_ID; + tlv->length = + sizeof(tlvbuf_wifidirect_operating_channel) - + MRVL_TLV_HEADER_SIZE; + + if (argc == 2) { + cmd_buf->action = ACTION_GET; + } else { + cmd_buf->action = cpu_to_le16(ACTION_SET); + tlv->operating_channel = (t_u8)atoi(argv[2]); + } + endian_convert_tlv_header_out(tlv); +#ifdef DEBUG + hexdump(buffer, cmd_len, ' '); +#endif + ret = wifidirect_ioctl((t_u8 *)buffer, &cmd_len, + MRVDRV_SIZE_OF_CMD_BUFFER); + endian_convert_tlv_header_in(tlv); +#ifdef DEBUG + hexdump(buffer, cmd_len + BUF_HEADER_SIZE, ' '); +#endif + /* Process Response */ + if (ret == SUCCESS) { + /* Verify response */ + if (cmd_buf->cmd_code != + (HostCmd_CMD_WIFIDIRECT_PARAMS_CONFIG | + WIFIDIRECTCMD_RESP_CHECK)) { + printf("ERR:Corrupted response!\n"); + goto done; + } + /* Print response */ + if (cmd_buf->result == CMD_SUCCESS) { + if (argc == 2) { + printf("Operating Channel = %d\n", + (int)tlv->operating_channel); + } else { + printf("Operating Channel setting successful!\n"); + } + } else { + if (argc == 2) { + printf("ERR:Couldn't get Operating Channel!\n"); + } else { + printf("ERR:Couldn't set Operating Channel!\n"); + } + } + } else { + printf("ERR:Command sending failed!\n"); + } +done: + if (buffer) + free(buffer); + return; +} + +/** + * @brief Show usage information for the wifidirect Invitation List command + * + * @return N/A + */ +static void +print_wifidirect_cfg_invitation_list_usage(void) +{ + printf("\nUsage : wifidirect_cfg_invitation_list [mac_addr]"); + printf("\nIf mac_addr parameter is provided, 'set' is performed otherwise 'get' is performed.\n"); + return; +} + +/** + * @brief Set/get wifidirect InvitationList + * + * Usage: "Usage : wifidirect_cfg_invitation_list [mac_addr]" + * + * @param argc Number of arguments + * @param argv Pointer to the arguments + * @return None + */ +static void +wifidirect_cfg_cmd_invitation_list(int argc, char *argv[]) +{ + wifidirect_params_config *cmd_buf = NULL; + tlvbuf_wifidirect_invitation_list *tlv = NULL; + t_u8 *buffer = NULL; + t_u16 cmd_len = 0; + int opt, ret = 0, ctr = 1; + + while ((opt = getopt_long(argc, argv, "+", cmd_options, NULL)) != -1) { + switch (opt) { + default: + print_wifidirect_cfg_invitation_list_usage(); + return; + } + } + argc -= optind; + argv += optind; + + /* Check arguments */ + if ((argc < 2) || (argc > 3)) { + printf("ERR:Wrong number of arguments!\n"); + print_wifidirect_cfg_invitation_list_usage(); + return; + } + + cmd_len = + sizeof(wifidirect_params_config) + + sizeof(tlvbuf_wifidirect_invitation_list); + + buffer = (t_u8 *)malloc(MRVDRV_SIZE_OF_CMD_BUFFER); + + if (!buffer) { + printf("ERR:Cannot allocate memory!\n"); + goto done; + } + + memset(buffer, 0, MRVDRV_SIZE_OF_CMD_BUFFER); + + cmd_buf = (wifidirect_params_config *)buffer; + tlv = (tlvbuf_wifidirect_invitation_list *)(buffer + + sizeof + (wifidirect_params_config)); + + cmd_buf->cmd_code = HostCmd_CMD_WIFIDIRECT_PARAMS_CONFIG; + cmd_buf->size = cmd_len - BUF_HEADER_SIZE; + cmd_buf->seq_num = 0; + cmd_buf->result = 0; + + tlv->tag = MRVL_WIFIDIRECT_INVITATION_LIST_TLV_ID; + tlv->length = + sizeof(tlvbuf_wifidirect_invitation_list) - + MRVL_TLV_HEADER_SIZE; + + if (argc == 2) { + cmd_buf->action = ACTION_GET; + cmd_len += (WIFIDIRECT_INVITATION_LIST_MAX - 1) * ETH_ALEN; + } else { + cmd_buf->action = cpu_to_le16(ACTION_SET); + if ((ret = mac2raw(argv[2], tlv->inv_peer_addr)) != SUCCESS) { + printf("ERR:Invalid MAC address %s\n", argv[2]); + goto done; + } + } + endian_convert_tlv_header_out(tlv); +#ifdef DEBUG + hexdump(buffer, cmd_len, ' '); +#endif + ret = wifidirect_ioctl((t_u8 *)buffer, &cmd_len, + MRVDRV_SIZE_OF_CMD_BUFFER); + endian_convert_tlv_header_in(tlv); +#ifdef DEBUG + hexdump(buffer, cmd_len + BUF_HEADER_SIZE, ' '); +#endif + /* Process Response */ + if (ret == SUCCESS) { + /* Verify response */ + if (cmd_buf->cmd_code != + (HostCmd_CMD_WIFIDIRECT_PARAMS_CONFIG | + WIFIDIRECTCMD_RESP_CHECK)) { + printf("ERR:Corrupted response!\n"); + goto done; + } + /* Print response */ + if (cmd_buf->result == CMD_SUCCESS) { + if (argc == 2) { + /* reusing variable cmd_len */ + cmd_len = tlv->length; + if (cmd_len > 0) { + printf("Invitation List =>"); + while (cmd_len >= ETH_ALEN) { + if (memcmp + (tlv->inv_peer_addr, + "\x00\x00\x00\x00\x00\x00", + ETH_ALEN)) { + printf("\n\t [%d] ", + ctr++); + print_mac(tlv-> + inv_peer_addr); + } + cmd_len -= ETH_ALEN; + tlv = (tlvbuf_wifidirect_invitation_list *)(((t_u8 *)(tlv)) + ETH_ALEN); + } + if (ctr == 1) + printf(" empty."); + } else + printf("Invitation List is empty.\n"); + printf("\n"); + } else { + printf("Invitation List setting successful!\n"); + } + } else { + if (argc == 2) { + printf("ERR:Couldn't get Invitation List!\n"); + } else { + printf("ERR:Couldn't set Invitation List!\n"); + } + } + } else { + printf("ERR:Command sending failed!\n"); + } +done: + if (buffer) + free(buffer); + return; +} + +/** + * @brief Show usage information for the wifidirect noa config command + * + * @return N/A + */ +static void +print_wifidirect_cfg_noa_usage(void) +{ + printf("Usage : wifidirect_cfg_noa [ ]\n"); + printf("If NOA parameters are provided, 'set' is performed otherwise 'get' is performed.\n"); + return; +} + +/** + * @brief Set/get wifidirect NoA parameters + * + * Usage: "Usage : wifidirect_cfg_noa [ ]" + * + * @param argc Number of arguments + * @param argv Pointer to the arguments + * @return None + */ +static void +wifidirect_cfg_cmd_noa(int argc, char *argv[]) +{ + wifidirect_params_config *cmd_buf = NULL; + tlvbuf_wifidirect_noa_config *tlv = NULL; + t_u8 *buffer = NULL; + t_u16 cmd_len = 0; + int opt, ret = 0; + + while ((opt = getopt_long(argc, argv, "+", cmd_options, NULL)) != -1) { + switch (opt) { + default: + print_wifidirect_cfg_noa_usage(); + return; + } + } + argc -= optind; + argv += optind; + + /* Check arguments */ + if ((argc != 2) && (argc != 4) && (argc != 7)) { + printf("ERR: Wrong number of arguments!\n"); + print_wifidirect_cfg_noa_usage(); + return; + } + if (argc > 2) { + if (argc == 4) { + if (strcmp(argv[2], "enable") == 0) { + printf("ERR: index, count_type, duration and interval must be" " specified if noa is enabled!\n"); + print_wifidirect_cfg_noa_usage(); + return; + } else if (strcmp(argv[2], "disable")) { + print_wifidirect_cfg_noa_usage(); + return; + } + if (atoi(argv[3]) > WIFIDIRECT_NOA_DESC_MAX) { + print_wifidirect_cfg_noa_usage(); + return; + } + } else { + if (atoi(argv[3]) > WIFIDIRECT_NOA_DESC_MAX || + (is_input_valid(WIFIDIRECT_COUNT_TYPE, 1, &argv[4]) + != SUCCESS) || + (is_input_valid(WIFIDIRECT_DURATION, 1, &argv[5]) != + SUCCESS) || + (is_input_valid(WIFIDIRECT_INTERVAL, 1, &argv[6]) != + SUCCESS)) { + print_wifidirect_cfg_noa_usage(); + return; + } + } + } + cmd_len = + sizeof(wifidirect_params_config) + + sizeof(tlvbuf_wifidirect_noa_config); + + buffer = (t_u8 *)malloc(MRVDRV_SIZE_OF_CMD_BUFFER); + + if (!buffer) { + printf("ERR:Cannot allocate memory!\n"); + goto done; + } + + memset(buffer, 0, MRVDRV_SIZE_OF_CMD_BUFFER); + + cmd_buf = (wifidirect_params_config *)buffer; + tlv = (tlvbuf_wifidirect_noa_config *)(buffer + + sizeof + (wifidirect_params_config)); + + cmd_buf->cmd_code = HostCmd_CMD_WIFIDIRECT_PARAMS_CONFIG; + cmd_buf->size = cmd_len - BUF_HEADER_SIZE; + cmd_buf->seq_num = 0; + cmd_buf->result = 0; + + tlv->tag = MRVL_WIFIDIRECT_NOA_TLV_ID; + tlv->length = + sizeof(tlvbuf_wifidirect_noa_config) - MRVL_TLV_HEADER_SIZE; + + if (argc == 2) { + cmd_buf->action = ACTION_GET; + cmd_len += + (sizeof(tlvbuf_wifidirect_noa_config) - + MRVL_TLV_HEADER_SIZE) + * (WIFIDIRECT_NOA_DESC_MAX - 1); + } else { + cmd_buf->action = cpu_to_le16(ACTION_SET); + if (strcmp(argv[2], "disable")) { + /* enable case */ + tlv->enable_noa = 1; + tlv->enable_noa = cpu_to_le16(tlv->enable_noa); + } + tlv->noa_index = (t_u8)atoi(argv[3]); + + if (tlv->enable_noa) { + tlv->count_type = (t_u8)atoi(argv[4]); + tlv->duration = (t_u32)atoi(argv[5]); + tlv->duration = cpu_to_le32(tlv->duration); + tlv->interval = (t_u32)atoi(argv[6]); + tlv->interval = cpu_to_le32(tlv->interval); + } + } + endian_convert_tlv_header_out(tlv); +#ifdef DEBUG + hexdump(buffer, cmd_len, ' '); +#endif + ret = wifidirect_ioctl((t_u8 *)buffer, &cmd_len, + MRVDRV_SIZE_OF_CMD_BUFFER); + endian_convert_tlv_header_in(tlv); +#ifdef DEBUG + hexdump(buffer, cmd_len + BUF_HEADER_SIZE, ' '); +#endif + /* Process Response */ + if (ret == SUCCESS) { + /* Verify response */ + if (cmd_buf->cmd_code != + (HostCmd_CMD_WIFIDIRECT_PARAMS_CONFIG | + WIFIDIRECTCMD_RESP_CHECK)) { + printf("ERR:Corrupted response!\n"); + goto done; + } + /* Print response */ + if (cmd_buf->result == CMD_SUCCESS) { + if (argc == 2) { + if (tlv->length) + printf("NoA settings:\n"); + else + printf("NoA parameters are not configured.\n"); + if (tlv->length >= + sizeof(tlvbuf_wifidirect_noa_config) - + MRVL_TLV_HEADER_SIZE) { + tlv->enable_noa = + le16_to_cpu(tlv->enable_noa); + if (tlv->enable_noa) { + printf("[%d] NoA is enabled!\n", + (int)tlv->noa_index); + printf("CountType = %d\n", + (int)tlv->count_type); + printf("Duration = %dms\n", + le32_to_cpu(tlv-> + duration)); + printf("Interval = %dms\n", + le32_to_cpu(tlv-> + interval)); + } else { + printf("[%d] NoA is disabled!\n", (int)tlv->noa_index); + } + } + } else { + printf("NoA setting successful!\n"); + } + } else { + if (argc == 2) { + printf("ERR:Couldn't get NoA parameters!\n"); + } else { + printf("ERR:Couldn't set NoA parameters!\n"); + } + } + } else { + printf("ERR:Command sending failed!\n"); + } +done: + if (buffer) + free(buffer); + return; +} + +/** + * @brief Show usage information for the wifidirect opp_ps config command + * + * @return N/A + */ +static void +print_wifidirect_cfg_opp_ps_usage(void) +{ + printf("Usage : wifidirect_cfg_opp_ps []\n"); + printf("For 'set', both enable flag and CTWindow should be provided.\n"); + printf("If no parameter is specified,'get' is performed.\n"); + return; +} + +/** + * @brief Set/get wifidirect Opportunistic Power Save + * + * Usage: "Usage : wifidirect_cfg_opp_ps []" + * + * @param argc Number of arguments + * @param argv Pointer to the arguments + * @return None + */ +static void +wifidirect_cfg_cmd_opp_ps(int argc, char *argv[]) +{ + wifidirect_params_config *cmd_buf = NULL; + tlvbuf_wifidirect_opp_ps_config *tlv = NULL; + t_u8 *buffer = NULL; + t_u16 cmd_len = 0; + t_u8 opp_ps = 0, ctwindow = 0; + int opt, ret = 0; + + while ((opt = getopt_long(argc, argv, "+", cmd_options, NULL)) != -1) { + switch (opt) { + default: + print_wifidirect_cfg_opp_ps_usage(); + return; + } + } + argc -= optind; + argv += optind; + + /* Check arguments */ + if ((argc < 2) || (argc > 4)) { + printf("ERR: Wrong number of arguments!\n"); + print_wifidirect_cfg_opp_ps_usage(); + return; + } + if (argc == 3) { + if (strcmp(argv[2], "enable") == 0) { + printf("ERR: If Opp PS is enabled, CTWindow must be specified!\n"); + print_wifidirect_cfg_opp_ps_usage(); + return; + } else if (strcmp(argv[2], "disable")) { + print_wifidirect_cfg_opp_ps_usage(); + return; + } + } + if (argc == 4) { + if (strcmp(argv[2], "disable") == 0) { + printf("ERR: Extra parameter %s for disable command.\n", + argv[3]); + return; + } + if (is_input_valid(WIFIDIRECT_CTWINDOW, 1, &argv[3]) != SUCCESS) { + print_wifidirect_cfg_opp_ps_usage(); + return; + } + } + + cmd_len = + sizeof(wifidirect_params_config) + + sizeof(tlvbuf_wifidirect_opp_ps_config); + + buffer = (t_u8 *)malloc(MRVDRV_SIZE_OF_CMD_BUFFER); + + if (!buffer) { + printf("ERR:Cannot allocate memory!\n"); + goto done; + } + + memset(buffer, 0, MRVDRV_SIZE_OF_CMD_BUFFER); + + cmd_buf = (wifidirect_params_config *)buffer; + tlv = (tlvbuf_wifidirect_opp_ps_config *)(buffer + + sizeof + (wifidirect_params_config)); + + cmd_buf->cmd_code = HostCmd_CMD_WIFIDIRECT_PARAMS_CONFIG; + cmd_buf->size = cmd_len - BUF_HEADER_SIZE; + cmd_buf->seq_num = 0; + cmd_buf->result = 0; + + tlv->tag = MRVL_WIFIDIRECT_OPP_PS_TLV_ID; + tlv->length = + sizeof(tlvbuf_wifidirect_opp_ps_config) - MRVL_TLV_HEADER_SIZE; + + if (argc == 2) { + cmd_buf->action = ACTION_GET; + } else { + cmd_buf->action = cpu_to_le16(ACTION_SET); + if (strcmp(argv[2], "disable")) + opp_ps = 1; + if (argc == 4) + tlv->ctwindow_opp_ps = + (t_u8)atoi(argv[3]) | SET_OPP_PS(opp_ps);; + } + endian_convert_tlv_header_out(tlv); +#ifdef DEBUG + hexdump(buffer, cmd_len, ' '); +#endif + ret = wifidirect_ioctl((t_u8 *)buffer, &cmd_len, + MRVDRV_SIZE_OF_CMD_BUFFER); + endian_convert_tlv_header_in(tlv); +#ifdef DEBUG + hexdump(buffer, cmd_len + BUF_HEADER_SIZE, ' '); +#endif + /* Process Response */ + if (ret == SUCCESS) { + /* Verify response */ + if (cmd_buf->cmd_code != + (HostCmd_CMD_WIFIDIRECT_PARAMS_CONFIG | + WIFIDIRECTCMD_RESP_CHECK)) { + printf("ERR:Corrupted response!\n"); + goto done; + } + /* Print response */ + if (cmd_buf->result == CMD_SUCCESS) { + if (argc == 2) { + opp_ps = GET_OPP_PS(tlv->ctwindow_opp_ps); + if (opp_ps) { + ctwindow = + (tlv-> + ctwindow_opp_ps) & + CT_WINDOW_MASK; + printf("Opportunistic Power Save enabled!\n"); + printf("CTWindow = %d\n", ctwindow); + } else { + printf("Opportunistic Power Save disabled!\n"); + } + } else { + printf("Opportunistic power save setting successful!\n"); + } + } else { + if (argc == 2) { + printf("ERR:Couldn't get Opportunistic power save and CTWindow!\n"); + } else { + printf("ERR:Couldn't set Opportunistic power save and CTWindow!\n"); + } + } + } else { + printf("ERR:Command sending failed!\n"); + } +done: + if (buffer) + free(buffer); + return; +} + +/** + * @brief Show usage information for the wifidirect capability config command + * + * @return N/A + */ +static void +print_wifidirect_cfg_capability_usage(void) +{ + printf("Usage : wifidirect_capability [ ]\n"); + printf("For 'set' both DeviceCapability and GroupCapability should be provided.\n"); + printf("If no parameter is specified,'get' is performed.\n"); + return; +} + +/** + * @brief Set/get wifidirect Capability + * + * Usage: "Usage : wifidirect_cfg_capability [ ]" + * + * @param argc Number of arguments + * @param argv Pointer to the arguments + * @return None + */ +static void +wifidirect_cfg_cmd_capability(int argc, char *argv[]) +{ + wifidirect_params_config *cmd_buf = NULL; + tlvbuf_wifidirect_capability_config *tlv = NULL; + t_u8 *buffer = NULL; + t_u16 cmd_len = 0; + int opt, ret = 0; + + while ((opt = getopt_long(argc, argv, "+", cmd_options, NULL)) != -1) { + switch (opt) { + default: + print_wifidirect_cfg_capability_usage(); + return; + } + } + argc -= optind; + argv += optind; + + /* Check arguments */ + if ((argc < 2) || (argc > 4) || (argc == 3)) { + printf("ERR: Wrong number of arguments!\n"); + print_wifidirect_cfg_capability_usage(); + return; + } + if (argc == 4) { + if ((is_input_valid(WIFIDIRECT_DEVICECAPABILITY, 1, &argv[2]) != + SUCCESS) || + (is_input_valid(WIFIDIRECT_GROUPCAPABILITY, 1, &argv[3]) != + SUCCESS)) { + print_wifidirect_cfg_capability_usage(); + return; + } + } + cmd_len = + sizeof(wifidirect_params_config) + + sizeof(tlvbuf_wifidirect_capability_config); + + buffer = (t_u8 *)malloc(MRVDRV_SIZE_OF_CMD_BUFFER); + + if (!buffer) { + printf("ERR:Cannot allocate memory!\n"); + goto done; + } + + memset(buffer, 0, MRVDRV_SIZE_OF_CMD_BUFFER); + + cmd_buf = (wifidirect_params_config *)buffer; + tlv = (tlvbuf_wifidirect_capability_config *)(buffer + + sizeof + (wifidirect_params_config)); + + cmd_buf->cmd_code = HostCmd_CMD_WIFIDIRECT_PARAMS_CONFIG; + cmd_buf->size = cmd_len - BUF_HEADER_SIZE; + cmd_buf->seq_num = 0; + cmd_buf->result = 0; + + tlv->tag = MRVL_WIFIDIRECT_CAPABILITY_TLV_ID; + tlv->length = + sizeof(tlvbuf_wifidirect_capability_config) - + MRVL_TLV_HEADER_SIZE; + + if (argc == 2) { + cmd_buf->action = ACTION_GET; + } else { + cmd_buf->action = cpu_to_le16(ACTION_SET); + tlv->dev_capability = (t_u8)atoi(argv[2]); + tlv->group_capability = (t_u8)atoi(argv[3]); + } + endian_convert_tlv_header_out(tlv); +#ifdef DEBUG + hexdump(buffer, cmd_len, ' '); +#endif + ret = wifidirect_ioctl((t_u8 *)buffer, &cmd_len, + MRVDRV_SIZE_OF_CMD_BUFFER); + endian_convert_tlv_header_in(tlv); +#ifdef DEBUG + hexdump(buffer, cmd_len + BUF_HEADER_SIZE, ' '); +#endif + /* Process Response */ + if (ret == SUCCESS) { + /* Verify response */ + if (cmd_buf->cmd_code != + (HostCmd_CMD_WIFIDIRECT_PARAMS_CONFIG | + WIFIDIRECTCMD_RESP_CHECK)) { + printf("ERR:Corrupted response!\n"); + goto done; + } + /* Print response */ + if (cmd_buf->result == CMD_SUCCESS) { + if (argc == 2) { + printf("Device Capability = %d\n", + (int)tlv->dev_capability); + printf("Group Capability = %d\n", + (int)tlv->group_capability); + } else { + printf("Capability setting successful!\n"); + } + } else { + if (argc == 2) { + printf("ERR:Couldn't get Capability info!\n"); + } else { + printf("ERR:Couldn't set Capability!\n"); + } + } + } else { + printf("ERR:Command sending failed!\n"); + } +done: + if (buffer) + free(buffer); + return; +} + +/** + * @brief Show usage information for the wifidirect_cfg_persistent_group_record command + * + * $return N/A + */ +static void +print_wifidirect_peristent_group_usage(void) +{ + printf("\nUsage : wifidirect_cfg_persistent_group_record [index] \ + > \ + [ ]\n"); + printf("\nIssue set or get request using appropriate parameters.\n"); + return; +} + +/** + * @brief Creates a wifidirect_persistent group record request and + * sends to the driver + * + * Usage: "Usage : wifidirect_cfg_cmd_persistent_group_record [index] < + * > + * [ ]" + * + * @param argc Number of arguments + * @param argv Pointer to the arguments + * @return SUCCESS or FAILURE + **/ +static void +wifidirect_cfg_cmd_persistent_group_record(int argc, char *argv[]) +{ + wifidirect_params_config *cmd_buf = NULL; + tlvbuf_wifidirect_persistent_group *tlv = NULL; + t_u8 index = 0, role = 0, var_len = 0, psk_len = 0; + t_u8 *buffer = NULL; + int pi; + t_u16 cmd_len = 0, buf_len = 0; + int opt, ret; + + while ((opt = getopt_long(argc, argv, "+", cmd_options, NULL)) != -1) { + switch (opt) { + default: + print_wifidirect_peristent_group_usage(); + return; + } + } + argc -= optind; + argv += optind; + + /* Check arguments */ + if (argc != 2 && argc != 3 && argc != 8 && argc != 9 && argc != 10) { + printf("ERR:wrong number of arguments.\n"); + print_wifidirect_peristent_group_usage(); + return; + } + /* error checks */ + if (argc > 2) { + index = atoi(argv[2]); + if (index >= WIFIDIRECT_PERSISTENT_GROUP_MAX) { + printf("ERR:wrong index. Value values are [0-3]\n"); + return; + } + } + if (argc > 3) { + role = atoi(argv[3]); + if ((role != 1) && (role != 2)) { + printf("ERR:Incorrect Role. Use 2 for client, 1 for group owner.\n"); + return; + } + if (role == 1 && argc == 8) { + printf("ERR:Insufficient arguments. Please provide peer mac address(es) for group owner.\n"); + return; + } + } + + cmd_len = sizeof(wifidirect_params_config); + buffer = (t_u8 *)malloc(MRVDRV_SIZE_OF_CMD_BUFFER); + if (!buffer) { + printf("ERR:Cannot allocate memory!\n"); + goto done; + } + memset(buffer, 0, MRVDRV_SIZE_OF_CMD_BUFFER); + cmd_buf = (wifidirect_params_config *)buffer; + cmd_buf->cmd_code = HostCmd_CMD_WIFIDIRECT_PARAMS_CONFIG; + cmd_buf->seq_num = 0; + cmd_buf->result = 0; + tlv = (tlvbuf_wifidirect_persistent_group *)(buffer + + sizeof + (wifidirect_params_config)); + + tlv->tag = MRVL_WIFIDIRECT_PERSISTENT_GROUP_TLV_ID; + + /* parsing commands based on arguments */ + switch (argc) { + case 2: + cmd_buf->action = ACTION_GET; + tlv->length = 0; + cmd_len += MRVL_TLV_HEADER_SIZE + tlv->length; + cmd_buf->size = cmd_len - BUF_HEADER_SIZE; + buf_len = MRVDRV_SIZE_OF_CMD_BUFFER; + break; + + case 3: + cmd_buf->action = ACTION_GET; + tlv->rec_index = index; + tlv->length = sizeof(index); + cmd_len += MRVL_TLV_HEADER_SIZE + tlv->length; + cmd_buf->size = cmd_len - BUF_HEADER_SIZE; + buf_len = MRVDRV_SIZE_OF_CMD_BUFFER; + break; + + default: + cmd_buf->action = cpu_to_le16(ACTION_SET); + tlv->rec_index = index; + tlv->dev_role = role; + if ((ret = mac2raw(argv[4], tlv->group_bssid)) != SUCCESS) { + printf("ERR:Invalid MAC address %s\n", argv[4]); + goto done; + } + if ((ret = mac2raw(argv[5], tlv->dev_mac_address)) != SUCCESS) { + printf("ERR:Invalid MAC address %s\n", argv[5]); + goto done; + } + + /* ssid */ + tlv->group_ssid_len = strlen(argv[6]); + var_len += tlv->group_ssid_len; + memcpy(tlv->group_ssid, argv[6], tlv->group_ssid_len); + + /* adjust pointer from here */ + /* psk */ + if (!strncasecmp("0x", argv[7], 2)) { + argv[7] += 2; + if (strlen(argv[7]) / 2 != WIFIDIRECT_PSK_LEN_MAX) { + printf("ERR:Incorrect PSK length %d. It should be %d.\n", (t_u32)strlen(argv[7]) / 2, WIFIDIRECT_PSK_LEN_MAX); + goto done; + } + string2raw(argv[7], tlv->psk + var_len); + *(&tlv->psk_len + var_len) = WIFIDIRECT_PSK_LEN_MAX; + var_len += WIFIDIRECT_PSK_LEN_MAX; + } else { + /* ascii */ + psk_len = strlen(argv[7]); + if (psk_len < WIFIDIRECT_PASSPHRASE_LEN_MIN || + psk_len >= WIFIDIRECT_PSK_LEN_MAX) { + printf("ERR:Incorrect passphrase length %d. Valid range is [8-63]\n", psk_len); + goto done; + } + memcpy(tlv->psk + var_len, argv[7], psk_len); + *(&tlv->psk_len + var_len) = psk_len; + var_len += psk_len; + } + + tlv->length = + sizeof(tlvbuf_wifidirect_persistent_group) - + MRVL_TLV_HEADER_SIZE + var_len; + *(&tlv->num_peers + var_len) = 0; + + if (argc == 9 || argc == 10) { + if ((ret = + mac2raw(argv[8], tlv->peer_mac_addrs[0] + var_len)) + != SUCCESS) { + printf("ERR:Invalid MAC address %s\n", argv[8]); + goto done; + } + *(&tlv->num_peers + var_len) = 1; + } + if (argc == 10) { + if ((ret = + mac2raw(argv[9], tlv->peer_mac_addrs[1] + var_len)) + != SUCCESS) { + printf("ERR:Invalid MAC address %s\n", argv[8]); + goto done; + } + *(&tlv->num_peers + var_len) = 2; + } + + tlv->length += *(&tlv->num_peers + var_len) * ETH_ALEN; + cmd_len += MRVL_TLV_HEADER_SIZE + tlv->length; + buf_len = cmd_len; + cmd_buf->size = cmd_len - BUF_HEADER_SIZE; + break; + } +#ifdef DEBUG + hexdump(buffer, cmd_len, ' '); +#endif + endian_convert_tlv_header_out(tlv); + + /* Send collective command */ + wifidirect_ioctl((t_u8 *)buffer, &cmd_len, buf_len); + + endian_convert_tlv_header_in(tlv); +#ifdef DEBUG + hexdump(buffer, cmd_len, ' '); +#endif + + if (argc == 2 || argc == 3) { + if (tlv->length > 0) + printf("Persistent group information =>\n"); + else + printf("Persistent group information is empty.\n"); + buf_len = tlv->length; + while (buf_len > + (sizeof(tlvbuf_wifidirect_persistent_group) - + 2 * ETH_ALEN)) { + printf("\n\t Index = [%d]\n", tlv->rec_index); + if (tlv->dev_role == 1) + printf("\t Role = Group owner\n"); + else + printf("\t Role = Client\n"); + printf("\t GroupBssId - "); + print_mac(tlv->group_bssid); + printf("\n\t DeviceId - "); + print_mac(tlv->dev_mac_address); + printf("\n\t SSID = "); + for (index = 0; index < tlv->group_ssid_len; index++) + printf("%c", tlv->group_ssid[index]); + var_len = tlv->group_ssid_len; + printf("\n\t PSK = "); + for (index = 0; index < *(&tlv->psk_len + var_len); + index++) { + if (index == 16) + printf("\n\t "); + printf("%02x ", *(&tlv->psk[index] + var_len)); + } + var_len += *(&tlv->psk_len + var_len); + if (tlv->dev_role == 1) { + for (pi = 0; pi < *(&tlv->num_peers + var_len); + pi++) { + printf("\n\t Peer Mac address(%d) = ", + pi); + print_mac(tlv->peer_mac_addrs[pi] + + var_len); + } + var_len += + (*(&tlv->num_peers + var_len) * + ETH_ALEN); + } + if (argc == 2) + printf("\n\t -----------------------------------------"); + if (tlv->dev_role == 1) { + buf_len -= + sizeof + (tlvbuf_wifidirect_persistent_group) - + MRVL_TLV_HEADER_SIZE + var_len; + tlv = (tlvbuf_wifidirect_persistent_group + *)(((t_u8 *)(tlv)) + + (sizeof + (tlvbuf_wifidirect_persistent_group) + - MRVL_TLV_HEADER_SIZE + var_len)); + } else { + /* num_peer field willnt be present */ + buf_len -= + sizeof + (tlvbuf_wifidirect_persistent_group) - + MRVL_TLV_HEADER_SIZE - sizeof(t_u8) + + var_len; + tlv = (tlvbuf_wifidirect_persistent_group + *)(((t_u8 *)(tlv)) + + (sizeof + (tlvbuf_wifidirect_persistent_group) + - MRVL_TLV_HEADER_SIZE - + sizeof(t_u8) + var_len)); + } + } + printf("\n"); + } else { + printf("Setting persistent group information successful!\n"); + } +done: + if (buffer) + free(buffer); + return; +} + +/** + * @brief Show usage information for the wifidirect_cfg_persistent_group_invoke command + * + * $return N/A + */ +static void +print_wifidirect_peristent_group_invoke_usage(void) +{ + printf("\nUsage : wifidirect_cfg_persistent_group_invoke [index] | \n"); + return; +} + +/** + * @brief Creates a wifidirect_persistent group Invoke request and + * sends to the driver + * + * Usage: "Usage : wifidirect_cfg_cmd_persistent_group_invoke [index] | " + * + * @param argc Number of arguments + * @param argv Pointer to the arguments + * @return SUCCESS or FAILURE + **/ +static void +wifidirect_cfg_cmd_persistent_group_invoke(int argc, char *argv[]) +{ + wifidirect_params_config *cmd_buf = NULL; + tlvbuf_wifidirect_persistent_group *tlv = NULL; + t_u8 index; + t_u8 *buffer = NULL; + t_u16 cmd_len = 0; + int opt; + + while ((opt = getopt_long(argc, argv, "+", cmd_options, NULL)) != -1) { + switch (opt) { + default: + print_wifidirect_peristent_group_invoke_usage(); + return; + } + } + argc -= optind; + argv += optind; + + /* Check arguments */ + if (argc != 3) { + printf("ERR:wrong number of arguments.\n"); + print_wifidirect_peristent_group_invoke_usage(); + return; + } + + cmd_len = sizeof(wifidirect_params_config); + buffer = (t_u8 *)malloc(MRVDRV_SIZE_OF_CMD_BUFFER); + if (!buffer) { + printf("ERR:Cannot allocate memory!\n"); + goto done; + } + memset(buffer, 0, MRVDRV_SIZE_OF_CMD_BUFFER); + cmd_buf = (wifidirect_params_config *)buffer; + cmd_buf->cmd_code = HostCmd_CMD_WIFIDIRECT_PARAMS_CONFIG; + cmd_buf->seq_num = 0; + cmd_buf->result = 0; + cmd_buf->action = cpu_to_le16(ACTION_SET); + tlv = (tlvbuf_wifidirect_persistent_group *)(buffer + + sizeof + (wifidirect_params_config)); + + tlv->tag = MRVL_WIFIDIRECT_PERSISTENT_GROUP_TLV_ID; + tlv->length = sizeof(index); + + index = atoi(argv[2]); + if (index >= WIFIDIRECT_PERSISTENT_GROUP_MAX) { + printf("ERR:wrong index. Value values are [0-3]\n"); + goto done; + } + if (!isdigit(argv[2][0])) { + if (strcmp(argv[2], "cancel")) { + printf("ERR:Incorrect input. Use index [0-3] or \"cancel\" \n"); + goto done; + } else + index = WIFIDIRECT_PERSISTENT_RECORD_CANCEL; + } + tlv->rec_index = index; + + cmd_len += MRVL_TLV_HEADER_SIZE + tlv->length; + cmd_buf->size = cmd_len - BUF_HEADER_SIZE; +#ifdef DEBUG + hexdump(buffer, cmd_len, ' '); +#endif + endian_convert_tlv_header_out(tlv); + + /* Send collective command */ + wifidirect_ioctl((t_u8 *)buffer, &cmd_len, MRVDRV_SIZE_OF_CMD_BUFFER); + +#ifdef DEBUG + hexdump(buffer, cmd_len + BUF_HEADER_SIZE, ' '); +#endif + + printf("Persistent group %s successful!\n", + (index == + WIFIDIRECT_PERSISTENT_RECORD_CANCEL) ? "cancel" : "invoke"); +done: + if (buffer) + free(buffer); + return; +} + +/** + * @brief Show usage information for the wifidirect presence request parameters command + * + * @return N/A + */ +static void +print_wifidirect_cfg_presence_req_params_usage(void) +{ + printf("Usage : wifidirect_cfg_presence_req_params [ ]\n"); + printf(" : Type 1: preferred values, 2: acceptable values.\n"); + printf("If presence request parameters are provided, " + " 'set' is performed otherwise 'get' is performed.\n"); + return; +} + +/** + * @brief Set/get wifidirect presence request parameters + * + * Usage: "Usage : wifidirect_cfg_presence_req_params [ ]" + * + * @param argc Number of arguments + * @param argv Pointer to the arguments + * @return None + */ +static void +wifidirect_cfg_cmd_presence_req_params(int argc, char *argv[]) +{ + wifidirect_params_config *cmd_buf = NULL; + tlvbuf_wifidirect_presence_req_params *tlv = NULL; + t_u8 *buffer = NULL; + t_u16 cmd_len = 0; + int opt, ret = 0; + + while ((opt = getopt_long(argc, argv, "+", cmd_options, NULL)) != -1) { + switch (opt) { + default: + print_wifidirect_cfg_presence_req_params_usage(); + return; + } + } + argc -= optind; + argv += optind; + + /* Check arguments */ + if (argc < 2) { + printf("ERR: Wrong number of arguments!\n"); + print_wifidirect_cfg_presence_req_params_usage(); + return; + } else if ((argc > 2) && ((argc != 5) + || + (is_input_valid + (WIFIDIRECT_PRESENCE_REQ_TYPE, 1, + &argv[2]) != SUCCESS) + || + (is_input_valid + (WIFIDIRECT_DURATION, 1, + &argv[3]) != SUCCESS) + || + (is_input_valid + (WIFIDIRECT_INTERVAL, 1, + &argv[4]) != SUCCESS))) { + print_wifidirect_cfg_presence_req_params_usage(); + return; + } + cmd_len = + sizeof(wifidirect_params_config) + + sizeof(tlvbuf_wifidirect_presence_req_params); + + buffer = (t_u8 *)malloc(MRVDRV_SIZE_OF_CMD_BUFFER); + + if (!buffer) { + printf("ERR:Cannot allocate memory!\n"); + goto done; + } + + memset(buffer, 0, MRVDRV_SIZE_OF_CMD_BUFFER); + + cmd_buf = (wifidirect_params_config *)buffer; + tlv = (tlvbuf_wifidirect_presence_req_params *)(buffer + + sizeof + (wifidirect_params_config)); + + cmd_buf->cmd_code = HostCmd_CMD_WIFIDIRECT_PARAMS_CONFIG; + cmd_buf->size = cmd_len - BUF_HEADER_SIZE; + cmd_buf->seq_num = 0; + cmd_buf->result = 0; + + tlv->tag = MRVL_WIFIDIRECT_PRESENCE_REQ_PARAMS_TLV_ID; + tlv->length = + sizeof(tlvbuf_wifidirect_presence_req_params) - + MRVL_TLV_HEADER_SIZE; + + if (argc == 2) { + cmd_buf->action = ACTION_GET; + } else { + cmd_buf->action = cpu_to_le16(ACTION_SET); + tlv->presence_req_type = (t_u8)atoi(argv[2]); + tlv->duration = (t_u32)atoi(argv[3]); + tlv->duration = cpu_to_le32(tlv->duration); + tlv->interval = (t_u32)atoi(argv[4]); + tlv->interval = cpu_to_le32(tlv->interval); + } + endian_convert_tlv_header_out(tlv); +#ifdef DEBUG + hexdump(buffer, cmd_len, ' '); +#endif + ret = wifidirect_ioctl((t_u8 *)buffer, &cmd_len, + MRVDRV_SIZE_OF_CMD_BUFFER); + endian_convert_tlv_header_in(tlv); +#ifdef DEBUG + hexdump(buffer, cmd_len + BUF_HEADER_SIZE, ' '); +#endif + /* Process Response */ + if (ret == SUCCESS) { + /* Verify response */ + if (cmd_buf->cmd_code != + (HostCmd_CMD_WIFIDIRECT_PARAMS_CONFIG | + WIFIDIRECTCMD_RESP_CHECK)) { + printf("ERR:Corrupted response!\n"); + goto done; + } + /* Print response */ + if (cmd_buf->result == CMD_SUCCESS) { + if (argc == 2) { + printf("Presence request type = %d\n", + (int)tlv->presence_req_type); + printf("Duration of NoA descriptor = %d\n", + le32_to_cpu(tlv->duration)); + printf("Interval of NoA descriptor = %d\n", + le32_to_cpu(tlv->interval)); + } else { + printf("Presence request parameters setting successful!\n"); + } + } else { + if (argc == 2) { + printf("ERR:Couldn't get Presence request parameters!\n"); + } else { + printf("ERR:Couldn't set Presence request parameters!\n"); + } + } + } else { + printf("ERR:Command sending failed!\n"); + } +done: + if (buffer) + free(buffer); + return; +} + +/** + * @brief Show usage information for the wifidirect extended listen timing parameters command + * + * @return N/A + */ +static void +print_wifidirect_cfg_ext_listen_time_usage(void) +{ + printf("Usage : wifidirect_cfg_ext_listen_time [ ]\n"); + printf("If extended listen timing parameters are provided, " + "'set' is performed otherwise 'get' is performed.\n"); + return; +} + +/** + * @brief Set/get wifidirect extended listen time parameters + * + * Usage: "Usage : wifidirect_cfg_ext_listen_time [ ]" + * + * @param argc Number of arguments + * @param argv Pointer to the arguments + * @return None + */ +static void +wifidirect_cfg_cmd_ext_listen_time(int argc, char *argv[]) +{ + wifidirect_params_config *cmd_buf = NULL; + tlvbuf_wifidirect_mrvl_ext_listen_time *tlv = NULL; + t_u8 *buffer = NULL; + t_u16 cmd_len = 0; + int opt, ret = 0; + + while ((opt = getopt_long(argc, argv, "+", cmd_options, NULL)) != -1) { + switch (opt) { + default: + print_wifidirect_cfg_ext_listen_time_usage(); + return; + } + } + argc -= optind; + argv += optind; + + /* Check arguments */ + if (argc < 2) { + printf("ERR: Wrong number of arguments!\n"); + print_wifidirect_cfg_ext_listen_time_usage(); + return; + } else if ((argc > 2) && ((argc != 4) + || + (is_input_valid + (WIFIDIRECT_ATTR_EXTENDED_TIME, 1, + &argv[2]) != SUCCESS) + || + (is_input_valid + (WIFIDIRECT_ATTR_EXTENDED_TIME, 1, + &argv[3]) != SUCCESS))) { + print_wifidirect_cfg_ext_listen_time_usage(); + return; + } + cmd_len = + sizeof(wifidirect_params_config) + + sizeof(tlvbuf_wifidirect_mrvl_ext_listen_time); + + buffer = (t_u8 *)malloc(MRVDRV_SIZE_OF_CMD_BUFFER); + + if (!buffer) { + printf("ERR:Cannot allocate memory!\n"); + goto done; + } + + memset(buffer, 0, MRVDRV_SIZE_OF_CMD_BUFFER); + + cmd_buf = (wifidirect_params_config *)buffer; + tlv = (tlvbuf_wifidirect_mrvl_ext_listen_time *)(buffer + + sizeof + (wifidirect_params_config)); + + cmd_buf->cmd_code = HostCmd_CMD_WIFIDIRECT_PARAMS_CONFIG; + cmd_buf->size = cmd_len - BUF_HEADER_SIZE; + cmd_buf->seq_num = 0; + cmd_buf->result = 0; + + tlv->tag = MRVL_WIFIDIRECT_EXTENDED_LISTEN_TIME_TLV_ID; + tlv->length = + sizeof(tlvbuf_wifidirect_mrvl_ext_listen_time) - + MRVL_TLV_HEADER_SIZE; + if (argc == 2) { + cmd_buf->action = ACTION_GET; + } else { + cmd_buf->action = cpu_to_le16(ACTION_SET); + tlv->duration = cpu_to_le16((t_u16)atoi(argv[2])); + tlv->interval = cpu_to_le16((t_u16)atoi(argv[3])); + } + endian_convert_tlv_header_out(tlv); +#ifdef DEBUG + hexdump(buffer, cmd_len, ' '); +#endif + ret = wifidirect_ioctl((t_u8 *)buffer, &cmd_len, + MRVDRV_SIZE_OF_CMD_BUFFER); + endian_convert_tlv_header_in(tlv); +#ifdef DEBUG + hexdump(buffer, cmd_len + BUF_HEADER_SIZE, ' '); +#endif + /* Process Response */ + if (ret == SUCCESS) { + /* Verify response */ + if (cmd_buf->cmd_code != + (HostCmd_CMD_WIFIDIRECT_PARAMS_CONFIG | + WIFIDIRECTCMD_RESP_CHECK)) { + printf("ERR:Corrupted response!\n"); + goto done; + } + /* Print response */ + if (cmd_buf->result == CMD_SUCCESS) { + if (argc == 2) { + printf("Availability Period = %d\n", + le16_to_cpu(tlv->duration)); + printf("Availability Interval = %d\n", + le16_to_cpu(tlv->interval)); + } else { + printf("Extended listen timing parameters setting successful!\n"); + } + } else { + if (argc == 2) + printf("ERR:Couldn't get Extended listen time!\n"); + else + printf("ERR:Couldn't set Extended listen time!\n"); + } + } else { + printf("ERR:Command sending failed!\n"); + } +done: + if (buffer) + free(buffer); + return; +} + +/** + * @brief Show usage information for the wifidirect provisioing parameters command + * + * @return N/A + */ +static void +print_wifidirect_cfg_provisioning_params_usage(void) +{ + printf("Usage : wifidirect_cfg_provisioning_params [ ]\n"); + printf(" : Action 1: Request parameters 2: Response parameters.\n"); + printf("If provisioning protocol parameters are provided, " + "'set' is performed otherwise 'get' is performed.\n"); + return; +} + +/** + * @brief Set/get wifidirect provisioning protocol related parameters + * + * Usage: "Usage : wifidirect_cfg_provisioning_params [ + * ]" + * + * @param argc Number of arguments + * @param argv Pointer to the arguments + * @return None + */ +static void +wifidirect_cfg_cmd_provisioning_params(int argc, char *argv[]) +{ + wifidirect_params_config *cmd_buf = NULL; + tlvbuf_wifidirect_provisioning_params *tlv = NULL; + t_u8 *buffer = NULL; + t_u16 cmd_len = 0; + int opt, ret = 0; + + while ((opt = getopt_long(argc, argv, "+", cmd_options, NULL)) != -1) { + switch (opt) { + default: + print_wifidirect_cfg_provisioning_params_usage(); + return; + } + } + argc -= optind; + argv += optind; + + /* Check arguments */ + if (argc < 2) { + printf("ERR: Wrong number of arguments!\n"); + print_wifidirect_cfg_provisioning_params_usage(); + return; + } else if ((argc > 2) && (argc != 5)) { + print_wifidirect_cfg_provisioning_params_usage(); + return; + } + cmd_len = + sizeof(wifidirect_params_config) + + sizeof(tlvbuf_wifidirect_provisioning_params); + + buffer = (t_u8 *)malloc(MRVDRV_SIZE_OF_CMD_BUFFER); + + if (!buffer) { + printf("ERR:Cannot allocate memory!\n"); + goto done; + } + + memset(buffer, 0, MRVDRV_SIZE_OF_CMD_BUFFER); + + cmd_buf = (wifidirect_params_config *)buffer; + tlv = (tlvbuf_wifidirect_provisioning_params *)(buffer + + sizeof + (wifidirect_params_config)); + + cmd_buf->cmd_code = HostCmd_CMD_WIFIDIRECT_PARAMS_CONFIG; + cmd_buf->size = cmd_len - BUF_HEADER_SIZE; + cmd_buf->seq_num = 0; + cmd_buf->result = 0; + + tlv->tag = MRVL_WIFIDIRECT_PROVISIONING_PARAMS_TLV_ID; + tlv->length = + sizeof(tlvbuf_wifidirect_provisioning_params) - + MRVL_TLV_HEADER_SIZE; + if (argc == 2) { + cmd_buf->action = ACTION_GET; + } else { + cmd_buf->action = cpu_to_le16(ACTION_SET); + tlv->action = cpu_to_le16((t_u16)A2HEXDECIMAL(argv[2])); + tlv->config_methods = cpu_to_le16((t_u16)A2HEXDECIMAL(argv[3])); + tlv->dev_password = cpu_to_le16((t_u16)A2HEXDECIMAL(argv[4])); + } + endian_convert_tlv_header_out(tlv); +#ifdef DEBUG + hexdump(buffer, cmd_len, ' '); +#endif + ret = wifidirect_ioctl((t_u8 *)buffer, &cmd_len, + MRVDRV_SIZE_OF_CMD_BUFFER); + endian_convert_tlv_header_in(tlv); +#ifdef DEBUG + hexdump(buffer, cmd_len + BUF_HEADER_SIZE, ' '); +#endif + /* Process Response */ + if (ret == SUCCESS) { + /* Verify response */ + if (cmd_buf->cmd_code != + (HostCmd_CMD_WIFIDIRECT_PARAMS_CONFIG | + WIFIDIRECTCMD_RESP_CHECK)) { + printf("ERR:Corrupted response!\n"); + goto done; + } + /* Print response */ + if (cmd_buf->result == CMD_SUCCESS) { + if (argc == 2) { + printf("Action = %s %s\n", + (le16_to_cpu(tlv->action)) == + 1 ? "Request" : "Response", + "parameters"); + printf("Config Methods = %02X\n", + le16_to_cpu(tlv->config_methods)); + printf("Device Password ID = %02X\n", + le16_to_cpu(tlv->dev_password)); + } else { + printf("Provisioning protocol parameters setting successful!\n"); + } + } else { + if (argc == 2) + printf("ERR:Couldn't get provisioing parameters!\n"); + else + printf("ERR:Couldn't set provisioing parameters!\n"); + } + } else { + printf("ERR:Command sending failed!\n"); + } +done: + if (buffer) + free(buffer); + return; +} + +/** + * @brief Show usage information for the wifidirect WPS params command + * + * @return N/A + */ +static void +print_wifidirect_cfg_wps_params_usage(void) +{ + printf("\nUsage : wifidirect_cfg_wps_params [pin/pbc/none]"); + printf("\nIf pin/pbc/none is provided, 'set' is performed" + " otherwise 'get' is performed.\n"); + return; +} + +/** + * @brief Set/get wifidirect WPS parametters + * + * Usage: "Usage : wifidirect_cfg_wps_params [pin/pbc/none]" + * + * @param argc Number of arguments + * @param argv Pointer to the arguments + * @return None + */ +static void +wifidirect_cfg_cmd_wps_params(int argc, char *argv[]) +{ + wifidirect_params_config *cmd_buf = NULL; + tlvbuf_wifidirect_wps_params *tlv = NULL; + t_u8 *buffer = NULL; + t_u16 cmd_len = 0; + int opt, ret = 0, param = 0; + + while ((opt = getopt_long(argc, argv, "+", cmd_options, NULL)) != -1) { + switch (opt) { + default: + print_wifidirect_cfg_wps_params_usage(); + return; + } + } + argc -= optind; + argv += optind; + + /* Check arguments */ + if ((argc < 2) || (argc > 3)) { + printf("ERR:Wrong number of arguments!\n"); + print_wifidirect_cfg_wps_params_usage(); + return; + } + + cmd_len = + sizeof(wifidirect_params_config) + + sizeof(tlvbuf_wifidirect_wps_params); + + buffer = (t_u8 *)malloc(MRVDRV_SIZE_OF_CMD_BUFFER); + + if (!buffer) { + printf("ERR:Cannot allocate memory!\n"); + goto done; + } + + memset(buffer, 0, MRVDRV_SIZE_OF_CMD_BUFFER); + + cmd_buf = (wifidirect_params_config *)buffer; + tlv = (tlvbuf_wifidirect_wps_params *)(buffer + + sizeof + (wifidirect_params_config)); + + cmd_buf->cmd_code = HostCmd_CMD_WIFIDIRECT_PARAMS_CONFIG; + cmd_buf->size = cmd_len - BUF_HEADER_SIZE; + cmd_buf->seq_num = 0; + cmd_buf->result = 0; + + tlv->tag = MRVL_WIFIDIRECT_WPS_PARAMS_TLV_ID; + tlv->length = + sizeof(tlvbuf_wifidirect_wps_params) - MRVL_TLV_HEADER_SIZE; + + if (argc == 2) { + cmd_buf->action = ACTION_GET; + } else { + if (strncmp(argv[2], "pin", 3) == 0) + param = 1; + else if (strncmp(argv[2], "pbc", 3) == 0) + param = 2; + else if (strncmp(argv[2], "none", 4)) { + printf("Invalid input, should be pin/pbc or none.\n"); + goto done; + } + cmd_buf->action = cpu_to_le16(ACTION_SET); + tlv->action = cpu_to_le16(param); + } + endian_convert_tlv_header_out(tlv); +#ifdef DEBUG + hexdump(buffer, cmd_len, ' '); +#endif + ret = wifidirect_ioctl((t_u8 *)buffer, &cmd_len, + MRVDRV_SIZE_OF_CMD_BUFFER); + endian_convert_tlv_header_in(tlv); +#ifdef DEBUG + hexdump(buffer, cmd_len + BUF_HEADER_SIZE, ' '); +#endif + /* Process Response */ + if (ret == SUCCESS) { + /* Verify response */ + if (cmd_buf->cmd_code != + (HostCmd_CMD_WIFIDIRECT_PARAMS_CONFIG | + WIFIDIRECTCMD_RESP_CHECK)) { + printf("ERR:Corrupted response!\n"); + goto done; + } + /* Print response */ + if (cmd_buf->result == CMD_SUCCESS) { + if (argc == 2) { + printf("WPS password parameter =>"); + switch (le16_to_cpu(tlv->action)) { + case 1: + printf("Pin\n"); + break; + case 2: + printf("PBC\n"); + break; + default: + printf("None\n"); + break; + } + } else { + printf("WPS parameter setting successful!\n"); + } + } else { + if (argc == 2) { + printf("ERR:Couldn't get WPS parameters !\n"); + } else { + printf("ERR:Couldn't set WPS parameters !\n"); + } + } + } else { + printf("ERR:Command sending failed!\n"); + } +done: + if (buffer) + free(buffer); + return; +} + +/** + * @brief Checkes a particular input for validatation. + * + * @param cmd Type of input + * @param argc Number of arguments + * @param argv Pointer to the arguments + * @return SUCCESS or FAILURE + */ +int +is_input_valid(valid_inputs cmd, int argc, char *argv[]) +{ + int i; + int ret = SUCCESS; + char country[6] = { ' ', ' ', 0, 0, 0, 0 }; + char wifidirect_dev_name[34]; + + memset(wifidirect_dev_name, 0, sizeof(wifidirect_dev_name)); + if (argc == 0) + return FAILURE; + switch (cmd) { + case WIFIDIRECT_MINDISCOVERYINT: + if (argc != 1) { + printf("ERR:Incorrect number of arguments for MinDiscoveryInterval\n"); + ret = FAILURE; + } else { + if ((ISDIGIT(argv[0]) == 0) || + (atoi(argv[0]) >= (1 << 16))) { + printf("ERR:MinDiscoveryInterval must be 2 bytes\n"); + ret = FAILURE; + } + } + break; + case WIFIDIRECT_MAXDISCOVERYINT: + if (argc != 1) { + printf("ERR:Incorrect number of arguments for MaxDiscoveryInterval\n"); + ret = FAILURE; + } else { + if ((ISDIGIT(argv[0]) == 0) || + (atoi(argv[0]) >= (1 << 16))) { + printf("ERR:MaxDiscoveryInterval must be 2 bytes\n"); + ret = FAILURE; + } + } + break; + case WIFIDIRECT_DEVICECAPABILITY: + if (argc != 1) { + printf("ERR:Incorrect number of arguments for DeviceCapability\n"); + ret = FAILURE; + } else { + if ((ISDIGIT(argv[0]) == 0) || + (atoi(argv[0]) > MAX_DEV_CAPABILITY) || + (atoi(argv[0]) < 0)) { + printf("ERR:DeviceCapability must be in the range [0:%d]\n", MAX_DEV_CAPABILITY); + ret = FAILURE; + } + } + break; + case WIFIDIRECT_GROUPCAPABILITY: + if (argc != 1) { + printf("ERR:Incorrect number of arguments for GroupCapability\n"); + ret = FAILURE; + } else { + if ((ISDIGIT(argv[0]) == 0) || + (atoi(argv[0]) > MAX_GRP_CAPABILITY) || + (atoi(argv[0]) < 0)) { + printf("ERR:GroupCapability must be in the range [0:%d]\n", MAX_GRP_CAPABILITY); + ret = FAILURE; + } + } + break; + case CHANNEL: + if ((argc != 1) && (argc != 2)) { + printf("ERR: Incorrect arguments for channel.\n"); + ret = FAILURE; + } else { + if (argc == 2) { + if ((ISDIGIT(argv[1]) == 0) || + (atoi(argv[1]) < 0) || + (atoi(argv[1]) > 1)) { + printf("ERR: MODE must be either 0 or 1\n"); + ret = FAILURE; + } + if ((atoi(argv[1]) == 1) && + (atoi(argv[0]) != 0)) { + printf("ERR: Channel must be 0 for ACS; MODE = 1.\n"); + ret = FAILURE; + } + } + if ((argc == 1) || (atoi(argv[1]) == 0)) { + if ((ISDIGIT(argv[0]) == 0) || + (atoi(argv[0]) < 1) || + (atoi(argv[0]) > MAX_CHANNELS)) { + printf("ERR: Channel must be in the range of 1 to %d, configured - %d\n", MAX_CHANNELS, atoi(argv[0])); + ret = FAILURE; + } + } + } + break; + case SCANCHANNELS: + if (argc > MAX_CHANNELS) { + printf("ERR: Invalid List of Channels\n"); + ret = FAILURE; + } else { + for (i = 0; i < argc; i++) { + if ((ISDIGIT(argv[i]) == 0) || + (atoi(argv[i]) < 1) || + (atoi(argv[i]) > MAX_CHANNELS)) { + printf("ERR: Channel must be in the range of 1 to %d, configured - %d\n", MAX_CHANNELS, atoi(argv[i])); + ret = FAILURE; + break; + } + } + if ((ret != FAILURE) && + (has_dup_channel(argc, argv) != SUCCESS)) { + printf("ERR: Duplicate channel values entered\n"); + ret = FAILURE; + } + } + break; + case WIFIDIRECT_INTENT: + if (argc != 1) { + printf("ERR:Incorrect number of arguments for intent\n"); + ret = FAILURE; + } else { + if ((ISDIGIT(argv[0]) == 0) || + (atoi(argv[0]) > MAX_INTENT) || + (atoi(argv[0]) < 0)) { + printf("ERR:Intent must be in the range [0:%d]\n", MAX_INTENT); + ret = FAILURE; + } + } + break; + case WIFIDIRECT_MANAGEABILITY: + if (argc != 1) { + printf("ERR:Incorrect number of arguments for manageability\n"); + ret = FAILURE; + } else { + if ((ISDIGIT(argv[0]) == 0) || (atoi(argv[0]) < 0) || + (atoi(argv[0]) > 1)) { + printf("ERR:Manageability must be either 0 or 1\n"); + ret = FAILURE; + } + } + break; + case WIFIDIRECT_GROUP_WIFIDIRECT_DEVICE_NAME: + /* 2 extra characters for quotes around device name */ + if ((strlen(argv[0]) > 34)) { + printf("ERR:WIFIDIRECT Device name string length must not be more than 32\n"); + ret = FAILURE; + } else { + strncpy(wifidirect_dev_name, argv[0], + sizeof(wifidirect_dev_name) - 1); + if ((wifidirect_dev_name[0] != '"') || + (wifidirect_dev_name + [strlen(wifidirect_dev_name) - 1] != '"')) { + printf("ERR:WIFIDIRECT Device name must be within double quotes!\n"); + ret = FAILURE; + } + } + break; + case WIFIDIRECT_COUNTRY: + /* 2 extra characters for quotes around country */ + if ((strlen(argv[0]) > 5) || (strlen(argv[0]) < 4)) { + printf("ERR:Country string must have length 2 or 3\n"); + ret = FAILURE; + } else { + strncpy(country, argv[0], sizeof(country) - 1); + if ((country[0] != '"') || + (country[strlen(country) - 1] != '"')) { + printf("ERR:country code must be within double quotes!\n"); + ret = FAILURE; + } else { + for (i = 1; i < strlen(country) - 2; i++) { + if ((toupper(country[i]) < 'A') || + (toupper(country[i]) > 'Z')) { + printf("ERR:Invalid Country Code\n"); + ret = FAILURE; + } + } + } + } + break; + case WIFIDIRECT_NO_OF_CHANNELS: + if (argc != 1) { + printf("ERR:Incorrect number of arguments for num of channels\n"); + ret = FAILURE; + } else { + if ((ISDIGIT(argv[0]) == 0) || + (atoi(argv[0]) > MAX_CHANNELS)) { + printf("ERR:Number of channels should be less than %d\n", MAX_CHANNELS); + ret = FAILURE; + } + } + break; + case WIFIDIRECT_NOA_INDEX: + if (argc != 1) { + printf("ERR:Incorrect number of arguments for NoA Index\n"); + ret = FAILURE; + } else { + if ((ISDIGIT(argv[0]) == 0) || + (atoi(argv[0]) < MIN_NOA_INDEX) || + (atoi(argv[0]) > MAX_NOA_INDEX)) { + printf("ERR:NoA index should be in the range [%d:%d]\n", MIN_NOA_INDEX, MAX_NOA_INDEX); + ret = FAILURE; + } + } + break; + case WIFIDIRECT_OPP_PS: + if (argc != 1) { + printf("ERR:Incorrect number of arguments for Opp PS\n"); + ret = FAILURE; + } else { + if ((ISDIGIT(argv[0]) == 0) || ((atoi(argv[0]) != 0) && + (atoi(argv[0]) != 1))) { + printf("ERR:Opp PS must be either 0 or 1\n"); + ret = FAILURE; + } + } + break; + case WIFIDIRECT_CTWINDOW: + if (argc != 1) { + printf("ERR:Incorrect number of arguments for CTWindow\n"); + ret = FAILURE; + } else { + if ((ISDIGIT(argv[0]) == 0) || + (atoi(argv[0]) > MAX_CTWINDOW) || + (atoi(argv[0]) < MIN_CTWINDOW)) { + printf("ERR:CT Window must be in the range [%d:%d]\n", MIN_CTWINDOW, MAX_CTWINDOW); + ret = FAILURE; + } + } + break; + case WIFIDIRECT_COUNT_TYPE: + if (argc != 1) { + printf("ERR:Incorrect number of arguments for Count/Type\n"); + ret = FAILURE; + } else { + if ((ISDIGIT(argv[0]) == 0) || (atoi(argv[0]) == 0) || + (atoi(argv[0]) > MAX_COUNT_TYPE) || + (atoi(argv[0]) < MIN_COUNT_TYPE)) { + printf("ERR:Count/Type must be in the range [%d:%d] or 255\n", MIN_COUNT_TYPE, MAX_COUNT_TYPE); + ret = FAILURE; + } + } + break; + case WIFIDIRECT_PRESENCE_REQ_TYPE: + if (argc != 1) { + printf("ERR:Incorrect number of arguments for Presence request type\n"); + ret = FAILURE; + } else { + if ((ISDIGIT(argv[0]) == 0) || ((atoi(argv[0]) != 1) + && (atoi(argv[0]) != + 2))) { + printf("ERR:Presence Type must be 1 or 2.\n"); + ret = FAILURE; + } + } + break; + case WIFIDIRECT_DURATION: + if (argc != 1) { + printf("ERR:Incorrect number of arguments for Duration\n"); + ret = FAILURE; + } + break; + case WIFIDIRECT_INTERVAL: + if (argc != 1) { + printf("ERR:Incorrect number of arguments for Interval\n"); + ret = FAILURE; + } + break; + case WIFIDIRECT_START_TIME: + if (argc != 1) { + printf("ERR:Incorrect number of arguments for Start Time\n"); + ret = FAILURE; + } + break; + case WIFIDIRECT_PRIDEVTYPEOUI: + if (argc > MAX_PRIMARY_OUI_LEN) { + printf("ERR: Incorrect number of PrimaryDeviceTypeOUI arguments.\n"); + ret = FAILURE; + break; + } + for (i = 0; i < argc; i++) { + if (IS_HEX_OR_DIGIT(argv[i]) == FAILURE) { + printf("ERR:Unsupported OUI\n"); + ret = FAILURE; + break; + } + } + if (! + ((A2HEXDECIMAL(argv[0]) == 0x00) && + (A2HEXDECIMAL(argv[1]) == 0x50) + && (A2HEXDECIMAL(argv[2]) == 0xF2) && + (A2HEXDECIMAL(argv[3]) == 0x04))) { + printf("ERR:Unsupported OUI\n"); + ret = FAILURE; + break; + } + break; + case WIFIDIRECT_REGULATORYCLASS: + if (argc != 1) { + printf("ERR:Incorrect number of arguments for RegulatoryClass\n"); + ret = FAILURE; + } else { + if ((ISDIGIT(argv[0]) == 0) || + (atoi(argv[0]) > MAX_REG_CLASS) || + (atoi(argv[0]) < MIN_REG_CLASS)) { + printf("ERR:RegulatoryClass must be in the range [%d:%d] or 255\n", MIN_REG_CLASS, MAX_REG_CLASS); + ret = FAILURE; + } + } + break; + case WIFIDIRECT_PRIDEVTYPECATEGORY: + if (argc != 1) { + printf("ERR:Incorrect number of arguments for PrimaryDeviceTypeCategory\n"); + ret = FAILURE; + } else { + if ((ISDIGIT(argv[0]) == 0) || + (atoi(argv[0]) > MAX_PRIDEV_TYPE_CAT) || + (atoi(argv[0]) < MIN_PRIDEV_TYPE_CAT)) { + printf("ERR:PrimaryDeviceTypeCategory must be in the range [%d:%d]\n", MIN_PRIDEV_TYPE_CAT, MAX_PRIDEV_TYPE_CAT); + ret = FAILURE; + } + } + break; + case WIFIDIRECT_SECONDARYDEVCOUNT: + if (argc != 1) { + printf("ERR:Incorrect number of arguments for SecondaryDeviceCount\n"); + ret = FAILURE; + } else { + if ((ISDIGIT(argv[0]) == 0) || + (atoi(argv[0]) > MAX_SECONDARY_DEVICE_COUNT)) { + printf("ERR:SecondaryDeviceCount must be less than 15.\n"); + ret = FAILURE; + } + } + break; + case WIFIDIRECT_INTERFACECOUNT: + if (argc != 1) { + printf("ERR:Incorrect number of arguments for InterfaceCount\n"); + ret = FAILURE; + } else { + if ((ISDIGIT(argv[0]) == 0) || + (atoi(argv[0]) > MAX_INTERFACE_ADDR_COUNT)) { + printf("ERR:IntefaceCount must be in range.[0-41]\n"); + ret = FAILURE; + } + } + break; + case WIFIDIRECT_GROUP_SECONDARYDEVCOUNT: + if (argc != 1) { + printf("ERR:Incorrect number of arguments for SecondaryDeviceCount\n"); + ret = FAILURE; + } else { + if ((ISDIGIT(argv[0]) == 0) || + (atoi(argv[0]) > + MAX_GROUP_SECONDARY_DEVICE_COUNT)) { + printf("ERR:SecondaryDeviceCount must be less than 2.\n"); + ret = FAILURE; + } + } + break; + case WIFIDIRECT_ATTR_CONFIG_TIMEOUT: + if (argc != 1) { + printf("ERR:Incorrect number of arguments for Timeout Configuration\n"); + ret = FAILURE; + } else { + if ((ISDIGIT(argv[0]) == 0) || (atoi(argv[0]) > 255)) { + printf("ERR:TimeoutConfig must be in the range [0:255]\n"); + ret = FAILURE; + } + } + break; + case WIFIDIRECT_ATTR_EXTENDED_TIME: + if (argc != 1) { + printf("ERR:Incorrect number of arguments for Extended time.\n"); + ret = FAILURE; + } else { + if ((ISDIGIT(argv[0]) == 0) || (atoi(argv[0]) > 65535) + || (atoi(argv[0]) < 1)) { + printf("ERR:Extended Time must be in the range [1:65535]\n"); + ret = FAILURE; + } + } + break; + + case WIFIDIRECT_PRIDEVTYPESUBCATEGORY: + if (argc != 1) { + printf("ERR:Incorrect number of arguments for PrimaryDeviceTypeSubCategory\n"); + ret = FAILURE; + } else { + if ((ISDIGIT(argv[0]) == 0) || + (atoi(argv[0]) > MAX_PRIDEV_TYPE_SUBCATEGORY) || + (atoi(argv[0]) < MIN_PRIDEV_TYPE_SUBCATEGORY)) { + printf("ERR:PrimaryDeviceTypeSubCategory must be in the range [%d:%d]\n", MIN_PRIDEV_TYPE_SUBCATEGORY, MAX_PRIDEV_TYPE_SUBCATEGORY); + ret = FAILURE; + } + } + break; + case WIFIDIRECT_INVITATIONFLAG: + if (argc != 1) { + printf("ERR:Incorrect number of arguments for InvitationFlag\n"); + ret = FAILURE; + } else { + if ((ISDIGIT(argv[0]) == 0) || (atoi(argv[0]) < 0) || + (atoi(argv[0]) > 1)) { + printf("ERR:Invitation flag must be either 0 or 1\n"); + ret = FAILURE; + } + } + break; + case WIFIDIRECT_WPSCONFMETHODS: + if (argc != 1) { + printf("ERR:Incorrect number of arguments for WPSConfigMethods\n"); + ret = FAILURE; + } else { + if ((IS_HEX_OR_DIGIT(argv[0]) == 0) || + (A2HEXDECIMAL(argv[0]) > MAX_WPS_CONF_METHODS) || + (A2HEXDECIMAL(argv[0]) < MIN_WPS_CONF_METHODS)) { + printf("ERR:WPSConfigMethods must be in the range [%d:%d]\n", MIN_WPS_CONF_METHODS, MAX_WPS_CONF_METHODS); + ret = FAILURE; + } + } + break; + case WIFIDIRECT_WPSVERSION: + if (argc != 1) { + printf("ERR:Incorrect number of arguments for WPSVersion\n"); + ret = FAILURE; + } else { + if ((A2HEXDECIMAL(argv[0]) < 0x10) && + (A2HEXDECIMAL(argv[0]) > 0x20)) { + printf("ERR:Incorrect WPS Version %s\n", + argv[0]); + ret = FAILURE; + } + } + break; + case WIFIDIRECT_WPSSETUPSTATE: + if (argc != 1) { + printf("ERR:Incorrect number of arguments for WPSSetupState\n"); + ret = FAILURE; + } else { + if ((IS_HEX_OR_DIGIT(argv[0]) == 0) || + ((A2HEXDECIMAL(argv[0]) != 0x01) + && (A2HEXDECIMAL(argv[0]) != 0x02))) { + printf("ERR:Incorrect WPSSetupState %s\n", + argv[0]); + ret = FAILURE; + } + } + break; + case WIFIDIRECT_WPSREQRESPTYPE: + if (argc != 1) { + printf("ERR:Incorrect number of arguments for WPSRequestType\n"); + ret = FAILURE; + } else { + if ((IS_HEX_OR_DIGIT(argv[0]) == 0) || + (A2HEXDECIMAL(argv[0]) > WPS_MAX_REQUESTTYPE)) { + printf("ERR:Incorrect WPSRequestType %s\n", + argv[0]); + ret = FAILURE; + } + } + break; + case WIFIDIRECT_WPSSPECCONFMETHODS: + if (argc != 1) { + printf("ERR:Incorrect number of arguments for WPSSpecConfigMethods\n"); + ret = FAILURE; + } else { + if ((IS_HEX_OR_DIGIT(argv[0]) == 0) || + ((t_u16)A2HEXDECIMAL(argv[0]) > + WPS_MAX_SPECCONFMETHODS) || + ((t_u16)A2HEXDECIMAL(argv[0]) < + WPS_MIN_SPECCONFMETHODS)) { + printf("ERR:WPSSpecConfigMethods must be in the range [%d:%d]\n", WPS_MIN_SPECCONFMETHODS, WPS_MAX_SPECCONFMETHODS); + ret = FAILURE; + } + } + break; + case WIFIDIRECT_WPSDEVICENAME: + if (argc != 1) { + printf("ERR:Incorrect number of arguments\n"); + ret = FAILURE; + } else { + if (argv[0][0] == '"') { + argv[0]++; + } + if (argv[0][strlen(argv[0]) - 1] == '"') { + argv[0][strlen(argv[0]) - 1] = '\0'; + } + if (strlen(argv[0]) > WPS_DEVICE_NAME_MAX_LEN) { + printf("ERR:Device name should contain" + " less than 32 charactors.\n"); + ret = FAILURE; + } + } + break; + case WIFIDIRECT_WPSMANUFACTURER: + if (argc != 1) { + printf("ERR:Incorrect number of arguments\n"); + ret = FAILURE; + } else { + if (strlen(argv[0]) > WPS_MANUFACT_MAX_LEN) { + printf("ERR:Manufacturer name should contain" + "less than 64 charactors.\n"); + ret = FAILURE; + } + } + break; + case WIFIDIRECT_WPSMODELNAME: + if (argc != 1) { + printf("ERR:Incorrect number of arguments\n"); + ret = FAILURE; + } else { + if (strlen(argv[0]) > WPS_MODEL_MAX_LEN) { + printf("ERR:Model name should contain" + " less than 64 charactors.\n"); + ret = FAILURE; + } + } + break; + case WIFIDIRECT_WPSUUID: + if (argc > WPS_UUID_MAX_LEN) { + printf("ERR: Incorrect number of WPSUUID arguments.\n"); + ret = FAILURE; + } else { + for (i = 0; i < argc; i++) { + if (IS_HEX_OR_DIGIT(argv[i]) == FAILURE) { + printf("ERR:Unsupported UUID\n"); + ret = FAILURE; + break; + } + } + } + break; + case WIFIDIRECT_WPSPRIMARYDEVICETYPE: + if (argc > WPS_DEVICE_TYPE_MAX_LEN) { + printf("ERR: Incorrect number of WPSPrimaryDeviceType arguments.\n"); + ret = FAILURE; + break; + } + for (i = 0; i < argc; i++) { + if (IS_HEX_OR_DIGIT(argv[i]) == FAILURE) { + printf("ERR:Unsupported primary device type\n"); + ret = FAILURE; + break; + } + } + if (! + ((A2HEXDECIMAL(argv[2]) == 0x00) && + (A2HEXDECIMAL(argv[3]) == 0x50) + && (A2HEXDECIMAL(argv[4]) == 0xF2) && + (A2HEXDECIMAL(argv[5]) == 0x04))) { + printf("ERR:Unsupported OUI\n"); + ret = FAILURE; + break; + } + break; + case WIFIDIRECT_WPSRFBAND: + if (argc != 1) { + printf("ERR:Incorrect number of arguments for WPSRFBand\n"); + ret = FAILURE; + } else { + if ((IS_HEX_OR_DIGIT(argv[0]) == 0) || + ((A2HEXDECIMAL(argv[0]) != 0x01) + && (A2HEXDECIMAL(argv[0]) != 0x02))) { + printf("ERR:Incorrect WPSRFBand %s\n", argv[0]); + ret = FAILURE; + } + } + break; + case WIFIDIRECT_WPSASSOCIATIONSTATE: + if (argc != 1) { + printf("ERR:Incorrect number of arguments for WPSAssociationState\n"); + ret = FAILURE; + } else { + if ((IS_HEX_OR_DIGIT(argv[0]) == 0) || + ((t_u16)A2HEXDECIMAL(argv[0]) > + WPS_MAX_ASSOCIATIONSTATE)) { + printf("ERR:WPSAssociationState must be in the range [%d:%d]\n", WPS_MIN_ASSOCIATIONSTATE, WPS_MAX_ASSOCIATIONSTATE); + ret = FAILURE; + } + } + break; + case WIFIDIRECT_WPSCONFIGURATIONERROR: + if (argc != 1) { + printf("ERR:Incorrect number of arguments for WPSConfigurationError\n"); + ret = FAILURE; + } else { + if ((IS_HEX_OR_DIGIT(argv[0]) == 0) || + ((t_u16)A2HEXDECIMAL(argv[0]) > + WPS_MAX_CONFIGURATIONERROR)) { + printf("ERR:WPSConfigurationError must be in the range [%d:%d]\n", WPS_MIN_CONFIGURATIONERROR, WPS_MAX_CONFIGURATIONERROR); + ret = FAILURE; + } + } + break; + case WIFIDIRECT_WPSDEVICEPASSWORD: + if (argc != 1) { + printf("ERR:Incorrect number of arguments for WPSDevicePassword\n"); + ret = FAILURE; + } else { + if ((IS_HEX_OR_DIGIT(argv[0]) == 0) || + ((t_u16)A2HEXDECIMAL(argv[0]) > + WPS_MAX_DEVICEPASSWORD)) { + printf("ERR:WPSDevicePassword must be in the range [%d:%d]\n", WPS_MIN_DEVICEPASSWORD, WPS_MAX_DEVICEPASSWORD); + ret = FAILURE; + } + } + break; + case WIFIDIRECT_WPSMODELNUMBER: + if (argc > WPS_MODEL_MAX_LEN) { + printf("ERR: Incorrect number of WPSModelNumber arguments.\n"); + ret = FAILURE; + } else { + for (i = 0; i < argc; i++) { + if (IS_HEX_OR_DIGIT(argv[i]) == FAILURE) { + printf("ERR:Unsupported WPSModelNumber\n"); + ret = FAILURE; + break; + } + } + } + break; + case WIFIDIRECT_WPSSERIALNUMBER: + if (argc > WPS_SERIAL_MAX_LEN) { + printf("ERR: Incorrect number of WPSSerialNumber arguments.\n"); + ret = FAILURE; + } else { + for (i = 0; i < argc; i++) { + if (IS_HEX_OR_DIGIT(argv[i]) == FAILURE) { + printf("ERR:Unsupported WPSSerialNumber\n"); + ret = FAILURE; + break; + } + } + } + break; + case WIFIDIRECT_CATEGORY: + if (argc != 1) { + printf("ERR:Incorrect number of arguments for Category\n"); + ret = FAILURE; + } else { + if (ISDIGIT(argv[0]) == 0) { + printf("ERR:Category incorrect value\n"); + ret = FAILURE; + } + } + break; + case WIFIDIRECT_ACTION: + if (argc != 1) { + printf("ERR:Incorrect number of arguments for Action\n"); + ret = FAILURE; + } else { + if ((ISDIGIT(argv[0]) == 0) || + ((atoi(argv[0]) > 0x10) && + (atoi(argv[0]) != 0xDD))) { + printf("ERR:Action must be less than 0x10 or 0xDD\n"); + ret = FAILURE; + } + } + break; + case WIFIDIRECT_DIALOGTOKEN: + if (argc != 1) { + printf("ERR:Incorrect number of arguments for DialogToken\n"); + ret = FAILURE; + } else { + if (ISDIGIT(argv[0]) == 0) { + printf("ERR:DialogToken incorrect value\n"); + ret = FAILURE; + } + } + break; + case WIFIDIRECT_GAS_COMEBACK_DELAY: + if (argc != 1) { + printf("ERR:Incorrect number of arguments for GAS Comeback Delay\n"); + ret = FAILURE; + } + break; + case WIFIDIRECT_DISC_ADPROTOIE: + if (argc > MAX_ADPROTOIE_LEN) { + printf("ERR: Incorrect number of AdvertisementProtocolIE arguments.\n"); + ret = FAILURE; + break; + } + for (i = 0; i < argc; i++) { + if (IS_HEX_OR_DIGIT(argv[i]) == FAILURE) { + printf("ERR:Unsupported AdvertisementProtocolIE\n"); + ret = FAILURE; + break; + } + } + break; + case WIFIDIRECT_DISC_INFOID: + if (argc > MAX_INFOID_LEN) { + printf("ERR: Incorrect number of DiscoveryInformationID arguments.\n"); + ret = FAILURE; + break; + } + if (! + ((A2HEXDECIMAL(argv[0]) == 0xDD) && + (A2HEXDECIMAL(argv[1]) == 0xDD)) && + !((A2HEXDECIMAL(argv[0]) == 0xDE) && + (A2HEXDECIMAL(argv[1]) == 0x92))) { + printf("ERR:Unsupported DiscoveryInformationID\n"); + ret = FAILURE; + } + break; + case WIFIDIRECT_OUI: + if (argc > MAX_OUI_LEN) { + printf("ERR: Incorrect number of OUI arguments.\n"); + ret = FAILURE; + break; + } + for (i = 0; i < argc; i++) { + if (IS_HEX_OR_DIGIT(argv[i]) == FAILURE) { + printf("ERR:Unsupported OUI\n"); + ret = FAILURE; + break; + } + } + break; + case WIFIDIRECT_OUITYPE: + if (argc != 1) { + printf("ERR:Incorrect number of arguments for OUIType\n"); + ret = FAILURE; + } else { + if (ISDIGIT(argv[0]) == 0) { + printf("ERR:OUIType incorrect value\n"); + ret = FAILURE; + } + } + break; + case WIFIDIRECT_OUISUBTYPE: + if (argc != 1) { + printf("ERR:Incorrect number of arguments for OUISubtype\n"); + ret = FAILURE; + } else { + if (ISDIGIT(argv[0]) == 0) { + printf("ERR:OUISubtype incorrect value\n"); + ret = FAILURE; + } + } + break; + case WIFIDIRECT_DISC_SERVICEPROTO: + if (argc != 1) { + printf("ERR:Incorrect number of arguments for DiscoveryServiceProtocol\n"); + ret = FAILURE; + } else { + if ((ISDIGIT(argv[0]) == 0) || ((atoi(argv[0]) >= 4) && + (atoi(argv[0]) != + 0xFF))) { + printf("ERR:DiscoveryServiceProtocol incorrect value\n"); + ret = FAILURE; + } + } + break; + case WIFIDIRECT_SERVICEUPDATE_INDICATOR: + if (argc != 1) { + printf("ERR:Incorrect number of arguments for ServiceUpdateIndicator\n"); + ret = FAILURE; + } else { + if (ISDIGIT(argv[0]) == 0) { + printf("ERR:ServiceUpdateIndicator incorrect value\n"); + ret = FAILURE; + } + } + break; + case WIFIDIRECT_DISC_SERVICETRANSACID: + if (argc != 1) { + printf("ERR:Incorrect number of arguments for DiscoveryServiceTransactionID\n"); + ret = FAILURE; + } else { + if (ISDIGIT(argv[0]) == 0) { + printf("ERR:DiscoveryServiceTransactionID incorrect value\n"); + ret = FAILURE; + } + } + break; + case WIFIDIRECT_DISC_SERVICE_STATUS: + if (argc != 1) { + printf("ERR:Incorrect number of arguments for ServiceStatus\n"); + ret = FAILURE; + } else { + if ((ISDIGIT(argv[0]) == 0) || (atoi(argv[0]) >= 4)) { + printf("ERR:ServiceStatus incorrect value\n"); + ret = FAILURE; + } + } + break; + case WIFIDIRECT_DISC_DNSTYPE: + if (argc != 1) { + printf("ERR:Incorrect number of arguments for DiscoveryDNSType\n"); + ret = FAILURE; + } else { + if (ISDIGIT(argv[0]) == 0) { + printf("ERR:DiscoveryDNSType incorrect value\n"); + ret = FAILURE; + } + } + break; + case WIFIDIRECT_DISC_BONJOUR_VERSION: + if (argc != 1) { + printf("ERR:Incorrect number of arguments for Version\n"); + ret = FAILURE; + } else { + if (ISDIGIT(argv[0]) == 0) { + printf("ERR:Version incorrect value\n"); + ret = FAILURE; + } + } + break; + case WIFIDIRECT_DISC_UPNP_VERSION: + if (argc != 1) { + printf("ERR:Incorrect number of arguments for Version\n"); + ret = FAILURE; + } + break; + case WIFIDIRECT_ENABLE_SCAN: + if (argc != 1) { + printf("ERR:Incorrect number of arguments for EnableScan\n"); + ret = FAILURE; + } else { + if ((ISDIGIT(argv[0]) == 0) || ((atoi(argv[0]) != 0) && + (atoi(argv[0]) != 1))) { + printf("ERR:EnableScan must be 0 or 1.\n"); + ret = FAILURE; + } + } + break; + + case WIFIDIRECT_DEVICE_STATE: + if (argc != 1) { + printf("ERR:Incorrect number of arguments for DeviceState\n"); + ret = FAILURE; + } else { + if (ISDIGIT(argv[0]) == 0) { + printf("ERR:Incorrect DeviceState.\n"); + ret = FAILURE; + } + } + break; + + default: + printf("Parameter validity for %d ignored\n", cmd); + break; + } + return ret; +} + +/** Structure of command table*/ +typedef struct { + /** Command name */ + char *cmd; + /** Command function pointer */ + void (*func) (int argc, char *argv[]); + /** Command usuage */ + char *help; +} command_table; + +/** WIFIDIRECT command table */ +static command_table wifidirect_command[] = { + {"wifidirect_config", wifidirectcmd_config, + "\tSet/get wifidirect configuration"}, + {"wifidirect_params_config", wifidirectcmd_params_config, + "\tSet/get wifidirect parameter's configuration"}, + {"wifidirect_action_frame", wifidirectcmd_action_frame, + "\tSend wifidirect action frame."}, + {"wifidirect_mode", wifidirectcmd_status, + "\tSet/get WIFIDIRECT start/stop status"}, + {"wifidirect_discovery_request", wifidirectcmd_service_discovery, + "Send wifidirect service discovery request"}, + {"wifidirect_discovery_response", wifidirectcmd_service_discovery, + "Send wifidirect service discovery response"}, + {"wifidirect_gas_comeback_request", + wifidirectcmd_gas_comeback_discovery, + "Send wifidirect GAS comeback request frame"}, + {"wifidirect_gas_comeback_response", + wifidirectcmd_gas_comeback_discovery, + "Send wifidirect GAS comeback response frame"}, + {"wifidirect_cfg_persistent_group_record", + wifidirect_cfg_cmd_persistent_group_record, + "Set/get information about a persistent group"}, + {"wifidirect_cfg_persistent_group_invoke", + wifidirect_cfg_cmd_persistent_group_invoke, + "Invoke or disable a persistent group"}, + {"wifidirect_cfg_discovery_period", wifidirect_cfg_cmd_discovery_period, + "\tSet/get discovery period"}, + {"wifidirect_cfg_intent", wifidirect_cfg_cmd_intent, + "\tSet/get intent"}, + {"wifidirect_cfg_capability", wifidirect_cfg_cmd_capability, + "\tSet/get capability"}, + {"wifidirect_cfg_noa", wifidirect_cfg_cmd_noa, + "\tSet/get notice of absence"}, + {"wifidirect_cfg_opp_ps", wifidirect_cfg_cmd_opp_ps, + "\tSet/get Opportunistic PS"}, + {"wifidirect_cfg_invitation_list", wifidirect_cfg_cmd_invitation_list, + "\tSet/get invitation list"}, + {"wifidirect_cfg_listen_channel", wifidirect_cfg_cmd_listen_channel, + "\tSet/get listen channel"}, + {"wifidirect_cfg_op_channel", wifidirect_cfg_cmd_op_channel, + "\tSet/get operating channel"}, + {"wifidirect_cfg_presence_req_params", + wifidirect_cfg_cmd_presence_req_params, + "\tSet/get presence request parameters"}, + {"wifidirect_cfg_ext_listen_time", wifidirect_cfg_cmd_ext_listen_time, + "Set/get extended listen timing parameters"}, + {"wifidirect_cfg_provisioning_params", + wifidirect_cfg_cmd_provisioning_params, + "Set/get provisioning protocol related parameters"}, + {"wifidirect_cfg_wps_params", wifidirect_cfg_cmd_wps_params, + "Set/get WPS protocol related parameters"}, + {NULL, NULL, 0} +}; + +/** + * @brief Entry function for wifidirectutl + * @param argc number of arguments + * @param argv A pointer to arguments array + * @return SUCCESS or FAILURE + */ +int +main(int argc, char *argv[]) +{ + int i; + + if (argc < 3) { + print_tool_usage(); + exit(1); + } + + strncpy(dev_name, argv[1], IFNAMSIZ); + /* Process command */ + for (i = 0; wifidirect_command[i].cmd; i++) { + if (strncmp + (wifidirect_command[i].cmd, argv[2], + strlen(wifidirect_command[i].cmd))) + continue; + if (strlen(wifidirect_command[i].cmd) != strlen(argv[2])) + continue; + wifidirect_command[i].func(argc, argv); + break; + } + if (!wifidirect_command[i].cmd) { + printf("ERR: %s is not supported\n", argv[2]); + exit(1); + } + return 0; + +} diff --git a/mxm_wifiex/wlan_src/mapp/wifidirectutl/wifidirectutl.h b/mxm_wifiex/wlan_src/mapp/wifidirectutl/wifidirectutl.h new file mode 100644 index 0000000..ffbb003 --- /dev/null +++ b/mxm_wifiex/wlan_src/mapp/wifidirectutl/wifidirectutl.h @@ -0,0 +1,1408 @@ +/** @file wifidirectutl.h + * + * @brief Header file for wifidirectutl application + * + * + * Copyright 2014-2020 NXP + * + * NXP CONFIDENTIAL + * The source code contained or described herein and all documents related to + * the source code (Materials) are owned by NXP, its + * suppliers and/or its licensors. Title to the Materials remains with NXP, + * its suppliers and/or its licensors. The Materials contain + * trade secrets and proprietary and confidential information of NXP, its + * suppliers and/or its licensors. The Materials are protected by worldwide copyright + * and trade secret laws and treaty provisions. No part of the Materials may be + * used, copied, reproduced, modified, published, uploaded, posted, + * transmitted, distributed, or disclosed in any way without NXP's prior + * express written permission. + * + * No license under any patent, copyright, trade secret or other intellectual + * property right is granted to or conferred upon you by disclosure or delivery + * of the Materials, either expressly, by implication, inducement, estoppel or + * otherwise. Any license under such intellectual property rights must be + * express and approved by NXP in writing. + * + */ +/************************************************************************ +Change log: + 07/10/09: Initial creation +************************************************************************/ +#ifndef _WIFIDIRECT_H +#define _WIFIDIRECT_H + +/** Character, 1 byte */ +typedef signed char t_s8; +/** Unsigned character, 1 byte */ +typedef unsigned char t_u8; + +/** Short integer */ +typedef signed short t_s16; +/** Unsigned short integer */ +typedef unsigned short t_u16; + +/** Integer */ +typedef signed int t_s32; +/** Unsigned integer */ +typedef unsigned int t_u32; + +/** Long long integer */ +typedef signed long long t_s64; +/** Unsigned long integer */ +typedef unsigned long long t_u64; + +#if (BYTE_ORDER == LITTLE_ENDIAN) +#undef BIG_ENDIAN_SUPPORT +#endif + +/** 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) )) + +/** Set opp_ps by shifting 7 bits left */ +#define SET_OPP_PS(x) ((x) << 7) + +/** Get opp_ps by masking and shifting 7 bits right */ +#define GET_OPP_PS(x) ((x) >> 7) + +/** CT window mask from opp_ps_ct_window combination */ +#define CT_WINDOW_MASK 0x7F +/** Invitation flag mask */ +#define INVITATION_FLAG_MASK 0x01 + +#ifdef BIG_ENDIAN_SUPPORT +/** Convert from 16 bit little endian format to CPU format */ +#define le16_to_cpu(x) swap_byte_16(x) +/** Convert from 32 bit little endian format to CPU format */ +#define le32_to_cpu(x) swap_byte_32(x) +/** Convert from 64 bit little endian format to CPU format */ +#define le64_to_cpu(x) swap_byte_64(x) +/** Convert to 16 bit little endian format from CPU format */ +#define cpu_to_le16(x) swap_byte_16(x) +/** Convert to 32 bit little endian format from CPU format */ +#define cpu_to_le32(x) swap_byte_32(x) +/** Convert to 64 bit little endian format from CPU format */ +#define cpu_to_le64(x) swap_byte_64(x) + +/** Convert WIFIDIRECTCMD header to little endian format from CPU format */ +#define endian_convert_request_header(x) \ + { \ + (x)->cmd_code = cpu_to_le16((x)->cmd_code); \ + (x)->size = cpu_to_le16((x)->size); \ + (x)->seq_num = cpu_to_le16((x)->seq_num); \ + (x)->result = cpu_to_le16((x)->result); \ + } + +/** Convert WIFIDIRECTCMD header from little endian format to CPU format */ +#define endian_convert_response_header(x) \ + { \ + (x)->cmd_code = le16_to_cpu((x)->cmd_code); \ + (x)->size = le16_to_cpu((x)->size); \ + (x)->seq_num = le16_to_cpu((x)->seq_num); \ + (x)->result = le16_to_cpu((x)->result); \ + } + +/** Convert WIFIDIRECT header to little endian format from CPU format */ +#define endian_convert_tlv_wifidirect_header_out(x) \ + { \ + (x)->length = cpu_to_le16((x)->length); \ + } + +/** Convert WIFIDIRECT header from little endian format to CPU format */ +#define endian_convert_tlv_wifidirect_header_in(x) \ + { \ + (x)->length = le16_to_cpu((x)->length); \ + } + +/** Convert TLV header to little endian format from CPU format */ +#define endian_convert_tlv_header_out(x) \ + { \ + (x)->tag = cpu_to_le16((x)->tag); \ + (x)->length = cpu_to_le16((x)->length); \ + } + +/** Convert TLV header from little endian format to CPU format */ +#define endian_convert_tlv_header_in(x) \ + { \ + (x)->tag = le16_to_cpu((x)->tag); \ + (x)->length = le16_to_cpu((x)->length); \ + } + +#else /* BIG_ENDIAN_SUPPORT */ +/** Do nothing */ +#define le16_to_cpu(x) x +/** Do nothing */ +#define le32_to_cpu(x) x +/** Do nothing */ +#define le64_to_cpu(x) x +/** Do nothing */ +#define cpu_to_le16(x) x +/** Do nothing */ +#define cpu_to_le32(x) x +/** Do nothing */ +#define cpu_to_le64(x) x + +/** Do nothing */ +#define endian_convert_request_header(x) +/** Do nothing */ +#define endian_convert_response_header(x) +/** Do nothing */ +#define endian_convert_tlv_wifidirect_header_out(x) +/** Do nothing */ +#define endian_convert_tlv_wifidirect_header_in(x) +/** Do nothing */ +#define endian_convert_tlv_header_out(x) +/** Do nothing */ +#define endian_convert_tlv_header_in(x) +#endif /* BIG_ENDIAN_SUPPORT */ + +/** Convert WPS TLV header to network order */ +#define endian_convert_tlv_wps_header_out(x) \ + { \ + (x)->tag = htons((x)->tag); \ + (x)->length = htons((x)->length); \ + } + +/** Convert WPS TLV header from network to host order */ +#define endian_convert_tlv_wps_header_in(t,l) \ + { \ + (t) = ntohs(t); \ + (l) = ntohs(l); \ + } + +/** Private command ID to set/get custom IE buffer */ +#define CUSTOM_IE (SIOCDEVPRIVATE + 13) + +/** TLV type ID definition */ +#define PROPRIETARY_TLV_BASE_ID 0x0100 +/** TLV: Management IE list */ +#define MRVL_MGMT_IE_LIST_TLV_ID (PROPRIETARY_TLV_BASE_ID + 0x69) //0x0169 +/** TLV: WifiDirect Discovery Period */ +#define MRVL_WIFIDIRECT_DISC_PERIOD_TLV_ID (PROPRIETARY_TLV_BASE_ID + 0x7c) //0x017c +/** TLV: WifiDirect Scan Enable */ +#define MRVL_WIFIDIRECT_SCAN_ENABLE_TLV_ID (PROPRIETARY_TLV_BASE_ID + 0x7d) //0x017d +/** TLV: WifiDirect Peer Device */ +#define MRVL_WIFIDIRECT_PEER_DEVICE_TLV_ID (PROPRIETARY_TLV_BASE_ID + 0x7e) //0x017e +/** TLV: WifiDirect Scan Request Peer Device */ +#define MRVL_WIFIDIRECT_SCAN_REQ_DEVICE_TLV_ID (PROPRIETARY_TLV_BASE_ID + 0x7f) //0x017f +/** TLV: WifiDirect Device State */ +#define MRVL_WIFIDIRECT_DEVICE_STATE_TLV_ID (PROPRIETARY_TLV_BASE_ID + 0x80) //0x0180 +/** TLV: WifiDirect Intent */ +#define MRVL_WIFIDIRECT_INTENT_TLV_ID (PROPRIETARY_TLV_BASE_ID + 0x81) //0x0181 +/** TLV: WifiDirect Capability */ +#define MRVL_WIFIDIRECT_CAPABILITY_TLV_ID (PROPRIETARY_TLV_BASE_ID + 0x82) //0x0182 +/** TLV: WifiDirect Notice of Absence */ +#define MRVL_WIFIDIRECT_NOA_TLV_ID (PROPRIETARY_TLV_BASE_ID + 0x83) //0x0183 +/** TLV: WifiDirect Opportunistic Power Save */ +#define MRVL_WIFIDIRECT_OPP_PS_TLV_ID (PROPRIETARY_TLV_BASE_ID + 0x84) //0x0184 +/** TLV: WifiDirect Invitation list */ +#define MRVL_WIFIDIRECT_INVITATION_LIST_TLV_ID (PROPRIETARY_TLV_BASE_ID + 0x85) //0x0185 +/** TLV: WifiDirect Listen channel */ +#define MRVL_WIFIDIRECT_LISTEN_CHANNEL_TLV_ID (PROPRIETARY_TLV_BASE_ID + 0x86) //0x0186 +/** TLV: WifiDirect Operating Channel */ +#define MRVL_WIFIDIRECT_OPERATING_CHANNEL_TLV_ID (PROPRIETARY_TLV_BASE_ID + 0x87) //0x0187 +/** TLV: WifiDirect Persistent Group */ +#define MRVL_WIFIDIRECT_PERSISTENT_GROUP_TLV_ID (PROPRIETARY_TLV_BASE_ID + 0x88) //0x0188 +/** TLV: WifiDirect Presence request parameters */ +#define MRVL_WIFIDIRECT_PRESENCE_REQ_PARAMS_TLV_ID (PROPRIETARY_TLV_BASE_ID + 0x8d) //0x018d +/** TLV: WifiDirect Extended Listen Time */ +#define MRVL_WIFIDIRECT_EXTENDED_LISTEN_TIME_TLV_ID (PROPRIETARY_TLV_BASE_ID + 0x8e) //0x018e +/** TLV: WifiDirect Provisioning parameters */ +#define MRVL_WIFIDIRECT_PROVISIONING_PARAMS_TLV_ID (PROPRIETARY_TLV_BASE_ID + 0x8f) //0x018f +/** TLV: WifiDirect WPS parameters */ +#define MRVL_WIFIDIRECT_WPS_PARAMS_TLV_ID (PROPRIETARY_TLV_BASE_ID + 0x90) //0x0190 + +/** Max Device capability */ +#define MAX_DEV_CAPABILITY 255 +/** Max group capability */ +#define MAX_GRP_CAPABILITY 255 +/** Max Intent */ +#define MAX_INTENT 15 +/** Max length of Primary device type OUI */ +#define MAX_PRIMARY_OUI_LEN 4 +/** Min value of Regulatory class */ +#define MIN_REG_CLASS 1 +/** Max value of Regulatory class */ +#define MAX_REG_CLASS 255 +/** Min value of NoA index */ +#define MIN_NOA_INDEX 0 +/** Max value of NoA index */ +#define MAX_NOA_INDEX 255 +/** Min value of CTwindow */ +#define MIN_CTWINDOW 0 +/** Max value of CTwindow */ +#define MAX_CTWINDOW 63 +/** Min value of Count/Type */ +#define MIN_COUNT_TYPE 1 +/** Max value of Count/Type */ +#define MAX_COUNT_TYPE 255 +/** Min Primary Device type category */ +#define MIN_PRIDEV_TYPE_CAT 1 +/** Max Primary Device type category */ +#define MAX_PRIDEV_TYPE_CAT 11 +/** Min Primary Device type subcategory */ +#define MIN_PRIDEV_TYPE_SUBCATEGORY 1 +/** Max Primary Device type subcategory */ +#define MAX_PRIDEV_TYPE_SUBCATEGORY 9 +/** Min value of WPS config method */ +#define MIN_WPS_CONF_METHODS 0x01 +/** Max value of WPS config method */ +#define MAX_WPS_CONF_METHODS 0xffff +/** Max length of Advertisement Protocol IE */ +#define MAX_ADPROTOIE_LEN 4 +/** Max length of Discovery Information ID */ +#define MAX_INFOID_LEN 2 +/** Max length of OUI */ +#define MAX_OUI_LEN 3 +/** Max count of interface list */ +#define MAX_INTERFACE_ADDR_COUNT 41 +/** Max count of secondary device types */ +#define MAX_SECONDARY_DEVICE_COUNT 15 +/** Max count of group secondary device types*/ +#define MAX_GROUP_SECONDARY_DEVICE_COUNT 2 +/** Maximum length of lines in configuration file */ +#define MAX_CONFIG_LINE 1024 +/** Maximum number of arguments in configuration file */ +#define MAX_ARGS_NUM 256 +/** Maximum channels */ +#define MAX_CHANNELS 165 +/** Maximum number of NoA descriptors */ +#define MAX_NOA_DESCRIPTORS 8 +/** Maximum number of channel list entries */ +#define MAX_CHAN_LIST 8 +/** Maximum buffer size for channel entries */ +#define MAX_BUFFER_SIZE 64 +/** WPS Minimum version number */ +#define WPS_MIN_VERSION 0x10 +/** WPS Maximum version number */ +#define WPS_MAX_VERSION 0x20 +/** WPS Minimum request type */ +#define WPS_MIN_REQUESTTYPE 0x00 +/** WPS Maximum request type */ +#define WPS_MAX_REQUESTTYPE 0x04 +/** WPS Minimum config methods */ +#define WPS_MIN_SPECCONFMETHODS 0x0001 +/** WPS Maximum config methods */ +#define WPS_MAX_SPECCONFMETHODS 0xFFFF +/** WPS UUID maximum length */ +#define WPS_UUID_MAX_LEN 16 +/** WPS Device Type maximum length */ +#define WPS_DEVICE_TYPE_MAX_LEN 8 +/** WPS Minimum association state */ +#define WPS_MIN_ASSOCIATIONSTATE 0x0000 +/** WPS Maximum association state */ +#define WPS_MAX_ASSOCIATIONSTATE 0x0004 +/** WPS Minimum configuration error */ +#define WPS_MIN_CONFIGURATIONERROR 0x0000 +/** WPS Maximum configuration error */ +#define WPS_MAX_CONFIGURATIONERROR 0x0012 +/** WPS Minimum Device password ID */ +#define WPS_MIN_DEVICEPASSWORD 0x0000 +/** WPS Maximum Device password ID */ +#define WPS_MAX_DEVICEPASSWORD 0x000f +/** WPS Device Name maximum length */ +#define WPS_DEVICE_NAME_MAX_LEN 32 +/** WPS Model maximum length */ +#define WPS_MODEL_MAX_LEN 32 +/** WPS Serial maximum length */ +#define WPS_SERIAL_MAX_LEN 32 +/** WPS Manufacturer maximum length */ +#define WPS_MANUFACT_MAX_LEN 64 +/** WPS Device Info OUI+Type+SubType Length */ +#define WPS_DEVICE_TYPE_LEN 8 + +/** Maximum value of invitation list index */ +#define WIFIDIRECT_INVITATION_LIST_MAX 5 +/** Maximum value of persistent group index */ +#define WIFIDIRECT_PERSISTENT_GROUP_MAX 4 +/** Minimum length of Passphrase */ +#define WIFIDIRECT_PASSPHRASE_LEN_MIN 8 +/** Maximum length of PSK */ +#define WIFIDIRECT_PSK_LEN_MAX 64 +/** Persistent group cancel command */ +#define WIFIDIRECT_PERSISTENT_RECORD_CANCEL 0xFF +/** Maximum value of noA descriptors */ +#define WIFIDIRECT_NOA_DESC_MAX 2 +/** Country string last byte 0x04 */ +#define WIFIDIRECT_COUNTRY_LAST_BYTE 0x04 + +#ifdef __GNUC__ +/** Structure packing begins */ +#define PACK_START +/** Structure packeing end */ +#define PACK_END __attribute__ ((packed)) +#else +/** Structure packing begins */ +#define PACK_START __packed +/** Structure packeing end */ +#define PACK_END +#endif + +#ifndef ETH_ALEN +/** MAC address length */ +#define ETH_ALEN 6 +#endif + +/** Action field value : get */ +#define ACTION_GET 0 +/** Action field value : set */ +#define ACTION_SET 1 + +/** Success */ +#define SUCCESS 1 +/** Failure */ +#define FAILURE 0 +/** MAC BROADCAST */ +#define WIFIDIRECT_RET_MAC_BROADCAST 0x1FF +/** MAC MULTICAST */ +#define WIFIDIRECT_RET_MAC_MULTICAST 0x1FE + +/** Command is successful */ +#define CMD_SUCCESS 0 +/** Command fails */ +#define CMD_FAILURE -1 + +/** + * Hex or Decimal to Integer + * @param num string to convert into decimal or hex + */ +#define A2HEXDECIMAL(num) \ + (strncasecmp("0x", (num), 2)?(unsigned int) strtoll((num),NULL,0):a2hex((num)))\ + +/** + * Check of decimal or hex string + * @param num string + */ +#define IS_HEX_OR_DIGIT(num) \ + (strncasecmp("0x", (num), 2)?ISDIGIT((num)):ishexstring((num)))\ + +/** Find minimum value */ +#ifndef MIN +#define MIN(a, b) ((a) < (b) ? (a) : (b)) +#endif /* MIN */ + +/** Level of wifidirect parameters in the wifidirect.conf file */ +typedef enum { + WIFIDIRECT_PARAMS_CONFIG = 1, + WIFIDIRECT_CAPABILITY_CONFIG, + WIFIDIRECT_GROUP_OWNER_INTENT_CONFIG, + WIFIDIRECT_CHANNEL_CONFIG, + WIFIDIRECT_MANAGEABILITY_CONFIG, + WIFIDIRECT_CHANNEL_LIST_CONFIG, + WIFIDIRECT_NOTICE_OF_ABSENCE, + WIFIDIRECT_NOA_DESCRIPTOR, + WIFIDIRECT_DEVICE_INFO_CONFIG, + WIFIDIRECT_GROUP_INFO_CONFIG, + WIFIDIRECT_GROUP_SEC_INFO_CONFIG, + WIFIDIRECT_GROUP_CLIENT_INFO_CONFIG, + WIFIDIRECT_DEVICE_SEC_INFO_CONFIG, + WIFIDIRECT_GROUP_ID_CONFIG, + WIFIDIRECT_GROUP_BSS_ID_CONFIG, + WIFIDIRECT_DEVICE_ID_CONFIG, + WIFIDIRECT_INTERFACE_CONFIG, + WIFIDIRECT_TIMEOUT_CONFIG, + WIFIDIRECT_EXTENDED_TIME_CONFIG, + WIFIDIRECT_INTENDED_ADDR_CONFIG, + WIFIDIRECT_OPCHANNEL_CONFIG, + WIFIDIRECT_INVITATION_FLAG_CONFIG, + WIFIDIRECT_WPSIE, + WIFIDIRECT_DISCOVERY_REQUEST_RESPONSE = 0x20, + WIFIDIRECT_DISCOVERY_QUERY, + WIFIDIRECT_DISCOVERY_SERVICE, + WIFIDIRECT_DISCOVERY_VENDOR, + WIFIDIRECT_DISCOVERY_QUERY_RESPONSE_PER_PROTOCOL, + WIFIDIRECT_EXTRA, +} wifidirect_param_level; + +/** Valid Input Commands */ +typedef enum { + SCANCHANNELS, + CHANNEL, + WIFIDIRECT_DEVICECAPABILITY, + WIFIDIRECT_GROUPCAPABILITY, + WIFIDIRECT_INTENT, + WIFIDIRECT_REGULATORYCLASS, + WIFIDIRECT_MANAGEABILITY, + WIFIDIRECT_COUNTRY, + WIFIDIRECT_NO_OF_CHANNELS, + WIFIDIRECT_NOA_INDEX, + WIFIDIRECT_OPP_PS, + WIFIDIRECT_CTWINDOW, + WIFIDIRECT_COUNT_TYPE, + WIFIDIRECT_DURATION, + WIFIDIRECT_INTERVAL, + WIFIDIRECT_START_TIME, + WIFIDIRECT_PRIDEVTYPECATEGORY, + WIFIDIRECT_PRIDEVTYPEOUI, + WIFIDIRECT_PRIDEVTYPESUBCATEGORY, + WIFIDIRECT_SECONDARYDEVCOUNT, + WIFIDIRECT_GROUP_SECONDARYDEVCOUNT, + WIFIDIRECT_GROUP_WIFIDIRECT_DEVICE_NAME, + WIFIDIRECT_INTERFACECOUNT, + WIFIDIRECT_ATTR_CONFIG_TIMEOUT, + WIFIDIRECT_ATTR_EXTENDED_TIME, + WIFIDIRECT_WPSCONFMETHODS, + WIFIDIRECT_WPSVERSION, + WIFIDIRECT_WPSSETUPSTATE, + WIFIDIRECT_WPSREQRESPTYPE, + WIFIDIRECT_WPSSPECCONFMETHODS, + WIFIDIRECT_WPSUUID, + WIFIDIRECT_WPSPRIMARYDEVICETYPE, + WIFIDIRECT_WPSRFBAND, + WIFIDIRECT_WPSASSOCIATIONSTATE, + WIFIDIRECT_WPSCONFIGURATIONERROR, + WIFIDIRECT_WPSDEVICENAME, + WIFIDIRECT_WPSDEVICEPASSWORD, + WIFIDIRECT_WPSMANUFACTURER, + WIFIDIRECT_WPSMODELNAME, + WIFIDIRECT_WPSMODELNUMBER, + WIFIDIRECT_WPSSERIALNUMBER, + WIFIDIRECT_CATEGORY, + WIFIDIRECT_ACTION, + WIFIDIRECT_DIALOGTOKEN, + WIFIDIRECT_DISC_ADPROTOIE, + WIFIDIRECT_GAS_COMEBACK_DELAY, + WIFIDIRECT_DISC_INFOID, + WIFIDIRECT_OUI, + WIFIDIRECT_OUITYPE, + WIFIDIRECT_OUISUBTYPE, + WIFIDIRECT_SERVICEUPDATE_INDICATOR, + WIFIDIRECT_DISC_SERVICEPROTO, + WIFIDIRECT_DISC_SERVICETRANSACID, + WIFIDIRECT_DISC_SERVICE_STATUS, + WIFIDIRECT_MINDISCOVERYINT, + WIFIDIRECT_MAXDISCOVERYINT, + WIFIDIRECT_ENABLE_SCAN, + WIFIDIRECT_DEVICE_STATE, + WIFIDIRECT_INVITATIONFLAG, + WIFIDIRECT_DISC_DNSTYPE, + WIFIDIRECT_DISC_BONJOUR_VERSION, + WIFIDIRECT_DISC_UPNP_VERSION, + WIFIDIRECT_PRESENCE_REQ_TYPE, +} valid_inputs; + +/** WIFIDIRECT IE header len */ +#define WIFIDIRECT_IE_HEADER_LEN 3 + +/** AP CMD header */ +#define WIFIDIRECT_CMD_HEADER /** Buf Size */ \ + t_u32 buf_size; \ + /** Command Code */ \ + t_u16 cmd_code; \ + /** Size */ \ + t_u16 size; \ + /** Sequence Number */ \ + t_u16 seq_num; \ + /** Result */ \ + t_s16 result + +/** TLV header size */ +#define MRVL_TLV_HEADER_SIZE 4 + +/** NXP private command identifier */ +#define CMD_NXP "MRVL_CMD" +/** NXP private command for hostcmd */ +#define PRIV_CMD_HOSTCMD "hostcmd" + +/** WIFIDIRECTCMD buffer */ +typedef PACK_START struct _wifidirectcmdbuf { + /** Header */ + WIFIDIRECT_CMD_HEADER; +} PACK_END wifidirectcmdbuf; + +/** MRVL private CMD structure */ +typedef PACK_START struct _mrvl_priv_cmd { + /** Command buffer */ + t_u8 *buf; + /** Used length */ + t_u32 used_len; + /** Total length */ + t_u32 total_len; +} PACK_END mrvl_priv_cmd; + +/** TLV buffer : WifiDirect Custom IE Buffer Format*/ +typedef PACK_START struct special_mask_custom_ie_buf { + /** Vendor Specific OUI */ + t_u8 Oui[4]; + /** Vendor Specific Buffer */ + t_u8 wfd_ie[]; +} PACK_END special_mask_custom_ie_buf; + +/** TLV buffer : WifiDirect IE device Id */ +typedef PACK_START struct _tlvbuf_wifidirect_device_id { + /** TLV Header tag */ + t_u8 tag; + /** TLV Header length */ + t_u16 length; + /** WIFIDIRECT device MAC address */ + t_u8 dev_mac_address[ETH_ALEN]; +} PACK_END tlvbuf_wifidirect_device_id; + +/** TLV buffer : WifiDirect IE capability */ +typedef PACK_START struct _tlvbuf_wifidirect_capability { + /** TLV Header tag */ + t_u8 tag; + /** TLV Header length */ + t_u16 length; + /** WIFIDIRECT device capability */ + t_u8 dev_capability; + /** WIFIDIRECT group capability */ + t_u8 group_capability; +} PACK_END tlvbuf_wifidirect_capability; + +/** TLV buffer : WifiDirect IE Group owner intent */ +typedef PACK_START struct _tlvbuf_wifidirect_group_owner_intent { + /** TLV Header tag */ + t_u8 tag; + /** TLV Header length */ + t_u16 length; + /** WIFIDIRECT device group owner intent */ + t_u8 dev_intent; +} PACK_END tlvbuf_wifidirect_group_owner_intent; + +/** TLV buffer : WifiDirect IE channel */ +typedef PACK_START struct _tlvbuf_wifidirect_channel { + /** TLV Header tag */ + t_u8 tag; + /** TLV Header length */ + t_u16 length; + /** WIFIDIRECT country string */ + t_u8 country_string[3]; + /** WIFIDIRECT regulatory class */ + t_u8 regulatory_class; + /** WIFIDIRECT channel number */ + t_u8 channel_number; +} PACK_END tlvbuf_wifidirect_channel; + +/** TLV buffer : WifiDirect IE invitation flag */ +typedef PACK_START struct _tlvbuf_wifidirect_invitation_flag { + /** TLV Header tag */ + t_u8 tag; + /** TLV Header length */ + t_u16 length; + /** WIFIDIRECT invitation flag */ + t_u8 invitation_flag; +} PACK_END tlvbuf_wifidirect_invitation_flag; + +/** Channel Entry */ +typedef PACK_START struct _chan_entry { + /** WIFIDIRECT regulatory class */ + t_u8 regulatory_class; + /** WIFIDIRECT no of channels */ + t_u8 num_of_channels; + /** WIFIDIRECT channel number */ + t_u8 chan_list[]; +} PACK_END chan_entry; + +/** NoA Descriptor */ +typedef PACK_START struct _noa_descriptor { + /** WIFIDIRECT count OR type */ + t_u8 count_type; + /** WIFIDIRECT duration */ + t_u32 duration; + /** WIFIDIRECT interval */ + t_u32 interval; + /** WIFIDIRECT start time */ + t_u32 start_time; +} PACK_END noa_descriptor; + +/** TLV buffer : WifiDirect IE channel list */ +typedef PACK_START struct _tlvbuf_wifidirect_channel_list { + /** TLV Header tag */ + t_u8 tag; + /** TLV Header length */ + t_u16 length; + /** WIFIDIRECT country string */ + t_u8 country_string[3]; + /** WIFIDIRECT channel entry list */ + chan_entry wifidirect_chan_entry_list[]; +} PACK_END tlvbuf_wifidirect_channel_list; + +/** TLV buffer : WifiDirect IE Manageability */ +typedef PACK_START struct _tlvbuf_wifidirect_manageability { + /** TLV Header tag */ + t_u8 tag; + /** TLV Header length */ + t_u16 length; + /** WIFIDIRECT Manageability */ + t_u8 manageability; +} PACK_END tlvbuf_wifidirect_manageability; + +/** TLV buffer : WifiDirect IE Notice of Absence */ +typedef PACK_START struct _tlvbuf_wifidirect_notice_of_absence { + /** TLV Header tag */ + t_u8 tag; + /** TLV Header length */ + t_u16 length; + /** WIFIDIRECT NoA Index */ + t_u8 noa_index; + /** WIFIDIRECT CTWindow and OppPS parameters */ + t_u8 ctwindow_opp_ps; + /** WIFIDIRECT NoA Descriptor list */ + noa_descriptor wifidirect_noa_descriptor_list[]; +} PACK_END tlvbuf_wifidirect_notice_of_absence; + +/** TLV buffer : WifiDirect IE device Info */ +typedef PACK_START struct _tlvbuf_wifidirect_device_info { + /** TLV Header tag */ + t_u8 tag; + /** TLV Header length */ + t_u16 length; + /** WIFIDIRECT device address */ + t_u8 dev_address[ETH_ALEN]; + /** WPS config methods */ + t_u16 config_methods; + /** Primary device type : category */ + t_u16 primary_category; + /** Primary device type : OUI */ + t_u8 primary_oui[4]; + /** Primary device type : sub-category */ + t_u16 primary_subcategory; + /** Secondary Device Count */ + t_u8 secondary_dev_count; + /** Secondary Device Info */ + t_u8 secondary_dev_info[0]; + /** WPS Device Name Tag */ + t_u16 device_name_type; + /** WPS Device Name Length */ + t_u16 device_name_len; + /** Device name */ + t_u8 device_name[]; +} PACK_END tlvbuf_wifidirect_device_info; + +/** TLV buffer : wifidirect IE WIFIDIRECT Group Info- Client Dev Info */ +typedef PACK_START struct _wifidirect_client_dev_info { + /** Length of each device */ + t_u8 dev_length; + /** WIFIDIRECT device address */ + t_u8 wifidirect_dev_address[ETH_ALEN]; + /** WIFIDIRECT Interface address */ + t_u8 wifidirect_intf_address[ETH_ALEN]; + /** WIFIDIRECT Device capability*/ + t_u8 wifidirect_dev_capability; + /** WPS config methods */ + t_u16 config_methods; + /** Primary device type : category */ + t_u16 primary_category; + /** Primary device type : OUI */ + t_u8 primary_oui[4]; + /** Primary device type : sub-category */ + t_u16 primary_subcategory; + /** Secondary Device Count */ + t_u8 wifidirect_secondary_dev_count; + /** Secondary Device Info */ + t_u8 wifidirect_secondary_dev_info[0]; + /** WPS WIFIDIRECT Device Name Tag */ + t_u16 wifidirect_device_name_type; + /** WPS WIFIDIRECT Device Name Length */ + t_u16 wifidirect_device_name_len; + /** WIFIDIRECT Device name */ + t_u8 wifidirect_device_name[]; +} PACK_END wifidirect_client_dev_info; + +/** TLV buffer : wifidirect IE WIFIDIRECT Group Info */ +typedef PACK_START struct _tlvbuf_wifidirect_group_info { + /** TLV Header tag */ + t_u8 tag; + /** TLV Header length */ + t_u16 length; + /** Secondary Device Info */ + t_u8 wifidirect_client_dev_list[]; +} PACK_END tlvbuf_wifidirect_group_info; + +/** TLV buffer : WifiDirect IE group Id */ +typedef PACK_START struct _tlvbuf_wifidirect_group_id { + /** TLV Header tag */ + t_u8 tag; + /** TLV Header length */ + t_u16 length; + /** WIFIDIRECT group MAC address */ + t_u8 group_address[ETH_ALEN]; + /** WIFIDIRECT group SSID */ + t_u8 group_ssid[]; +} PACK_END tlvbuf_wifidirect_group_id; + +/** TLV buffer : WifiDirect IE group BSS Id */ +typedef PACK_START struct _tlvbuf_wifidirect_group_bss_id { + /** TLV Header tag */ + t_u8 tag; + /** TLV Header length */ + t_u16 length; + /** WIFIDIRECT group Bss Id */ + t_u8 group_bssid[ETH_ALEN]; +} PACK_END tlvbuf_wifidirect_group_bss_id; + +/** TLV buffer : WifiDirect IE Interface */ +typedef PACK_START struct _tlvbuf_wifidirect_interface { + /** TLV Header tag */ + t_u8 tag; + /** TLV Header length */ + t_u16 length; + /** WIFIDIRECT interface Id */ + t_u8 interface_id[ETH_ALEN]; + /** WIFIDIRECT interface count */ + t_u8 interface_count; + /** WIFIDIRECT interface addresslist */ + t_u8 interface_idlist[]; +} PACK_END tlvbuf_wifidirect_interface; + +/** TLV buffer : WifiDirect configuration timeout */ +typedef PACK_START struct _tlvbuf_wifidirect_config_timeout { + /** TLV Header tag */ + t_u8 tag; + /** TLV Header length */ + t_u16 length; + /** Group configuration timeout */ + t_u8 group_config_timeout; + /** Device configuration timeout */ + t_u8 device_config_timeout; +} PACK_END tlvbuf_wifidirect_config_timeout; + +/** TLV buffer : WifiDirect extended listen time */ +typedef PACK_START struct _tlvbuf_wifidirect_ext_listen_time { + /** TLV Header tag */ + t_u8 tag; + /** TLV Header length */ + t_u16 length; + /** Availability period */ + t_u16 availability_period; + /** Availability interval */ + t_u16 availability_interval; +} PACK_END tlvbuf_wifidirect_ext_listen_time; + +/** TLV buffer : WifiDirect Intended Interface Address */ +typedef PACK_START struct _tlvbuf_wifidirect_intended_addr { + /** TLV Header tag */ + t_u8 tag; + /** TLV Header length */ + t_u16 length; + /** WIFIDIRECT Group interface address */ + t_u8 group_address[ETH_ALEN]; +} PACK_END tlvbuf_wifidirect_intended_addr; + +/** TLV buffer : WifiDirect WPS IE */ +typedef PACK_START struct _tlvbuf_wifidirect_wps_ie { + /** TLV Header tag */ + t_u16 tag; + /** TLV Header length */ + t_u16 length; + /** WIFIDIRECT WPS IE data */ + t_u8 data[]; +} PACK_END tlvbuf_wps_ie; + +/** HostCmd_CMD_WIFIDIRECT_MODE_CONFIG */ +typedef PACK_START struct _wifidirect_mode_config { + /** Header */ + WIFIDIRECT_CMD_HEADER; + /** Action */ + t_u16 action; /* 0 = ACT_GET; 1 = ACT_SET; */ + /** wifidirect mode data */ + t_u16 mode; +} PACK_END wifidirect_mode_config; + +/** HostCmd_CMD_WIFIDIRECT_PARAMS_CONFIG */ +typedef PACK_START struct _wifidirect_params_config { + /** Header */ + WIFIDIRECT_CMD_HEADER; + /** Action */ + t_u16 action; /* 0 = ACT_GET; 1 = ACT_SET; */ + /** TLV data */ + t_u8 wifidirect_tlv[]; +} PACK_END wifidirect_params_config; + +/** Internal WIFIDIRECT structure for Query Data */ +typedef PACK_START struct wifidirect_query_data { + union { + PACK_START struct upnp_specific_query { + /** version field */ + t_u8 version; + /** value */ + t_u8 value[]; + } PACK_END upnp; + + PACK_START struct bonjour_specific_query { + /** DNS name */ + t_u8 dns[0]; + /** DNS type */ + t_u8 dns_type; + /** version field */ + t_u8 version; + } PACK_END bonjour; + } u; +} PACK_END wifidirect_query_data; + +/** Internal WIFIDIRECT structure for Response Data */ +typedef PACK_START struct wifidirect_Response_data { + union { + PACK_START struct upnp_specific_response { + /** version field */ + t_u8 version; + /** value */ + t_u8 value[]; + } PACK_END upnp; + + PACK_START struct bonjour_specific_response { + /** DNS name */ + t_u8 dns[0]; + /** DNS type */ + t_u8 dns_type; + /** version field */ + t_u8 version; + /** DNS name */ + t_u8 record[]; + } PACK_END bonjour; + } u; +} PACK_END wifidirect_response_data; + +/** HostCmd_CMD_WIFIDIRECT_SERVICE_DISCOVERY request */ +typedef PACK_START struct _wifidirect_discovery_request { + /** Header */ + WIFIDIRECT_CMD_HEADER; + /** Peer mac address */ + t_u8 peer_mac_addr[ETH_ALEN]; + /** Category */ + t_u8 category; + /** Action */ + t_u8 action; + /** Dialog taken */ + t_u8 dialog_taken; + /** Advertize protocol IE */ + t_u8 advertize_protocol_ie[MAX_ADPROTOIE_LEN]; + /** Query request Length */ + t_u16 query_len; + /** Information identifier */ + t_u8 info_id[MAX_INFOID_LEN]; + /** Request Length */ + t_u16 request_len; + /** OUI */ + t_u8 oui[MAX_OUI_LEN]; + /** OUI sub type */ + t_u8 oui_sub_type; + /** Service update indicator */ + t_u16 service_update_indicator; + /** Vendor Length */ + t_u16 vendor_len; + /** Service protocol */ + t_u8 service_protocol; + /** Service transaction Id */ + t_u8 service_transaction_id; + /** Query Data */ + wifidirect_query_data disc_query; +} PACK_END wifidirect_discovery_request; + +/** HostCmd_CMD_WIFIDIRECT_SERVICE_DISCOVERY response */ +typedef PACK_START struct _wifidirect_discovery_response { + /** Header */ + WIFIDIRECT_CMD_HEADER; + /** Peer mac address */ + t_u8 peer_mac_addr[ETH_ALEN]; + /** Category */ + t_u8 category; + /** Action */ + t_u8 action; + /** Dialog taken */ + t_u8 dialog_taken; + /** Status code */ + t_u16 status_code; + /** GAS comback reply */ + t_u16 gas_reply; + /** Advertize protocol IE */ + t_u8 advertize_protocol_ie[MAX_ADPROTOIE_LEN]; + /** Query response Length */ + t_u16 query_len; + /** Information identifier */ + t_u8 info_id[MAX_INFOID_LEN]; + /** Response Length */ + t_u16 response_len; + /** OUI */ + t_u8 oui[MAX_OUI_LEN]; + /** OUI sub type */ + t_u8 oui_sub_type; + /** Service update indicator */ + t_u16 service_update_indicator; + /** Vendor Length */ + t_u16 vendor_len; + /** Service protocol */ + t_u8 service_protocol; + /** Service transaction Id */ + t_u8 service_transaction_id; + /** Discovery status code */ + t_u8 disc_status_code; + /** Response Data */ + wifidirect_response_data disc_resp; +} PACK_END wifidirect_discovery_response; + +/** HostCmd_CMD_WIFIDIRECT_GAS_COMEBACK_SERVICE request */ +typedef PACK_START struct _wifidirect_gas_comeback_request { + /** Header */ + WIFIDIRECT_CMD_HEADER; + /** Peer mac address */ + t_u8 peer_mac_addr[ETH_ALEN]; + /** Category */ + t_u8 category; + /** Action */ + t_u8 action; + /** Dialog taken */ + t_u8 dialog_taken; +} PACK_END wifidirect_gas_comeback_request; + +/** HostCmd_CMD_WIFIDIRECT_GAS_COMEBACK_SERVICE response */ +typedef PACK_START struct _wifidirect_gas_comeback_response { + /** Header */ + WIFIDIRECT_CMD_HEADER; + /** Peer mac address */ + t_u8 peer_mac_addr[ETH_ALEN]; + /** Category */ + t_u8 category; + /** Action */ + t_u8 action; + /** Dialog taken */ + t_u8 dialog_taken; + /** Status code */ + t_u16 status_code; + /** Gas response fragment ID */ + t_u8 gas_fragment_id; + /** GAS comback reply */ + t_u16 gas_reply; + /** Advertize protocol IE */ + t_u8 advertize_protocol_ie[MAX_ADPROTOIE_LEN]; + /** Query response Length */ + t_u16 query_len; + /** Information identifier */ + t_u8 info_id[MAX_INFOID_LEN]; + /** Response Length */ + t_u16 response_len; + /** Response status code */ + t_u8 resp_status_code; + /** OUI */ + t_u8 oui[MAX_OUI_LEN]; + /** OUI sub type */ + t_u8 oui_sub_type; + /** Service update indicator */ + t_u16 service_update_indicator; + /** Vendor Length */ + t_u16 vendor_len; + /** Service protocol */ + t_u8 service_protocol; + /** Service transaction Id */ + t_u8 service_transaction_id; + /** Discovery status code */ + t_u8 disc_status_code; + /** Response Data */ + wifidirect_response_data disc_resp; +} PACK_END wifidirect_gas_comeback_response; + +/** HostCmd_CMD_WIFIDIRECT_ACTION_FRAME request */ +typedef PACK_START struct _wifidirect_action_frame { + /** Header */ + WIFIDIRECT_CMD_HEADER; + /** Peer mac address */ + t_u8 peer_mac_addr[ETH_ALEN]; + /** Category */ + t_u8 category; + /** Action */ + t_u8 action; + /** OUI */ + t_u8 oui[MAX_OUI_LEN]; + /** OUI type */ + t_u8 oui_type; + /** OUI sub type */ + t_u8 oui_sub_type; + /** Dialog taken */ + t_u8 dialog_taken; + /** IE List of TLVs */ + t_u8 ie_list[]; +} PACK_END wifidirect_action_frame; + +/** custom IE */ +typedef 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[]; +} PACK_END custom_ie; + +/** TLV buffer : custom IE */ +typedef PACK_START struct _tlvbuf_custom_ie { + /** Tag */ + t_u16 tag; + /** Length */ + t_u16 length; + /** custom IE data */ + custom_ie ie_data[]; +} PACK_END tlvbuf_custom_ie; + +/** TLV buffer : persistent group */ +typedef PACK_START struct _tlvbuf_wifidirect_persistent_group { + /** Tag */ + t_u16 tag; + /** Length */ + t_u16 length; + /** Record Index */ + t_u8 rec_index; + /** Device Role */ + t_u8 dev_role; + /** wifidirect group Bss Id */ + t_u8 group_bssid[ETH_ALEN]; + /** wifidirect device MAC address */ + t_u8 dev_mac_address[ETH_ALEN]; + /** wifidirect group SSID length */ + t_u8 group_ssid_len; + /** wifidirect group SSID */ + t_u8 group_ssid[0]; + /** wifidirect PSK length */ + t_u8 psk_len; + /** wifidirect PSK */ + t_u8 psk[0]; + /** Num of PEER MAC Addresses */ + t_u8 num_peers; + /** PEER MAC Addresses List */ + t_u8 peer_mac_addrs[][ETH_ALEN]; +} PACK_END tlvbuf_wifidirect_persistent_group; + +/** TLV buffer : WifiDirect discovery period */ +typedef PACK_START struct _tlvbuf_wifidirect_discovery_period { + /** Tag */ + t_u16 tag; + /** Length */ + t_u16 length; + /** Min discovery interval */ + t_u16 min_disc_interval; + /** Max discovery interval */ + t_u16 max_disc_interval; +} PACK_END tlvbuf_wifidirect_discovery_period; + +/** TLV buffer : WifiDirect Intent */ +typedef PACK_START struct _tlvbuf_wifidirect_intent { + /** Tag */ + t_u16 tag; + /** Length */ + t_u16 length; + /** Intent value */ + t_u8 intent; +} PACK_END tlvbuf_wifidirect_intent; + +/** TLV buffer : WifiDirect Invitation List */ +typedef PACK_START struct _tlvbuf_wifidirect_invitation_list { + /** Tag */ + t_u16 tag; + /** Length */ + t_u16 length; + /** Invitation peer address*/ + t_u8 inv_peer_addr[ETH_ALEN]; +} PACK_END tlvbuf_wifidirect_invitation_list; + +/** TLV buffer : WifiDirect Listen Channel */ +typedef PACK_START struct _tlvbuf_wifidirect_listen_channel { + /** Tag */ + t_u16 tag; + /** Length */ + t_u16 length; + /** Country str */ + t_u8 country_str[3]; + /** operating class */ + t_u8 operating_class; + /** Listen Channel */ + t_u8 listen_channel; +} PACK_END tlvbuf_wifidirect_listen_channel; + +/** TLV buffer : WifiDirect Operating Channel */ +typedef PACK_START struct _tlvbuf_wifidirect_operating_channel { + /** Tag */ + t_u16 tag; + /** Length */ + t_u16 length; + /** Country str */ + t_u8 country_str[3]; + /** operating class */ + t_u8 operating_class; + /** Operating Channel */ + t_u8 operating_channel; +} PACK_END tlvbuf_wifidirect_operating_channel; + +/** TLV buffer : WifiDirect NoA config */ +typedef PACK_START struct _tlvbuf_wifidirect_noa_config { + /** Tag */ + t_u16 tag; + /** Length */ + t_u16 length; + /** Enable/Disable NoA */ + t_u16 enable_noa; + /** Index */ + t_u8 noa_index; + /** CountType */ + t_u8 count_type; + /** Duration */ + t_u32 duration; + /** Interval */ + t_u32 interval; +} PACK_END tlvbuf_wifidirect_noa_config; + +/** TLV buffer : wifidirect OppPS config */ +typedef PACK_START struct _tlvbuf_opp_ps_config { + /** Tag */ + t_u16 tag; + /** Length */ + t_u16 length; + /** CTWindow and OppPS*/ + t_u8 ctwindow_opp_ps; +} PACK_END tlvbuf_wifidirect_opp_ps_config; + +/** TLV buffer : wifidirect capability config */ +typedef PACK_START struct _tlvbuf_capability_config { + /** Tag */ + t_u16 tag; + /** Length */ + t_u16 length; + /** Device capability */ + t_u8 dev_capability; + /** Group capability */ + t_u8 group_capability; +} PACK_END tlvbuf_wifidirect_capability_config; + +/** TLV buffer : WifiDirect Presence Request Parameters */ +typedef PACK_START struct _tlvbuf_wifidirect_presence_req_params { + /** Tag */ + t_u16 tag; + /** Length */ + t_u16 length; + /** Presence Request Type */ + t_u8 presence_req_type; + /** Duration */ + t_u32 duration; + /** Interval */ + t_u32 interval; +} PACK_END tlvbuf_wifidirect_presence_req_params; + +/** TLV buffer : WifiDirect Extended Listen Timing parameters*/ +typedef PACK_START struct _tlvbuf_mrvl_wifidirect_ext_listen_time { + /** Tag */ + t_u16 tag; + /** Length */ + t_u16 length; + /** Duration */ + t_u16 duration; + /** Interval */ + t_u16 interval; +} PACK_END tlvbuf_wifidirect_mrvl_ext_listen_time; + +/** TLV buffer : WifiDirect Provisioning parameters*/ +typedef PACK_START struct _tlvbuf_wifidirect_provisioning_params { + /** Tag */ + t_u16 tag; + /** Length */ + t_u16 length; + /** action */ + t_u16 action; + /** config methods */ + t_u16 config_methods; + /** config methods */ + t_u16 dev_password; +} PACK_END tlvbuf_wifidirect_provisioning_params; + +/** TLV buffer : WifiDirect WPS parameters*/ +typedef PACK_START struct _tlvbuf_wifidirect_wps_params { + /** Tag */ + t_u16 tag; + /** Length */ + t_u16 length; + /** action */ + t_u16 action; +} PACK_END tlvbuf_wifidirect_wps_params; + +/** Max size of custom IE buffer */ +#define MAX_SIZE_IE_BUFFER (256) +/** Size of command buffer */ +#define MRVDRV_SIZE_OF_CMD_BUFFER (3* 1024) +/** Maximum size of set/get configurations */ +#define MAX_CFG_DATA_SIZE 3000 /* less than MRVDRV_SIZE_OF_CMD_BUFFER */ +/** 4 byte header to store buf len*/ +#define BUF_HEADER_SIZE 4 +/** OUI Type WFA WIFIDIRECT */ +#define OUI_TYPE_WFA_WIFIDIRECT 9 + +/** MRVL private command ioctl number */ +#define MRVLPRIVCMD (SIOCDEVPRIVATE + 14) +/** Host Command ID bit mask (bit 11:0) */ +#define HostCmd_CMD_ID_MASK 0x0fff +/** WIFIDIRECTCMD response check */ +#define WIFIDIRECTCMD_RESP_CHECK 0x8000 + +/** Host Command ID : wifidirect mode config */ +#define HostCmd_CMD_WIFIDIRECT_MODE_CONFIG 0x00eb +/** Host Command ID: WIFIDIRECT_SET_PARAMS */ +#define HostCmd_CMD_WIFIDIRECT_PARAMS_CONFIG 0x00ea +/** Host Command ID: WIFIDIRECT_SERVICE_DISCOVERY */ +#define HostCmd_CMD_WIFIDIRECT_SERVICE_DISCOVERY 0x00ec +/** Host Command ID: WIFIDIRECT_ACTION_FRAME */ +#define HostCmd_CMD_802_11_ACTION_FRAME 0x00f4 + +/** TLV : WifiDirect param capability */ +#define TLV_TYPE_WIFIDIRECT_CAPABILITY 0x0002 +/** TLV : WifiDirect param device Id */ +#define TLV_TYPE_WIFIDIRECT_DEVICE_ID 0x0003 +/** TLV : WifiDirect param group owner intent */ +#define TLV_TYPE_WIFIDIRECT_GROUPOWNER_INTENT 0x0004 +/** TLV : WifiDirect param config timeout */ +#define TLV_TYPE_WIFIDIRECT_CONFIG_TIMEOUT 0x0005 +/** TLV : WifiDirect param channel */ +#define TLV_TYPE_WIFIDIRECT_CHANNEL 0x0006 +/** TLV : WifiDirect param group bssId */ +#define TLV_TYPE_WIFIDIRECT_GROUP_BSS_ID 0x0007 +/** TLV : WifiDirect param extended listen time */ +#define TLV_TYPE_WIFIDIRECT_EXTENDED_LISTEN_TIME 0x0008 +/** TLV : WifiDirect param intended address */ +#define TLV_TYPE_WIFIDIRECT_INTENDED_ADDRESS 0x0009 +/** TLV : WifiDirect param manageability */ +#define TLV_TYPE_WIFIDIRECT_MANAGEABILITY 0x000a +/** TLV : WifiDirect param channel list */ +#define TLV_TYPE_WIFIDIRECT_CHANNEL_LIST 0x000b +/** TLV : WifiDirect Notice of Absence */ +#define TLV_TYPE_WIFIDIRECT_NOTICE_OF_ABSENCE 0x000c +/** TLV : WifiDirect param device Info */ +#define TLV_TYPE_WIFIDIRECT_DEVICE_INFO 0x000d +/** TLV : WifiDirect param Group Info */ +#define TLV_TYPE_WIFIDIRECT_GROUP_INFO 0x000e +/** TLV : WifiDirect param group Id */ +#define TLV_TYPE_WIFIDIRECT_GROUP_ID 0x000f +/** TLV : WifiDirect param interface */ +#define TLV_TYPE_WIFIDIRECT_INTERFACE 0x0010 +/** TLV : WifiDirect param operating channel */ +#define TLV_TYPE_WIFIDIRECT_OPCHANNEL 0x0011 +/** TLV : WifiDirect param invitation flag */ +#define TLV_TYPE_WIFIDIRECT_INVITATION_FLAG 0x0012 + +/** enum : WPS attribute type */ +typedef enum { + SC_AP_Channel = 0x1001, + SC_Association_State = 0x1002, + SC_Authentication_Type = 0x1003, + SC_Authentication_Type_Flags = 0x1004, + SC_Authenticator = 0x1005, + SC_Config_Methods = 0x1008, + SC_Configuration_Error = 0x1009, + SC_Confirmation_URL4 = 0x100A, + SC_Confirmation_URL6 = 0x100B, + SC_Connection_Type = 0x100C, + SC_Connection_Type_Flags = 0x100D, + SC_Credential = 0x100E, + SC_Device_Name = 0x1011, + SC_Device_Password_ID = 0x1012, + SC_E_Hash1 = 0x1014, + SC_E_Hash2 = 0x1015, + SC_E_SNonce1 = 0x1016, + SC_E_SNonce2 = 0x1017, + SC_Encrypted_Settings = 0x1018, + SC_Encryption_Type = 0X100F, + SC_Encryption_Type_Flags = 0x1010, + SC_Enrollee_Nonce = 0x101A, + SC_Feature_ID = 0x101B, + SC_Identity = 0X101C, + SC_Identity_Proof = 0X101D, + SC_Key_Wrap_Authenticator = 0X101E, + SC_Key_Identifier = 0X101F, + SC_MAC_Address = 0x1020, + SC_Manufacturer = 0x1021, + SC_Message_Type = 0x1022, + SC_Model_Name = 0x1023, + SC_Model_Number = 0x1024, + SC_Network_Index = 0x1026, + SC_Network_Key = 0x1027, + SC_Network_Key_Index = 0x1028, + SC_New_Device_Name = 0x1029, + SC_New_Password = 0x102A, + SC_OOB_Device_Password = 0X102C, + SC_OS_Version = 0X102D, + SC_Power_Level = 0X102F, + SC_PSK_Current = 0x1030, + SC_PSK_Max = 0x1031, + SC_Public_Key = 0x1032, + SC_Radio_Enabled = 0x1033, + SC_Reboot = 0x1034, + SC_Registrar_Current = 0x1035, + SC_Registrar_Established = 0x1036, + SC_Registrar_List = 0x1037, + SC_Registrar_Max = 0x1038, + SC_Registrar_Nonce = 0x1039, + SC_Request_Type = 0x103A, + SC_Response_Type = 0x103B, + SC_RF_Band = 0X103C, + SC_R_Hash1 = 0X103D, + SC_R_Hash2 = 0X103E, + SC_R_SNonce1 = 0X103F, + SC_R_SNonce2 = 0x1040, + SC_Selected_Registrar = 0x1041, + SC_Serial_Number = 0x1042, + SC_Simple_Config_State = 0x1044, + SC_SSID = 0x1045, + SC_Total_Networks = 0x1046, + SC_UUID_E = 0x1047, + SC_UUID_R = 0x1048, + SC_Vendor_Extension = 0x1049, + SC_Version = 0x104A, + SC_X_509_Certificate_Request = 0x104B, + SC_X_509_Certificate = 0x104C, + SC_EAP_Identity = 0x104D, + SC_Message_Counter = 0x104E, + SC_Public_Key_Hash = 0x104F, + SC_Rekey_Key = 0x1050, + SC_Key_Lifetime = 0x1051, + SC_Permitted_Config_Methods = 0x1052, + SC_SelectedRegistrarConfigMethods = 0x1053, + SC_Primary_Device_Type = 0x1054, + SC_Secondary_Device_Type_List = 0x1055, + SC_Portable_Device = 0x1056, + SC_AP_Setup_Locked = 0x1057, + SC_Application_List = 0x1058, + SC_EAP_Type = 0x1059, + SC_Initialization_Vector = 0x1060, + SC_Key_Provided_Auto = 0x1061, + SC_8021x_Enabled = 0x1062, + SC_App_Session_key = 0x1063, + SC_WEP_Transmit_Key = 0x1064, +} wps_simple_config_attribute; + +/** Function Prototype Declaration */ +int is_input_valid(valid_inputs cmd, int argc, char *argv[]); +unsigned char hexc2bin(char chr); + +/** + * @brief isdigit for String. + * + * @param x Char string + * @return FAILURE for non-digit. + * SUCCESS for digit + */ +static inline int +ISDIGIT(char *x) +{ + unsigned int i; + for (i = 0; i < strlen(x); i++) + if (isdigit(x[i]) == 0) + return FAILURE; + return SUCCESS; +} +#endif /* _WIFIDIRECT_H */ diff --git a/mxm_wifiex/wlan_src/script/load b/mxm_wifiex/wlan_src/script/load new file mode 100644 index 0000000..e9819c9 --- /dev/null +++ b/mxm_wifiex/wlan_src/script/load @@ -0,0 +1,16 @@ +#! /bin/bash +if echo $1 2>&1 | grep dbg > /dev/null; then + insmod mlan-dbg.ko +else + insmod mlan.ko +fi +insmod $1.ko $2 $3 $4 $5 $6 $7 $8 +for (( i = 1; i <= 10; i++ )) +do + ifconfig -a 2>&1 | grep -E "(mlan0|uap0|wfd0)" > /dev/null + if [ $? -eq 0 ]; then + exit + fi + sleep 1 +done + diff --git a/mxm_wifiex/wlan_src/script/unload b/mxm_wifiex/wlan_src/script/unload new file mode 100644 index 0000000..1251e58 --- /dev/null +++ b/mxm_wifiex/wlan_src/script/unload @@ -0,0 +1,20 @@ +#! /bin/bash +ifconfig mlan0 down +ifconfig uap0 down +ifconfig mmlan0 down +ifconfig muap0 down +ifconfig wfd0 down +ifconfig wfd1 down +ifconfig mwfd0 down +ifconfig mwfd1 down +for (( i = 0; i <= 30; i++ )) +do + rmmod moal 2> /dev/null + lsmod 2>&1 | grep moal > /dev/null + if [ ! $? -eq 0 ]; then + break + fi + sleep 1 +done +rmmod mlan +sleep 5 diff --git a/mxm_wifiex/wlan_src/script/usbconfig b/mxm_wifiex/wlan_src/script/usbconfig new file mode 100644 index 0000000000000000000000000000000000000000..bc61a611036a4979cf18cac41f20a436f352c382 GIT binary patch literal 9098 zcmds6eQ;FQb-!9IuvTP{h=OGx&a+z?|~vU^t%%x2wJwTI#-I?*ZADdXT6$)RAL^klzVf4!R2jHAFM$HqcVghd}ip zx|MxafIbYO?2mxnFL4}`XovKbuBbB&I;Z~^>+%PX)AzS)%xsx1FG0QtbO&f9NctD~ z{6szJXVy20Th&?`h13F~O%nu2cY}yuAwY6K#E%dly@Ys1xJ5eT8l>X*`Ua{7-1ic_4lRH2P97L_apd`Z|nv$%oIP zp2-7|zX$E)XI%sAU$6E1scwIc4M^Vyk^dF}lF^@Q;k9RtzPF1h*($`-$jN_?miNyZ ze^a;rj>dcDjc=j8L+iu&*s1%!sre5BkNNan1?*vbW$$9C7g%Mo@c*DH&R~J{U&!~a zX$!CA>hBQtwnz4E-m`0~u=|qfq_B7F-nV7*ZhPPM?fWA=cF*Q5yCb%+A3S1rC;F3l zH<8<#isti)ys+*5flS)YyV0C$+X6xbj75xd<-=4`P(vmTkNF}2A zgq=)dfWBxfA!}o)OkS5VX*ZWi*#r50*^+m2iCiv|lK^VFG%H4f){DFw&lFrS5KW~r zG0~UJL1-Upb1{q%8_3F{%;Jy%Gw`3z*kF#j$xK=#1|iPgwGWoXlWDt~JVTfol1Xg$fJo?d(T26K5Qhub@B$nRT!Z6#IT z%yB66Fvmf0kU4h2A?7&H4l~CA6K9S?&0&s_Q_P`EmN^!<%N&Q$Aafjif504v&~fHC zd`>XO=6r@Z4#WecH;Xqz-e=gVEl~4w9v7LUyzuVI;)9KOH7L$&d~UAiD|jBfjBEMJ>YZ_ zAC{P&aCQ=RNlcG8UBsOd(=*ON;x>utA?Gl$B{4na(4g@KiRm#XODrU&=bS;}iFZ-a zLJvB}iLXmcPdd*Kk4a3AI;V+8f!DtEnbPaU8xvhU-Ogd02Tncy9(vfR|6(xYWgu_z z^lA8hzlRRu(cz0LaBy{(i_>U1IqC+gV+S9-a`Cj}!TcQG^ctiKcS+?VBS%DWH2C%B zfveYEWL9oCd96@+bpcswu3Rj=t>*N_LwJlp)}7}$1PTqsoAnMWt7FAW4UoeD6z}E8 zG?|J+(}AO_iZ_Gh$aJ;i)1%sNeV4T>R~~(&`|9Ncz>ouoE$BL(4iEWsw`IGMlVOE==O4CN()}8l`2O< zOU@m?yFrMJk?AF0{3D9o6OzOH{q-6SRXhCKXe~u1AVZBfvE*E5aARcZbBXeS35X=q zmikiU=Hie^2cSHaYJ_x>7x58@dWr_<_rYGIxyw512pcO-JY%R8o)TVE-1uCF+B zP83#B>OM;SfRTEJQpdThuuPYHCvvV!cD|8dN4>afl<-+yAg0Et=V$E=+cVa_hEl%|n2kV5p3~~UZ^4?WB zegoCw(KE^Y^KWxp;eMFY<1Ut?PkNh_irO8OLy%M)Y!>cvc^FPf5zszV?rfH)C$^Sk zX^;bRHCD3?@~rgEs}a2(Fg7HH*6qSkqrP3uN^IzOhGVbEj3+rt5eLN!k=@s`sxRMvPK zQ0e8##uJ{>t8ES)incc80Cg@^-A!P@WMLI>spXaH@C@mMKC>r0CZu|X0-Tj!f(GZ6 z29*_5`aaa?=f>DCq~hLbj4#c_g9p!!-+g#L^fC{?<#=iF(%>8^He)G_e3}37R_oZ> zw=YZuKKW{XS?Ncmx2sKO%X=nT-`RfQoxmrrmVTN0S@BZ+qo1+$a}P3&z$tw zy3dRf!zf+e!?64jw5acKzE9>7y_t+Fx@Bf<%cK+HKt9@^xZe_%W#MH!mPz*|`>i!c zENk_VL@tk4-Buj=GYwimOTJF*N*{@)l5tDDxm)SNKyM;fCvM*wO|Nn-zT{ic^fBwe z{w7 zgl7urc%4uq@$*2BaKF`(w^p~rTkFL3Xfl)ONFHnI0$ zm(Ol(GQ{{L_^pj)1_q)qEuT%ql6}cU{BHB@jmfO?kT5yRe0CZ7G0Obz=XWc=#rZwR z@3Ec3co#?BbOP__%%2K|C^LhO{C3A9Ox_tF6a234z{=*A!B;`%4uRkA(|51HA+~3wi}~4fF=cC~^=B{3d+UNn>^TZ(vidqPz$P%sn8nW9!!Yt<|`W zX|+Bc?g)2S?QL!A+CI^~)>_?->E9W3RsEXwR`LIzIh;Q>;6{5z7~iofcT7osGiOB@ z+b0p;yk*xKH`*`4PBia`aQs*r9aZk;M7Td)2M%5kxOn^*v`FUKSg_wfTDE^En${oaHIxgk-K=@pjeQtp71{iog7kM9K^ zUk~_t-iPnceSG}(J@h`~z6?J4nB&U3Zt#tv%=u-ae$?aJAlgB`Has8N@BlEnqe_;E zzY8*ae2#R0?;sg;A`j^z$nc#4-zo5QXdY%p_7#*lKF8(j-YEFE&P_6WS5ZNECXsKk zufh~zo|I+yu4424$N=Pqk2&Yoq!2FLyWlA9f9lC`sR!3Gbu;N8?!eX?rBG?)nRb89 z^MhDLLsTq5VKp+(1BKNHd~PeO2H^8tVKrOkd0Q)IRP9&Qt`<7?rNT0k&vS)o#q51| zE$+LSxSyEU%AKj=H45`BWA?teR^R+{AEsnzogIvD~b5?NYH-j;G zNaj7DR-dq3cdW0KZzZ$$)3y5Th3iPQtLOvQi^BesgZ+6j&8AuzP4Q#@jwk;LIgbs` zD0u=mWV$A_UrQ(z<;XekM>;vHi`EA zEdcMuIP=u^hsd9YKA%EP{@0O@0W%Im{1)=oQZV$Y#sO@E{{k*+{6XM&IT-pEjqe3c zoC=1%ukl9Uwvk}yCmMem_=ztBL;nf96!L!$*sKr6C;EUNK>vGn`xC%SEg-I@Q@~uG z+&PViTzy%$->uufp|PX!Ujm!?YzW+{@{X9v#Fzd-<9^gp{!cajmd3Y$PwV+@3@j7x z0`op}i)^nKi}m4R;y3qcY~oKFf&KBP&AQ#hpZ04!tj9Z~F;_PAc^sJQU)g(y7y{;H zroqnw^En7s>Cdm|{+{mt4Pf4o8UC}tet-N8Ft2vIb^m_^Hv5h7tJm3%J70dVaK8Q> zn90PmYH_6bg$zmQuT*(*t60w|{cME-e;TYmTTYL6(+q-w|??FJ!wzthe z4{n`l$|5p^ci?O);U?nYwP1~B?EX}yH=45Lo3tG*3?jsYH*7mz7#KKaL`U{+o0V+9 z_U_GlBDO&s#*}BJ%GY!$b>@p73Kw`oAmYhvunSNCr& zxS9RZztEZAZrXeqt@WEBb@B%=WpwjB@yu-{_%Sf>a$Nt6;HUqZ)ZgM5qep9q>=0|>gcKqfr N_*@%|hvx*x{|6e$5-I=y literal 0 HcmV?d00001 diff --git a/mxm_wifiex/wlan_src/script/wifidirect/start_auto_go.sh b/mxm_wifiex/wlan_src/script/wifidirect/start_auto_go.sh new file mode 100644 index 0000000..78aa8a8 --- /dev/null +++ b/mxm_wifiex/wlan_src/script/wifidirect/start_auto_go.sh @@ -0,0 +1,30 @@ +#!/bin/bash +# iwpriv mlan0 drvdbg 0x20037 +# change the mac address +./wifidirect/update_mac.sh +echo "wfd0 Mac address updated in config/wifidirect.conf" + + +./wifidirectutl wfd0 wifidirect_config config/wifidirect.conf +#ifdef STREAM_2X2 +iwpriv wfd0 bssrole 1 +#else +# iwpriv wfd0 bssrole 1 +#endif +./uaputl.exe -i wfd0 sys_config config/uaputl_wifidirect.conf +#ifdef STREAM_2X2 +iwpriv wfd0 bssrole 0 +#else +# iwpriv wfd0 bssrole 0 +#endif +# iwpriv wfd0 bssrole 1 +# change the group owner parameters +# either in uaputl_wifidirect.conf or using CLI below +#./uaputl.exe -i wfd0 sys_cfg_wpa_passphrase 1234567890 +#./uaputl.exe -i wfd0 sys_cfg_eapol_gwk_hsk 2000 3 +#./uaputl.exe -i wfd0 sys_cfg_eapol_pwk_hsk 2000 3 +# iwpriv wfd0 bssrole 0 +./wifidirectutl wfd0 wifidirect_mode 1 +iwpriv wfd0 bssrole 1 +./wifidirectutl wfd0 wifidirect_mode 2 +./uaputl.exe -i wfd0 bss_start diff --git a/mxm_wifiex/wlan_src/script/wifidirect/start_find_phase.sh b/mxm_wifiex/wlan_src/script/wifidirect/start_find_phase.sh new file mode 100644 index 0000000..26ddd60 --- /dev/null +++ b/mxm_wifiex/wlan_src/script/wifidirect/start_find_phase.sh @@ -0,0 +1,25 @@ +#!/bin/bash +# iwpriv wfd0 drvdbg 0x20037 +#change the mac address +./wifidirect/update_mac.sh +echo "wfd0 Mac address updated in config/wifidirect.conf" + +#ifdef STREAM_2X2 +iwpriv wfd0 bssrole 1 +#else +# iwpriv wfd0 bssrole 1 +#endif +./uaputl.exe -i wfd0 sys_config config/uaputl_wifidirect.conf +#ifdef STREAM_2X2 +iwpriv wfd0 bssrole 0 +#else +# iwpriv wfd0 bssrole 0 +#endif +./wifidirectutl wfd0 wifidirect_config config/wifidirect.conf +# change the passphrase +# either in uaputl_wifidirect.conf or using CLI below +#./uaputl.exe -i wfd0 sys_cfg_wpa_passphrase 1234567890 +./wifidirectutl wfd0 wifidirect_mode 1 +./wifidirectutl wfd0 wifidirect_params_config config/wifidirect.conf +./mlanutl wfd0 hostcmd config/bg_scan_wifidirect.conf bgscfg +./wifidirectutl wfd0 wifidirect_mode 4 diff --git a/mxm_wifiex/wlan_src/script/wifidirect/start_listen_state.sh b/mxm_wifiex/wlan_src/script/wifidirect/start_listen_state.sh new file mode 100644 index 0000000..91c1e4d --- /dev/null +++ b/mxm_wifiex/wlan_src/script/wifidirect/start_listen_state.sh @@ -0,0 +1,18 @@ +#!/bin/bash +iwpriv wfd0 drvdbg 0x20037 +# change the mac address +ifconfig mlan0 hw ether 00:50:43:21:0e:08 +ifconfig wfd0 hw ether 00:50:43:21:0e:08 +ifconfig uap0 hw ether 00:50:43:21:0e:08 + +iwpriv wfd0 deepsleep 0 +iwconfig wfd0 power off + +iwpriv wfd0 bssrole 1 +./uaputl.exe -i wfd0 sys_config config/uaputl_wifidirect.conf +iwpriv wfd0 bssrole 0 +./wifidirectutl wfd0 wifidirect_config config/wifidirect.conf +./uaputl.exe -i wfd0 sys_cfg_protocol 32 +./uaputl.exe -i wfd0 sys_cfg_cipher 8 8 +./uaputl.exe -i wfd0 sys_cfg_wpa_passphrase 1234567890 +./wifidirectutl wfd0 wifidirect_mode 1 diff --git a/mxm_wifiex/wlan_src/script/wifidirect/stop_auto_go.sh b/mxm_wifiex/wlan_src/script/wifidirect/stop_auto_go.sh new file mode 100644 index 0000000..eda03ef --- /dev/null +++ b/mxm_wifiex/wlan_src/script/wifidirect/stop_auto_go.sh @@ -0,0 +1,8 @@ +#!/bin/bash +./uaputl.exe -i wfd0 bss_stop +sleep 1 +iwpriv wfd0 bssrole 0 +./wifidirectutl wfd0 wifidirect_mode 0 +# IE clear assume index 0, 1 +./uaputl.exe -i wfd0 sys_cfg_custom_ie 0 0 +./uaputl.exe -i wfd0 sys_cfg_custom_ie 1 0 diff --git a/mxm_wifiex/wlan_src/script/wifidirect/stop_wifidirect_client.sh b/mxm_wifiex/wlan_src/script/wifidirect/stop_wifidirect_client.sh new file mode 100644 index 0000000..5ae1ad5 --- /dev/null +++ b/mxm_wifiex/wlan_src/script/wifidirect/stop_wifidirect_client.sh @@ -0,0 +1,6 @@ +#!/bin/bash +# deauth the GO first +./wifidirectutl wfd0 wifidirect_mode 0 +# IE clear assume index 0, 1 +./uaputl.exe -i wfd0 sys_cfg_custom_ie 0 0 +./uaputl.exe -i wfd0 sys_cfg_custom_ie 1 0 diff --git a/mxm_wifiex/wlan_src/script/wifidirect/update_mac.sh b/mxm_wifiex/wlan_src/script/wifidirect/update_mac.sh new file mode 100644 index 0000000..d744db9 --- /dev/null +++ b/mxm_wifiex/wlan_src/script/wifidirect/update_mac.sh @@ -0,0 +1,16 @@ +#!/bin/bash +MAC=`ifconfig wfd0 | grep wfd0 | tr -s ' ' | cut -d ' ' -f5` +MAC26=`echo $MAC | cut -d ':' -f2-6` +LAA=`echo $MAC | cut -d ':' -f1` +LAA=$((0x$LAA+2)) +if [ $LAA -lt 16 ] ; then +LAA=`printf "%X\n" $LAA` +MACLAA=0$LAA:$MAC26 +else +LAA=`printf "%X\n" $LAA` +MACLAA=$LAA:$MAC26 +fi +sed "s/00:50:43:00:00:00/$MAC/" config/wifidirect.conf > tmp$$ +mv tmp$$ config/wifidirect.conf +sed "s/02:50:43:00:00:00/$MACLAA/" config/wifidirect.conf > tmp$$ +mv tmp$$ config/wifidirect.conf